Skip to content

Commit

Permalink
Merge a87c961 into a2b7e0e
Browse files Browse the repository at this point in the history
  • Loading branch information
kibertoad committed Jan 30, 2019
2 parents a2b7e0e + a87c961 commit d7b0731
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 40 deletions.
3 changes: 2 additions & 1 deletion UPGRADING.md
Expand Up @@ -3,7 +3,8 @@
### Upgrading to version 0.16.0+

* MSSQL: DB versions older than 2008 are no longer supported, make sure to update your DB;
* PostgreSQL|MySQL: it is recommended to use options object for `table.datetime` and `table.timestamp` methods instead of argument options. See documentation for these methods for more details.
* PostgreSQL|MySQL: it is recommended to use options object for `table.datetime` and `table.timestamp` methods instead of argument options. See documentation for these methods for more details;
* Node 6: There are known issues with duplicate event listeners when using knex.js with Node 6 (resulting in MaxListenersExceededWarning under certain use-cases (such as reusing single knex instance to run migrations or seeds multiple times)). Please upgrade to Node 8+ as soon as possible (knex 0.17.0 will be dropping Node 6 support altogether).

### Upgrading to version 0.15.0+

Expand Down
10 changes: 8 additions & 2 deletions bin/cli.js
Expand Up @@ -44,7 +44,10 @@ function initKnex(env, opts) {
checkLocalModule(env);
if (process.cwd() !== env.cwd) {
process.chdir(env.cwd);
console.log('Working directory changed to', color.magenta(tildify(env.cwd)));
console.log(
'Working directory changed to',
color.magenta(tildify(env.cwd))
);
}

if (!opts.knexfile) {
Expand Down Expand Up @@ -102,7 +105,10 @@ function invoke(env) {
.version(
color.blue('Knex CLI version: ', color.green(cliPkg.version)) +
'\n' +
color.blue('Local Knex version: ', color.green(env.modulePackage.version)) +
color.blue(
'Local Knex version: ',
color.green(env.modulePackage.version)
) +
'\n'
)
.option('--debug', 'Run with debugging.')
Expand Down
9 changes: 3 additions & 6 deletions knex.js
@@ -1,3 +1,5 @@
const { isNode6 } = require('./lib/util/version-helper');

// Knex.js
// --------------
// (c) 2013-present Tim Griesser
Expand All @@ -6,12 +8,7 @@
// http://knexjs.org

// Should be safe to remove after support for Node.js 6 is dropped
if (
process &&
process.versions &&
process.versions.node &&
process.versions.node.startsWith('6.')
) {
if (isNode6()) {
const oldPromise = global.Promise;

require('@babel/polyfill');
Expand Down
26 changes: 13 additions & 13 deletions package.json
Expand Up @@ -35,7 +35,7 @@
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.2.3",
"@babel/preset-env": "^7.3.1",
"@types/node": "*",
"JSONStream": "^1.3.5",
"async": "^2.6.1",
Expand All @@ -45,29 +45,29 @@
"chai-subset-in-order": "^2.1.2",
"coveralls": "^3.0.2",
"cross-env": "^5.2.0",
"eslint": "5.10.0",
"eslint-config-prettier": "^3.3.0",
"eslint-plugin-import": "^2.14.0",
"husky": "^1.2.1",
"eslint": "5.12.1",
"eslint-config-prettier": "^3.6.0",
"eslint-plugin-import": "^2.16.0",
"husky": "^1.3.1",
"jake": "^8.0.19",
"json-loader": "^0.5.7",
"lint-staged": "^8.1.0",
"lint-staged": "^8.1.1",
"mocha": "^5.2.0",
"mock-fs": "^4.7.0",
"mssql": "^5.0.0-alpha.1",
"mysql": "^2.16.0",
"mysql2": "^1.6.4",
"nyc": "^13.1.0",
"pg": "^7.7.1",
"pg": "^7.8.0",
"pg-query-stream": "^1.1.2",
"prettier": "^1.15.3",
"rimraf": "^2.6.2",
"sinon": "^7.2.2",
"prettier": "^1.16.2",
"rimraf": "^2.6.3",
"sinon": "^7.2.3",
"sinon-chai": "^3.3.0",
"source-map-support": "^0.5.9",
"sqlite3": "^4.0.4",
"source-map-support": "^0.5.10",
"sqlite3": "^4.0.6",
"tap-spec": "^5.0.0",
"tape": "^4.9.1",
"tape": "^4.9.2",
"through": "^2.3.8",
"toxiproxy-node-client": "^2.0.6"
},
Expand Down
46 changes: 36 additions & 10 deletions src/util/make-knex.js
Expand Up @@ -4,15 +4,17 @@ import Migrator from '../migrate/Migrator';
import Seeder from '../seed/Seeder';
import FunctionHelper from '../functionhelper';
import QueryInterface from '../query/methods';
import { assign } from 'lodash';
import { assign, merge } from 'lodash';
import batchInsert from './batchInsert';
import * as bluebird from 'bluebird';
import { isNode6 } from './version-helper';

export default function makeKnex(client) {
// The object we're potentially using to kick off an initial chain.
function knex(tableName, options) {
return createQueryBuilder(knex.context, tableName, options);
}

redefineProperties(knex, client);
return knex;
}
Expand Down Expand Up @@ -81,15 +83,16 @@ function initContext(knexFn) {
withUserParams(params) {
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 = Object.create(this.client.constructor.prototype); // Clone client to avoid leaking listeners that are set on it
merge(knexClone.client, this.client);
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, knexClone.client);
_copyEventListeners('query', knexFn, knexClone);
_copyEventListeners('query-error', knexFn, knexClone);
_copyEventListeners('query-response', knexFn, knexClone);
_copyEventListeners('start', knexFn, knexClone);
knexClone.userParams = params;
return knexClone;
},
Expand All @@ -99,6 +102,12 @@ function initContext(knexFn) {
knexFn.context = knexContext;
}
}
function _copyEventListeners(eventName, sourceKnex, targetKnex) {
const listeners = sourceKnex.listeners(eventName);
listeners.forEach((listener) => {
targetKnex.on(eventName, listener);
});
}

function redefineProperties(knex, client) {
// Allow chaining methods from the root object, before
Expand Down Expand Up @@ -194,21 +203,38 @@ function redefineProperties(knex, client) {
knex[key] = ee[key];
}

// Unfortunately, something seems to be broken in Node 6 and removing events from a clone also mutates original Knex,
// which is highly undesireable
if (knex._internalListeners && !isNode6()) {
knex._internalListeners.forEach(({ eventName, listener }) => {
knex.client.removeListener(eventName, listener); // Remove duplicates for copies
});
}
knex._internalListeners = [];

// Passthrough all "start" and "query" events to the knex object.
knex.client.on('start', function(obj) {
_addInternalListener(knex, 'start', (obj) => {
knex.emit('start', obj);
});
knex.client.on('query', function(obj) {
_addInternalListener(knex, 'query', (obj) => {
knex.emit('query', obj);
});
knex.client.on('query-error', function(err, obj) {
_addInternalListener(knex, 'query-error', (err, obj) => {
knex.emit('query-error', err, obj);
});
knex.client.on('query-response', function(response, obj, builder) {
_addInternalListener(knex, 'query-response', (response, obj, builder) => {
knex.emit('query-response', response, obj, builder);
});
}

function _addInternalListener(knex, eventName, listener) {
knex.client.on(eventName, listener);
knex._internalListeners.push({
eventName,
listener,
});
}

function createQueryBuilder(knexContext, tableName, options) {
const qb = knexContext.queryBuilder();
if (!tableName)
Expand Down
12 changes: 12 additions & 0 deletions src/util/version-helper.js
@@ -0,0 +1,12 @@
function isNode6() {
return (
process &&
process.versions &&
process.versions.node &&
process.versions.node.startsWith('6.')
);
}

module.exports = {
isNode6,
};
2 changes: 2 additions & 0 deletions test/index.js
Expand Up @@ -31,6 +31,8 @@ describe('Query Building Tests', function() {
require('./unit/schema/oracledb');
require('./unit/migrate/migration-list-resolver');
require('./unit/seed/seeder');
// require('./unit/interface'); ToDo Uncomment after fixed
require('./unit/knex');
});

describe('Integration Tests', function() {
Expand Down
26 changes: 24 additions & 2 deletions test/integration/builder/additional.js
Expand Up @@ -5,6 +5,7 @@
const Knex = require('../../../knex');
const _ = require('lodash');
const Promise = require('bluebird');
const { isNode6 } = require('../../../lib/util/version-helper');

module.exports = function(knex) {
describe('Additional', function() {
Expand Down Expand Up @@ -45,6 +46,9 @@ module.exports = function(knex) {
});

it('should pass query context for raw responses', () => {
if (isNode6()) {
return;
}
return knex
.raw('select * from ??', ['accounts'])
.queryContext('the context')
Expand Down Expand Up @@ -104,6 +108,9 @@ module.exports = function(knex) {
});

it('should work using camelCased table name', () => {
if (isNode6()) {
return;
}
return knex('testTableTwo')
.columnInfo()
.then((res) => {
Expand All @@ -118,6 +125,9 @@ module.exports = function(knex) {
});

it('should work using snake_cased table name', () => {
if (isNode6()) {
return;
}
return knex('test_table_two')
.columnInfo()
.then((res) => {
Expand Down Expand Up @@ -958,6 +968,9 @@ module.exports = function(knex) {
});

it('Event: query-response', function() {
if (isNode6()) {
return;
}
let queryCount = 0;

const onQueryResponse = function(response, obj, builder) {
Expand Down Expand Up @@ -986,7 +999,10 @@ module.exports = function(knex) {
});
});

it('Event: does not duplicate listeners on a copy with user params', function() {
it('Event: preserves listeners on a copy with user params', function() {
if (isNode6()) {
return;
}
let queryCount = 0;

const onQueryResponse = function(response, obj, builder) {
Expand All @@ -1012,14 +1028,17 @@ module.exports = function(knex) {
})
.then(function() {
expect(Object.keys(knex._events).length).to.equal(1);
expect(Object.keys(knexCopy._events).length).to.equal(0);
expect(Object.keys(knexCopy._events).length).to.equal(1);
knex.removeListener('query-response', onQueryResponse);
expect(Object.keys(knex._events).length).to.equal(0);
expect(queryCount).to.equal(4);
});
});

it('Event: query-error', function() {
if (isNode6()) {
return;
}
let queryCountKnex = 0;
let queryCountBuilder = 0;
const onQueryErrorKnex = function(error, obj) {
Expand Down Expand Up @@ -1055,6 +1074,9 @@ module.exports = function(knex) {
});

it('Event: start', function() {
if (isNode6()) {
return;
}
return knex('accounts')
.insert({ last_name: 'Start event test' })
.then(function() {
Expand Down
5 changes: 5 additions & 0 deletions test/integration/builder/transaction.js
Expand Up @@ -6,6 +6,7 @@ const Promise = testPromise;
const Knex = require('../../../knex');
const _ = require('lodash');
const sinon = require('sinon');
const { isNode6 } = require('../../../lib/util/version-helper');

module.exports = function(knex) {
// Certain dialects do not have proper insert with returning, so if this is true
Expand Down Expand Up @@ -362,6 +363,10 @@ module.exports = function(knex) {
});

it('#855 - Query Event should trigger on Transaction Client AND main Client', function() {
if (isNode6()) {
return;
}

let queryEventTriggered = false;

knex.once('query', function(queryData) {
Expand Down
15 changes: 15 additions & 0 deletions test/integration/helpers/knex-builder.js
@@ -0,0 +1,15 @@
const knex = require('../../../knex');
const config = require('../../knexfile');

/*
Please do not remove this file even though it is not referenced anywhere.
This helper is meant for local debugging of specific tests.
*/

function getSqliteKnex() {
return knex(config.sqlite3);
}

module.exports = {
getSqliteKnex,
};

0 comments on commit d7b0731

Please sign in to comment.