2024-05-16 01:04:15 +00:00
|
|
|
import sqlWasmUrl from "@jlongster/sql.js/dist/sql-wasm.wasm?url";
|
2024-05-16 03:37:00 +00:00
|
|
|
import { MigrateDeploy } from "@prisma/migrate";
|
2024-05-16 01:04:15 +00:00
|
|
|
import initSqlJs from "@jlongster/sql.js";
|
|
|
|
import { SQLiteFS } from "absurd-sql";
|
2024-05-16 06:02:44 +00:00
|
|
|
import type { BindParams, Database, Statement } from "sql.js";
|
2024-05-16 01:04:15 +00:00
|
|
|
import IndexedDBBackend from "absurd-sql/dist/indexeddb-backend";
|
|
|
|
import { RpcProvider } from "worker-rpc";
|
2024-05-16 03:37:00 +00:00
|
|
|
import executeMigrations from "./migrations";
|
2024-05-16 04:37:23 +00:00
|
|
|
import { DbStatusCode } from "./constants";
|
2024-05-16 01:04:15 +00:00
|
|
|
|
|
|
|
async function init() {
|
2024-05-16 04:37:23 +00:00
|
|
|
const rpcProvider = new RpcProvider((message, transfer) =>
|
|
|
|
self.postMessage(message, undefined, transfer),
|
|
|
|
);
|
|
|
|
self.addEventListener("message", (evt) => rpcProvider.dispatch(evt.data));
|
|
|
|
|
2024-05-16 06:02:44 +00:00
|
|
|
const preparedStatementHandles = new Map<number, Statement>();
|
|
|
|
let ctr = 0;
|
|
|
|
const fresh = () => {
|
|
|
|
return ctr++;
|
|
|
|
};
|
|
|
|
|
2024-05-16 01:04:15 +00:00
|
|
|
const SQL = await initSqlJs({
|
|
|
|
locateFile: (file) => {
|
|
|
|
switch (file) {
|
|
|
|
case "sql-wasm.wasm":
|
|
|
|
return sqlWasmUrl;
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2024-05-16 04:37:23 +00:00
|
|
|
rpcProvider.signal("db", { status: DbStatusCode.LOADED_SQLITE });
|
|
|
|
|
2024-05-16 06:22:26 +00:00
|
|
|
console.log("new SQLITEFS", SQLiteFS, SQL, IndexedDBBackend);
|
2024-05-16 01:04:15 +00:00
|
|
|
const sqlFS = new SQLiteFS(SQL.FS, new IndexedDBBackend());
|
2024-05-16 06:22:26 +00:00
|
|
|
console.log("REGISTER FOR IDB", sqlFS);
|
2024-05-16 01:04:15 +00:00
|
|
|
SQL.register_for_idb(sqlFS);
|
|
|
|
|
2024-05-16 06:22:26 +00:00
|
|
|
console.log("MKDIR SQL");
|
2024-05-16 01:04:15 +00:00
|
|
|
SQL.FS.mkdir("/sql");
|
2024-05-16 06:22:26 +00:00
|
|
|
console.log("MOUNT SQLFS");
|
2024-05-16 01:04:15 +00:00
|
|
|
SQL.FS.mount(sqlFS, {}, "/sql");
|
|
|
|
|
|
|
|
const path = "/sql/db.sqlite";
|
|
|
|
if (typeof SharedArrayBuffer === "undefined") {
|
|
|
|
const stream = SQL.FS.open(path, "a+");
|
|
|
|
await stream.node.contents.readIfFallback();
|
|
|
|
SQL.FS.close(stream);
|
|
|
|
}
|
|
|
|
|
2024-05-16 06:22:26 +00:00
|
|
|
globalThis.SQL = SQL;
|
|
|
|
console.log("OPEN DB", SQL);
|
2024-05-16 03:37:00 +00:00
|
|
|
const db: Database = new SQL.Database(path, { filename: true });
|
2024-05-16 06:22:26 +00:00
|
|
|
console.log("RUN PRAGMA");
|
|
|
|
db.run("PRAGMA journal_mode=MEMORY");
|
|
|
|
console.log("DONE");
|
2024-05-16 01:04:15 +00:00
|
|
|
|
2024-05-16 04:37:23 +00:00
|
|
|
rpcProvider.signal("db", { status: DbStatusCode.OPENED_DATABASE });
|
2024-05-16 01:04:15 +00:00
|
|
|
|
2024-05-16 04:37:23 +00:00
|
|
|
await executeMigrations(db);
|
2024-05-16 01:04:15 +00:00
|
|
|
|
2024-05-16 04:37:23 +00:00
|
|
|
rpcProvider.signal("db", { status: DbStatusCode.RAN_MIGRATIONS });
|
2024-05-16 01:04:15 +00:00
|
|
|
|
2024-05-16 04:37:23 +00:00
|
|
|
rpcProvider.registerRpcHandler("run", ({ s, p }: Args) => db.run(s, p));
|
2024-05-16 01:04:15 +00:00
|
|
|
|
2024-05-16 04:37:23 +00:00
|
|
|
rpcProvider.registerRpcHandler("exec", ({ s, p }: Args) => db.exec(s, p));
|
2024-05-16 01:04:15 +00:00
|
|
|
|
2024-05-16 06:02:44 +00:00
|
|
|
rpcProvider.registerRpcHandler("prepare", ({ s, p }: Args) => {
|
|
|
|
const preparedStatement = db.prepare(s, p);
|
|
|
|
const id = fresh();
|
|
|
|
preparedStatementHandles.set(id, preparedStatement);
|
|
|
|
return id;
|
|
|
|
});
|
|
|
|
|
|
|
|
rpcProvider.registerRpcHandler("preparedFree", ({ h }) => {
|
|
|
|
const prepared = preparedStatementHandles.get(h);
|
|
|
|
if (!prepared) return;
|
|
|
|
prepared.free();
|
|
|
|
prepared.freemem();
|
|
|
|
});
|
|
|
|
|
|
|
|
rpcProvider.registerRpcHandler("preparedRun", ({ h, p }) => {
|
|
|
|
const prepared = preparedStatementHandles.get(h);
|
|
|
|
if (!prepared) return;
|
|
|
|
prepared.run(p);
|
|
|
|
});
|
|
|
|
|
|
|
|
rpcProvider.registerRpcHandler("bulkInsert", ({ s, p, data }) => {
|
|
|
|
const preparedStatement = db.prepare(s, p);
|
|
|
|
db.run("BEGIN TRANSACTION");
|
|
|
|
|
|
|
|
// TODO: yo how do bulk inserts work again
|
|
|
|
for (const entry of data) {
|
|
|
|
const mapped = Object.fromEntries(
|
|
|
|
Object.entries(entry).map(([key, value]) => [`$${key}`, value]),
|
|
|
|
);
|
|
|
|
preparedStatement.run(mapped);
|
|
|
|
}
|
|
|
|
db.run("COMMIT TRANSACTION");
|
|
|
|
});
|
|
|
|
|
2024-05-16 04:37:23 +00:00
|
|
|
rpcProvider.signal("db", { status: DbStatusCode.READY });
|
2024-05-16 06:02:44 +00:00
|
|
|
rpcProvider.signal(DbStatusCode.READY);
|
2024-05-16 03:37:00 +00:00
|
|
|
}
|
2024-05-16 01:04:15 +00:00
|
|
|
|
2024-05-16 03:37:00 +00:00
|
|
|
init();
|
2024-05-16 04:37:23 +00:00
|
|
|
|
|
|
|
interface Args {
|
|
|
|
s: string;
|
|
|
|
p?: BindParams;
|
|
|
|
}
|