// Portable SQLite facade. Rust owns the connection and executes every statement. import { SqliteStorage } from '@earendil-works/pi-durable/storage/sqlite'; const op = (kind: string, sql = '', params: any[] = []) => Deno.core.ops.op_sql(kind, sql, params.map(p => p instanceof Uint8Array ? Array.from(p) : typeof p === 'bigint' ? Number(p) : p)); export async function openStorage(path: string) { op('open', path); let tail = Promise.resolve(); const queue = (call: () => Promise): Promise => { const result = tail.then(call); tail = result.then(() => {}, () => {}); return result; }; const executor = { exec: async (sql: string) => { op('exec', sql); }, run: async (sql: string, ...params: any[]) => { op('run', sql, params); }, runCounted: async (sql: string, ...params: any[]) => op('run', sql, params).changes, get: async (sql: string, ...params: any[]) => (await executor.all(sql, ...params))[0], all: async (sql: string, ...params: any[]) => op('all', sql, params).map((row: any) => Object.fromEntries(Object.entries(row).map(([key, value]) => [key, Array.isArray(value) ? new Uint8Array(value) : value]))), }; const database = Object.fromEntries(Object.entries(executor).map(([name, method]) => [name, (...args: any[]) => queue(() => method(...args))])); database.transaction = (callback: any) => queue(async () => { op('exec', 'BEGIN IMMEDIATE'); try { const result = await callback(executor); op('exec', 'COMMIT'); return result; } catch (error) { op('exec', 'ROLLBACK'); throw error; } }); database.close = () => queue(async () => { op('close'); }); return SqliteStorage.open(database as any); }