Skip to content

Commit 46d47e3

Browse files
committed
allow modular usage of VFS:
* add 'createWasmInitializer' function - creating a function akin to 'initWasm' with custom setup (WASM ModuleFactory, vfsFactory) * keep the default 'initWasm' (Asyncify build, IDBBatchAtomic) for API consistency * add (optional) parameter for 'initializer' in browserdb, react and direct-connect-browser packages
1 parent 700d5a1 commit 46d47e3

File tree

4 files changed

+67
-16
lines changed

4 files changed

+67
-16
lines changed

packages/crsqlite-wasm/src/index.ts

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,19 @@ type SQLiteAPI = ReturnType<typeof SQLite.Factory>;
1212
export class SQLite3 {
1313
constructor(private base: SQLiteAPI) {}
1414

15-
open(filename?: string, mode: string = "c") {
15+
open(filename: string = ":memory:", mode: string = "c", vfs_name?: string) {
1616
return serialize(
1717
null,
1818
undefined,
1919
() => {
2020
return this.base.open_v2(
21-
filename || ":memory:",
21+
filename,
2222
SQLite.SQLITE_OPEN_CREATE |
2323
SQLite.SQLITE_OPEN_READWRITE |
2424
SQLite.SQLITE_OPEN_URI,
25-
filename != null ? "idb-batch-atomic" : undefined
25+
// My understanding is that filename = ":memory:" case doesn't care about the vfs_name, whereas not specifying
26+
// the vfs_name will use the default vfs (which is the desired VFS if set up using 'iniwWasm')
27+
vfs_name
2628
);
2729
},
2830
topLevelMutex
@@ -47,14 +49,28 @@ export class SQLite3 {
4749
}
4850
}
4951

50-
export default async function initWasm(
52+
export type VFSFactory = (module: SQLiteAPI) => Promise<SQLiteVFS>;
53+
export type ModuleFactory = (moduleArg?: Record<string, any>) => any;
54+
55+
export type WasmInitializerConfig = {
56+
ModuleFactory: ModuleFactory;
57+
vfsFactory: VFSFactory;
58+
};
59+
60+
export type WasmInitializer = (
61+
locateWasm?: (file: string) => string
62+
) => Promise<SQLite3>;
63+
64+
async function initWasmInternal(
65+
ModuleFactory: ModuleFactory,
66+
vfsFactory: VFSFactory,
5167
locateWasm?: (file: string) => string
5268
): Promise<SQLite3> {
5369
if (api != null) {
5470
return api;
5571
}
5672

57-
const wasmModule = await SQLiteAsyncESMFactory({
73+
const wasmModule = await ModuleFactory({
5874
locateFile(file: string) {
5975
if (locateWasm) {
6076
return locateWasm(file);
@@ -63,9 +79,37 @@ export default async function initWasm(
6379
},
6480
});
6581
const sqlite3 = SQLite.Factory(wasmModule);
66-
const vfs = await IDBBatchAtomicVFS.create("idb-batch-atomic", wasmModule);
82+
const vfs = await vfsFactory(wasmModule);
6783
sqlite3.vfs_register(vfs, true);
6884

6985
api = new SQLite3(sqlite3);
7086
return api;
7187
}
88+
89+
/**
90+
* Default initializer (for backwards compatibility), uses:
91+
* - asyncify WASM build
92+
* - IDB Batch Atomic VFS
93+
*/
94+
export default async function initWasm(
95+
locateWasm?: (file: string) => string
96+
): Promise<SQLite3> {
97+
const ModuleFactory = SQLiteAsyncESMFactory;
98+
const vfsFactory: VFSFactory = (module) =>
99+
IDBBatchAtomicVFS.create("idb-batch-atomic", module);
100+
return initWasmInternal(ModuleFactory, vfsFactory, locateWasm);
101+
}
102+
103+
/**
104+
* Creates a custom wasm initializer (same signature as default `initWasm`) allowing
105+
* consumer to provide:
106+
* - custom WASM glue factory
107+
* - custom VFS implementation.
108+
*/
109+
export function createWasmInitializer({
110+
ModuleFactory,
111+
vfsFactory,
112+
}: WasmInitializerConfig): WasmInitializer {
113+
return (locateWasm?: (file: string) => string) =>
114+
initWasmInternal(ModuleFactory, vfsFactory, locateWasm);
115+
}

packages/direct-connect-browser/src/common/DB.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import initWasm from "@vlcn.io/crsqlite-wasm";
1+
import initWasm, { WasmInitializer } from "@vlcn.io/crsqlite-wasm";
22
import { DBAsync, StmtAsync } from "@vlcn.io/xplat-api";
33
import { TXAsync } from "@vlcn.io/xplat-api";
44
import { DBID } from "@vlcn.io/xplat-api";
@@ -100,8 +100,12 @@ export class DB {
100100
}
101101
}
102102

103-
export default async function getDB(wasmUri: string | undefined, dbid: DBID) {
104-
const sqlite = await initWasm(wasmUri ? () => wasmUri : undefined);
103+
export default async function getDB(
104+
wasmUri: string | undefined,
105+
dbid: DBID,
106+
initializer: WasmInitializer = initWasm
107+
) {
108+
const sqlite = await initializer(wasmUri ? () => wasmUri : undefined);
105109
const db = await sqlite.open(dbid);
106110

107111
const [pullChangesetStmt, applyChangesetStmt, updatePeerTrackerStmt] =

packages/react/src/db/DBFactory.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import initWasm, { SQLite3 } from "@vlcn.io/crsqlite-wasm";
1+
import initWasm, { SQLite3, WasmInitializer } from "@vlcn.io/crsqlite-wasm";
22
import tblrx from "@vlcn.io/rx-tbl";
33
import { CtxAsync } from "../context.js";
44
import { Mutex } from "async-mutex";
@@ -14,12 +14,12 @@ const dbMap = new Map<DBID, [string, CtxAsync]>();
1414
const hooks = new Map<DBID, () => CtxAsync | null>();
1515

1616
let initPromise: Promise<SQLite3> | null = null;
17-
function init(wasmUri?: string) {
17+
function init(wasmUri?: string, initializer: WasmInitializer = initWasm) {
1818
if (initPromise) {
1919
return initPromise;
2020
}
2121

22-
initPromise = initWasm(wasmUri ? () => wasmUri : undefined);
22+
initPromise = initializer(wasmUri ? () => wasmUri : undefined);
2323
return initPromise;
2424
}
2525

packages/ws-browserdb/src/index.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { DB } from "@vlcn.io/ws-client";
2-
import initWasm, { DB as WasmDB } from "@vlcn.io/crsqlite-wasm";
2+
import initWasm, {
3+
DB as WasmDB,
4+
WasmInitializer,
5+
} from "@vlcn.io/crsqlite-wasm";
36
import { Change } from "@vlcn.io/ws-common";
47
import { StmtAsync, firstPick } from "@vlcn.io/xplat-api";
58
import tblrx from "@vlcn.io/rx-tbl";
@@ -139,9 +142,9 @@ class WrappedDB implements DB {
139142
*/
140143
export function createDbProvider(
141144
wasmUri?: string
142-
): (dbname: string) => PromiseLike<DB> {
143-
return async (dbname: string): Promise<DB> => {
144-
const sqlite = await initWasm(wasmUri ? () => wasmUri : undefined);
145+
): (dbname: string, initializer?: WasmInitializer) => PromiseLike<DB> {
146+
return async (dbname: string, initializer = initWasm): Promise<DB> => {
147+
const sqlite = await initializer(wasmUri ? () => wasmUri : undefined);
145148
const db = await sqlite.open(dbname);
146149

147150
const [pullChangesetStmt, applyChangesetStmt, updatePeerTrackerStmt] =

0 commit comments

Comments
 (0)