59 lines · 2.3 KB
import { Database } from "bun:sqlite";
import { describe, expect, test } from "bun:test";
import { ScopedStore } from "./store";

/** Just enough of DurableObjectStorage for ScopedStore, on bun:sqlite. */
function fakeStorage() {
  const db = new Database(":memory:");
  const kv = new Map<string, unknown>();
  const sql = {
    exec(query: string, ...params: unknown[]) {
      const statement = db.query(query);
      const rows = /^\s*(SELECT|PRAGMA|WITH)/i.test(query) ? (statement.all(...(params as never[])) as unknown[]) : [];
      if (rows.length === 0 && !/^\s*(SELECT|WITH)/i.test(query)) statement.run(...(params as never[]));
      return {
        toArray: () => rows,
        one: () => {
          if (rows.length !== 1) throw new Error("expected one row");
          return rows[0];
        },
      };
    },
  };
  return {
    sql,
    get: async (key: string) => kv.get(key),
    put: async (key: string, value: unknown) => void kv.set(key, value),
    deleteAll: async () => kv.clear(),
    transactionSync: <T>(fn: () => T) => db.transaction(fn)(),
  } as unknown as DurableObjectStorage;
}

const SCHEMA = ["CREATE TABLE IF NOT EXISTS items (id TEXT PRIMARY KEY, title TEXT)"];

describe("ScopedStore", () => {
  test("applies the schema once and re-applies it when the DDL changes", async () => {
    const storage = fakeStorage();
    const store = new ScopedStore(storage, SCHEMA);
    await store.prepare();
    expect(store.run("INSERT INTO items VALUES ('a', 'one')", []).changes).toBe(1);
    const grown = new ScopedStore(storage, [...SCHEMA, "CREATE TABLE IF NOT EXISTS tags (id TEXT PRIMARY KEY)"]);