1// The BUDGET Durable Object namespace for tests: one JevBudget's counting 2// (src/budget-counter.ts) per name, each on its own in-memory SQLite, as 3// 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'; 6 7// 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} 18 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}