2016-05-17 01:01:34 +10:00
|
|
|
import { EventEmitter } from 'events';
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2018-08-24 11:39:20 +02:00
|
|
|
import Migrator from '../migrate/Migrator';
|
2016-05-17 01:01:34 +10:00
|
|
|
import Seeder from '../seed';
|
|
|
|
import FunctionHelper from '../functionhelper';
|
|
|
|
import QueryInterface from '../query/methods';
|
2018-07-09 08:10:34 -04:00
|
|
|
import { assign } from 'lodash';
|
2017-03-22 21:44:36 +01:00
|
|
|
import batchInsert from './batchInsert';
|
2018-11-19 12:55:50 +01:00
|
|
|
import * as bluebird from 'bluebird';
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
export default function makeKnex(client) {
|
2015-05-09 13:58:18 -04:00
|
|
|
// The object we're potentially using to kick off an initial chain.
|
2017-01-26 16:22:09 +00:00
|
|
|
function knex(tableName, options) {
|
2018-11-19 12:55:50 +01:00
|
|
|
return createQueryBuilder(knex.context, tableName, options);
|
2015-05-09 13:58:18 -04:00
|
|
|
}
|
2018-11-19 12:55:50 +01:00
|
|
|
redefineProperties(knex, client);
|
|
|
|
return knex;
|
|
|
|
}
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2018-11-19 12:55:50 +01:00
|
|
|
function initContext(knexFn) {
|
|
|
|
const knexContext = knexFn.context || {};
|
|
|
|
assign(knexContext, {
|
2016-05-17 01:01:34 +10:00
|
|
|
queryBuilder() {
|
2018-11-19 12:55:50 +01:00
|
|
|
return this.client.queryBuilder();
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
raw() {
|
2018-11-19 12:55:50 +01:00
|
|
|
return this.client.raw.apply(this.client, arguments);
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
batchInsert(table, batch, chunkSize = 1000) {
|
2017-03-22 21:44:36 +01:00
|
|
|
return batchInsert(this, table, batch, chunkSize);
|
2016-02-02 21:19:36 +01:00
|
|
|
},
|
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// Runs a new transaction, taking a container and returning a promise
|
|
|
|
// for when the transaction is resolved.
|
2016-05-17 01:01:34 +10:00
|
|
|
transaction(container, config) {
|
2018-11-19 12:55:50 +01:00
|
|
|
const trx = this.client.transaction(container, config);
|
2018-09-26 22:27:59 +02:00
|
|
|
trx.userParams = this.userParams;
|
|
|
|
return trx;
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
// Typically never needed, initializes the pool for a knex client.
|
2016-05-17 01:01:34 +10:00
|
|
|
initialize(config) {
|
2018-11-19 12:55:50 +01:00
|
|
|
return this.client.initializePool(config);
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
// Convenience method for tearing down the pool.
|
2016-05-17 01:01:34 +10:00
|
|
|
destroy(callback) {
|
2018-11-19 12:55:50 +01:00
|
|
|
return this.client.destroy(callback);
|
2018-05-02 12:31:16 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
ref(ref) {
|
2018-11-19 12:55:50 +01:00
|
|
|
return this.client.ref(ref);
|
2018-07-09 08:10:34 -04:00
|
|
|
},
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2018-09-26 22:27:59 +02:00
|
|
|
withUserParams(params) {
|
2018-11-19 12:55:50 +01:00
|
|
|
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);
|
2018-09-26 22:27:59 +02:00
|
|
|
if (parentPrototype) {
|
|
|
|
Object.setPrototypeOf(knexClone.client, parentPrototype);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-19 12:55:50 +01:00
|
|
|
redefineProperties(knexClone, knexClone.client);
|
2018-09-26 22:27:59 +02:00
|
|
|
knexClone.userParams = params;
|
|
|
|
return knexClone;
|
|
|
|
},
|
|
|
|
});
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2018-11-19 12:55:50 +01:00
|
|
|
if (!knexFn.context) {
|
|
|
|
knexFn.context = knexContext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function redefineProperties(knex, client) {
|
2015-05-09 13:58:18 -04:00
|
|
|
// Allow chaining methods from the root object, before
|
|
|
|
// any other information is specified.
|
|
|
|
QueryInterface.forEach(function(method) {
|
|
|
|
knex[method] = function() {
|
2018-07-09 08:10:34 -04:00
|
|
|
const builder = knex.queryBuilder();
|
|
|
|
return builder[method].apply(builder, arguments);
|
|
|
|
};
|
|
|
|
});
|
2015-07-02 18:28:34 -04:00
|
|
|
|
2018-11-19 12:55:50 +01:00
|
|
|
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,
|
|
|
|
},
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2018-11-19 12:55:50 +01:00
|
|
|
client: {
|
|
|
|
get() {
|
|
|
|
return knex.context.client;
|
|
|
|
},
|
|
|
|
set(client) {
|
|
|
|
knex.context.client = client;
|
|
|
|
},
|
|
|
|
configurable: true,
|
|
|
|
},
|
2016-09-12 18:11:56 -04:00
|
|
|
|
2018-11-19 12:55:50 +01:00
|
|
|
userParams: {
|
|
|
|
get() {
|
|
|
|
return knex.context.userParams;
|
|
|
|
},
|
|
|
|
set(userParams) {
|
|
|
|
knex.context.userParams = userParams;
|
|
|
|
},
|
|
|
|
configurable: true,
|
|
|
|
},
|
2016-09-12 18:11:56 -04:00
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
schema: {
|
2016-05-17 01:01:34 +10:00
|
|
|
get() {
|
2018-09-26 22:27:59 +02:00
|
|
|
return knex.client.schemaBuilder();
|
2018-07-09 08:10:34 -04:00
|
|
|
},
|
2018-09-26 22:27:59 +02:00
|
|
|
configurable: true,
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
migrate: {
|
2016-05-17 01:01:34 +10:00
|
|
|
get() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return new Migrator(knex);
|
|
|
|
},
|
2018-09-26 22:27:59 +02:00
|
|
|
configurable: true,
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
seed: {
|
2016-05-17 01:01:34 +10:00
|
|
|
get() {
|
2018-07-09 08:10:34 -04:00
|
|
|
return new Seeder(knex);
|
|
|
|
},
|
2018-09-26 22:27:59 +02:00
|
|
|
configurable: true,
|
2015-05-09 13:58:18 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
fn: {
|
2016-05-17 01:01:34 +10:00
|
|
|
get() {
|
2018-09-26 22:27:59 +02:00
|
|
|
return new FunctionHelper(knex.client);
|
2018-07-09 08:10:34 -04:00
|
|
|
},
|
2018-09-26 22:27:59 +02:00
|
|
|
configurable: true,
|
2018-07-09 08:10:34 -04:00
|
|
|
},
|
|
|
|
});
|
2015-05-09 13:58:18 -04:00
|
|
|
|
2018-11-19 12:55:50 +01:00
|
|
|
initContext(knex);
|
|
|
|
knex.Promise = bluebird;
|
|
|
|
knex.client = client;
|
|
|
|
knex.client.makeKnex = makeKnex;
|
|
|
|
knex.userParams = {};
|
|
|
|
|
2018-09-26 22:27:59 +02:00
|
|
|
// Hook up the "knex" object as an EventEmitter.
|
|
|
|
const ee = new EventEmitter();
|
|
|
|
for (const key in ee) {
|
|
|
|
knex[key] = ee[key];
|
|
|
|
}
|
|
|
|
|
2015-05-09 13:58:18 -04:00
|
|
|
// Passthrough all "start" and "query" events to the knex object.
|
2018-09-26 22:27:59 +02:00
|
|
|
knex.client.on('start', function(obj) {
|
2018-07-09 08:10:34 -04:00
|
|
|
knex.emit('start', obj);
|
|
|
|
});
|
2018-09-26 22:27:59 +02:00
|
|
|
knex.client.on('query', function(obj) {
|
2018-07-09 08:10:34 -04:00
|
|
|
knex.emit('query', obj);
|
|
|
|
});
|
2018-09-26 22:27:59 +02:00
|
|
|
knex.client.on('query-error', function(err, obj) {
|
2018-07-09 08:10:34 -04:00
|
|
|
knex.emit('query-error', err, obj);
|
|
|
|
});
|
2018-09-26 22:27:59 +02:00
|
|
|
knex.client.on('query-response', function(response, obj, builder) {
|
2018-07-09 08:10:34 -04:00
|
|
|
knex.emit('query-response', response, obj, builder);
|
|
|
|
});
|
2018-09-26 22:27:59 +02:00
|
|
|
}
|
2016-02-26 19:51:35 +01:00
|
|
|
|
2018-11-19 12:55:50 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-09-26 22:27:59 +02:00
|
|
|
function shallowCloneFunction(originalFunction) {
|
2018-11-19 12:55:50 +01:00
|
|
|
const fnContext = Object.create(
|
|
|
|
Object.getPrototypeOf(originalFunction),
|
|
|
|
Object.getOwnPropertyDescriptors(originalFunction)
|
2018-09-26 22:27:59 +02:00
|
|
|
);
|
2018-11-19 12:55:50 +01:00
|
|
|
|
|
|
|
const knexContext = {};
|
|
|
|
const knexFnWrapper = (tableName, options) => {
|
|
|
|
return createQueryBuilder(knexContext, tableName, options);
|
|
|
|
};
|
|
|
|
|
|
|
|
const clonedFunction = knexFnWrapper.bind(fnContext);
|
2018-09-26 22:27:59 +02:00
|
|
|
Object.assign(clonedFunction, originalFunction);
|
2018-11-19 12:55:50 +01:00
|
|
|
clonedFunction._context = knexContext;
|
2018-09-26 22:27:59 +02:00
|
|
|
return clonedFunction;
|
2015-11-02 14:54:38 +11:00
|
|
|
}
|