import _ from 'lodash';

/**
 * @ignore
 */
export function getDialect(knex) {
  return knex.client.dialect;
}

/**
 * @ignore
 */
export function isPostgres(knex) {
  return getDialect(knex) === 'postgresql';
}

/**
 * @ignore
 */
export function isMySql(knex) {
  return getDialect(knex) === 'mysql';
}

/**
 * @ignore
 */
export function isSqlite(knex) {
  return getDialect(knex) === 'sqlite3';
}

/**
 * @ignore
 */
export function isKnexQueryBuilder(knexQueryBuilder) {
  return knexQueryBuilder
    && knexQueryBuilder.client
    && _.isString(knexQueryBuilder.client.dialect);
}

/**
 * @ignore
 */
export function overwriteForDatabase(input) {
  if (!input) {
    input = (inst) => inst.knex();
  }

  if (_.isFunction(input)) {
    return overwriteForDatabaseClass(input);
  } else {
    return overwriteForDatabaseMethod(input);
  }
}

/**
 * @ignore
 */
function overwriteForDatabaseClass(input) {
  return function (constructor) {
    const getKnex = input;

    if (constructor['@overwriteForDatabase']) {
      return;
    }

    Object.defineProperty(constructor, '@overwriteForDatabase', {
      enumerable: false,
      writable: false,
      value: { getKnex }
    });
  };
}

/**
 * @ignore
 */
function overwriteForDatabaseMethod(input) {
  return function (target, property, descriptor) {
    const methodNameByDialect = input;
    const defaultImpl = descriptor.value;

    descriptor.value = function () {
      let knex = this.constructor['@overwriteForDatabase'].getKnex(this);
      let dialect = getDialect(knex);

      if (dialect in methodNameByDialect) {
        let methodName = methodNameByDialect[dialect];
        return this[methodName].apply(this, arguments);
      } else {
        return defaultImpl.apply(this, arguments);
      }
    };
  };
}

@@ -18,16 +18,77 @@
 dash';%0A%0A
+const OVERWRITE_FOR_DATABASE_KEY = %60@overwriteForDatabase%60;%0A%0A
 /**%0A * @
@@ -713,62 +713,401 @@
 %7B%0A  
-if (!input) %7B%0A    input = (inst) =%3E inst.knex();%0A  %7D
+// If there is no input or if the input is a function, we assume that the%0A  // decorator was applied to a class instead of a method.%0A  let isClassDecorator = _.isUndefined(input) %7C%7C _.isFunction(input);%0A%0A  if (isClassDecorator) %7B%0A    // In case of class decorator, the input should be a function that returns%0A    // a knex instance that the method version can use.%0A    let getKnex = input;
 %0A%0A
+  
   if
@@ -1116,26 +1116,146 @@
 _.is
-Function(input)) %7B
+Undefined(getKnex)) %7B%0A      // The default getter attempts to call a function called %60knex%60.%0A      getKnex = (inst) =%3E inst.knex();%0A    %7D%0A
 %0A   
@@ -1288,21 +1288,23 @@
 seClass(
-input
+getKnex
 );%0A  %7D e
@@ -1416,21 +1416,23 @@
 seClass(
-input
+getKnex
 ) %7B%0A  re
@@ -1469,79 +1469,110 @@
     
+if (
 const
- getKnex = input;%0A%0A    if (constructor%5B'@overwriteForDatabase'%5D) %7B
+ructor%5BOVERWRITE_FOR_DATABASE_KEY%5D) %7B%0A      // Knex getter is already registered. Do nothing.
 %0A   
@@ -1628,39 +1628,42 @@
 ructor, 
-'@overwriteForDatabase'
+OVERWRITE_FOR_DATABASE_KEY
 , %7B%0A    
@@ -2019,31 +2019,34 @@
 tor%5B
-'@overwriteForDatabase'
+OVERWRITE_FOR_DATABASE_KEY
 %5D.ge
@@ -2097,16 +2097,71 @@
 knex);%0A%0A
+      // Call the correct method based on the dialect.%0A
       if

refactor dbUtils