05/23 Phase 14

This commit is contained in:
2026-05-23 12:58:57 -04:00
parent ae0c64f731
commit 8eea1e976f
9 changed files with 851 additions and 2 deletions
+67
View File
@@ -19,6 +19,73 @@ logger = logging.getLogger(__name__)
# GAMES
# ══════════════════════════════════════════════════════════════════════════════
_BUILTIN_GAMES = {"Powerball", "Mega Millions"}
def add_game(name: str, main_count: int, main_max: int,
bonus_count: int = 0, bonus_max: int = 0) -> int:
"""
Insert a new game row. Returns the new game id.
Raises ValueError if name is blank or already exists.
"""
name = name.strip()
if not name:
raise ValueError("Game name cannot be blank.")
conn = get_connection()
try:
cursor = conn.cursor()
cursor.execute(
"SELECT id FROM games WHERE name = ?", (name,)
)
if cursor.fetchone():
raise ValueError(f"A game named '{name}' already exists.")
cursor.execute(
"""INSERT INTO games (name, main_count, main_max, bonus_count, bonus_max, active)
VALUES (?, ?, ?, ?, ?, 1)""",
(name, main_count, main_max, bonus_count, bonus_max),
)
conn.commit()
new_id = cursor.lastrowid
logger.info("[DB] Added custom game id=%d name='%s'", new_id, name)
return new_id
except Exception:
conn.rollback()
raise
finally:
conn.close()
def delete_game(game_id: int) -> bool:
"""
Delete a game by id. Returns True on success, False if the game has draws
(to protect data integrity) or is a built-in game.
"""
conn = get_connection()
try:
cursor = conn.cursor()
cursor.execute("SELECT name FROM games WHERE id = ?", (game_id,))
row = cursor.fetchone()
if row is None:
return False
if row["name"] in _BUILTIN_GAMES:
logger.warning("[DB] Refused to delete built-in game '%s'", row["name"])
return False
cursor.execute("SELECT COUNT(*) as cnt FROM draws WHERE game_id = ?", (game_id,))
if cursor.fetchone()["cnt"] > 0:
logger.warning("[DB] Refused to delete game id=%d — has draws", game_id)
return False
cursor.execute("DELETE FROM predictions WHERE game_id = ?", (game_id,))
cursor.execute("DELETE FROM games WHERE id = ?", (game_id,))
conn.commit()
logger.info("[DB] Deleted custom game id=%d", game_id)
return True
except Exception:
conn.rollback()
raise
finally:
conn.close()
def get_all_games(active_only=False):
"""
Return list of all games as sqlite3.Row objects.