Skip to content

Commit 674af82

Browse files
committed
Add betting functionality with user management and betting tables
- Implemented user creation and retrieval functions in the database. - Added betting tables for users and bets, including necessary fields.
1 parent 43003a5 commit 674af82

5 files changed

Lines changed: 1000 additions & 7 deletions

File tree

db.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,128 @@ export function clearAllRounds() {
4141
db.exec("DELETE FROM rounds;");
4242
db.exec("DELETE FROM sqlite_sequence WHERE name = 'rounds';");
4343
}
44+
45+
// ── Betting tables ──────────────────────────────────────────────────────────
46+
47+
db.exec(`
48+
CREATE TABLE IF NOT EXISTS users (
49+
id TEXT PRIMARY KEY,
50+
nickname TEXT UNIQUE NOT NULL,
51+
balance INTEGER DEFAULT 1000,
52+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
53+
);
54+
`);
55+
56+
db.exec(`
57+
CREATE TABLE IF NOT EXISTS bets (
58+
id INTEGER PRIMARY KEY AUTOINCREMENT,
59+
user_id TEXT NOT NULL,
60+
round_num INTEGER NOT NULL,
61+
contestant TEXT NOT NULL,
62+
amount INTEGER NOT NULL,
63+
won INTEGER,
64+
payout INTEGER DEFAULT 0,
65+
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
66+
UNIQUE(user_id, round_num)
67+
);
68+
`);
69+
70+
// ── Betting functions ───────────────────────────────────────────────────────
71+
72+
export function createUser(id: string, nickname: string) {
73+
const stmt = db.prepare("INSERT INTO users (id, nickname) VALUES ($id, $nickname)");
74+
stmt.run({ $id: id, $nickname: nickname });
75+
return { id, nickname, balance: 1000 };
76+
}
77+
78+
export function getUser(id: string) {
79+
return db.query("SELECT id, nickname, balance FROM users WHERE id = $id").get({ $id: id }) as { id: string; nickname: string; balance: number } | null;
80+
}
81+
82+
export function placeBet(userId: string, roundNum: number, contestant: string, amount: number) {
83+
const user = getUser(userId);
84+
if (!user) throw new Error("User not found");
85+
if (amount <= 0) throw new Error("Amount must be positive");
86+
if (amount > user.balance) throw new Error("Insufficient balance");
87+
88+
const existing = db.query("SELECT id FROM bets WHERE user_id = $userId AND round_num = $roundNum").get({ $userId: userId, $roundNum: roundNum });
89+
if (existing) throw new Error("Already bet this round");
90+
91+
db.exec("BEGIN");
92+
try {
93+
db.prepare("INSERT INTO bets (user_id, round_num, contestant, amount) VALUES ($userId, $roundNum, $contestant, $amount)")
94+
.run({ $userId: userId, $roundNum: roundNum, $contestant: contestant, $amount: amount });
95+
db.prepare("UPDATE users SET balance = balance - $amount WHERE id = $userId")
96+
.run({ $amount: amount, $userId: userId });
97+
db.exec("COMMIT");
98+
} catch (e) {
99+
db.exec("ROLLBACK");
100+
throw e;
101+
}
102+
103+
return {
104+
bet: { userId, roundNum, contestant, amount },
105+
balance: user.balance - amount,
106+
};
107+
}
108+
109+
export function resolveBets(roundNum: number, winnerName: string | null) {
110+
const bets = db.query("SELECT id, user_id, contestant, amount FROM bets WHERE round_num = $roundNum AND won IS NULL")
111+
.all({ $roundNum: roundNum }) as { id: number; user_id: string; contestant: string; amount: number }[];
112+
113+
if (bets.length === 0) return;
114+
115+
db.exec("BEGIN");
116+
try {
117+
for (const bet of bets) {
118+
if (winnerName === null) {
119+
// Tie — refund
120+
db.prepare("UPDATE bets SET won = 0, payout = $amount WHERE id = $id")
121+
.run({ $amount: bet.amount, $id: bet.id });
122+
db.prepare("UPDATE users SET balance = balance + $amount WHERE id = $userId")
123+
.run({ $amount: bet.amount, $userId: bet.user_id });
124+
} else if (bet.contestant === winnerName) {
125+
const payout = bet.amount * 2;
126+
db.prepare("UPDATE bets SET won = 1, payout = $payout WHERE id = $id")
127+
.run({ $payout: payout, $id: bet.id });
128+
db.prepare("UPDATE users SET balance = balance + $payout WHERE id = $userId")
129+
.run({ $payout: payout, $userId: bet.user_id });
130+
} else {
131+
db.prepare("UPDATE bets SET won = 0, payout = 0 WHERE id = $id")
132+
.run({ $id: bet.id });
133+
}
134+
}
135+
db.exec("COMMIT");
136+
} catch (e) {
137+
db.exec("ROLLBACK");
138+
throw e;
139+
}
140+
}
141+
142+
export function getLeaderboard(limit = 10) {
143+
return db.query("SELECT id, nickname, balance FROM users ORDER BY balance DESC LIMIT $limit")
144+
.all({ $limit: limit }) as { id: string; nickname: string; balance: number }[];
145+
}
146+
147+
export function getBetsForRound(roundNum: number) {
148+
const rows = db.query(
149+
"SELECT contestant, COUNT(*) as count, SUM(amount) as total FROM bets WHERE round_num = $roundNum GROUP BY contestant"
150+
).all({ $roundNum: roundNum }) as { contestant: string; count: number; total: number }[];
151+
152+
const result: Record<string, { count: number; total: number }> = {};
153+
for (const row of rows) {
154+
result[row.contestant] = { count: row.count, total: row.total };
155+
}
156+
return result;
157+
}
158+
159+
export function getUserBetForRound(userId: string, roundNum: number) {
160+
return db.query("SELECT contestant, amount, won, payout FROM bets WHERE user_id = $userId AND round_num = $roundNum")
161+
.get({ $userId: userId, $roundNum: roundNum }) as { contestant: string; amount: number; won: number | null; payout: number } | null;
162+
}
163+
164+
export function clearAllBets() {
165+
db.exec("DELETE FROM bets;");
166+
db.exec("DELETE FROM users;");
167+
db.exec("DELETE FROM sqlite_sequence WHERE name = 'bets';");
168+
}

0 commit comments

Comments
 (0)