88 lines
2.9 KiB
TypeScript
88 lines
2.9 KiB
TypeScript
import Database from 'better-sqlite3';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { env } from '$env/dynamic/private';
|
|
|
|
let _db: Database.Database | null = null;
|
|
|
|
export function getDb(): Database.Database {
|
|
if (_db) return _db;
|
|
|
|
const DB_PATH = env.DB_PATH ?? path.join(process.cwd(), 'data', 'game-grid.db');
|
|
const dir = path.dirname(DB_PATH);
|
|
if (!fs.existsSync(dir)) {
|
|
fs.mkdirSync(dir, { recursive: true });
|
|
}
|
|
|
|
_db = new Database(DB_PATH);
|
|
_db.pragma('journal_mode = WAL');
|
|
_db.pragma('foreign_keys = ON');
|
|
initSchema(_db);
|
|
return _db;
|
|
}
|
|
|
|
function initSchema(db: Database.Database): void {
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS series (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
slug TEXT NOT NULL UNIQUE,
|
|
title TEXT NOT NULL,
|
|
library TEXT NOT NULL CHECK(library IN ('public','private')),
|
|
folder_path TEXT NOT NULL,
|
|
has_cover INTEGER NOT NULL DEFAULT 0,
|
|
last_scanned_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS games (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
slug TEXT NOT NULL UNIQUE,
|
|
title TEXT NOT NULL,
|
|
library TEXT NOT NULL CHECK(library IN ('public','private')),
|
|
folder_path TEXT NOT NULL,
|
|
description TEXT NOT NULL DEFAULT '',
|
|
genre TEXT NOT NULL DEFAULT '',
|
|
has_cover INTEGER NOT NULL DEFAULT 0,
|
|
has_wide INTEGER NOT NULL DEFAULT 0,
|
|
last_scanned_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS game_files (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
game_id INTEGER NOT NULL REFERENCES games(id) ON DELETE CASCADE,
|
|
filename TEXT NOT NULL,
|
|
rel_path TEXT NOT NULL,
|
|
platform TEXT NOT NULL,
|
|
is_dir INTEGER NOT NULL DEFAULT 0,
|
|
file_size INTEGER NOT NULL DEFAULT 0
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS screenshots (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
game_id INTEGER NOT NULL REFERENCES games(id) ON DELETE CASCADE,
|
|
filename TEXT NOT NULL,
|
|
rel_path TEXT NOT NULL,
|
|
sort_order INTEGER NOT NULL DEFAULT 0
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS tags (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE COLLATE NOCASE
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS game_tags (
|
|
game_id INTEGER NOT NULL REFERENCES games(id) ON DELETE CASCADE,
|
|
tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
|
|
PRIMARY KEY (game_id, tag_id)
|
|
);
|
|
`);
|
|
|
|
const cols = db.prepare('PRAGMA table_info(games)').all() as Array<{ name: string }>;
|
|
if (!cols.some((c) => c.name === 'series_id')) {
|
|
db.exec(
|
|
'ALTER TABLE games ADD COLUMN series_id INTEGER REFERENCES series(id) ON DELETE SET NULL'
|
|
);
|
|
}
|
|
}
|