37 lines · 1.5 KB
import type { Database } from "bun:sqlite";
import type { ScopedDb, ScopedStatement, ScopedValue } from "./scoped-db/types";

/**
 * Test double for `~/server/scoped-db` that routes every repository and account to one bun:sqlite database
 * (typically the test's full D1 schema). For integration-style tests that seed and assert on one database:
 * scoped queries in the code under test always filter by their owner, so sharing the file is equivalent.
 * Use `memoryScopes()` from `scoped-db/testing` when isolation between scopes matters.
 */
export function sharedScopes(db: Database) {
  const meta = (result: { changes: number; lastInsertRowid: number | bigint }) => ({
    meta: { changes: result.changes, last_row_id: Number(result.lastInsertRowid) },
  });
  const make = (scopeId: string): ScopedDb => ({
    scopeId,
    async first<T>(sql: string, ...params: ScopedValue[]) {
      return (db.query(sql).get(...params) as T | null) ?? null;
    },
    async all<T>(sql: string, ...params: ScopedValue[]) {
      return db.query(sql).all(...params) as T[];
    },
    async run(sql: string, ...params: ScopedValue[]) {
      return meta(db.query(sql).run(...params));
    },
    async batch(statements: ScopedStatement[]) {
      return db.transaction(() =>
        statements.map((statement) => meta(db.query(statement.sql).run(...statement.params))),
      )();
    },
  });
  return {
    repoDb: make,
    accountDb: make,
    stmt: (sql: string, ...params: ScopedValue[]): ScopedStatement => ({ sql, params }),
  };
}