paper-dynasty-database/migrations/migrate_roster_junction_table.py
Cal Corum 44b6222ad5 fix: refactor Roster from 26 FK columns to RosterSlot junction table (#29)
- Remove card_1..card_26 FK columns from Roster ORM model
- Add RosterSlot model with (roster, slot, card) and a unique index on (roster, slot)
- Activate get_cards() helper on Roster using the new junction table
- Register RosterSlot in create_tables for SQLite dev environments
- Add migrations/migrate_roster_junction_table.py to backfill existing data

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 15:34:39 -06:00

66 lines
1.8 KiB
Python

"""
Migration: Replace 26 FK columns on Roster with RosterSlot junction table.
Creates the `rosterslot` table and migrates existing lineup data from the
card_1..card_26 columns. Safe to re-run (skips rosters already migrated).
Usage:
python migrations/migrate_roster_junction_table.py
"""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
from app.db_engine import db, Roster, RosterSlot
SLOTS = 26
def migrate():
db.connect(reuse_if_open=True)
# Create the table if it doesn't exist yet
db.create_tables([RosterSlot], safe=True)
# Read raw rows from the old schema via plain SQL so we don't depend on
# the ORM model knowing about the legacy card_N columns.
cursor = db.execute_sql("SELECT * FROM roster")
columns = [desc[0] for desc in cursor.description]
migrated = 0
skipped = 0
with db.atomic():
for row in cursor.fetchall():
row_dict = dict(zip(columns, row))
roster_id = row_dict["id"]
already_migrated = (
RosterSlot.select().where(RosterSlot.roster == roster_id).exists()
)
if already_migrated:
skipped += 1
continue
slots_to_insert = []
for slot_num in range(1, SLOTS + 1):
col = f"card_{slot_num}_id"
card_id = row_dict.get(col)
if card_id is not None:
slots_to_insert.append(
{"roster": roster_id, "slot": slot_num, "card": card_id}
)
if slots_to_insert:
RosterSlot.insert_many(slots_to_insert).execute()
migrated += 1
print(f"Migration complete: {migrated} rosters migrated, {skipped} already done.")
db.close()
if __name__ == "__main__":
migrate()