lilith-platform.live/codebase/@features/image-protection/backend-api/src/db.ts
2026-04-07 16:34:14 -07:00

68 lines
1.9 KiB
TypeScript

/**
* Database -- Bun SQLite connection and schema management.
*
* Lazy-initialized singleton. DB path configurable via DB_PATH env var.
*/
import { Database } from 'bun:sqlite';
import { logger } from './logger';
const DB_PATH = process.env['DB_PATH'] ?? './data/protection.db';
let db: Database | null = null;
export function getDb(): Database {
if (!db) {
db = new Database(DB_PATH, { create: true });
db.run('PRAGMA journal_mode = WAL');
db.run('PRAGMA foreign_keys = ON');
db.run('PRAGMA busy_timeout = 5000');
}
return db;
}
export function initSchema(): void {
const d = getDb();
d.run(`
CREATE TABLE IF NOT EXISTS photos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filename TEXT NOT NULL UNIQUE,
original_path TEXT NOT NULL,
output_path TEXT,
webp_path TEXT,
width INTEGER,
height INTEGER,
protection_status TEXT NOT NULL DEFAULT 'unprotected',
ssim_score REAL,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
protected_at TEXT
)
`);
d.run(`
CREATE TABLE IF NOT EXISTS protection_jobs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
photo_id INTEGER NOT NULL REFERENCES photos(id) ON DELETE CASCADE,
status TEXT NOT NULL DEFAULT 'queued',
current_layer TEXT,
layers_completed INTEGER NOT NULL DEFAULT 0,
total_layers INTEGER NOT NULL DEFAULT 8,
ssim_score REAL,
error_message TEXT,
started_at TEXT,
completed_at TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
// Additive migration: job_type column added for adversary-view jobs.
// ALTER TABLE … ADD COLUMN is idempotent-safe in SQLite when wrapped in a try/catch.
try {
d.run("ALTER TABLE protection_jobs ADD COLUMN job_type TEXT NOT NULL DEFAULT 'protect'");
} catch {
// Column already exists — safe to ignore
}
logger.info('Database schema initialized', { path: DB_PATH });
}