@livestore/wa-sqlite 1.0.1-dev.0

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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +78 -0
  3. package/dist/wa-sqlite-async.mjs +16 -0
  4. package/dist/wa-sqlite-async.wasm +0 -0
  5. package/dist/wa-sqlite-jspi.mjs +16 -0
  6. package/dist/wa-sqlite-jspi.wasm +0 -0
  7. package/dist/wa-sqlite.mjs +16 -0
  8. package/dist/wa-sqlite.wasm +0 -0
  9. package/package.json +45 -0
  10. package/src/FacadeVFS.js +508 -0
  11. package/src/VFS.js +222 -0
  12. package/src/WebLocksMixin.js +412 -0
  13. package/src/examples/AccessHandlePoolVFS.js +458 -0
  14. package/src/examples/IDBBatchAtomicVFS.js +820 -0
  15. package/src/examples/IDBMirrorVFS.js +875 -0
  16. package/src/examples/MemoryAsyncVFS.js +100 -0
  17. package/src/examples/MemoryVFS.js +176 -0
  18. package/src/examples/OPFSAdaptiveVFS.js +437 -0
  19. package/src/examples/OPFSAnyContextVFS.js +300 -0
  20. package/src/examples/OPFSCoopSyncVFS.js +590 -0
  21. package/src/examples/OPFSPermutedVFS.js +1214 -0
  22. package/src/examples/README.md +89 -0
  23. package/src/examples/tag.js +82 -0
  24. package/src/sqlite-api.js +914 -0
  25. package/src/sqlite-constants.js +275 -0
  26. package/src/types/globals.d.ts +60 -0
  27. package/src/types/index.d.ts +1302 -0
  28. package/src/types/tsconfig.json +6 -0
  29. package/test/AccessHandlePoolVFS.test.js +27 -0
  30. package/test/IDBBatchAtomicVFS.test.js +97 -0
  31. package/test/IDBMirrorVFS.test.js +27 -0
  32. package/test/MemoryAsyncVFS.test.js +27 -0
  33. package/test/MemoryVFS.test.js +27 -0
  34. package/test/OPFSAdaptiveVFS.test.js +27 -0
  35. package/test/OPFSAnyContextVFS.test.js +27 -0
  36. package/test/OPFSCoopSyncVFS.test.js +27 -0
  37. package/test/OPFSPermutedVFS.test.js +27 -0
  38. package/test/TestContext.js +96 -0
  39. package/test/WebLocksMixin.test.js +521 -0
  40. package/test/api.test.js +49 -0
  41. package/test/api_exec.js +89 -0
  42. package/test/api_misc.js +63 -0
  43. package/test/api_statements.js +426 -0
  44. package/test/callbacks.test.js +373 -0
  45. package/test/sql.test.js +64 -0
  46. package/test/sql_0001.js +49 -0
  47. package/test/sql_0002.js +52 -0
  48. package/test/sql_0003.js +83 -0
  49. package/test/sql_0004.js +81 -0
  50. package/test/sql_0005.js +76 -0
  51. package/test/test-worker.js +204 -0
  52. package/test/vfs_xAccess.js +2 -0
  53. package/test/vfs_xClose.js +52 -0
  54. package/test/vfs_xOpen.js +91 -0
  55. package/test/vfs_xRead.js +38 -0
  56. package/test/vfs_xWrite.js +36 -0
@@ -0,0 +1,6 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020"
4
+ },
5
+ "files": ["index.d.ts"]
6
+ }
@@ -0,0 +1,27 @@
1
+ import { TestContext } from "./TestContext.js";
2
+ import { vfs_xOpen } from "./vfs_xOpen.js";
3
+ import { vfs_xAccess } from "./vfs_xAccess.js";
4
+ import { vfs_xClose } from "./vfs_xClose.js";
5
+ import { vfs_xRead } from "./vfs_xRead.js";
6
+ import { vfs_xWrite } from "./vfs_xWrite.js";
7
+
8
+ const CONFIG = 'AccessHandlePoolVFS';
9
+ const BUILDS = ['default', 'asyncify', 'jspi'];
10
+
11
+ const supportsJSPI = await TestContext.supportsJSPI();
12
+
13
+ describe(CONFIG, function() {
14
+ for (const build of BUILDS) {
15
+ if (build === 'jspi' && !supportsJSPI) return;
16
+
17
+ describe(build, function() {
18
+ const context = new TestContext({ build, config: CONFIG });
19
+
20
+ vfs_xAccess(context);
21
+ vfs_xOpen(context);
22
+ vfs_xClose(context);
23
+ vfs_xRead(context);
24
+ vfs_xWrite(context);
25
+ });
26
+ }
27
+ });
@@ -0,0 +1,97 @@
1
+ import { TestContext } from "./TestContext.js";
2
+ import { vfs_xOpen } from "./vfs_xOpen.js";
3
+ import { vfs_xAccess } from "./vfs_xAccess.js";
4
+ import { vfs_xClose } from "./vfs_xClose.js";
5
+ import { vfs_xRead } from "./vfs_xRead.js";
6
+ import { vfs_xWrite } from "./vfs_xWrite.js";
7
+
8
+ import SQLiteESMFactory from '../dist/wa-sqlite-async.mjs';
9
+ import * as SQLite from '../src/sqlite-api.js';
10
+ import { IDBBatchAtomicVFS } from "../src/examples/IDBBatchAtomicVFS.js";
11
+
12
+ const CONFIG = 'IDBBatchAtomicVFS';
13
+ const BUILDS = ['asyncify', 'jspi'];
14
+
15
+ const supportsJSPI = await TestContext.supportsJSPI();
16
+
17
+ describe(CONFIG, function() {
18
+ for (const build of BUILDS) {
19
+ if (build === 'jspi' && !supportsJSPI) return;
20
+
21
+ describe(build, function() {
22
+ const context = new TestContext({ build, config: CONFIG });
23
+
24
+ vfs_xAccess(context);
25
+ vfs_xOpen(context);
26
+ vfs_xClose(context);
27
+ vfs_xRead(context);
28
+ vfs_xWrite(context);
29
+ });
30
+ }
31
+
32
+ it('should upgrade v5', async function() {
33
+ await idbX(indexedDB.deleteDatabase('test'));
34
+
35
+ {
36
+ // Load IndexedDB with v5 data.
37
+ const db = await new Promise((resolve, reject) => {
38
+ const request = indexedDB.open('test', 5);
39
+ request.onupgradeneeded = () => {
40
+ const db = request.result;
41
+ db.createObjectStore('blocks', {
42
+ keyPath: ['path', 'offset', 'version']
43
+ }).createIndex('version', ['path', 'version']);
44
+ };
45
+ request.onsuccess = () => resolve(request.result);
46
+ request.onerror = () => reject(request.error);
47
+ });
48
+
49
+ const data = await fetch(new URL('./data/idbv5.json', import.meta.url))
50
+ .then(response => response.json());
51
+ const blocks = db.transaction('blocks', 'readwrite').objectStore('blocks');
52
+ await Promise.all(data.blocks.map(block => {
53
+ block.data = new Uint8Array(block.data);
54
+ return idbX(blocks.put(block));
55
+ }));
56
+ db.close();
57
+ }
58
+
59
+ // Initialize SQLite.
60
+ const module = await SQLiteESMFactory();
61
+ const sqlite3 = SQLite.Factory(module);
62
+
63
+ const vfs = await IDBBatchAtomicVFS.create('test', module);
64
+ // @ts-ignore
65
+ sqlite3.vfs_register(vfs, true);
66
+
67
+ const db = await sqlite3.open_v2('demo');
68
+
69
+ let integrity = '';
70
+ await sqlite3.exec(db, 'PRAGMA integrity_check', (row, columns) => {
71
+ integrity = /** @type {string} */(row[0]);
72
+ });
73
+ expect(integrity).toBe('ok');
74
+
75
+ const rows = [];
76
+ await sqlite3.exec(db, 'SELECT x FROM foo ORDER BY rowid LIMIT 3', (row, columns) => {
77
+ rows.push(row[0]);
78
+ });
79
+ expect(rows).toEqual([1, 2, 3]);
80
+
81
+ await sqlite3.close(db);
82
+ await vfs.close();
83
+
84
+ await idbX(indexedDB.deleteDatabase('test'));
85
+ });
86
+ });
87
+
88
+ /**
89
+ * @param {IDBRequest} request
90
+ * @returns {Promise}
91
+ */
92
+ function idbX(request) {
93
+ return new Promise((resolve, reject) => {
94
+ request.onsuccess = () => resolve(request.result);
95
+ request.onerror = () => reject(request.error);
96
+ });
97
+ }
@@ -0,0 +1,27 @@
1
+ import { TestContext } from "./TestContext.js";
2
+ import { vfs_xOpen } from "./vfs_xOpen.js";
3
+ import { vfs_xAccess } from "./vfs_xAccess.js";
4
+ import { vfs_xClose } from "./vfs_xClose.js";
5
+ import { vfs_xRead } from "./vfs_xRead.js";
6
+ import { vfs_xWrite } from "./vfs_xWrite.js";
7
+
8
+ const CONFIG = 'IDBMirrorVFS';
9
+ const BUILDS = ['asyncify', 'jspi'];
10
+
11
+ const supportsJSPI = await TestContext.supportsJSPI();
12
+
13
+ describe(CONFIG, function() {
14
+ for (const build of BUILDS) {
15
+ if (build === 'jspi' && !supportsJSPI) return;
16
+
17
+ describe(build, function() {
18
+ const context = new TestContext({ build, config: CONFIG });
19
+
20
+ vfs_xAccess(context);
21
+ vfs_xOpen(context);
22
+ vfs_xClose(context);
23
+ vfs_xRead(context);
24
+ vfs_xWrite(context);
25
+ });
26
+ }
27
+ });
@@ -0,0 +1,27 @@
1
+ import { TestContext } from "./TestContext.js";
2
+ import { vfs_xOpen } from "./vfs_xOpen.js";
3
+ import { vfs_xAccess } from "./vfs_xAccess.js";
4
+ import { vfs_xClose } from "./vfs_xClose.js";
5
+ import { vfs_xRead } from "./vfs_xRead.js";
6
+ import { vfs_xWrite } from "./vfs_xWrite.js";
7
+
8
+ const CONFIG = 'MemoryAsyncVFS';
9
+ const BUILDS = ['asyncify', 'jspi'];
10
+
11
+ const supportsJSPI = await TestContext.supportsJSPI();
12
+
13
+ describe(CONFIG, function() {
14
+ for (const build of BUILDS) {
15
+ if (build === 'jspi' && !supportsJSPI) return;
16
+
17
+ describe(build, function() {
18
+ const context = new TestContext({ build, config: CONFIG });
19
+
20
+ vfs_xAccess(context);
21
+ vfs_xOpen(context);
22
+ vfs_xClose(context);
23
+ vfs_xRead(context);
24
+ vfs_xWrite(context);
25
+ });
26
+ }
27
+ });
@@ -0,0 +1,27 @@
1
+ import { TestContext } from "./TestContext.js";
2
+ import { vfs_xOpen } from "./vfs_xOpen.js";
3
+ import { vfs_xAccess } from "./vfs_xAccess.js";
4
+ import { vfs_xClose } from "./vfs_xClose.js";
5
+ import { vfs_xRead } from "./vfs_xRead.js";
6
+ import { vfs_xWrite } from "./vfs_xWrite.js";
7
+
8
+ const CONFIG = 'MemoryVFS';
9
+ const BUILDS = ['default', 'asyncify', 'jspi'];
10
+
11
+ const supportsJSPI = await TestContext.supportsJSPI();
12
+
13
+ describe(CONFIG, function() {
14
+ for (const build of BUILDS) {
15
+ if (build === 'jspi' && !supportsJSPI) return;
16
+
17
+ describe(build, function() {
18
+ const context = new TestContext({ build, config: CONFIG });
19
+
20
+ vfs_xAccess(context);
21
+ vfs_xOpen(context);
22
+ vfs_xClose(context);
23
+ vfs_xRead(context);
24
+ vfs_xWrite(context);
25
+ });
26
+ }
27
+ });
@@ -0,0 +1,27 @@
1
+ import { TestContext } from "./TestContext.js";
2
+ import { vfs_xOpen } from "./vfs_xOpen.js";
3
+ import { vfs_xAccess } from "./vfs_xAccess.js";
4
+ import { vfs_xClose } from "./vfs_xClose.js";
5
+ import { vfs_xRead } from "./vfs_xRead.js";
6
+ import { vfs_xWrite } from "./vfs_xWrite.js";
7
+
8
+ const CONFIG = 'OPFSAdaptiveVFS';
9
+ const BUILDS = ['asyncify', 'jspi'];
10
+
11
+ const supportsJSPI = await TestContext.supportsJSPI();
12
+
13
+ describe(CONFIG, function() {
14
+ for (const build of BUILDS) {
15
+ if (build === 'jspi' && !supportsJSPI) return;
16
+
17
+ describe(build, function() {
18
+ const context = new TestContext({ build, config: CONFIG });
19
+
20
+ vfs_xAccess(context);
21
+ vfs_xOpen(context);
22
+ vfs_xClose(context);
23
+ vfs_xRead(context);
24
+ vfs_xWrite(context);
25
+ });
26
+ }
27
+ });
@@ -0,0 +1,27 @@
1
+ import { TestContext } from "./TestContext.js";
2
+ import { vfs_xOpen } from "./vfs_xOpen.js";
3
+ import { vfs_xAccess } from "./vfs_xAccess.js";
4
+ import { vfs_xClose } from "./vfs_xClose.js";
5
+ import { vfs_xRead } from "./vfs_xRead.js";
6
+ import { vfs_xWrite } from "./vfs_xWrite.js";
7
+
8
+ const CONFIG = 'OPFSAnyContextVFS';
9
+ const BUILDS = ['asyncify', 'jspi'];
10
+
11
+ const supportsJSPI = await TestContext.supportsJSPI();
12
+
13
+ describe(CONFIG, function() {
14
+ for (const build of BUILDS) {
15
+ if (build === 'jspi' && !supportsJSPI) return;
16
+
17
+ describe(build, function() {
18
+ const context = new TestContext({ build, config: CONFIG });
19
+
20
+ vfs_xAccess(context);
21
+ vfs_xOpen(context);
22
+ vfs_xClose(context);
23
+ vfs_xRead(context);
24
+ vfs_xWrite(context);
25
+ });
26
+ }
27
+ });
@@ -0,0 +1,27 @@
1
+ import { TestContext } from "./TestContext.js";
2
+ import { vfs_xOpen } from "./vfs_xOpen.js";
3
+ import { vfs_xAccess } from "./vfs_xAccess.js";
4
+ import { vfs_xClose } from "./vfs_xClose.js";
5
+ import { vfs_xRead } from "./vfs_xRead.js";
6
+ import { vfs_xWrite } from "./vfs_xWrite.js";
7
+
8
+ const CONFIG = 'OPFSCoopSyncVFS';
9
+ const BUILDS = ['default', 'asyncify', 'jspi'];
10
+
11
+ const supportsJSPI = await TestContext.supportsJSPI();
12
+
13
+ describe(CONFIG, function() {
14
+ for (const build of BUILDS) {
15
+ if (build === 'jspi' && !supportsJSPI) return;
16
+
17
+ describe(build, function() {
18
+ const context = new TestContext({ build, config: CONFIG });
19
+
20
+ vfs_xAccess(context);
21
+ vfs_xOpen(context);
22
+ vfs_xClose(context);
23
+ vfs_xRead(context);
24
+ vfs_xWrite(context);
25
+ });
26
+ }
27
+ });
@@ -0,0 +1,27 @@
1
+ import { TestContext } from "./TestContext.js";
2
+ import { vfs_xOpen } from "./vfs_xOpen.js";
3
+ import { vfs_xAccess } from "./vfs_xAccess.js";
4
+ import { vfs_xClose } from "./vfs_xClose.js";
5
+ import { vfs_xRead } from "./vfs_xRead.js";
6
+ import { vfs_xWrite } from "./vfs_xWrite.js";
7
+
8
+ const CONFIG = 'OPFSPermutedVFS';
9
+ const BUILDS = ['asyncify', 'jspi'];
10
+
11
+ const supportsJSPI = await TestContext.supportsJSPI();
12
+
13
+ describe(CONFIG, function() {
14
+ for (const build of BUILDS) {
15
+ if (build === 'jspi' && !supportsJSPI) return;
16
+
17
+ describe(build, function() {
18
+ const context = new TestContext({ build, config: CONFIG });
19
+
20
+ vfs_xAccess(context);
21
+ vfs_xOpen(context);
22
+ vfs_xClose(context);
23
+ vfs_xRead(context);
24
+ vfs_xWrite(context);
25
+ });
26
+ }
27
+ });
@@ -0,0 +1,96 @@
1
+ import * as Comlink from 'comlink';
2
+
3
+ const TEST_WORKER_URL = './test-worker.js';
4
+ const TEST_WORKER_TERMINATE = true;
5
+
6
+ const mapProxyToReleaser = new WeakMap();
7
+ const workerFinalization = new FinalizationRegistry(release => release());
8
+
9
+ /**
10
+ * @typedef TestContextParams
11
+ * @property {string} [build]
12
+ * @property {string} [config]
13
+ * @property {boolean} [reset]
14
+ */
15
+
16
+ /** @type {TestContextParams} */
17
+ const DEFAULT_PARAMS = Object.freeze({
18
+ build: 'default',
19
+ config: 'default',
20
+ reset: true
21
+ });
22
+
23
+ export class TestContext {
24
+ #params = structuredClone(DEFAULT_PARAMS);
25
+
26
+ /**
27
+ * @param {TestContextParams} params
28
+ */
29
+ constructor(params = {}) {
30
+ Object.assign(this.#params, params);
31
+ }
32
+
33
+ async create(extras = {}) {
34
+ const url = new URL(TEST_WORKER_URL, import.meta.url);
35
+ for (const [key, value] of Object.entries(this.#params)) {
36
+ url.searchParams.set(key, value.toString());
37
+ }
38
+ for (const [key, value] of Object.entries(extras)) {
39
+ url.searchParams.set(key, value.toString());
40
+ }
41
+
42
+ const worker = new Worker(url, { type: 'module' });
43
+ const port = await new Promise(resolve => {
44
+ worker.addEventListener('message', (event) => {
45
+ if (event.ports[0]) {
46
+ return resolve(event.ports[0]);
47
+ }
48
+ const e = new Error(event.data.message);
49
+ throw Object.assign(e, event.data);
50
+ }, { once: true });
51
+ });
52
+
53
+ const proxy = Comlink.wrap(port);
54
+ if (TEST_WORKER_TERMINATE) {
55
+ function releaser() {
56
+ worker.terminate();
57
+ }
58
+ mapProxyToReleaser.set(proxy, releaser);
59
+ workerFinalization.register(proxy, releaser);
60
+ }
61
+
62
+ return proxy;
63
+ }
64
+
65
+ async destroy(proxy) {
66
+ proxy[Comlink.releaseProxy]();
67
+ const releaser = mapProxyToReleaser.get(proxy);
68
+ if (releaser) {
69
+ workerFinalization.unregister(releaser);
70
+ releaser();
71
+ }
72
+ }
73
+
74
+ // https://github.com/WebAssembly/js-promise-integration/issues/21#issuecomment-1634843621
75
+ static async supportsJSPI() {
76
+ try {
77
+ const m = new Uint8Array([
78
+ 0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 1, 111, 0, 3, 2, 1, 0, 7, 5, 1,
79
+ 1, 111, 0, 0, 10, 4, 1, 2, 0, 11,
80
+ ]);
81
+ const { instance } = await WebAssembly.instantiate(m);
82
+ // @ts-ignore
83
+ new WebAssembly.Function(
84
+ {
85
+ parameters: [],
86
+ results: ["externref"],
87
+ },
88
+ instance.exports.o,
89
+ { promising: "first" }
90
+ );
91
+ return true;
92
+ } catch (e) {
93
+ return false;
94
+ }
95
+ }
96
+ }