Phase 2.1: Card mirror system for deckbuilding features

- Created MtgCardMirror and DeckCardLink models in mirror_models.py
- Created card_mirror_service.py with sync_mirrors functionality
- Added sync_mirrors() method to mtgjson_manager.py
- Added mirror_get_db() dependency to database.py
- Added DecklistFile.status column (DRAUGHT/FINAL)
- Updated DeckCreate schema with status field
- Added DeckWithCardsResponse schema with card_count
- Updated deck router to query card mirrors and return card counts
- Added plain text deck content support
This commit is contained in:
2026-07-22 03:35:57 +00:00
parent a01e33eb5e
commit 2c74a107bc
9 changed files with 744 additions and 70 deletions
+82
View File
@@ -903,6 +903,88 @@ class MTGJSONManager:
'duration': duration,
})
async def sync_mirrors(self):
"""Sync mirrored cards from mtg_cards to mtg_cards_mirror.
This should be called after a successful refresh to ensure
the mirror table is up-to-date with the latest card data.
"""
from sqlalchemy import insert, update
logger.info("Syncing card mirrors...")
async with mtg_async_session() as session:
# Get all cards from mtg_cards
cards_stmt = text("""
SELECT id, name, mana_cost, type_line, oracle_text, power, toughness,
rarity, layout, artist, flavor_text, numbers, identifiers, images,
image, card_parts, keywords, legalities, set_code, set_name
FROM mtg_cards
""")
result = await session.execute(cards_stmt)
cards = result.fetchall()
synced_count = 0
for card in cards:
# Upsert into mtg_cards_mirror
await session.execute(text("""
INSERT INTO mtg_cards_mirror (source_id, name, mana_cost, type_line, oracle_text,
power, toughness, rarity, layout, artist, flavor_text,
numbers, identifiers, images, image, card_parts,
keywords, legalities, set_code, set_name)
VALUES (:source_id, :name, :mana_cost, :type_line, :oracle_text,
:power, :toughness, :rarity, :layout, :artist, :flavor_text,
:numbers, :identifiers, :images, :image, :card_parts,
:keywords, :legalities, :set_code, :set_name)
ON CONFLICT (name) DO UPDATE SET
mana_cost = EXCLUDED.mana_cost,
type_line = EXCLUDED.type_line,
oracle_text = EXCLUDED.oracle_text,
power = EXCLUDED.power,
toughness = EXCLUDED.toughness,
rarity = EXCLUDED.rarity,
layout = EXCLUDED.layout,
artist = EXCLUDED.artist,
flavor_text = EXCLUDED.flavor_text,
numbers = EXCLUDED.numbers,
identifiers = EXCLUDED.identifiers,
images = EXCLUDED.images,
image = EXCLUDED.image,
card_parts = EXCLUDED.card_parts,
keywords = EXCLUDED.keywords,
legalities = EXCLUDED.legalities,
set_code = EXCLUDED.set_code,
set_name = EXCLUDED.set_name,
synced_at = CURRENT_TIMESTAMP
"""), {
'source_id': card[0],
'name': card[1],
'mana_cost': card[2],
'type_line': card[3],
'oracle_text': card[4],
'power': card[5],
'toughness': card[6],
'rarity': card[7],
'layout': card[8],
'artist': card[9],
'flavor_text': card[10],
'numbers': card[11],
'identifiers': card[12],
'images': card[13],
'image': card[14],
'card_parts': card[15],
'keywords': card[16],
'legalities': card[17],
'set_code': card[18],
'set_name': card[19],
})
synced_count += 1
await session.commit()
logger.info(f"Synced {synced_count} card mirrors")
return synced_count
async def run_refresh(self) -> bool:
"""Run complete refresh cycle from local files."""
logger.info("Starting local file refresh")