jevstrudel.git / worker / test / budget.ts

The BUDGET Durable Object namespace for tests: one JevBudget's counting (src/budget-counter.ts) per name, each on its own in-memory SQLite, as each Durable Object has its own storage. The clock is the test's.

4import { DatabaseSync, type SQLInputValue } from 'node:sqlite';
5import { balance, createSchema, spend, type Sql } from '../src/budget-counter';

A Durable Object's ctx.storage.sql, on Node's SQLite.

8export function memorySql(): Sql {
9  const db = new DatabaseSync(':memory:');
10  return {
11    // run at once, as the Durable Object's exec does; the rows are read after
12    exec: ((query: string, ...bindings: unknown[]) => {
13      const rows = db.prepare(query).all(...(bindings as SQLInputValue[]));
14      return { toArray: () => rows };
15    }) as Sql['exec'],
16  };
17}
19export function memoryBudgets(limit: number, now: () => number = Date.now) {
20  const objects = new Map<string, Sql>();
21  const object = (name: string) => {
22    let sql = objects.get(name);
23    if (!sql) {
24      sql = memorySql();
25      createSchema(sql);
26      objects.set(name, sql);
27    }
28    return sql;
29  };
30  return {
31    idFromName: (name: string) => ({ name }),
32    get: ({ name }: { name: string }) => ({
33      spend: async (calls = 1) => spend(object(name), limit, now(), calls),
34      balance: async () => balance(object(name), limit, now()),
35    }),
36  };
37}