Add webm_path and webp_path columns to ghosts (idempotent migration)
ALTER TABLE guarded by a column-existence check so existing production databases gain the columns without data loss.
This commit is contained in:
+1
-74
@@ -1,74 +1 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import { mkdirSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const DB_PATH = join(__dirname, 'newbury.sqlite');
|
||||
|
||||
mkdirSync(__dirname, { recursive: true });
|
||||
|
||||
const db = new Database(DB_PATH);
|
||||
db.pragma('journal_mode = WAL');
|
||||
db.pragma('foreign_keys = ON');
|
||||
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'admin',
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS abilities (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
kind TEXT NOT NULL DEFAULT 'common', -- common | boss
|
||||
charges INTEGER,
|
||||
cooldown TEXT,
|
||||
effect TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ghosts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
display_name TEXT, -- shown on the lock-on label; falls back to name
|
||||
type TEXT NOT NULL, -- red | yellow | blue
|
||||
rarity INTEGER NOT NULL, -- 1..4 (stars)
|
||||
speed INTEGER NOT NULL DEFAULT 0,
|
||||
range INTEGER NOT NULL DEFAULT 0,
|
||||
charge_shot INTEGER NOT NULL DEFAULT 0,
|
||||
health INTEGER NOT NULL,
|
||||
damage INTEGER NOT NULL,
|
||||
ability TEXT,
|
||||
is_boss INTEGER NOT NULL DEFAULT 0,
|
||||
set_number TEXT,
|
||||
set_name TEXT,
|
||||
image_path TEXT, -- uploaded GIF/PNG billboard (nullable)
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_ghosts_type ON ghosts(type);
|
||||
CREATE INDEX IF NOT EXISTS idx_ghosts_rarity ON ghosts(rarity);
|
||||
CREATE INDEX IF NOT EXISTS idx_ghosts_boss ON ghosts(is_boss);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sets (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
code TEXT UNIQUE NOT NULL, -- QR payload / scan code
|
||||
set_number TEXT, -- e.g. 70419 (reference only)
|
||||
set_name TEXT NOT NULL,
|
||||
boss_ghost_id INTEGER REFERENCES ghosts(id) ON DELETE SET NULL,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS set_ghosts (
|
||||
set_id INTEGER NOT NULL REFERENCES sets(id) ON DELETE CASCADE,
|
||||
ghost_id INTEGER NOT NULL REFERENCES ghosts(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (set_id, ghost_id)
|
||||
);
|
||||
`);
|
||||
|
||||
export default db;
|
||||
export { DB_PATH };
|
||||
aW1wb3J0IERhdGFiYXNlIGZyb20gJ2JldHRlci1zcWxpdGUzJzsKaW1wb3J0IHsgbWtkaXJTeW5jIH0gZnJvbSAnbm9kZTpmcyc7CmltcG9ydCB7IGRpcm5hbWUsIGpvaW4gfSBmcm9tICdub2RlOnBhdGgnOwppbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAnbm9kZTp1cmwnOwoKY29uc3QgX19kaXJuYW1lID0gZGlybmFtZShmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCkpOwpjb25zdCBEQl9QQVRIID0gam9pbihfX2Rpcm5hbWUsICduZXdidXJ5LnNxbGl0ZScpOwoKbWtkaXJTeW5jKF9fZGlybmFtZSwgeyByZWN1cnNpdmU6IHRydWUgfSk7Cgpjb25zdCBkYiA9IG5ldyBEYXRhYmFzZShEQl9QQVRIKTsKZGIucHJhZ21hKCdqb3VybmFsX21vZGUgPSBXQUwnKTsKZGIucHJhZ21hKCdmb3JlaWduX2tleXMgPSBPTicpOwoKZGIuZXhlYyhgCkNSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIHVzZXJzICgKICBpZCAgICAgICAgICAgIElOVEVHRVIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCwKICB1c2VybmFtZSAgICAgIFRFWFQgVU5JUVVFIE5PVCBOVUxMLAogIHBhc3N3b3JkX2hhc2ggVEVYVCBOT1QgTlVMTCwKICByb2xlICAgICAgICAgIFRFWFQgTk9UIE5VTEwgREVGQVVMVCAnYWRtaW4nLAogIGNyZWF0ZWRfYXQgICAgVEVYVCBOT1QgTlVMTCBERUZBVUxUIChkYXRldGltZSgnbm93JykpCik7CgpDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyBhYmlsaXRpZXMgKAogIGlkICAgICAgICBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsCiAgbmFtZSAgICAgIFRFWFQgVU5JUVVFIE5PVCBOVUxMLAogIGtpbmQgICAgICBURVhUIE5PVCBOVUxMIERFRkFVTFQgJ2NvbW1vbicsICAgLS0gY29tbW9uIHwgYm9zcwogIGNoYXJnZXMgICBJTlRFR0VSLAogIGNvb2xkb3duICBURVhULAogIGVmZmVjdCAgICBURVhUCik7CgpDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyBnaG9zdHMgKAogIGlkICAgICAgICAgICBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsCiAgbmFtZSAgICAgICAgIFRFWFQgTk9UIE5VTEwsCiAgZGlzcGxheV9uYW1lIFRFWFQsICAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gc2hvd24gb24gdGhlIGxvY2stb24gbGFiZWw7IGZhbGxzIGJhY2sgdG8gbmFtZQogIHR5cGUgICAgICAgICBURVhUIE5PVCBOVUxMLCAgICAgICAgICAgICAgICAgIC0tIHJlZCB8IHllbGxvdyB8IGJsdWUKICByYXJpdHkgICAgICAgSU5URUdFUiBOT1QgTlVMTCwgICAgICAgICAgICAgICAtLSAxLi40IChzdGFycykKICBzcGVlZCAgICAgICAgSU5URUdFUiBOT1QgTlVMTCBERUZBVUxUIDAsCiAgcmFuZ2UgICAgICAgIElOVEVHRVIgTk9UIE5VTEwgREVGQVVMVCAwLAogIGNoYXJnZV9zaG90ICBJTlRFR0VSIE5PVCBOVUxMIERFRkFVTFQgMCwKICBoZWFsdGggICAgICAgSU5URUdFUiBOT1QgTlVMTCwKICBkYW1hZ2UgICAgICAgSU5URUdFUiBOT1QgTlVMTCwKICBhYmlsaXR5ICAgICAgVEVYVCwKICBpc19ib3NzICAgICAgSU5URUdFUiBOT1QgTlVMTCBERUZBVUxUIDAsCiAgc2V0X251bWJlciAgIFRFWFQsCiAgc2V0X25hbWUgICAgIFRFWFQsCiAgaW1hZ2VfcGF0aCAgIFRFWFQsICAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gdXBsb2FkZWQgR0lGL1BORyBiaWxsYm9hcmQgKG51bGxhYmxlKQogIGVuYWJsZWQgICAgICBJTlRFR0VSIE5PVCBOVUxMIERFRkFVTFQgMSwKICBjcmVhdGVkX2F0ICAgVEVYVCBOT1QgTlVMTCBERUZBVUxUIChkYXRldGltZSgnbm93JykpCik7CkNSRUFURSBJTkRFWCBJRiBOT1QgRVhJU1RTIGlkeF9naG9zdHNfdHlwZSAgIE9OIGdob3N0cyh0eXBlKTsKQ1JFQVRFIElOREVYIElGIE5PVCBFWElTVFMgaWR4X2dob3N0c19yYXJpdHkgT04gZ2hvc3RzKHJhcml0eSk7CkNSRUFURSBJTkRFWCBJRiBOT1QgRVhJU1RTIGlkeF9naG9zdHNfYm9zcyAgIE9OIGdob3N0cyhpc19ib3NzKTsKCkNSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIHNldHMgKAogIGlkICAgICAgICAgIElOVEVHRVIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCwKICBjb2RlICAgICAgICBURVhUIFVOSVFVRSBOT1QgTlVMTCwgICAgICAgICAgICAtLSBRUiBwYXlsb2FkIC8gc2NhbiBjb2RlCiAgc2V0X251bWJlciAgVEVYVCwgICAgICAgICAgICAgICAgICAgICAgICAgICAgLS0gZS5nLiA3MDQxOSAocmVmZXJlbmNlIG9ubHkpCiAgc2V0X25hbWUgICAgVEVYVCBOT1QgTlVMTCwKICBib3NzX2dob3N0X2lkIElOVEVHRVIgUkVGRVJFTkNFUyBnaG9zdHMoaWQpIE9OIERFTEVURSBTRVQgTlVMTCwKICBlbmFibGVkICAgICBJTlRFR0VSIE5PVCBOVUxMIERFRkFVTFQgMSwKICBjcmVhdGVkX2F0ICBURVhUIE5PVCBOVUxMIERFRkFVTFQgKGRhdGV0aW1lKCdub3cnKSkKKTsKCkNSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIHNldF9naG9zdHMgKAogIHNldF9pZCAgIElOVEVHRVIgTk9UIE5VTEwgUkVGRVJFTkNFUyBzZXRzKGlkKSBPTiBERUxFVEUgQ0FTQ0FERSwKICBnaG9zdF9pZCBJTlRFR0VSIE5PVCBOVUxMIFJFRkVSRU5DRVMgZ2hvc3RzKGlkKSBPTiBERUxFVEUgQ0FTQ0FERSwKICBQUklNQVJZIEtFWSAoc2V0X2lkLCBnaG9zdF9pZCkKKTsKYCk7CgovKiAtLS0tIE1pZ3JhdGlvbnMgKGlkZW1wb3RlbnQpIC0tLS0KICogQWRkIHRyYW5zcGFyZW50LXZpZGVvIHNwcml0ZSBjb2x1bW5zIHRvIHRoZSBleGlzdGluZyBnaG9zdHMgdGFibGUgd2l0aG91dAogKiBkcm9wcGluZyBkYXRhLiB3ZWJtX3BhdGggaXMgdGhlIFZQOSthbHBoYSBiaWxsYm9hcmQ7IHdlYnBfcGF0aCBpcyB0aGUKICogYW5pbWF0ZWQtV2ViUCBmYWxsYmFjayB1c2VkIHdoZXJlIFZQOSBhbHBoYSBpc24ndCBzdXBwb3J0ZWQgKGUuZy4gaU9TKS4KICovCmZ1bmN0aW9uIGFkZENvbHVtbklmTWlzc2luZyh0YWJsZSwgY29sdW1uLCBkZWNsKSB7CiAgY29uc3QgY29scyA9IGRiLnByZXBhcmUoYFBSQUdNQSB0YWJsZV9pbmZvKCR7dGFibGV9KWApLmFsbCgpOwogIGlmICghY29scy5zb21lKChjKSA9PiBjLm5hbWUgPT09IGNvbHVtbikpIHsKICAgIGRiLmV4ZWMoYEFMVEVSIFRBQkxFICR7dGFibGV9IEFERCBDT0xVTU4gJHtjb2x1bW59ICR7ZGVjbH1gKTsKICB9Cn0KYWRkQ29sdW1uSWZNaXNzaW5nKCdnaG9zdHMnLCAnd2VibV9wYXRoJywgJ1RFWFQnKTsgLy8gVlA5K2FscGhhIGJpbGxib2FyZCAobnVsbGFibGUpCmFkZENvbHVtbklmTWlzc2luZygnZ2hvc3RzJywgJ3dlYnBfcGF0aCcsICdURVhUJyk7IC8vIGFuaW1hdGVkLVdlYlAgZmFsbGJhY2sgKG51bGxhYmxlKQoKZXhwb3J0IGRlZmF1bHQgZGI7CmV4cG9ydCB7IERCX1BBVEggfTsK
|
||||
Reference in New Issue
Block a user