db.ts

2.3 KB · raw

1import { Database } from "bun:sqlite";2import { mkdirSync } from "node:fs";3import { join } from "node:path";45// §19: only what the pages and the sync loop read so far; later phases add their tables.6const SCHEMA = `7CREATE TABLE IF NOT EXISTS settings (8	key   TEXT PRIMARY KEY,9	value TEXT NOT NULL10);11CREATE TABLE IF NOT EXISTS repos (12	name            TEXT PRIMARY KEY,13	public          INTEGER NOT NULL DEFAULT 0,14	category        TEXT NOT NULL DEFAULT '',15	homepage        TEXT NOT NULL DEFAULT '',16	sort_order      INTEGER NOT NULL DEFAULT 0,17	install1        TEXT NOT NULL DEFAULT '',18	install2        TEXT NOT NULL DEFAULT '',19	install3        TEXT NOT NULL DEFAULT '',20	last_sync_at    INTEGER,21	last_sync_error TEXT22);23`;2425export type RepoSettings = {26	name: string;27	homepage: string;28	installLines: string[];29};3031type RepoRow = {32	name: string;33	homepage: string;34	install1: string;35	install2: string;36	install3: string;37};3839export function openKeprDb(dataDir: string): Database {40	mkdirSync(dataDir, { recursive: true });41	const db = new Database(join(dataDir, "kepr.db"), { strict: true });42	db.run("PRAGMA journal_mode = WAL");43	db.run("PRAGMA busy_timeout = 5000");44	db.run(SCHEMA);45	return db;46}4748export function setting(db: Database, key: string): string | null {49	const row = db50		.query<{ value: string }, [string]>("SELECT value FROM settings WHERE key = ?")51		.get(key);52	return row?.value ?? null;53}5455/** Every repo starts private (§20); registering a known repo changes nothing. */56export function registerRepo(db: Database, name: string): void {57	db.query("INSERT OR IGNORE INTO repos (name) VALUES (?)").run(name);58}5960export function recordSync(db: Database, name: string, at: number, error: string | null): void {61	db.query("UPDATE repos SET last_sync_at = ?, last_sync_error = ? WHERE name = ?").run(62		at,63		error,64		name,65	);66}6768/** The settings of a public repo, or null when it is private or unknown: both must look missing. */69export function publicRepo(db: Database, name: string): RepoSettings | null {70	const row = db71		.query<RepoRow, [string]>(72			"SELECT name, homepage, install1, install2, install3 FROM repos WHERE name = ? AND public = 1",73		)74		.get(name);75	if (!row) return null;76	const installLines = [row.install1, row.install2, row.install3].filter((line) => line !== "");77	return { name: row.name, homepage: row.homepage, installLines };78}