@livestore/wa-sqlite 0.0.0-snapshot-b9a2e1dee494215d8c403be013e25cbf4d2cf380

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/dist/README.md +64 -0
  4. package/dist/fts5/wa-sqlite.mjs +2 -0
  5. package/dist/fts5/wa-sqlite.node.mjs +2 -0
  6. package/dist/fts5/wa-sqlite.node.wasm +0 -0
  7. package/dist/fts5/wa-sqlite.wasm +0 -0
  8. package/dist/wa-sqlite-async.mjs +2 -0
  9. package/dist/wa-sqlite-async.wasm +0 -0
  10. package/dist/wa-sqlite-jspi.mjs +2 -0
  11. package/dist/wa-sqlite-jspi.wasm +0 -0
  12. package/dist/wa-sqlite.mjs +2 -0
  13. package/dist/wa-sqlite.node.mjs +2 -0
  14. package/dist/wa-sqlite.node.wasm +0 -0
  15. package/dist/wa-sqlite.wasm +0 -0
  16. package/package.json +57 -0
  17. package/src/FacadeVFS.js +681 -0
  18. package/src/VFS.js +222 -0
  19. package/src/WebLocksMixin.js +414 -0
  20. package/src/examples/AccessHandlePoolVFS.js +458 -0
  21. package/src/examples/IDBBatchAtomicVFS.js +827 -0
  22. package/src/examples/IDBMirrorVFS.js +889 -0
  23. package/src/examples/MemoryAsyncVFS.js +100 -0
  24. package/src/examples/MemoryVFS.js +176 -0
  25. package/src/examples/OPFSAdaptiveVFS.js +437 -0
  26. package/src/examples/OPFSAnyContextVFS.js +300 -0
  27. package/src/examples/OPFSCoopSyncVFS.js +590 -0
  28. package/src/examples/OPFSPermutedVFS.js +1217 -0
  29. package/src/examples/README.md +89 -0
  30. package/src/examples/tag.js +82 -0
  31. package/src/sqlite-api.js +1339 -0
  32. package/src/sqlite-constants.js +275 -0
  33. package/src/types/globals.d.ts +60 -0
  34. package/src/types/index.d.ts +1531 -0
  35. package/src/types/tsconfig.json +6 -0
  36. package/test/AccessHandlePoolVFS.test.js +27 -0
  37. package/test/IDBBatchAtomicVFS.test.js +97 -0
  38. package/test/IDBMirrorVFS.test.js +27 -0
  39. package/test/MemoryAsyncVFS.test.js +27 -0
  40. package/test/MemoryVFS.test.js +27 -0
  41. package/test/OPFSAdaptiveVFS.test.js +27 -0
  42. package/test/OPFSAnyContextVFS.test.js +27 -0
  43. package/test/OPFSCoopSyncVFS.test.js +27 -0
  44. package/test/OPFSPermutedVFS.test.js +27 -0
  45. package/test/TestContext.js +96 -0
  46. package/test/WebLocksMixin.test.js +521 -0
  47. package/test/api.test.js +49 -0
  48. package/test/api_exec.js +89 -0
  49. package/test/api_misc.js +63 -0
  50. package/test/api_statements.js +447 -0
  51. package/test/callbacks.test.js +581 -0
  52. package/test/data/idbv5.json +1 -0
  53. package/test/sql.test.js +64 -0
  54. package/test/sql_0001.js +49 -0
  55. package/test/sql_0002.js +52 -0
  56. package/test/sql_0003.js +83 -0
  57. package/test/sql_0004.js +81 -0
  58. package/test/sql_0005.js +76 -0
  59. package/test/test-worker.js +204 -0
  60. package/test/vfs_xAccess.js +2 -0
  61. package/test/vfs_xClose.js +52 -0
  62. package/test/vfs_xOpen.js +91 -0
  63. package/test/vfs_xRead.js +38 -0
  64. package/test/vfs_xWrite.js +36 -0
@@ -0,0 +1,581 @@
1
+ import { TestContext } from "./TestContext.js";
2
+ import AsyncifyFactory from 'wa-sqlite/dist/wa-sqlite-async.mjs';
3
+ import JSPIFactory from 'wa-sqlite/dist/wa-sqlite-jspi.mjs';
4
+ import * as SQLite from '../src/sqlite-api.js';
5
+
6
+ const FACTORIES = new Map([
7
+ ['asyncify', AsyncifyFactory],
8
+ ['jspi', JSPIFactory]
9
+ ]);
10
+
11
+ const supportsJSPI = await TestContext.supportsJSPI();
12
+
13
+ for (const [key, factory] of FACTORIES) {
14
+ if (key === 'jspi' && !supportsJSPI) continue;
15
+
16
+ const sqlite3 = await factory().then(module => SQLite.Factory(module));
17
+ describe(`${key} create_function`, function() {
18
+ let db;
19
+ beforeEach(async function() {
20
+ db = await sqlite3.open_v2(':memory:');
21
+ });
22
+
23
+ afterEach(async function() {
24
+ await sqlite3.close(db);
25
+ });
26
+
27
+ it('should return an int', async function() {
28
+ let rc;
29
+
30
+ rc = await sqlite3.create_function(
31
+ db,
32
+ 'fn',
33
+ 0,
34
+ SQLite.SQLITE_DETERMINISTIC, 0,
35
+ (function(context, values) {
36
+ sqlite3.result_int(context, 42);
37
+ }));
38
+ expect(rc).toEqual(SQLite.SQLITE_OK);
39
+
40
+ let result;
41
+ rc = await sqlite3.exec(db, 'SELECT fn()', row => result = row[0]);
42
+ expect(rc).toEqual(SQLite.SQLITE_OK);
43
+ expect(result).toEqual(42);
44
+ });
45
+
46
+ it('should return an int64', async function() {
47
+ let rc;
48
+
49
+ rc = await sqlite3.create_function(
50
+ db,
51
+ 'fn',
52
+ 0,
53
+ SQLite.SQLITE_DETERMINISTIC, 0,
54
+ (function(context, values) {
55
+ sqlite3.result_int64(context, 0x7FFF_FFFF_FFFF_FFFFn);
56
+ }));
57
+ expect(rc).toEqual(SQLite.SQLITE_OK);
58
+
59
+ for await (const stmt of sqlite3.statements(db, 'SELECT fn()')) {
60
+ while (await sqlite3.step(stmt) === SQLite.SQLITE_ROW) {
61
+ const value = sqlite3.column_int64(stmt, 0);
62
+ expect(value).toEqual(0x7FFF_FFFF_FFFF_FFFFn);
63
+ }
64
+ }
65
+ });
66
+
67
+ it('should return a double', async function() {
68
+ let rc;
69
+
70
+ rc = await sqlite3.create_function(
71
+ db,
72
+ 'fn',
73
+ 0,
74
+ SQLite.SQLITE_DETERMINISTIC, 0,
75
+ (function(context, values) {
76
+ sqlite3.result_double(context, 3.14);
77
+ }));
78
+ expect(rc).toEqual(SQLite.SQLITE_OK);
79
+
80
+ let result;
81
+ rc = await sqlite3.exec(db, 'SELECT fn()', row => result = row[0]);
82
+ expect(rc).toEqual(SQLite.SQLITE_OK);
83
+ expect(result).toEqual(3.14);
84
+ });
85
+
86
+ it('should return a string', async function() {
87
+ let rc;
88
+
89
+ rc = await sqlite3.create_function(
90
+ db,
91
+ 'fn',
92
+ 0,
93
+ SQLite.SQLITE_DETERMINISTIC, 0,
94
+ (function(context, values) {
95
+ sqlite3.result_text(context, 'foobar');
96
+ }));
97
+ expect(rc).toEqual(SQLite.SQLITE_OK);
98
+
99
+ let result;
100
+ rc = await sqlite3.exec(db, 'SELECT fn()', row => result = row[0]);
101
+ expect(rc).toEqual(SQLite.SQLITE_OK);
102
+ expect(result).toEqual('foobar');
103
+ });
104
+
105
+ it('should return a blob', async function() {
106
+ let rc;
107
+
108
+ rc = await sqlite3.create_function(
109
+ db,
110
+ 'fn',
111
+ 0,
112
+ SQLite.SQLITE_DETERMINISTIC, 0,
113
+ (function(context, values) {
114
+ sqlite3.result_blob(context, new Uint8Array([0x12, 0x34, 0x56]));
115
+ }));
116
+ expect(rc).toEqual(SQLite.SQLITE_OK);
117
+
118
+ let result;
119
+ rc = await sqlite3.exec(db, 'SELECT fn()', row => result = row[0]);
120
+ expect(rc).toEqual(SQLite.SQLITE_OK);
121
+ expect(result).toEqual(new Uint8Array([0x12, 0x34, 0x56]));
122
+ });
123
+
124
+ it('should return null', async function() {
125
+ let rc;
126
+
127
+ rc = await sqlite3.create_function(
128
+ db,
129
+ 'fn',
130
+ 0,
131
+ SQLite.SQLITE_DETERMINISTIC, 0,
132
+ (function(context, values) {
133
+ sqlite3.result_null(context);
134
+ }));
135
+ expect(rc).toEqual(SQLite.SQLITE_OK);
136
+
137
+ let result;
138
+ rc = await sqlite3.exec(db, 'SELECT fn()', row => result = row[0]);
139
+ expect(rc).toEqual(SQLite.SQLITE_OK);
140
+ expect(result).toEqual(null);
141
+ });
142
+
143
+ it('should pass a fixed number of arguments', async function() {
144
+ let rc;
145
+
146
+ rc = await sqlite3.create_function(
147
+ db,
148
+ 'fn',
149
+ 5,
150
+ SQLite.SQLITE_DETERMINISTIC, 0,
151
+ (function(context, values) {
152
+ expect(sqlite3.value_type(values[0])).toEqual(SQLite.SQLITE_INTEGER);
153
+ expect(sqlite3.value_int(values[0])).toEqual(42);
154
+ expect(sqlite3.value_int64(values[0])).toEqual(42n);
155
+ expect(sqlite3.value(values[0])).toEqual(42);
156
+
157
+ expect(sqlite3.value_type(values[1])).toEqual(SQLite.SQLITE_FLOAT);
158
+ expect(sqlite3.value_double(values[1])).toEqual(3.14);
159
+ expect(sqlite3.value(values[1])).toEqual(3.14);
160
+
161
+ expect(sqlite3.value_type(values[2])).toEqual(SQLite.SQLITE_TEXT);
162
+ expect(sqlite3.value_text(values[2])).toEqual('hello');
163
+ expect(sqlite3.value(values[2])).toEqual('hello');
164
+
165
+ expect(sqlite3.value_type(values[3])).toEqual(SQLite.SQLITE_BLOB);
166
+ expect(sqlite3.value_blob(values[3])).toEqual(new Uint8Array([0x12, 0x34, 0x56]));
167
+ expect(sqlite3.value_bytes(values[3])).toEqual(3);
168
+ expect(sqlite3.value(values[3])).toEqual(new Uint8Array([0x12, 0x34, 0x56]));
169
+
170
+ expect(sqlite3.value_type(values[4])).toEqual(SQLite.SQLITE_NULL);
171
+ }));
172
+ expect(rc).toEqual(SQLite.SQLITE_OK);
173
+
174
+ rc = await sqlite3.exec(db, `
175
+ SELECT fn(42, 3.14, 'hello', x'123456', NULL)
176
+ `);
177
+ expect(rc).toEqual(SQLite.SQLITE_OK);
178
+ });
179
+
180
+ it('should pass a variable number of arguments', async function() {
181
+ let rc;
182
+
183
+ rc = await sqlite3.create_function(
184
+ db,
185
+ 'fn',
186
+ -1,
187
+ SQLite.SQLITE_DETERMINISTIC, 0,
188
+ (function(context, values) {
189
+ expect(values.length).toBe(5);
190
+
191
+ expect(sqlite3.value_type(values[0])).toEqual(SQLite.SQLITE_INTEGER);
192
+ expect(sqlite3.value_int(values[0])).toEqual(42);
193
+ expect(sqlite3.value_int64(values[0])).toEqual(42n);
194
+ expect(sqlite3.value_double(values[0])).toEqual(42.0);
195
+ expect(sqlite3.value(values[0])).toEqual(42);
196
+
197
+ expect(sqlite3.value_type(values[1])).toEqual(SQLite.SQLITE_FLOAT);
198
+ expect(sqlite3.value_double(values[1])).toEqual(3.14);
199
+ expect(sqlite3.value(values[1])).toEqual(3.14);
200
+
201
+ expect(sqlite3.value_type(values[2])).toEqual(SQLite.SQLITE_TEXT);
202
+ expect(sqlite3.value_text(values[2])).toEqual('hello');
203
+ expect(sqlite3.value(values[2])).toEqual('hello');
204
+
205
+ expect(sqlite3.value_type(values[3])).toEqual(SQLite.SQLITE_BLOB);
206
+ expect(sqlite3.value_blob(values[3])).toEqual(new Uint8Array([0x12, 0x34, 0x56]));
207
+ expect(sqlite3.value_bytes(values[3])).toEqual(3);
208
+ expect(sqlite3.value(values[3])).toEqual(new Uint8Array([0x12, 0x34, 0x56]));
209
+
210
+ expect(sqlite3.value_type(values[4])).toEqual(SQLite.SQLITE_NULL);
211
+ }));
212
+ expect(rc).toEqual(SQLite.SQLITE_OK);
213
+
214
+ rc = await sqlite3.exec(db, `
215
+ SELECT fn(42, 3.14, 'hello', x'123456', NULL)
216
+ `);
217
+ expect(rc).toEqual(SQLite.SQLITE_OK);
218
+ });
219
+
220
+ it('should create an aggregate function', async function() {
221
+ let rc;
222
+
223
+ let product = 1;
224
+ rc = await sqlite3.create_function(
225
+ db,
226
+ 'fn',
227
+ 1,
228
+ SQLite.SQLITE_DETERMINISTIC, 0,
229
+ null,
230
+ (function(context, values) {
231
+ const value = sqlite3.value_double(values[0]);
232
+ product *= value;
233
+ }),
234
+ (function(context) {
235
+ sqlite3.result_double(context, product);
236
+ }));
237
+ expect(rc).toEqual(SQLite.SQLITE_OK);
238
+
239
+ rc = await sqlite3.exec(db, `
240
+ SELECT fn(column1) FROM (VALUES (1), (2), (3), (4), (5));
241
+ `);
242
+ expect(rc).toEqual(SQLite.SQLITE_OK);
243
+ expect(product).toEqual(1 * 2 * 3 * 4 * 5);
244
+ });
245
+
246
+ it('should return asynchronously', async function() {
247
+ let rc;
248
+
249
+ rc = await sqlite3.create_function(
250
+ db,
251
+ 'fn',
252
+ 0,
253
+ SQLite.SQLITE_DETERMINISTIC, 0,
254
+ async (context, values) => {
255
+ await new Promise(resolve => setTimeout(resolve));
256
+ sqlite3.result_int(context, 42);
257
+ });
258
+ expect(rc).toEqual(SQLite.SQLITE_OK);
259
+
260
+ let result;
261
+ rc = await sqlite3.exec(db, 'SELECT fn()', row => result = row[0]);
262
+ expect(rc).toEqual(SQLite.SQLITE_OK);
263
+ expect(result).toEqual(42);
264
+ });
265
+ });
266
+
267
+ describe(`${key} progress_handler`, function() {
268
+ let db;
269
+ beforeEach(async function() {
270
+ db = await sqlite3.open_v2(':memory:');
271
+ });
272
+
273
+ afterEach(async function() {
274
+ await sqlite3.close(db);
275
+ });
276
+
277
+ it('should call progress handler', async function() {
278
+ let rc;
279
+
280
+ let count = 0;
281
+ await sqlite3.progress_handler(db, 1, () => ++count && 0, null);
282
+
283
+ rc = await sqlite3.exec(db, `
284
+ CREATE TABLE t AS
285
+ WITH RECURSIVE cnt(x) AS (
286
+ SELECT 1
287
+ UNION ALL
288
+ SELECT x+1 FROM cnt
289
+ LIMIT 100
290
+ )
291
+ SELECT x FROM cnt;
292
+ `);
293
+ expect(rc).toEqual(SQLite.SQLITE_OK);
294
+ expect(count).toBeGreaterThan(0);
295
+ });
296
+
297
+ it('should call asynchronous progress handler', async function() {
298
+ let rc;
299
+
300
+ let count = 0;
301
+ await sqlite3.progress_handler(db, 1, async () => ++count && 0, null);
302
+
303
+ rc = await sqlite3.exec(db, `
304
+ CREATE TABLE t AS
305
+ WITH RECURSIVE cnt(x) AS (
306
+ SELECT 1
307
+ UNION ALL
308
+ SELECT x+1 FROM cnt
309
+ LIMIT 100
310
+ )
311
+ SELECT x FROM cnt;
312
+ `);
313
+ expect(rc).toEqual(SQLite.SQLITE_OK);
314
+ expect(count).toBeGreaterThan(0);
315
+ });
316
+ });
317
+
318
+ describe(`${key} set_authorizer`, function() {
319
+ let db;
320
+ beforeEach(async function() {
321
+ db = await sqlite3.open_v2(':memory:');
322
+ });
323
+
324
+ afterEach(async function() {
325
+ await sqlite3.close(db);
326
+ });
327
+
328
+ it('should call authorizer', async function() {
329
+ let rc;
330
+
331
+ const authorizations = [];
332
+ rc = sqlite3.set_authorizer(db, (_, iActionCode, p3, p4, p5, p6) => {
333
+ authorizations.push([iActionCode, p3, p4, p5, p6]);
334
+ return SQLite.SQLITE_OK;
335
+ });
336
+ expect(rc).toEqual(SQLite.SQLITE_OK);
337
+
338
+ rc = await sqlite3.exec(db, 'CREATE TABLE t(x)');
339
+ expect(rc).toEqual(SQLite.SQLITE_OK);
340
+
341
+ let authCreateTable = false;
342
+ for (const authorization of authorizations) {
343
+ switch (authorization[0]) {
344
+ case SQLite.SQLITE_CREATE_TABLE:
345
+ authCreateTable = true;
346
+ expect(authorization[1]).toEqual('t');
347
+ expect(authorization[2]).toEqual('');
348
+ expect(authorization[3]).toEqual('main');
349
+ expect(authorization[4]).toEqual('');
350
+ break;
351
+ }
352
+ }
353
+ expect(authCreateTable).toBeTrue();
354
+ });
355
+
356
+ it('should deny authorization', async function() {
357
+ let rc;
358
+
359
+ rc = sqlite3.set_authorizer(db, (_, iActionCode, p3, p4, p5, p6) => {
360
+ return SQLite.SQLITE_DENY;
361
+ });
362
+ expect(rc).toEqual(SQLite.SQLITE_OK);
363
+
364
+ const result = sqlite3.exec(db, 'CREATE TABLE t(x)');
365
+ await expectAsync(result).toBeRejectedWith(new Error('not authorized'));
366
+ });
367
+
368
+ it('should call async authorizer', async function() {
369
+ let rc;
370
+
371
+ const authorizations = [];
372
+ rc = sqlite3.set_authorizer(db, async (_, iActionCode, p3, p4, p5, p6) => {
373
+ authorizations.push([iActionCode, p3, p4, p5, p6]);
374
+ return SQLite.SQLITE_OK;
375
+ });
376
+ expect(rc).toEqual(SQLite.SQLITE_OK);
377
+
378
+ rc = await sqlite3.exec(db, 'CREATE TABLE t(x)');
379
+ expect(rc).toEqual(SQLite.SQLITE_OK);
380
+
381
+ expect(authorizations.length).toBeGreaterThan(0);
382
+ });
383
+ });
384
+
385
+ describe(`${key} update_hook`, function() {
386
+ let db;
387
+ beforeEach(async function() {
388
+ db = await sqlite3.open_v2(':memory:');
389
+ });
390
+
391
+ afterEach(async function() {
392
+ await sqlite3.close(db);
393
+ });
394
+
395
+ it('should call update hook', async function() {
396
+ let rc;
397
+
398
+ let calls = [];
399
+ sqlite3.update_hook(db, (updateType, dbName, tblName, rowid) => {
400
+ calls.push([updateType, dbName, tblName, rowid]);
401
+ });
402
+
403
+ rc = await sqlite3.exec(db, `
404
+ CREATE TABLE t(i integer primary key, x);
405
+ INSERT INTO t VALUES (1, 'foo'), (2, 'bar'), (12345678987654321, 'baz');
406
+ `);
407
+ expect(rc).toEqual(SQLite.SQLITE_OK);
408
+ expect(calls).toEqual([
409
+ [18, "main", "t", 1n],
410
+ [18, "main", "t", 2n],
411
+ [18, "main", "t", 12345678987654321n],
412
+ ]);
413
+
414
+ calls.splice(0, calls.length);
415
+
416
+ await sqlite3.exec(db, `DELETE FROM t WHERE i = 2`);
417
+ expect(calls).toEqual([[9, "main", "t", 2n]]);
418
+
419
+ calls.splice(0, calls.length);
420
+
421
+ await sqlite3.exec(db, `UPDATE t SET x = 'bar' WHERE i = 1`);
422
+ expect(calls).toEqual([[23, "main", "t", 1n]]);
423
+ });
424
+ });
425
+
426
+ describe(`${key} commit_hook`, function() {
427
+ let db;
428
+ beforeEach(async function() {
429
+ db = await sqlite3.open_v2(':memory:');
430
+ });
431
+
432
+ afterEach(async function() {
433
+ await sqlite3.close(db);
434
+ });
435
+
436
+ it('should call commit hook', async function() {
437
+ let rc;
438
+
439
+ let callsCount = 0;
440
+ const resetCallsCount = () => callsCount = 0;
441
+
442
+ sqlite3.commit_hook(db, () => {
443
+ callsCount++;
444
+ return 0;
445
+ });
446
+ expect(callsCount).toEqual(0);
447
+ resetCallsCount();
448
+
449
+ rc = await sqlite3.exec(db, `
450
+ CREATE TABLE t(i integer primary key, x);
451
+ `);
452
+ expect(rc).toEqual(SQLite.SQLITE_OK);
453
+ expect(callsCount).toEqual(1);
454
+ resetCallsCount();
455
+
456
+ rc = await sqlite3.exec(db, `
457
+ SELECT * FROM t;
458
+ `);
459
+ expect(callsCount).toEqual(0);
460
+ resetCallsCount();
461
+
462
+ rc = await sqlite3.exec(db, `
463
+ BEGIN TRANSACTION;
464
+ INSERT INTO t VALUES (1, 'foo');
465
+ ROLLBACK;
466
+ `);
467
+ expect(callsCount).toEqual(0);
468
+ resetCallsCount();
469
+
470
+ rc = await sqlite3.exec(db, `
471
+ BEGIN TRANSACTION;
472
+ INSERT INTO t VALUES (1, 'foo');
473
+ INSERT INTO t VALUES (2, 'bar');
474
+ COMMIT;
475
+ `);
476
+ expect(callsCount).toEqual(1);
477
+ resetCallsCount();
478
+ });
479
+
480
+ it('can change commit hook', async function() {
481
+ let rc;
482
+ rc = await sqlite3.exec(db, `
483
+ CREATE TABLE t(i integer primary key, x);
484
+ `);
485
+ expect(rc).toEqual(SQLite.SQLITE_OK);
486
+
487
+ let a = 0;
488
+ let b = 0;
489
+
490
+ // set hook to increment `a` on commit
491
+ sqlite3.commit_hook(db, () => {
492
+ a++;
493
+ return 0;
494
+ });
495
+ rc = await sqlite3.exec(db, `
496
+ INSERT INTO t VALUES (1, 'foo');
497
+ `);
498
+ expect(a).toEqual(1);
499
+ expect(b).toEqual(0);
500
+
501
+ // switch to increment `b`
502
+ sqlite3.commit_hook(db, () => {
503
+ b++;
504
+ return 0;
505
+ });
506
+
507
+ rc = await sqlite3.exec(db, `
508
+ INSERT INTO t VALUES (2, 'bar');
509
+ `);
510
+ expect(rc).toEqual(SQLite.SQLITE_OK);
511
+ expect(a).toEqual(1);
512
+ expect(b).toEqual(1);
513
+
514
+ // disable hook by passing null
515
+ sqlite3.commit_hook(db, null);
516
+
517
+ rc = await sqlite3.exec(db, `
518
+ INSERT INTO t VALUES (3, 'qux');
519
+ `);
520
+ expect(rc).toEqual(SQLite.SQLITE_OK);
521
+ expect(a).toEqual(1);
522
+ expect(b).toEqual(1);
523
+ });
524
+
525
+ it('can rollback based on return value', async function() {
526
+ let rc;
527
+ rc = await sqlite3.exec(db, `
528
+ CREATE TABLE t(i integer primary key, x);
529
+ `);
530
+ expect(rc).toEqual(SQLite.SQLITE_OK);
531
+
532
+ // accept commit by returning 0
533
+ sqlite3.commit_hook(db, () => 0);
534
+ rc = await sqlite3.exec(db, `
535
+ INSERT INTO t VALUES (1, 'foo');
536
+ `);
537
+ expect(rc).toEqual(SQLite.SQLITE_OK);
538
+
539
+ // reject commit by returning 1, causing rollback
540
+ sqlite3.commit_hook(db, () => 1);
541
+ await expectAsync(
542
+ sqlite3.exec(db, `INSERT INTO t VALUES (2, 'bar');`)
543
+ ).toBeRejected();
544
+
545
+ // double-check that the insert was rolled back
546
+ let hasRow = false;
547
+ rc = await sqlite3.exec(db, `
548
+ SELECT * FROM t WHERE i = 2;
549
+ `, () => hasRow = true);
550
+ expect(rc).toEqual(SQLite.SQLITE_OK);
551
+ expect(hasRow).toBeFalse();
552
+ });
553
+
554
+ it('does not overwrite update_hook', async function() {
555
+ let rc;
556
+ rc = await sqlite3.exec(db, `
557
+ CREATE TABLE t(i integer primary key, x);
558
+ `);
559
+ expect(rc).toEqual(SQLite.SQLITE_OK);
560
+
561
+ let updateHookInvocationsCount = 0;
562
+ sqlite3.update_hook(db, (...args) => {
563
+ updateHookInvocationsCount++;
564
+ });
565
+
566
+ let commitHookInvocationsCount = 0;
567
+ sqlite3.commit_hook(db, () => {
568
+ commitHookInvocationsCount++;
569
+ return 0;
570
+ });
571
+
572
+ rc = await sqlite3.exec(db, `
573
+ INSERT INTO t VALUES (1, 'foo');
574
+ `);
575
+ expect(rc).toEqual(SQLite.SQLITE_OK);
576
+
577
+ expect(updateHookInvocationsCount).toEqual(1);
578
+ expect(commitHookInvocationsCount).toEqual(1);
579
+ });
580
+ });
581
+ }