Skip to content

Commit

Permalink
Merge 0b83cad into 723346f
Browse files Browse the repository at this point in the history
  • Loading branch information
kibertoad committed Nov 17, 2018
2 parents 723346f + 0b83cad commit d897862
Show file tree
Hide file tree
Showing 8 changed files with 261 additions and 110 deletions.
14 changes: 10 additions & 4 deletions src/migrate/Migrator.js
Expand Up @@ -7,6 +7,7 @@ import {
each,
filter,
get,
isFunction,
isBoolean,
isEmpty,
isUndefined,
Expand Down Expand Up @@ -46,10 +47,15 @@ const CONFIG_DEFAULT = Object.freeze({
// the migration.
export default class Migrator {
constructor(knex) {
this.knex = knex;
this.config = getMergedConfig(knex.client.config.migrations);
this.generator = new MigrationGenerator(knex.client.config.migrations);

// Clone knex instance and remove post-processing that is unnecessary for internal queries from a cloned config
this.knex = isFunction(knex)
? knex.withUserParams(knex.userParams)
: Object.assign({}, knex);
this.knex.client.config.wrapIdentifier = null;
this.knex.client.config.postProcessResponse = null;

this.config = getMergedConfig(this.knex.client.config.migrations);
this.generator = new MigrationGenerator(this.knex.client.config.migrations);
this._activeMigration = {
fileName: null,
};
Expand Down
29 changes: 17 additions & 12 deletions src/migrate/table-creator.js
Expand Up @@ -10,21 +10,26 @@ export function ensureTable(tableName, schemaName, trxOrKnex) {
const lockTableWithSchema = getLockTableNameWithSchema(tableName, schemaName);
return getSchemaBuilder(trxOrKnex, schemaName)
.hasTable(tableName)
.then(
(exists) =>
!exists && _createMigrationTable(tableName, schemaName, trxOrKnex)
)
.then(() => getSchemaBuilder(trxOrKnex, schemaName).hasTable(lockTable))
.then(
(exists) =>
.then((exists) => {
return !exists && _createMigrationTable(tableName, schemaName, trxOrKnex);
})
.then(() => {
return getSchemaBuilder(trxOrKnex, schemaName).hasTable(lockTable);
})
.then((exists) => {
return (
!exists && _createMigrationLockTable(lockTable, schemaName, trxOrKnex)
)
.then(() => getTable(trxOrKnex, lockTable, schemaName).select('*'))
.then(
(data) =>
);
})
.then(() => {
return getTable(trxOrKnex, lockTable, schemaName).select('*');
})
.then((data) => {
return (
!data.length &&
trxOrKnex.into(lockTableWithSchema).insert({ is_locked: 0 })
);
);
});
}

function _createMigrationTable(tableName, schemaName, trxOrKnex) {
Expand Down
124 changes: 90 additions & 34 deletions src/util/make-knex.js
Expand Up @@ -6,28 +6,26 @@ import FunctionHelper from '../functionhelper';
import QueryInterface from '../query/methods';
import { assign } from 'lodash';
import batchInsert from './batchInsert';
import * as bluebird from 'bluebird';

export default function makeKnex(client) {
// The object we're potentially using to kick off an initial chain.
function knex(tableName, options) {
const qb = knex.queryBuilder();
if (!tableName)
client.logger.warn(
'calling knex without a tableName is deprecated. Use knex.queryBuilder() instead.'
);
return tableName ? qb.table(tableName, options) : qb;
return createQueryBuilder(knex.context, tableName, options);
}
redefineProperties(knex, client);
return knex;
}

assign(knex, {
Promise: require('bluebird'),

// A new query builder instance.
function initContext(knexFn) {
const knexContext = knexFn.context || {};
assign(knexContext, {
queryBuilder() {
return client.queryBuilder();
return this.client.queryBuilder();
},

raw() {
return client.raw.apply(client, arguments);
return this.client.raw.apply(this.client, arguments);
},

batchInsert(table, batch, chunkSize = 1000) {
Expand All @@ -37,41 +35,48 @@ export default function makeKnex(client) {
// Runs a new transaction, taking a container and returning a promise
// for when the transaction is resolved.
transaction(container, config) {
const trx = client.transaction(container, config);
const trx = this.client.transaction(container, config);
trx.userParams = this.userParams;
return trx;
},

// Typically never needed, initializes the pool for a knex client.
initialize(config) {
return client.initializePool(config);
return this.client.initializePool(config);
},

// Convenience method for tearing down the pool.
destroy(callback) {
return client.destroy(callback);
return this.client.destroy(callback);
},

ref(ref) {
return client.ref(ref);
return this.client.ref(ref);
},

withUserParams(params) {
const knexClone = shallowCloneFunction(knex); // We need to include getters in our clone
if (knex.client) {
knexClone.client = Object.assign({}, knex.client); // Clone client to avoid leaking listeners that are set on it
const parentPrototype = Object.getPrototypeOf(knex.client);
const knexClone = shallowCloneFunction(knexFn); // We need to include getters in our clone
if (this.client) {
knexClone.client = Object.assign({}, this.client); // Clone client to avoid leaking listeners that are set on it
knexClone.client.config = Object.assign({}, this.client.config); // Clone client config to make sure they can be modified independently
const parentPrototype = Object.getPrototypeOf(this.client);
if (parentPrototype) {
Object.setPrototypeOf(knexClone.client, parentPrototype);
}
}

redefineProperties(knexClone);
redefineProperties(knexClone, knexClone.client);
knexClone.userParams = params;
return knexClone;
},
});

if (!knexFn.context) {
knexFn.context = knexContext;
}
}

function redefineProperties(knex, client) {
// Allow chaining methods from the root object, before
// any other information is specified.
QueryInterface.forEach(function(method) {
Expand All @@ -81,17 +86,47 @@ export default function makeKnex(client) {
};
});

knex.client = client;
redefineProperties(knex);
Object.defineProperties(knex, {
context: {
get() {
return knex._context;
},
set(context) {
knex._context = context;

// Redefine public API for knex instance that would be proxying methods from correct context
knex.raw = context.raw;
knex.batchInsert = context.batchInsert;
knex.transaction = context.transaction;
knex.initialize = context.initialize;
knex.destroy = context.destroy;
knex.ref = context.ref;
knex.withUserParams = context.withUserParams;
knex.queryBuilder = context.queryBuilder;
},
configurable: true,
},

client.makeKnex = makeKnex;
client: {
get() {
return knex.context.client;
},
set(client) {
knex.context.client = client;
},
configurable: true,
},

knex.userParams = {};
return knex;
}
userParams: {
get() {
return knex.context.userParams;
},
set(userParams) {
knex.context.userParams = userParams;
},
configurable: true,
},

function redefineProperties(knex) {
Object.defineProperties(knex, {
schema: {
get() {
return knex.client.schemaBuilder();
Expand Down Expand Up @@ -121,6 +156,12 @@ function redefineProperties(knex) {
},
});

initContext(knex);
knex.Promise = bluebird;
knex.client = client;
knex.client.makeKnex = makeKnex;
knex.userParams = {};

// Hook up the "knex" object as an EventEmitter.
const ee = new EventEmitter();
for (const key in ee) {
Expand All @@ -142,13 +183,28 @@ function redefineProperties(knex) {
});
}

function createQueryBuilder(knexContext, tableName, options) {
const qb = knexContext.queryBuilder();
if (!tableName)
knexContext.client.logger.warn(
'calling knex without a tableName is deprecated. Use knex.queryBuilder() instead.'
);
return tableName ? qb.table(tableName, options) : qb;
}

function shallowCloneFunction(originalFunction) {
const clonedFunction = originalFunction.bind(
Object.create(
Object.getPrototypeOf(originalFunction),
Object.getOwnPropertyDescriptors(originalFunction)
)
const fnContext = Object.create(
Object.getPrototypeOf(originalFunction),
Object.getOwnPropertyDescriptors(originalFunction)
);

const knexContext = {};
const knexFnWrapper = (tableName, options) => {
return createQueryBuilder(knexContext, tableName, options);
};

const clonedFunction = knexFnWrapper.bind(fnContext);
Object.assign(clonedFunction, originalFunction);
clonedFunction._context = knexContext;
return clonedFunction;
}

0 comments on commit d897862

Please sign in to comment.