Skip to content

Commit 98eaa71

Browse files
authored
Add beforeQuery hook to query method (#39)
* Add beforeQuery hook * Fix lints * Bump version * Adding onDuckdbShutdown to be called
1 parent 5a7a4d7 commit 98eaa71

File tree

7 files changed

+166
-16
lines changed

7 files changed

+166
-16
lines changed

.github/workflows/publish-package.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,25 @@ jobs:
2323
cd ./dist/meerkat-dbm
2424
echo "//npm.pkg.github.com/:_authToken=${{secrets.NPM_PACKAGE_PUBLISH_TOKEN}}" >> .npmrc
2525
npm publish
26+
continue-on-error: true
2627
2728
- run: |
2829
cd ./dist/meerkat-core
2930
echo "//npm.pkg.github.com/:_authToken=${{secrets.NPM_PACKAGE_PUBLISH_TOKEN}}" >> .npmrc
3031
npm publish
32+
continue-on-error: true
3133
3234
- run: |
3335
cd ./dist/meerkat-node
3436
echo "//npm.pkg.github.com/:_authToken=${{secrets.NPM_PACKAGE_PUBLISH_TOKEN}}" >> .npmrc
3537
npm publish
38+
continue-on-error: true
3639
3740
- run: |
3841
cd ./dist/meerkat-browser
3942
echo "//npm.pkg.github.com/:_authToken=${{secrets.NPM_PACKAGE_PUBLISH_TOKEN}}" >> .npmrc
4043
npm publish
41-
44+
continue-on-error: true
45+
4246
env:
4347
NODE_AUTH_TOKEN: ${{secrets.NPM_PACKAGE_PUBLISH_TOKEN}}

meerkat-dbm/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devrev/meerkat-dbm",
3-
"version": "0.0.132",
3+
"version": "0.0.133",
44
"dependencies": {
55
"tslib": "^2.3.0",
66
"@duckdb/duckdb-wasm": "^1.28.0",

meerkat-dbm/src/dbm/dbm.spec.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,35 @@ export class MockFileManager implements FileManagerType {
7171
delete this.fileBufferStore[fileName];
7272
}
7373
}
74+
75+
async getFilesNameForTables(tableNames: string[]): Promise<
76+
{
77+
tableName: string;
78+
files: string[];
79+
}[]
80+
> {
81+
const data: {
82+
tableName: string;
83+
files: string[];
84+
}[] = [];
85+
86+
for (const tableName of tableNames) {
87+
const files: string[] = [];
88+
89+
for (const key in this.fileBufferStore) {
90+
if (this.fileBufferStore[key].tableName === tableName) {
91+
files.push(key);
92+
}
93+
}
94+
95+
data.push({
96+
tableName,
97+
files,
98+
});
99+
}
100+
101+
return data;
102+
}
74103
}
75104

76105
const mockDB = {
@@ -135,6 +164,33 @@ describe('DBM', () => {
135164
});
136165

137166
describe('queryWithTableNames', () => {
167+
it('should call the beforeQuery hook', async () => {
168+
const beforeQuery = jest.fn();
169+
170+
await fileManager.registerFileBuffer({
171+
fileName: 'file1',
172+
tableName: 'table1',
173+
buffer: new Uint8Array(),
174+
});
175+
176+
const result = await dbm.queryWithTableNames(
177+
'SELECT * FROM table1',
178+
['table1'],
179+
{
180+
beforeQuery,
181+
}
182+
);
183+
184+
expect(beforeQuery).toBeCalledTimes(1);
185+
186+
expect(beforeQuery).toBeCalledWith([
187+
{
188+
tableName: 'table1',
189+
files: ['file1'],
190+
},
191+
]);
192+
});
193+
138194
it('should execute a query with table names', async () => {
139195
const result = await dbm.queryWithTableNames('SELECT * FROM table1', [
140196
'table1',
@@ -195,6 +251,8 @@ describe('DBM', () => {
195251
// If instanceManager.terminateDB is a method
196252
jest.spyOn(instanceManager, 'terminateDB');
197253

254+
const onDuckdbShutdown = jest.fn();
255+
198256
// If instanceManager.terminateDB is a function
199257
instanceManager.terminateDB = jest.fn();
200258
const options: DBMConstructorOptions = {
@@ -204,6 +262,7 @@ describe('DBM', () => {
204262
onEvent: (event) => {
205263
console.log(event);
206264
},
265+
onDuckdbShutdown: onDuckdbShutdown,
207266
options: {
208267
shutdownInactiveTime: 100,
209268
},
@@ -239,6 +298,12 @@ describe('DBM', () => {
239298
* wait for 200ms
240299
*/
241300
await new Promise((resolve) => setTimeout(resolve, 200));
301+
302+
/**
303+
* Expect onDuckdbShutdown to be called
304+
*/
305+
expect(onDuckdbShutdown).toBeCalled();
306+
242307
/**
243308
* Expect instanceManager.terminateDB to be called
244309
*/

meerkat-dbm/src/dbm/dbm.ts

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export interface DBMConstructorOptions {
88
fileManager: FileManagerType;
99
logger: DBMLogger;
1010
onEvent?: (event: DBMEvent) => void;
11+
onDuckdbShutdown?: () => void;
1112
instanceManager: InstanceManagerType;
1213
options?: {
1314
/**
@@ -16,6 +17,18 @@ export interface DBMConstructorOptions {
1617
shutdownInactiveTime?: number;
1718
};
1819
}
20+
21+
type BeforeQueryHook = (
22+
data: {
23+
tableName: string;
24+
files: string[];
25+
}[]
26+
) => Promise<void>;
27+
28+
type QueryOptions = {
29+
beforeQuery: BeforeQueryHook;
30+
};
31+
1932
export class DBM {
2033
private fileManager: FileManagerType;
2134
private instanceManager: InstanceManagerType;
@@ -31,25 +44,39 @@ export class DBM {
3144
* Timestamp when the query was added to the queue
3245
*/
3346
timestamp: number;
47+
options?: { beforeQuery: BeforeQueryHook };
3448
}[] = [];
49+
private beforeQuery?: ({
50+
query,
51+
tableByFiles,
52+
}: {
53+
query: string;
54+
tableByFiles: {
55+
tableName: string;
56+
files: string[];
57+
}[];
58+
}) => Promise<void>;
3559
private queryQueueRunning = false;
3660
private logger: DBMLogger;
3761
private onEvent?: (event: DBMEvent) => void;
3862
private options: DBMConstructorOptions['options'];
3963
private terminateDBTimeout: NodeJS.Timeout | null = null;
64+
private onDuckdbShutdown?: () => void;
4065

4166
constructor({
4267
fileManager,
4368
logger,
4469
onEvent,
4570
options,
4671
instanceManager,
72+
onDuckdbShutdown,
4773
}: DBMConstructorOptions) {
4874
this.fileManager = fileManager;
4975
this.logger = logger;
5076
this.onEvent = onEvent;
5177
this.options = options;
5278
this.instanceManager = instanceManager;
79+
this.onDuckdbShutdown = onDuckdbShutdown;
5380
}
5481

5582
private async _shutdown() {
@@ -58,6 +85,9 @@ export class DBM {
5885
this.connection = null;
5986
}
6087
this.logger.debug('Shutting down the DB');
88+
if (this.onDuckdbShutdown) {
89+
this.onDuckdbShutdown();
90+
}
6191
await this.instanceManager.terminateDB();
6292
}
6393

@@ -97,7 +127,11 @@ export class DBM {
97127
return this.connection;
98128
}
99129

100-
private async _queryWithTableNames(query: string, tableNames: string[]) {
130+
private async _queryWithTableNames(
131+
query: string,
132+
tableNames: string[],
133+
options?: QueryOptions
134+
) {
101135
/**
102136
* Load all the files into the database
103137
*/
@@ -117,6 +151,17 @@ export class DBM {
117151
duration: endMountTime - startMountTime,
118152
});
119153

154+
const tablesFileData = await this.fileManager.getFilesNameForTables(
155+
tableNames
156+
);
157+
158+
/**
159+
* Execute the beforeQuery hook
160+
*/
161+
if (options?.beforeQuery) {
162+
await options.beforeQuery(tablesFileData);
163+
}
164+
120165
/**
121166
* Execute the query
122167
*/
@@ -189,11 +234,11 @@ export class DBM {
189234
/**
190235
* Get the first query
191236
*/
192-
const query = this.queriesQueue.shift();
237+
const queueElement = this.queriesQueue.shift();
193238
/**
194239
* If there is no query, stop the queue
195240
*/
196-
if (!query) {
241+
if (!queueElement) {
197242
await this._stopQueryQueue();
198243
return;
199244
}
@@ -202,41 +247,42 @@ export class DBM {
202247
const startTime = Date.now();
203248
this.logger.debug(
204249
'Time since query was added to the queue:',
205-
startTime - query.timestamp,
250+
startTime - queueElement.timestamp,
206251
'ms',
207-
query.query
252+
queueElement.query
208253
);
209254

210255
this._emitEvent({
211256
event_name: 'query_queue_duration',
212-
duration: startTime - query.timestamp,
257+
duration: startTime - queueElement.timestamp,
213258
});
214259

215260
/**
216261
* Execute the query
217262
*/
218263
const result = await this._queryWithTableNames(
219-
query.query,
220-
query.tableNames
264+
queueElement.query,
265+
queueElement.tableNames,
266+
queueElement.options
221267
);
222268
const endTime = Date.now();
223269

224270
this.logger.debug(
225271
'Total time spent along with queue time',
226-
endTime - query.timestamp,
272+
endTime - queueElement.timestamp,
227273
'ms',
228-
query.query
274+
queueElement.query
229275
);
230276
/**
231277
* Resolve the promise
232278
*/
233-
query.promise.resolve(result);
279+
queueElement.promise.resolve(result);
234280
} catch (error) {
235-
this.logger.warn('Error while executing query:', query.query);
281+
this.logger.warn('Error while executing query:', queueElement.query);
236282
/**
237283
* Reject the promise, so the caller can catch the error
238284
*/
239-
query.promise.reject(error);
285+
queueElement.promise.reject(error);
240286
}
241287

242288
/**
@@ -266,7 +312,11 @@ export class DBM {
266312
return this.queryQueueRunning;
267313
}
268314

269-
public async queryWithTableNames(query: string, tableNames: string[]) {
315+
public async queryWithTableNames(
316+
query: string,
317+
tableNames: string[],
318+
options?: { beforeQuery: BeforeQueryHook }
319+
) {
270320
const promise = new Promise((resolve, reject) => {
271321
this.queriesQueue.push({
272322
query,
@@ -276,6 +326,7 @@ export class DBM {
276326
reject,
277327
},
278328
timestamp: Date.now(),
329+
options,
279330
});
280331
});
281332
this._startQueryQueue();

meerkat-dbm/src/file-manager/file-manager-type.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ export interface FileManagerType {
1717
unmountFileBufferByTableNames: (tableName: string[]) => Promise<void>;
1818
getFilesByTableName(tableName: string): Promise<FileData[]>;
1919
dropFilesByTableName(tableName: string, fileNames: string[]): Promise<void>;
20+
getFilesNameForTables(tableNames: string[]): Promise<
21+
{
22+
tableName: string;
23+
files: string[];
24+
}[]
25+
>;
2026
}
2127

2228
export interface FileManagerConstructorOptions {

meerkat-dbm/src/file-manager/indexed-db/indexed-db-file-manager.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,20 @@ export class IndexedDBFileManager implements FileManagerType {
128128
return fileData?.buffer;
129129
}
130130

131+
async getFilesNameForTables(tableNames: string[]): Promise<
132+
{
133+
tableName: string;
134+
files: string[];
135+
}[]
136+
> {
137+
const tableData = await this.indexedDB.tablesKey.bulkGet(tableNames);
138+
139+
return tableData.map((table) => ({
140+
tableName: table?.tableName ?? '',
141+
files: (table?.files ?? []).map((file) => file.fileName),
142+
}));
143+
}
144+
131145
async mountFileBufferByTableNames(tableNames: string[]): Promise<void> {
132146
const tableData = await this.indexedDB.tablesKey.bulkGet(tableNames);
133147

meerkat-dbm/src/file-manager/memory-file-manager.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ export class MemoryDBFileManager implements FileManagerType {
4646
// not needed for memory file manager
4747
}
4848

49+
async getFilesNameForTables(tableNames: string[]): Promise<
50+
{
51+
tableName: string;
52+
files: string[];
53+
}[]
54+
> {
55+
// not needed for memory file manager
56+
return [];
57+
}
58+
4959
async getFilesByTableName(tableName: string): Promise<FileData[]> {
5060
// not needed for memory file manager
5161
return [];

0 commit comments

Comments
 (0)