// Engine-neutral transactional writes. // // better-sqlite3 transactions take a *synchronous* callback (awaiting inside one // silently breaks atomicity), while node-postgres takes an async one. Rather than // fork every multi-write route into two near-identical branches, callers build a // plain list of operations and hand it here: the business logic stays in one // place and only the six lines below know which driver is underneath. import { db, isSqlite } from '../db/index.js'; export type TxOp = | { kind: 'insert'; table: any; values: any } | { kind: 'update'; table: any; values: any; where: any } | { kind: 'delete'; table: any; where: any }; export const insertOp = (table: any, values: any): TxOp => ({ kind: 'insert', table, values }); export const updateOp = (table: any, values: any, where: any): TxOp => ({ kind: 'update', table, values, where }); export const deleteOp = (table: any, where: any): TxOp => ({ kind: 'delete', table, where }); /** Apply every op inside a single transaction; any throw rolls back all of them. */ export async function runOps(ops: TxOp[]): Promise { if (ops.length === 0) return; if (isSqlite()) { (db as any).transaction((tx: any) => { for (const op of ops) { if (op.kind === 'insert') tx.insert(op.table).values(op.values).run(); else if (op.kind === 'update') tx.update(op.table).set(op.values).where(op.where).run(); else tx.delete(op.table).where(op.where).run(); } }); return; } await (db as any).transaction(async (tx: any) => { for (const op of ops) { if (op.kind === 'insert') await tx.insert(op.table).values(op.values); else if (op.kind === 'update') await tx.update(op.table).set(op.values).where(op.where); else await tx.delete(op.table).where(op.where); } }); }