""" 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()