Skip to content

Commit

Permalink
Merge 36a558d into 8e0ce7a
Browse files Browse the repository at this point in the history
  • Loading branch information
kibertoad committed Sep 25, 2018
2 parents 8e0ce7a + 36a558d commit 7c5a900
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 54 deletions.
6 changes: 5 additions & 1 deletion src/knex.js
Expand Up @@ -45,7 +45,11 @@ export default function Knex(config) {
connection: parseConnection(config.connection).connection,
});
}
return makeKnex(new Dialect(config));
const newKnex = makeKnex(new Dialect(config));
if (config.userParams) {
newKnex.userParams = config.userParams;
}
return newKnex;
}

// Expose Client on the main Knex namespace.
Expand Down
6 changes: 3 additions & 3 deletions src/migrate/Migrator.js
Expand Up @@ -81,9 +81,9 @@ export default class Migrator {
);

if (transactionForAll) {
return this.knex.transaction((trx) =>
this._runBatch(migrations, 'up', trx)
);
return this.knex.transaction((trx) => {
return this._runBatch(migrations, 'up', trx);
});
} else {
return this._runBatch(migrations, 'up');
}
Expand Down
2 changes: 1 addition & 1 deletion src/migrate/stub/coffee.stub
Expand Up @@ -10,4 +10,4 @@ exports.up = (knex, Promise) ->
exports.down = (knex, Promise) ->
<% if (d.tableName) { %>
knex.schema.dropTable "<%= d.tableName %>"
<% } %>
<% } %>
8 changes: 8 additions & 0 deletions src/transaction.js
Expand Up @@ -187,6 +187,14 @@ export default class Transaction extends EventEmitter {
function makeTransactor(trx, connection, trxClient) {
const transactor = makeKnex(trxClient);

transactor.withUserParams = () => {
throw new Error(
'Cannot set user params on a transaction - it can only inherit params from main knex instance'
);
};

transactor.userParams = trx.userParams;

transactor.transaction = function(container, options) {
return trxClient.transaction(container, options, trx);
};
Expand Down
88 changes: 51 additions & 37 deletions src/util/make-knex.js
Expand Up @@ -37,7 +37,9 @@ 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) {
return client.transaction(container, config);
const trx = client.transaction(container, config);
trx.userParams = this.userParams;
return trx;
},

// Typically never needed, initializes the pool for a knex client.
Expand All @@ -53,13 +55,22 @@ export default function makeKnex(client) {
ref(ref) {
return client.ref(ref);
},
});

// Hook up the "knex" object as an EventEmitter.
const ee = new EventEmitter();
for (const key in ee) {
knex[key] = ee[key];
}
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);
if (parentPrototype) {
Object.setPrototypeOf(knexClone.client, parentPrototype);
}
}

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

// Allow chaining methods from the root object, before
// any other information is specified.
Expand All @@ -71,70 +82,73 @@ export default function makeKnex(client) {
});

knex.client = client;
redefineProperties(knex);

const VERSION = '0.12.6';

Object.defineProperties(knex, {
__knex__: {
get() {
knex.client.logger.warn(
'knex.__knex__ is deprecated, you can get the module version' +
"by running require('knex/package').version"
);
return VERSION;
},
},
client.makeKnex = makeKnex;

VERSION: {
get() {
knex.client.logger.warn(
'knex.VERSION is deprecated, you can get the module version' +
"by running require('knex/package').version"
);
return VERSION;
},
},
knex.userParams = {};
return knex;
}

function redefineProperties(knex) {
Object.defineProperties(knex, {
schema: {
get() {
return client.schemaBuilder();
return knex.client.schemaBuilder();
},
configurable: true,
},

migrate: {
get() {
return new Migrator(knex);
},
configurable: true,
},

seed: {
get() {
return new Seeder(knex);
},
configurable: true,
},

fn: {
get() {
return new FunctionHelper(client);
return new FunctionHelper(knex.client);
},
configurable: true,
},
});

// Hook up the "knex" object as an EventEmitter.
const ee = new EventEmitter();
for (const key in ee) {
knex[key] = ee[key];
}

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

client.makeKnex = makeKnex;

return knex;
function shallowCloneFunction(originalFunction) {
const clonedFunction = originalFunction.bind(
Object.create(
Object.getPrototypeOf(originalFunction),
Object.getOwnPropertyDescriptors(originalFunction)
)
);
Object.assign(clonedFunction, originalFunction);
return clonedFunction;
}
58 changes: 51 additions & 7 deletions test/integration/builder/additional.js
Expand Up @@ -861,27 +861,71 @@ module.exports = function(knex) {
});
});

it('Event: query-error', function() {
it('Event: does not duplicate listeners on a copy with user params', function() {
var queryCount = 0;
var onQueryError = function(error, obj) {

var onQueryResponse = function(response, obj, builder) {
queryCount++;
expect(response).to.be.an('array');
expect(obj).to.be.an('object');
expect(obj.__knexUid).to.be.a('string');
expect(obj.__knexQueryUid).to.be.a('string');
expect(builder).to.be.an('object');
};
knex.on('query-response', onQueryResponse);
const knexCopy = knex.withUserParams({});

return knexCopy('accounts')
.select()
.on('query-response', onQueryResponse)
.then(function() {
return knexCopy.transaction(function(tr) {
return tr('accounts')
.select()
.on('query-response', onQueryResponse); //Transactions should emit the event as well
});
})
.then(function() {
expect(Object.keys(knex._events).length).to.equal(1);
expect(Object.keys(knexCopy._events).length).to.equal(0);
knex.removeListener('query-response', onQueryResponse);
expect(Object.keys(knex._events).length).to.equal(0);
expect(queryCount).to.equal(4);
});
});

it('Event: query-error', function() {
var queryCountKnex = 0;
var queryCountBuilder = 0;
var onQueryErrorKnex = function(error, obj) {
queryCountKnex++;
expect(obj).to.be.an('object');
expect(obj.__knexUid).to.be.a('string');
expect(obj.__knexQueryUid).to.be.a('string');
expect(error).to.be.an('error');
};

var onQueryErrorBuilder = function(error, obj) {
queryCountBuilder++;
expect(obj).to.be.an('object');
expect(obj.__knexUid).to.be.a('string');
expect(obj.__knexQueryUid).to.be.a('string');
expect(error).to.be.an('object');
expect(error).to.be.an('error');
};

knex.on('query-error', onQueryError);
knex.on('query-error', onQueryErrorKnex);

return knex
.raw('Broken query')
.on('query-error', onQueryError)
.on('query-error', onQueryErrorBuilder)
.then(function() {
expect(true).to.equal(false); //Should not be resolved
})
.catch(function() {
knex.removeListener('query-error', onQueryError);
expect(queryCount).to.equal(2);
knex.removeListener('query-error', onQueryErrorKnex);
knex.removeListener('query-error', onQueryErrorBuilder);
expect(queryCountBuilder).to.equal(1);
expect(queryCountKnex).to.equal(1);
});
});

Expand Down
57 changes: 54 additions & 3 deletions test/integration/migrate/index.js
Expand Up @@ -294,9 +294,12 @@ module.exports = function(knex) {
.spread(function(batchNo, log) {
expect(batchNo).to.equal(1);
expect(log).to.have.length(2);
var migrationPath = ['test', 'integration', 'migrate', 'test'].join(
path.sep
); //Test fails on windows if explicitly defining /test/integration/.. ~wubzz
const migrationPath = [
'test',
'integration',
'migrate',
'test',
].join(path.sep); //Test fails on windows if explicitly defining /test/integration/.. ~wubzz
expect(log[0]).to.contain(batchNo);
return knex('knex_migrations')
.select('*')
Expand Down Expand Up @@ -575,4 +578,52 @@ module.exports = function(knex) {
});
});
});

describe('knex.migrate.latest with custom config parameter for table name', function() {
before(function() {
return knex
.withUserParams({ customTableName: 'migration_test_2_1a' })
.migrate.latest({
directory: 'test/integration/migrate/test',
});
});

it('should create all specified tables and columns', function() {
const tables = [
'migration_test_1',
'migration_test_2',
'migration_test_2_1a',
];
return Promise.map(tables, function(table) {
return knex.schema.hasTable(table).then(function(exists) {
expect(exists).to.equal(true);
if (exists) {
return Promise.all([
knex.schema.hasColumn(table, 'id').then(function(exists) {
expect(exists).to.equal(true);
}),
knex.schema.hasColumn(table, 'name').then(function(exists) {
expect(exists).to.equal(true);
}),
]);
}
});
});
});

it('should not create unexpected tables', function() {
const table = 'migration_test_2_1';
knex.schema.hasTable(table).then(function(exists) {
expect(exists).to.equal(false);
});
});

after(function() {
return knex
.withUserParams({ customTableName: 'migration_test_2_1a' })
.migrate.rollback({
directory: 'test/integration/migrate/test',
});
});
});
};
6 changes: 4 additions & 2 deletions test/integration/migrate/test/20131019235306_migration_2.js
@@ -1,21 +1,23 @@
'use strict';

exports.up = function(knex, promise) {
const tableName2 = knex.userParams.customTableName || 'migration_test_2_1';
return knex.schema
.createTable('migration_test_2', function(t) {
t.increments();
t.string('name');
})
.then(() =>
knex.schema.createTable('migration_test_2_1', function(t) {
knex.schema.createTable(tableName2, function(t) {
t.increments();
t.string('name');
})
);
};

exports.down = function(knex, promise) {
const tableName2 = knex.userParams.customTableName || 'migration_test_2_1';
return knex.schema
.dropTable('migration_test_2')
.then(() => knex.schema.dropTable('migration_test_2_1'));
.then(() => knex.schema.dropTable(tableName2));
};

0 comments on commit 7c5a900

Please sign in to comment.