mirror of
https://github.com/knex/knex.git
synced 2025-07-12 03:21:06 +00:00
783 lines
24 KiB
JavaScript
783 lines
24 KiB
JavaScript
const Knex = require('../../lib/index');
|
|
const QueryBuilder = require('../../lib/query/querybuilder');
|
|
const { expect } = require('chai');
|
|
const sqliteConfig = require('../knexfile').sqlite3;
|
|
const sqlite3 = require('sqlite3');
|
|
const { noop } = require('lodash');
|
|
const sinon = require('sinon');
|
|
|
|
describe('knex', () => {
|
|
describe('supports passing existing connection', () => {
|
|
let connection;
|
|
beforeEach(() => {
|
|
connection = new sqlite3.Database(':memory:');
|
|
});
|
|
|
|
afterEach(() => {
|
|
connection.close();
|
|
});
|
|
|
|
it('happy path', (done) => {
|
|
const knex = Knex({ client: 'sqlite3' });
|
|
knex
|
|
.connection(connection)
|
|
.select(knex.raw('"0" as value'))
|
|
.then((result) => {
|
|
expect(result[0].value).to.equal('0');
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
it('throws error on unsupported config client value', () => {
|
|
expect(() => {
|
|
Knex({
|
|
client: 'dummy',
|
|
});
|
|
}).to.throw(
|
|
/Unknown configuration option 'client' value dummy. Note that it is case-sensitive, check documentation for supported values/
|
|
);
|
|
});
|
|
|
|
it('accepts supported config client value', () => {
|
|
expect(() => {
|
|
Knex({
|
|
client: 'mysql',
|
|
});
|
|
}).not.to.throw();
|
|
});
|
|
|
|
it('accepts supported config client value alias', () => {
|
|
expect(() => {
|
|
Knex({
|
|
client: 'sqlite',
|
|
});
|
|
}).not.to.throw();
|
|
});
|
|
|
|
it('supports creating copy with userParams', () => {
|
|
const knex = Knex({
|
|
client: 'sqlite',
|
|
});
|
|
|
|
const knexWithParams = knex.withUserParams({ userParam: '451' });
|
|
|
|
expect(knexWithParams).to.be.a('function');
|
|
expect(knexWithParams.userParams).to.deep.equal({ userParam: '451' });
|
|
expect(knexWithParams.client.config.client).to.equal('sqlite');
|
|
expect(knexWithParams.migrate).to.be.a('object');
|
|
});
|
|
|
|
it('supports passing user params in config', () => {
|
|
const knexWithParams = Knex({
|
|
client: 'sqlite',
|
|
userParams: {
|
|
userParam: '451',
|
|
},
|
|
});
|
|
|
|
expect(knexWithParams).to.be.a('function');
|
|
expect(knexWithParams.userParams).to.deep.equal({ userParam: '451' });
|
|
expect(knexWithParams.client.config.client).to.equal('sqlite');
|
|
expect(knexWithParams.migrate).to.be.a('object');
|
|
});
|
|
|
|
it('migrator of a copy with userParams has reference to correct Knex', () => {
|
|
const knex = Knex({
|
|
client: 'sqlite',
|
|
});
|
|
|
|
const knexWithParams = knex.withUserParams({ userParam: '451' });
|
|
|
|
expect(knexWithParams.migrate.knex.userParams).to.deep.equal({
|
|
userParam: '451',
|
|
});
|
|
});
|
|
|
|
it('copying does not result in duplicate listeners', () => {
|
|
const knex = Knex({
|
|
client: 'sqlite',
|
|
connection: ':memory:',
|
|
});
|
|
const knexWithParams = knex.withUserParams();
|
|
|
|
expect(knex.client.listeners('start').length).to.equal(1);
|
|
expect(knex.client.listeners('query').length).to.equal(1);
|
|
expect(knex.client.listeners('query-error').length).to.equal(1);
|
|
expect(knex.client.listeners('query-response').length).to.equal(1);
|
|
|
|
expect(knexWithParams.client.listeners('start').length).to.equal(1);
|
|
expect(knexWithParams.client.listeners('query').length).to.equal(1);
|
|
expect(knexWithParams.client.listeners('query-error').length).to.equal(1);
|
|
expect(knexWithParams.client.listeners('query-response').length).to.equal(
|
|
1
|
|
);
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('listeners added to knex directly get copied correctly', () => {
|
|
const knex = Knex({
|
|
client: 'sqlite',
|
|
connection: ':memory:',
|
|
});
|
|
const onQueryResponse = function (response, obj, builder) {};
|
|
expect(knex.listeners('query-response').length).to.equal(0);
|
|
knex.on('query-response', onQueryResponse);
|
|
|
|
const knexWithParams = knex.withUserParams();
|
|
|
|
expect(knex.listeners('query-response').length).to.equal(1);
|
|
expect(knexWithParams.listeners('query-response').length).to.equal(1);
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('listeners added to knex propagate to callback transaction correctly', async () => {
|
|
const knex = Knex({
|
|
client: 'sqlite',
|
|
connection: ':memory:',
|
|
});
|
|
let queryResponseWasPropagated = false;
|
|
let queryWasPropagated = false;
|
|
let startWasPropagated = false;
|
|
knex.on('start', () => {
|
|
startWasPropagated = true;
|
|
});
|
|
knex.on('query', () => {
|
|
queryWasPropagated = true;
|
|
});
|
|
knex.on('query-response', () => {
|
|
queryResponseWasPropagated = true;
|
|
});
|
|
|
|
await knex.transaction(async (trx) => {
|
|
await trx().select(1);
|
|
});
|
|
|
|
expect(startWasPropagated).to.equal(true);
|
|
expect(queryWasPropagated).to.equal(true);
|
|
expect(queryResponseWasPropagated).to.equal(true);
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('listeners added to knex propagate to promise transaction correctly', async () => {
|
|
const knex = Knex({
|
|
client: 'sqlite',
|
|
connection: ':memory:',
|
|
});
|
|
let queryResponseWasPropagated = false;
|
|
let queryWasPropagated = false;
|
|
let startWasPropagated = false;
|
|
knex.on('start', () => {
|
|
startWasPropagated = true;
|
|
});
|
|
knex.on('query', () => {
|
|
queryWasPropagated = true;
|
|
});
|
|
knex.on('query-response', () => {
|
|
queryResponseWasPropagated = true;
|
|
});
|
|
|
|
const trx = await knex.transaction();
|
|
await trx.select(1);
|
|
trx.commit();
|
|
|
|
expect(startWasPropagated).to.equal(true);
|
|
expect(queryWasPropagated).to.equal(true);
|
|
expect(queryResponseWasPropagated).to.equal(true);
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('adding listener to copy does not affect base knex', () => {
|
|
const knex = Knex({
|
|
client: 'sqlite',
|
|
connection: ':memory:',
|
|
});
|
|
|
|
expect(knex.client.listeners('start').length).to.equal(1);
|
|
expect(knex.client.listeners('query').length).to.equal(1);
|
|
expect(knex.client.listeners('query-error').length).to.equal(1);
|
|
expect(knex.client.listeners('query-response').length).to.equal(1);
|
|
|
|
const knexWithParams = knex.withUserParams();
|
|
knexWithParams.client.on('query', (obj) => {
|
|
knexWithParams.emit('query', obj);
|
|
});
|
|
|
|
expect(knex.client.listeners('start').length).to.equal(1);
|
|
expect(knex.client.listeners('query').length).to.equal(1);
|
|
expect(knex.client.listeners('query-error').length).to.equal(1);
|
|
expect(knex.client.listeners('query-response').length).to.equal(1);
|
|
expect(knexWithParams.client.listeners('query').length).to.equal(2);
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('sets correct postProcessResponse for builders instantiated from clone', () => {
|
|
const knex = Knex({
|
|
client: 'sqlite',
|
|
postProcessResponse: noop,
|
|
});
|
|
|
|
const knexWithParams = knex.withUserParams();
|
|
knexWithParams.client.config.postProcessResponse = null;
|
|
const builderForTable = knex('tableName');
|
|
const builderWithParamsForTable = knexWithParams('tableName');
|
|
|
|
expect(knex.client.config.postProcessResponse).to.equal(noop);
|
|
expect(knexWithParams.client.config.postProcessResponse).to.equal(null);
|
|
expect(builderForTable.client.config.postProcessResponse).to.equal(noop);
|
|
expect(
|
|
builderWithParamsForTable.client.config.postProcessResponse
|
|
).to.equal(null);
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('passes queryContext to wrapIdentifier in raw query', async function () {
|
|
if (!sqliteConfig) {
|
|
return this.skip();
|
|
}
|
|
|
|
const knex = Knex(
|
|
Object.assign({}, sqliteConfig, {
|
|
wrapIdentifier: (str, origImpl, queryContext) => {
|
|
if (!queryContext) {
|
|
throw Error('We should have queryContext here right?');
|
|
}
|
|
|
|
if (str === 'iAmGoingToBeConvertedToId') {
|
|
str = 'id';
|
|
}
|
|
return origImpl(str);
|
|
},
|
|
})
|
|
);
|
|
|
|
await knex.schema
|
|
.queryContext({ someStuff: true })
|
|
.dropTableIfExists('test')
|
|
.then(() => {
|
|
return knex.schema
|
|
.queryContext({ someStuff: true })
|
|
.createTable('test', (table) => {
|
|
table.increments('id');
|
|
table.string('text');
|
|
});
|
|
})
|
|
.then(() => {
|
|
return knex('test')
|
|
.queryContext({ someStuff: true })
|
|
.select('id')
|
|
.whereRaw('id = ??', 'iAmGoingToBeConvertedToId');
|
|
})
|
|
.then(() => {
|
|
return knex.schema.queryContext({ someStuff: true }).dropTable('test');
|
|
});
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('passes queryContext to wrapIdentifier in raw query in transaction', async function () {
|
|
if (!sqliteConfig) {
|
|
return this.skip();
|
|
}
|
|
|
|
const knex = Knex(
|
|
Object.assign({}, sqliteConfig, {
|
|
wrapIdentifier: (str, origImpl, queryContext) => {
|
|
if (!queryContext) {
|
|
throw Error('We should have queryContext here right?');
|
|
}
|
|
|
|
if (str === 'iAmGoingToBeConvertedToId') {
|
|
str = 'id';
|
|
}
|
|
return origImpl(str);
|
|
},
|
|
})
|
|
);
|
|
|
|
await knex.transaction((trx) => {
|
|
return trx.schema
|
|
.queryContext({ someStuff: true })
|
|
.dropTableIfExists('test')
|
|
.then(() => {
|
|
return trx.schema
|
|
.queryContext({ someStuff: true })
|
|
.createTable('test', (table) => {
|
|
table.increments('id');
|
|
table.string('text');
|
|
});
|
|
})
|
|
.then(() => {
|
|
return trx('test')
|
|
.queryContext({ someStuff: true })
|
|
.select('id')
|
|
.whereRaw('id = ??', 'iAmGoingToBeConvertedToId');
|
|
})
|
|
.then(() => {
|
|
return trx.schema.queryContext({ someStuff: true }).dropTable('test');
|
|
});
|
|
});
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('sets correct postProcessResponse for chained builders', () => {
|
|
const knex = Knex({
|
|
client: 'sqlite',
|
|
postProcessResponse: noop,
|
|
});
|
|
|
|
const knexWithParams = knex.withUserParams();
|
|
knexWithParams.client.config.postProcessResponse = null;
|
|
const builderForTable = knex('tableName').where('1 = 1');
|
|
const builderWithParamsForTable =
|
|
knexWithParams('tableName').where('1 = 1');
|
|
|
|
expect(knex.client.config.postProcessResponse).to.equal(noop);
|
|
expect(knexWithParams.client.config.postProcessResponse).to.equal(null);
|
|
expect(builderForTable.client.config.postProcessResponse).to.equal(noop);
|
|
expect(
|
|
builderWithParamsForTable.client.config.postProcessResponse
|
|
).to.equal(null);
|
|
|
|
knex.destroy();
|
|
});
|
|
|
|
it('throws if client module has not been installed', () => {
|
|
// create dummy dialect which always fails when trying to load driver
|
|
const SqliteClient = require(`../../lib/dialects/sqlite3/index.js`);
|
|
class ClientFoobar extends SqliteClient {}
|
|
|
|
ClientFoobar.prototype._driver = () => {
|
|
throw new Error('Cannot require...');
|
|
};
|
|
ClientFoobar.prototype.driverName = 'foo-bar';
|
|
|
|
expect(() => {
|
|
Knex({ client: ClientFoobar, connection: {} });
|
|
}).to.throw('Knex: run\n$ npm install foo-bar --save\nCannot require...');
|
|
});
|
|
|
|
describe('transaction', () => {
|
|
before(function skipSuiteIfSqliteConfigAbsent() {
|
|
// This is the case when the |DB| environment parameter does not include |sqlite|.
|
|
if (!sqliteConfig) {
|
|
return this.skip();
|
|
}
|
|
});
|
|
|
|
it('transaction of a copy with userParams retains userparams', async function () {
|
|
const knex = Knex(sqliteConfig);
|
|
|
|
const knexWithParams = knex.withUserParams({ userParam: '451' });
|
|
|
|
await knexWithParams.transaction(async (trx) => {
|
|
expect(trx.userParams).to.deep.equal({
|
|
userParam: '451',
|
|
});
|
|
});
|
|
|
|
knex.destroy();
|
|
});
|
|
|
|
it('propagates error correctly when all connections are in use', async function () {
|
|
const knex = Knex(sqliteConfig);
|
|
let trx;
|
|
let wasAsserted = false;
|
|
|
|
await knex
|
|
.transaction()
|
|
.then((newTrx) => {
|
|
trx = newTrx;
|
|
return knex.transaction();
|
|
})
|
|
.then(() => {
|
|
throw new Error('Should not reach here');
|
|
})
|
|
.catch((err) => {
|
|
wasAsserted = true;
|
|
expect(err.message).to.include('Timeout acquiring a connection');
|
|
});
|
|
|
|
expect(wasAsserted).to.equal(true);
|
|
trx.commit();
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('supports direct retrieval of a transaction from provider', async function () {
|
|
const knex = Knex(sqliteConfig);
|
|
const trxProvider = knex.transactionProvider();
|
|
const trxPromise = trxProvider();
|
|
|
|
let transaction;
|
|
await trxPromise
|
|
.then((trx) => {
|
|
transaction = trx;
|
|
expect(trx.client.transacting).to.equal(true);
|
|
return knex.transacting(trx).select(knex.raw('1 as result'));
|
|
})
|
|
.then((rows) => {
|
|
expect(rows[0].result).to.equal(1);
|
|
return transaction.commit();
|
|
})
|
|
.then(() => {
|
|
return transaction.executionPromise;
|
|
});
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('supports nested transaction for promise transactions', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
const trx = await knex.transaction();
|
|
const nestedTrx = await trx.transaction();
|
|
const nestedTrx2 = await nestedTrx.transaction();
|
|
expect(nestedTrx.name).to.equal('knex');
|
|
expect(nestedTrx2.name).to.equal('knex');
|
|
|
|
trx.commit();
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('does not reject rolled back nested transactions by default', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
const trx = await knex.transaction();
|
|
const nestedTrx = await trx.transaction();
|
|
await nestedTrx.rollback();
|
|
|
|
trx.commit();
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('supports accessing execution promise from standalone transaction', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
|
|
const trx = await knex.transaction();
|
|
const executionPromise = trx.executionPromise;
|
|
expect(executionPromise).to.be.ok;
|
|
|
|
expect(trx.client.transacting).to.equal(true);
|
|
const rows = await knex.transacting(trx).select(knex.raw('1 as result'));
|
|
expect(rows[0].result).to.equal(1);
|
|
await trx.commit();
|
|
|
|
const result = await executionPromise;
|
|
expect(result).to.be.undefined;
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('supports accessing execution promise from transaction with a callback', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
const trxPromise = new Promise((resolve, reject) => {
|
|
knex.transaction((transaction) => {
|
|
resolve(transaction);
|
|
});
|
|
});
|
|
const trx = await trxPromise;
|
|
const executionPromise = trx.executionPromise;
|
|
expect(executionPromise).to.be.ok;
|
|
|
|
expect(trx.client.transacting).to.equal(true);
|
|
const rows = await knex.transacting(trx).select(knex.raw('1 as result'));
|
|
expect(rows[0].result).to.equal(1);
|
|
await trx.commit();
|
|
|
|
const result = await executionPromise;
|
|
expect(result).to.be.undefined;
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('resolves execution promise if there was a manual rollback and transaction is set not to reject', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
|
|
const trx = await knex.transaction();
|
|
const executionPromise = trx.executionPromise;
|
|
|
|
expect(trx.client.transacting).to.equal(true);
|
|
const rows = await knex.transacting(trx).select(knex.raw('1 as result'));
|
|
expect(rows[0].result).to.equal(1);
|
|
await trx.rollback();
|
|
|
|
const result = await executionPromise;
|
|
expect(result).to.be.undefined;
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('does not reject transaction by default when handler is provided and there is a rollback', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
await knex.transaction((trx) => {
|
|
trx.rollback();
|
|
});
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('rejects execution promise if there was a manual rollback and transaction is set to reject', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
|
|
const trx = await knex.transaction(undefined, {
|
|
doNotRejectOnRollback: false,
|
|
});
|
|
const executionPromise = trx.executionPromise;
|
|
|
|
expect(trx.client.transacting).to.equal(true);
|
|
const rows = await knex.transacting(trx).select(knex.raw('1 as result'));
|
|
expect(rows[0].result).to.equal(1);
|
|
await trx.rollback();
|
|
|
|
let errorWasThrown;
|
|
try {
|
|
await executionPromise;
|
|
} catch (err) {
|
|
errorWasThrown = true;
|
|
expect(err.message).to.equal(
|
|
'Transaction rejected with non-error: undefined'
|
|
);
|
|
}
|
|
expect(errorWasThrown).to.be.true;
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('does not reject promise when rolling back a transaction', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
const trxProvider = knex.transactionProvider();
|
|
const trx = await trxProvider();
|
|
|
|
await trx.rollback();
|
|
await trx.executionPromise;
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('returns false when calling isCompleted on a transaction that is not complete', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
const trxProvider = knex.transactionProvider();
|
|
const trx = await trxProvider();
|
|
|
|
const completed = trx.isCompleted();
|
|
expect(completed).to.be.false;
|
|
|
|
trx.commit();
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('returns true when calling isCompleted on a transaction that is committed', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
const trxProvider = knex.transactionProvider();
|
|
const trx = await trxProvider();
|
|
|
|
await trx.commit();
|
|
|
|
const completed = trx.isCompleted();
|
|
expect(completed).to.be.true;
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('returns true when calling isCompleted on a transaction that is rolled back', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
const trxProvider = knex.transactionProvider();
|
|
const trx = await trxProvider();
|
|
|
|
await trx.rollback();
|
|
|
|
const completed = trx.isCompleted();
|
|
expect(completed).to.be.true;
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('returns false when calling isCompleted within a transaction handler', async () => {
|
|
const knex = Knex(sqliteConfig);
|
|
await knex.transaction((trx) => {
|
|
expect(trx.isCompleted()).to.be.false;
|
|
|
|
return trx.select(trx.raw('1 as result'));
|
|
});
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('creating transaction copy with user params should throw an error', async function () {
|
|
const knex = Knex(sqliteConfig);
|
|
|
|
await knex.transaction(async (trx) => {
|
|
expect(() => {
|
|
trx.withUserParams({ userParam: '451' });
|
|
}).to.throw(
|
|
/Cannot set user params on a transaction - it can only inherit params from main knex instance/
|
|
);
|
|
});
|
|
|
|
return knex.destroy();
|
|
});
|
|
});
|
|
|
|
describe('async stack traces', () => {
|
|
it('should capture stack trace on query builder instantiation', async function () {
|
|
if (!sqliteConfig) {
|
|
return this.skip();
|
|
}
|
|
|
|
const knex = Knex(
|
|
Object.assign({}, sqliteConfig, { asyncStackTraces: true })
|
|
);
|
|
|
|
await knex('some_nonexisten_table')
|
|
.select()
|
|
.catch((err) => {
|
|
expect(err.stack.split('\n')[1]).to.match(/at createQueryBuilder \(/); // the index 1 might need adjustment if the code is refactored
|
|
expect(typeof err.originalStack).to.equal('string');
|
|
});
|
|
|
|
return knex.destroy();
|
|
});
|
|
});
|
|
|
|
describe('extend query builder', () => {
|
|
before(function skipSuiteIfSqliteConfigAbsent() {
|
|
// This is the case when the |DB| environment parameter does not include |sqlite|.
|
|
if (!sqliteConfig) {
|
|
return this.skip();
|
|
}
|
|
});
|
|
|
|
let connection;
|
|
beforeEach(() => {
|
|
connection = new sqlite3.Database(':memory:');
|
|
});
|
|
|
|
afterEach(() => {
|
|
connection.close();
|
|
delete QueryBuilder.prototype.customSelect;
|
|
});
|
|
|
|
it('should extend default queryBuilder', (done) => {
|
|
Knex.QueryBuilder.extend('customSelect', function (value) {
|
|
return this.select(this.client.raw(`${value} as value`));
|
|
});
|
|
|
|
const knex = Knex({ client: 'sqlite3' });
|
|
knex
|
|
.connection(connection)
|
|
.customSelect(42)
|
|
.then((result) => {
|
|
expect(result[0].value).to.equal(42);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('should have custom method with transaction', async () => {
|
|
Knex.QueryBuilder.extend('customSelect', function (value) {
|
|
return this.select(this.client.raw(`${value} as value`));
|
|
});
|
|
|
|
const knex = Knex(sqliteConfig);
|
|
const trx = await knex.transaction();
|
|
|
|
const result = await trx.customSelect(42);
|
|
expect(result[0].value).to.equal(42);
|
|
|
|
trx.commit();
|
|
return knex.destroy();
|
|
});
|
|
|
|
context('const trx = knex.transaction(cb)', function () {
|
|
context('and cb returns a Promise', function () {
|
|
if (Promise.prototype.finally) {
|
|
it('returns a Transaction that defines a `finally(..)` method', async function () {
|
|
const knex = Knex(sqliteConfig);
|
|
const trx = knex.transaction(async (tx) => {});
|
|
try {
|
|
expect(trx.finally).to.be.a('function');
|
|
} finally {
|
|
await trx;
|
|
}
|
|
return knex.destroy();
|
|
});
|
|
} else {
|
|
it('returns a Transaction that does NOT define a `finally(..)` method', async function () {
|
|
const knex = Knex(sqliteConfig);
|
|
const trx = knex.transaction(async (tx) => {});
|
|
try {
|
|
expect(trx.finally).to.equal(undefined);
|
|
} finally {
|
|
await trx;
|
|
}
|
|
return knex.destroy();
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
it('should have custom method on knex with user params', async () => {
|
|
Knex.QueryBuilder.extend('customSelect', function (value) {
|
|
return this.select(this.client.raw(`${value} as value`));
|
|
});
|
|
|
|
const knex = Knex(sqliteConfig);
|
|
const knewWithParams = knex.withUserParams({ foo: 'bar' });
|
|
const result = await knewWithParams.customSelect(42);
|
|
expect(result[0].value).to.equal(42);
|
|
|
|
return knex.destroy();
|
|
});
|
|
|
|
it('should throw exception when extending existing method', () => {
|
|
expect(() =>
|
|
Knex.QueryBuilder.extend('select', function (value) {})
|
|
).to.throw(`Can't extend QueryBuilder with existing method ('select')`);
|
|
});
|
|
|
|
it('should contain the query context on a query-error event', async function () {
|
|
const spy = sinon.spy();
|
|
const context = { aPrimitive: true };
|
|
const knex = Knex(sqliteConfig)
|
|
.from('test')
|
|
.queryContext(context)
|
|
.on('query-error', spy);
|
|
|
|
try {
|
|
await knex.from('banana');
|
|
// eslint-disable-next-line no-empty
|
|
} catch (_e) {}
|
|
|
|
expect(spy).to.be.calledOnce;
|
|
const [[error, errorArgs]] = spy.args;
|
|
expect(error).to.be.instanceOf(Error);
|
|
expect(errorArgs).to.be.ok;
|
|
expect(errorArgs.queryContext).to.equal(context);
|
|
});
|
|
|
|
// TODO: Consider moving these somewhere that tests the
|
|
// QueryBuilder interface more directly.
|
|
context('qb = knex.select(1)', function () {
|
|
if (Promise.prototype.finally) {
|
|
it('returns a QueryBuilder that defines a `.finally(..)` method', async function () {
|
|
const knex = Knex(sqliteConfig);
|
|
const p = knex.select(1);
|
|
try {
|
|
expect(p.finally).to.be.a('function');
|
|
} finally {
|
|
await p;
|
|
}
|
|
return knex.destroy();
|
|
});
|
|
} else {
|
|
it('returns a QueryBuilder that does NOT define a `.finally(..)` method', async function () {
|
|
const knex = Knex(sqliteConfig);
|
|
const p = knex.select(1);
|
|
try {
|
|
expect(p.finally).to.equal(undefined);
|
|
} finally {
|
|
await p;
|
|
}
|
|
return knex.destroy();
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|