Add bun:sqlite persistence layer

This commit is contained in:
Jared Miller 2026-01-27 21:15:23 -05:00
parent a1864e5880
commit 415e49327e
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
3 changed files with 90 additions and 0 deletions

2
.gitignore vendored
View file

@ -32,3 +32,5 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Finder (MacOS) folder config # Finder (MacOS) folder config
.DS_Store .DS_Store
*.db

52
src/db.test.ts Normal file
View file

@ -0,0 +1,52 @@
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
import { initDb, saveUpdate, getUpdates, close } from "./db";
import { unlinkSync } from "fs";
const TEST_DB = ":memory:";
describe("db persistence", () => {
beforeEach(() => {
initDb(TEST_DB);
});
afterEach(() => {
close();
});
it("saves and retrieves updates for a room", () => {
const room = "test-room";
const update1 = new Uint8Array([1, 2, 3]);
const update2 = new Uint8Array([4, 5, 6]);
saveUpdate(room, update1);
saveUpdate(room, update2);
const updates = getUpdates(room);
expect(updates).toHaveLength(2);
expect(updates[0]).toEqual(update1);
expect(updates[1]).toEqual(update2);
});
it("returns empty array for unknown room", () => {
const updates = getUpdates("nonexistent");
expect(updates).toEqual([]);
});
it("rooms are isolated", () => {
const room1 = "room-one";
const room2 = "room-two";
const update1 = new Uint8Array([1, 1, 1]);
const update2 = new Uint8Array([2, 2, 2]);
saveUpdate(room1, update1);
saveUpdate(room2, update2);
const room1Updates = getUpdates(room1);
const room2Updates = getUpdates(room2);
expect(room1Updates).toHaveLength(1);
expect(room2Updates).toHaveLength(1);
expect(room1Updates[0]).toEqual(update1);
expect(room2Updates[0]).toEqual(update2);
});
});

36
src/db.ts Normal file
View file

@ -0,0 +1,36 @@
import { Database } from "bun:sqlite";
let db: Database | null = null;
export function initDb(path: string): void {
db = new Database(path);
db.exec(`
CREATE TABLE IF NOT EXISTS updates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
room TEXT NOT NULL,
data BLOB NOT NULL,
created_at INTEGER DEFAULT (unixepoch())
);
CREATE INDEX IF NOT EXISTS idx_room ON updates(room);
`);
}
export function saveUpdate(room: string, data: Uint8Array): void {
if (!db) throw new Error("Database not initialized");
const stmt = db.prepare("INSERT INTO updates (room, data) VALUES (?, ?)");
stmt.run(room, data);
}
export function getUpdates(room: string): Uint8Array[] {
if (!db) throw new Error("Database not initialized");
const stmt = db.prepare("SELECT data FROM updates WHERE room = ? ORDER BY id ASC");
const rows = stmt.all(room) as Array<{ data: Uint8Array }>;
return rows.map(row => row.data);
}
export function close(): void {
if (db) {
db.close();
db = null;
}
}