Skip to content

Commit 1dd17d4

Browse files
authored
feat: query cancel signal (#53)
* add: queue empty method * bump: version * refactor: folder * add: cancel signal * add: test * update: comment * fix: build * resolve: comments * fix: build * fix: test * update: package
1 parent b0b7715 commit 1dd17d4

File tree

16 files changed

+281
-88
lines changed

16 files changed

+281
-88
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,6 @@ Thumbs.db
4040

4141
# Next.js
4242
.next
43+
44+
# NX
45+
.nx

benchmarking/benchmarking-app/src/app/benchmarking-tests/dbm-benchmarking.spec.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import axios from 'axios';
2-
import { spawn } from 'child_process';
2+
import { ChildProcess, spawn } from 'child_process';
33
import * as puppeteer from 'puppeteer';
44

55
describe('Benchmarking DBMs', () => {
6-
let page;
7-
let browser;
8-
let appProcess;
6+
let page: puppeteer.Page;
7+
let browser: puppeteer.Browser;
8+
let appProcess: ChildProcess;
99

1010
let totalTimeForMemoryDB: number;
1111

benchmarking/benchmarking-app/src/app/dbm-context/raw-dbm-context.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const RawDBMProvider = ({ children }: { children: JSX.Element }) => {
3636
/**
3737
* Making the queryWithTableNames simply run the queries without sequence which is the default behavior
3838
*/
39-
dbm.queryWithTableNames = async (query, tableNames) => {
39+
dbm.queryWithTableNames = async ({ query, tableNames }) => {
4040
return dbm.query(query);
4141
};
4242
setdbm(dbm);

benchmarking/benchmarking-app/src/app/query-benchmarking/query-benchmarking.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const QueryBenchmarking = () => {
2323
const eachQueryStart = performance.now();
2424

2525
const promiseObj = dbm
26-
.queryWithTableNames(TEST_QUERIES[i], ['taxi'])
26+
.queryWithTableNames({ query: TEST_QUERIES[i], tableNames: ['taxi'] })
2727
.then((results) => {
2828
const end = performance.now();
2929
const time = end - eachQueryStart;

meerkat-dbm/package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
{
22
"name": "@devrev/meerkat-dbm",
3-
"version": "0.0.142",
3+
"version": "0.0.143",
44
"dependencies": {
55
"tslib": "^2.3.0",
66
"@duckdb/duckdb-wasm": "^1.28.0",
77
"dexie": "^3.2.4",
8-
"loglevel": "^1.8.1"
8+
"loglevel": "^1.8.1",
9+
"uuid": "^9.0.1"
910
},
1011
"repository": {
1112
"type": "git",

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

+110-31
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { FileData, Table, TableWiseFiles } from '../types';
99
import { DBM } from './dbm';
1010
import { InstanceManagerType } from './instance-manager';
1111
import { DBMConstructorOptions } from './types';
12+
1213
export class MockFileManager implements FileManagerType {
1314
private fileBufferStore: Record<string, FileBufferStore> = {};
1415
private tables: Record<string, Table> = {};
@@ -139,6 +140,13 @@ const mockDB = {
139140
}, 200);
140141
});
141142
},
143+
cancelSent: async () => {
144+
return new Promise((resolve) => {
145+
setTimeout(() => {
146+
resolve(true);
147+
}, 100);
148+
});
149+
},
142150
close: async () => {
143151
// do nothing
144152
},
@@ -203,13 +211,13 @@ describe('DBM', () => {
203211
buffer: new Uint8Array(),
204212
});
205213

206-
const result = await dbm.queryWithTableNames(
207-
'SELECT * FROM table1',
208-
['table1'],
209-
{
214+
const result = await dbm.queryWithTableNames({
215+
query: 'SELECT * FROM table1',
216+
tableNames: ['table1'],
217+
options: {
210218
preQuery,
211-
}
212-
);
219+
},
220+
});
213221

214222
expect(preQuery).toBeCalledTimes(1);
215223

@@ -222,19 +230,22 @@ describe('DBM', () => {
222230
});
223231

224232
it('should execute a query with table names', async () => {
225-
const result = await dbm.queryWithTableNames('SELECT * FROM table1', [
226-
'table1',
227-
]);
233+
const result = await dbm.queryWithTableNames({
234+
query: 'SELECT * FROM table1',
235+
tableNames: ['table1'],
236+
});
228237
expect(result).toEqual(['SELECT * FROM table1']);
229238
});
230239

231240
it('should execute multiple queries with table names', async () => {
232-
const promise1 = dbm.queryWithTableNames('SELECT * FROM table1', [
233-
'table1',
234-
]);
235-
const promise2 = dbm.queryWithTableNames('SELECT * FROM table2', [
236-
'table1',
237-
]);
241+
const promise1 = dbm.queryWithTableNames({
242+
query: 'SELECT * FROM table1',
243+
tableNames: ['table1'],
244+
});
245+
const promise2 = dbm.queryWithTableNames({
246+
query: 'SELECT * FROM table2',
247+
tableNames: ['table1'],
248+
});
238249
/**
239250
* Number of queries in the queue should be 1 as the first query is running
240251
*/
@@ -260,9 +271,10 @@ describe('DBM', () => {
260271
/**
261272
* Execute another query
262273
*/
263-
const promise3 = dbm.queryWithTableNames('SELECT * FROM table3', [
264-
'table1',
265-
]);
274+
const promise3 = dbm.queryWithTableNames({
275+
query: 'SELECT * FROM table3',
276+
tableNames: ['table1'],
277+
});
266278

267279
/**
268280
* Now the queue should be running
@@ -302,16 +314,18 @@ describe('DBM', () => {
302314
/**
303315
* Execute a query
304316
*/
305-
const promise1 = dbm.queryWithTableNames('SELECT * FROM table1', [
306-
'table1',
307-
]);
317+
const promise1 = dbm.queryWithTableNames({
318+
query: 'SELECT * FROM table1',
319+
tableNames: ['table1'],
320+
});
308321

309322
/**
310323
* Execute another query
311324
*/
312-
const promise2 = dbm.queryWithTableNames('SELECT * FROM table2', [
313-
'table1',
314-
]);
325+
const promise2 = dbm.queryWithTableNames({
326+
query: 'SELECT * FROM table2',
327+
tableNames: ['table1'],
328+
});
315329

316330
/**
317331
* Wait for the queries to complete
@@ -361,16 +375,18 @@ describe('DBM', () => {
361375
/**
362376
* Execute a query
363377
*/
364-
const promise1 = dbm.queryWithTableNames('SELECT * FROM table1', [
365-
'table1',
366-
]);
378+
const promise1 = dbm.queryWithTableNames({
379+
query: 'SELECT * FROM table1',
380+
tableNames: ['table1'],
381+
});
367382

368383
/**
369384
* Execute another query
370385
*/
371-
const promise2 = dbm.queryWithTableNames('SELECT * FROM table2', [
372-
'table1',
373-
]);
386+
const promise2 = dbm.queryWithTableNames({
387+
query: 'SELECT * FROM table2',
388+
tableNames: ['table1'],
389+
});
374390

375391
/**
376392
* Wait for the queries to complete
@@ -404,7 +420,10 @@ describe('DBM', () => {
404420
/**
405421
* Execute a query
406422
*/
407-
await dbm.queryWithTableNames('SELECT * FROM table1', ['table1']);
423+
await dbm.queryWithTableNames({
424+
query: 'SELECT * FROM table1',
425+
tableNames: ['table1'],
426+
});
408427

409428
/**
410429
* wait for 200ms
@@ -417,4 +436,64 @@ describe('DBM', () => {
417436
expect(instanceManager.terminateDB).not.toBeCalled();
418437
});
419438
});
439+
440+
describe('cancel query execution', () => {
441+
it('should cancel the current executing query when abort is emitted', async () => {
442+
const abortController1 = new AbortController();
443+
444+
// check the current query throws error abort is emitted
445+
try {
446+
const promise = dbm.queryWithTableNames({
447+
query: 'SELECT * FROM table1',
448+
tableNames: ['table1'],
449+
options: {
450+
signal: abortController1.signal,
451+
},
452+
});
453+
454+
abortController1.abort();
455+
456+
await promise;
457+
458+
expect(promise).not.toBeDefined();
459+
} catch (e) {
460+
expect(e).toBeDefined();
461+
}
462+
});
463+
464+
it('should cancel the query in the queue when abort is emitted', async () => {
465+
const abortController1 = new AbortController();
466+
const abortController2 = new AbortController();
467+
468+
const mockDBMQuery = jest.spyOn(dbm, 'query');
469+
470+
const promise1 = dbm.queryWithTableNames({
471+
query: 'SELECT * FROM table1',
472+
tableNames: ['table1'],
473+
options: {
474+
signal: abortController1.signal,
475+
},
476+
});
477+
478+
const promise2 = dbm.queryWithTableNames({
479+
query: 'SELECT * FROM table2',
480+
tableNames: ['table2'],
481+
options: {
482+
signal: abortController2.signal,
483+
},
484+
});
485+
486+
abortController2.abort();
487+
488+
const promises = await Promise.allSettled([promise1, promise2]);
489+
490+
// the first query should be fulfilled
491+
expect(mockDBMQuery).toBeCalledWith('SELECT * FROM table1');
492+
expect(promises[0].status).toBe('fulfilled');
493+
494+
// the second query should be rejected as it was aborted
495+
expect(mockDBMQuery).not.toBeCalledWith('SELECT * FROM table2');
496+
expect(promises[1].status).toBe('rejected');
497+
});
498+
});
420499
});

0 commit comments

Comments
 (0)