@evolu/web
Version:
Evolu for web
86 lines (85 loc) • 3 kB
JavaScript
import { bytesToHex, createPreparedStatementsCache, } from "@evolu/common";
import sqlite3InitModule from "@evolu/sqlite-wasm";
// @ts-expect-error Missing types.
globalThis.sqlite3ApiConfig = {
warn: (arg) => {
// Ignore irrelevant warning.
// https://github.com/sqlite/sqlite-wasm/issues/62
if (typeof arg === "string" &&
arg.startsWith("Ignoring inability to install OPFS sqlite3_vfs"))
return;
// eslint-disable-next-line no-console
console.warn(arg);
},
};
// Init ASAP.
const sqlite3Promise = sqlite3InitModule();
export const createWasmSqliteDriver = async (name, options) => {
const sqlite3 = await sqlite3Promise;
// This is used to make OPFS default vfs for multipleciphers
// @ts-expect-error Missing types (update @evolu/sqlite-wasm types)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
sqlite3.capi.sqlite3mc_vfs_create("opfs", 1);
let db;
if (options?.memory) {
db = new sqlite3.oo1.DB(":memory:");
}
else if (options?.encryptionKey) {
const pool = await sqlite3.installOpfsSAHPoolVfs({ directory: `.${name}` });
db = new pool.OpfsSAHPoolDb("file:evolu1.db?vfs=multipleciphers-opfs-sahpool");
db.exec(`
PRAGMA cipher = 'sqlcipher';
PRAGMA legacy = 4;
PRAGMA key = "x'${bytesToHex(options.encryptionKey)}'";
`);
}
else {
const pool = await sqlite3.installOpfsSAHPoolVfs({ name });
db = new pool.OpfsSAHPoolDb("file:evolu1.db");
}
let isDisposed = false;
const cache = createPreparedStatementsCache((sql) => db.prepare(sql), (statement) => {
statement.finalize();
});
const driver = {
exec: (query, isMutation) => {
const prepared = cache.get(query);
if (prepared) {
prepared.bind(query.parameters);
if (isMutation) {
prepared.stepReset();
return {
rows: [],
changes: db.changes(),
};
}
const rows = [];
while (prepared.step()) {
rows.push(prepared.get({}));
}
prepared.reset();
return {
rows: rows,
changes: 0,
};
}
const rows = db.exec(query.sql, {
returnValue: "resultRows",
rowMode: "object",
bind: query.parameters,
});
const changes = db.changes();
return { rows, changes };
},
export: () => sqlite3.capi.sqlite3_js_db_export(db),
[Symbol.dispose]: () => {
if (isDisposed)
return;
isDisposed = true;
// poolUtil.unlink?
cache[Symbol.dispose]();
db.close();
},
};
return driver;
};