feat: add SQLite schema and seed data

This commit is contained in:
achmad
2026-05-29 16:31:19 +07:00
parent 70d2b1b52d
commit 0bd3cb3bb4
2 changed files with 240 additions and 0 deletions
+212
View File
@@ -0,0 +1,212 @@
import Database from 'better-sqlite3';
import path from 'path';
import { seedDatabase } from './seed';
const DB_PATH = process.env.DB_PATH || path.join(process.cwd(), 'data', 'zombie_invasion.db');
let db: Database.Database;
export function getDb(): Database.Database {
if (!db) {
const fs = require('fs');
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);
seedDatabase();
}
return db;
}
function initSchema(db: Database.Database) {
db.exec(`
CREATE TABLE IF NOT EXISTS players (
steam_id TEXT PRIMARY KEY,
player_name TEXT NOT NULL,
profile_level INTEGER DEFAULT 1,
free_currency INTEGER DEFAULT 0,
donate_currency INTEGER DEFAULT 0,
dust_currency INTEGER DEFAULT 0,
arcade_pack_credits TEXT DEFAULT '{"standard":0,"premium":0}',
sounds_wheel TEXT DEFAULT '{}',
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS game_sessions (
game_id TEXT PRIMARY KEY,
match_id INTEGER,
session_id TEXT,
status TEXT DEFAULT 'active',
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS game_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
steam_id TEXT NOT NULL,
game_id TEXT,
match_id INTEGER,
result TEXT,
hero TEXT,
hero_level INTEGER,
difficulty TEXT,
duration INTEGER,
kills INTEGER DEFAULT 0,
deaths INTEGER DEFAULT 0,
score INTEGER DEFAULT 0,
outgoing_damage REAL DEFAULT 0,
incoming_damage REAL DEFAULT 0,
items TEXT,
modifiers TEXT,
aghanim_scepter INTEGER DEFAULT 0,
aghanim_shard INTEGER DEFAULT 0,
gold_earned INTEGER DEFAULT 0,
session_id TEXT,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS battle_passes (
steam_id TEXT PRIMARY KEY,
level INTEGER DEFAULT 0,
experience INTEGER DEFAULT 0,
has_premium INTEGER DEFAULT 0,
claimed_rewards TEXT DEFAULT '[]',
claimed_premium_rewards TEXT DEFAULT '[]',
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS battle_pass_quests (
id INTEGER PRIMARY KEY AUTOINCREMENT,
steam_id TEXT NOT NULL,
quest_id TEXT NOT NULL,
type TEXT NOT NULL,
name TEXT,
description TEXT,
progress INTEGER DEFAULT 0,
target INTEGER DEFAULT 1,
completed INTEGER DEFAULT 0,
claimed INTEGER DEFAULT 0,
reward_exp INTEGER DEFAULT 0,
reward_free_currency INTEGER DEFAULT 0,
quality TEXT,
npc TEXT,
target_item TEXT,
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS purchases (
id INTEGER PRIMARY KEY AUTOINCREMENT,
steam_id TEXT NOT NULL,
item_id TEXT NOT NULL,
item_category TEXT,
card_id INTEGER,
price_free INTEGER DEFAULT 0,
price_donate INTEGER DEFAULT 0,
price_dust INTEGER DEFAULT 0,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS active_effects (
steam_id TEXT PRIMARY KEY,
effects TEXT DEFAULT '{}',
updated_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS promo_codes (
code TEXT PRIMARY KEY,
free_currency INTEGER DEFAULT 0,
donate_currency INTEGER DEFAULT 0,
dust_currency INTEGER DEFAULT 0,
max_uses INTEGER DEFAULT 1,
current_uses INTEGER DEFAULT 0,
expires_at TEXT
);
CREATE TABLE IF NOT EXISTS promo_redemptions (
steam_id TEXT,
code TEXT,
redeemed_at TEXT DEFAULT (datetime('now')),
PRIMARY KEY (steam_id, code)
);
CREATE TABLE IF NOT EXISTS card_levels (
steam_id TEXT PRIMARY KEY,
card_levels TEXT DEFAULT '{}',
updated_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS decks (
steam_id TEXT,
deck_index INTEGER,
name TEXT DEFAULT 'My Deck',
cards TEXT DEFAULT '[]',
updated_at TEXT DEFAULT (datetime('now')),
PRIMARY KEY (steam_id, deck_index)
);
CREATE TABLE IF NOT EXISTS equipment (
steam_id TEXT PRIMARY KEY,
equipment TEXT DEFAULT '{}',
updated_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS arsenal_loadouts (
steam_id TEXT,
hero_name TEXT,
loadout TEXT DEFAULT '{}',
updated_at TEXT DEFAULT (datetime('now')),
PRIMARY KEY (steam_id, hero_name)
);
CREATE TABLE IF NOT EXISTS arsenal_inventory (
steam_id TEXT,
instance_id TEXT,
item_name TEXT,
quality TEXT,
upgrade_level INTEGER DEFAULT 0,
serial INTEGER,
global_serial INTEGER,
owner_name TEXT,
pinned INTEGER DEFAULT 0,
favorite INTEGER DEFAULT 0,
stats TEXT DEFAULT '[]',
PRIMARY KEY (steam_id, instance_id)
);
CREATE TABLE IF NOT EXISTS arsenal_market_listings (
listing_id TEXT PRIMARY KEY,
steam_id TEXT NOT NULL,
instance_id TEXT,
item_name TEXT,
quality TEXT,
upgrade_level INTEGER DEFAULT 0,
serial INTEGER,
global_serial INTEGER,
price_free INTEGER DEFAULT 0,
status TEXT DEFAULT 'active',
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS arsenal_market_sales (
id INTEGER PRIMARY KEY AUTOINCREMENT,
listing_id TEXT,
seller_steam_id TEXT,
buyer_steam_id TEXT,
item_name TEXT,
price_free INTEGER,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS death_sentence_contracts (
steam_id TEXT PRIMARY KEY,
contracts TEXT DEFAULT '{}',
updated_at TEXT DEFAULT (datetime('now'))
);
`);
}
+28
View File
@@ -0,0 +1,28 @@
import { getDb } from './db';
export function seedDatabase() {
const db = getDb();
const count = db.prepare('SELECT COUNT(*) as c FROM promo_codes').get() as { c: number };
if (count.c > 0) return;
const insert = db.prepare(`
INSERT INTO promo_codes (code, free_currency, donate_currency, dust_currency, max_uses, expires_at)
VALUES (?, ?, ?, ?, ?, ?)
`);
const codes = [
['WELCOME100', 100, 0, 0, 100, null],
['ZOMBIE500', 500, 50, 0, 50, null],
['DONATE100', 0, 100, 0, 20, null],
['DUST250', 0, 0, 250, 30, null],
];
const tx = db.transaction(() => {
for (const c of codes) {
insert.run(...c);
}
});
tx();
console.log('Database seeded with promo codes');
}