1
0

feat: schema versioning with v2 migration (loans, last_played_at)

This commit is contained in:
2026-09-03 20:43:33 +02:00
parent bc3db9e4f7
commit 3bdbd8315c
4 changed files with 108 additions and 3 deletions

View File

@@ -5,6 +5,7 @@ import crypto from 'node:crypto'
export interface Config {
dataDir: string
artworkDir: string
backupsDir: string
dbPath: string
port: number
sessionSecret: string
@@ -15,9 +16,12 @@ export function loadConfig(env: Record<string, string | undefined> = process.env
mkdirSync(dataDir, { recursive: true })
const artworkDir = path.join(dataDir, 'artwork-cache')
mkdirSync(artworkDir, { recursive: true })
const backupsDir = path.join(dataDir, 'backups')
mkdirSync(backupsDir, { recursive: true })
return {
dataDir,
artworkDir,
backupsDir,
dbPath: path.join(dataDir, 'record-shop.db'),
port: Number(env.PORT ?? 3000),
sessionSecret: getOrCreateSecret(dataDir),

View File

@@ -10,8 +10,7 @@ export function openDatabase(path: string): DB {
return db
}
export function migrate(db: DB): void {
db.exec(`
const BASE_SCHEMA = `
CREATE TABLE IF NOT EXISTS app_meta (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
@@ -76,5 +75,42 @@ export function migrate(db: DB): void {
album_id INTEGER NOT NULL REFERENCES digital_albums(id) ON DELETE CASCADE,
PRIMARY KEY (user_id, item_id)
);
`)
`
function getSchemaVersion(db: DB): number {
const row = db.prepare("SELECT value FROM app_meta WHERE key = 'schema_version'").get() as
| { value: string }
| undefined
return row ? Number(row.value) : 0
}
function setSchemaVersion(db: DB, version: number): void {
db.prepare(
`INSERT INTO app_meta (key, value) VALUES ('schema_version', ?)
ON CONFLICT(key) DO UPDATE SET value = excluded.value`
).run(String(version))
}
/** Upgrade steps for databases created before schema versioning existed. */
export function migrateUpgrades(db: DB): void {
const version = getSchemaVersion(db)
if (version < 2) {
db.exec(`
ALTER TABLE digital_albums ADD COLUMN last_played_at TEXT;
CREATE TABLE IF NOT EXISTS loans (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
item_id INTEGER NOT NULL REFERENCES collection_items(id) ON DELETE CASCADE,
borrower TEXT NOT NULL,
lent_at TEXT NOT NULL DEFAULT (datetime('now')),
returned_at TEXT
);
`)
setSchemaVersion(db, 2)
}
}
export function migrate(db: DB): void {
db.exec(BASE_SCHEMA)
migrateUpgrades(db)
}