Skip to content

Commit

Permalink
add pre exec hook
Browse files Browse the repository at this point in the history
  • Loading branch information
ccyphers committed May 7, 2024
1 parent 9659a20 commit a74bd83
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 0 deletions.
18 changes: 18 additions & 0 deletions lib/execution/internal/ensure-connection-callback.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,24 @@ function ensureConnectionCallback(runner) {
if (Array.isArray(sql)) {
return runner.queryArray(sql);
}

if (typeof runner.client.config.preExecHook === 'function') {
return runner.client.config.preExecHook(sql).then((hookRes) => {
hookRes = hookRes || {};

if (!hookRes.hasOwnProperty('continue')) {
hookRes.continue = true;
}

if (hookRes.continue) {
return runner.query(sql);
} else {
hookRes.data = hookRes.data || [];
return Promise.resolve(hookRes.data);
}
});
}

return runner.query(sql);
}

Expand Down
95 changes: 95 additions & 0 deletions test/integration2/query/select/hooks.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
const { expect } = require('chai');
const {
Db,
getAllDbs,
getKnexForDb,
} = require('../../util/knex-instance-provider');

describe('Selects', () => {
describe('select query', () => {
getAllDbs()
// only sqlite is currently supported
.filter((db) => db === Db.SQLite)
.forEach((db) => {
describe(db, () => {
let knex;

after(() => {
return knex.destroy();
});

afterEach(async () => {
await knex.schema.dropTable('fts_products');
});

/* this is a good example for when you might have a pre hook
that checks some other cache first and returns that data on HIT
If HIT one would set continue to false to indicate not to EXEC the SQL,
but rather short circuit with cache data
*/
it('does not query DB and returns data from preExecHook', async () => {
const settings = {
preExecHook(queryObj) {
return Promise.resolve({
continue: false,
data: ['short circuit pre exec hook'],
});
},
};

knex = getKnexForDb(db, settings);
await knex.schema.raw(
'CREATE VIRTUAL TABLE fts_products USING fts5(name);'
);

const matchingRows = await knex
.select('*')
.from('fts_products')
.where('name', 'match', 'red shirt');

expect(matchingRows).to.eql(['short circuit pre exec hook']);
});

/* example preExecHook where SQL is executed as continue is true
In the above cache example in this case it would represent a MISS,
where you would fall back to EXEC SQL and then you could store response
in local cache.
Or you could use continue as true in other example for some generic logging
and such.
*/
it('defines preExecHook but returns data from db', async () => {
const settings = {
preExecHook(queryObj) {
return Promise.resolve({ continue: true });
},
};

knex = getKnexForDb(db, settings);
await knex.schema.raw(
'CREATE VIRTUAL TABLE fts_products USING fts5(name);'
);

await knex('fts_products').insert([
{ name: 'Red flannel shirt' },
{ name: 'Blue flannel shirt' },
{ name: 'Red polo shirt' },
{ name: 'Blue polo shirt' },
{ name: 'Red hooded jacket' },
{ name: 'Blue hooded jacket' },
]);

const matchingRows = await knex
.select('*')
.from('fts_products')
.where('name', 'match', 'red shirt');

expect(matchingRows).to.eql([
{ name: 'Red flannel shirt' },
{ name: 'Red polo shirt' },
]);
});
});
});
});
});
8 changes: 8 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2726,6 +2726,13 @@ declare namespace Knex {
nullable: boolean;
}

type PreExecHookPromiseResponse = {
continue: boolean;
data: [];
};

type PreExecHook = Promise<PreExecHookPromiseResponse>;

interface Config<SV extends {} = any> {
debug?: boolean;
client?: string | typeof Client;
Expand All @@ -2735,6 +2742,7 @@ declare namespace Knex {
connection?: string | StaticConnectionConfig | ConnectionConfigProvider;
pool?: PoolConfig;
migrations?: MigratorConfig;
preExecHook?: () => PreExecHook;
postProcessResponse?: (result: any, queryContext: any) => any;
wrapIdentifier?: (
value: string,
Expand Down

0 comments on commit a74bd83

Please sign in to comment.