Final project commit: MTGJSON data integration and backend API

This commit is contained in:
wall-o
2026-07-20 01:09:45 +00:00
parent b170dfd577
commit db01e29a54
37 changed files with 9674 additions and 198 deletions
+190
View File
@@ -0,0 +1,190 @@
"""
MTG Card Interaction Database Schema
Defines the database schema for storing card interactions.
Includes tables for synergies, counters, evolutions, and statistics.
"""
from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, ForeignKey, UniqueConstraint
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from datetime import datetime
Base = declarative_base()
class CardSynergy(Base):
"""
Synergy between two cards.
Synergies are positive interactions where cards work well together.
Examples: Archetype support, mechanic combos, mana base compatibility.
"""
__tablename__ = 'mtg_card_synergies'
id = Column(Integer, primary_key=True, autoincrement=True)
card_a_id = Column(Integer, ForeignKey('mtg_cards.id'), nullable=False)
card_b_id = Column(Integer, ForeignKey('mtg_cards.id'), nullable=False)
synergy_type = Column(String(50), nullable=False) # 'archetype', 'mechanic', 'mana', 'combo'
strength = Column(Integer, nullable=False) # 1-5 (1=weak, 5=strong)
notes = Column(String(500), nullable=True)
confidence = Column(Float, nullable=False, default=0.8)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Unique constraint to prevent duplicates
__table_args__ = (
UniqueConstraint('card_a_id', 'card_b_id', 'synergy_type', name='uq_synergy_pair_type'),
)
# Relationships
card_a = relationship('MtgCard', foreign_keys=[card_a_id])
card_b = relationship('MtgCard', foreign_keys=[card_b_id])
def __repr__(self):
return f"<CardSynergy(id={self.id}, card_a={self.card_a_id}, card_b={self.card_b_id}, type={self.synergy_type})>"
class CardCounter(Base):
"""
Counter relationship between two cards.
Counters are negative interactions where one card is disadvantaged by another.
Examples: Different color identities, outclassed stats, countered by specific spells.
"""
__tablename__ = 'mtg_card_counters'
id = Column(Integer, primary_key=True, autoincrement=True)
card_a_id = Column(Integer, ForeignKey('mtg_cards.id'), nullable=False)
card_b_id = Column(Integer, ForeignKey('mtg_cards.id'), nullable=False)
counter_type = Column(String(50), nullable=False) # 'color', 'stats', 'spell', 'keyword'
strength = Column(Integer, nullable=False) # 1-5 (1=weak, 5=strong)
notes = Column(String(500), nullable=True)
confidence = Column(Float, nullable=False, default=0.7)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Unique constraint to prevent duplicates
__table_args__ = (
UniqueConstraint('card_a_id', 'card_b_id', 'counter_type', name='uq_counter_pair_type'),
)
# Relationships
card_a = relationship('MtgCard', foreign_keys=[card_a_id])
card_b = relationship('MtgCard', foreign_keys=[card_b_id])
def __repr__(self):
return f"<CardCounter(id={self.id}, card_a={self.card_a_id}, card_b={self.card_b_id}, type={self.counter_type})>"
class CardEvolution(Base):
"""
Evolution relationship for a card.
Evolutions track when a card has been reprinted, transformed, or evolved.
Examples: Same name in different sets, transform pairs, double-sided cards.
"""
__tablename__ = 'mtg_card_evolution'
id = Column(Integer, primary_key=True, autoincrement=True)
card_id = Column(Integer, ForeignKey('mtg_cards.id'), nullable=False)
evolved_card_id = Column(Integer, ForeignKey('mtg_cards.id'), nullable=False)
evolution_type = Column(String(50), nullable=False) # 'reprint', 'transform', 'double_sided'
strength = Column(Integer, nullable=False) # 1-5 (1=weak, 5=strong)
notes = Column(String(500), nullable=True)
confidence = Column(Float, nullable=False, default=0.9)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Unique constraint to prevent duplicates
__table_args__ = (
UniqueConstraint('card_id', 'evolved_card_id', 'evolution_type', name='uq_evolution_pair_type'),
)
# Relationships
card = relationship('MtgCard', foreign_keys=[card_id])
evolved_card = relationship('MtgCard', foreign_keys=[evolved_card_id])
def __repr__(self):
return f"<CardEvolution(id={self.id}, card={self.card_id}, evolved={self.evolved_card_id}, type={self.evolution_type})>"
class CardInteractionStats(Base):
"""
Aggregated interaction statistics for a card.
Tracks total interactions, average strength, and primary archetypes/themes.
"""
__tablename__ = 'mtg_card_interaction_stats'
id = Column(Integer, primary_key=True, autoincrement=True)
card_id = Column(Integer, ForeignKey('mtg_cards.id'), nullable=False, unique=True)
# Interaction counts
total_synergies = Column(Integer, nullable=False, default=0)
total_counters = Column(Integer, nullable=False, default=0)
total_evolutions = Column(Integer, nullable=False, default=0)
total_partners = Column(Integer, nullable=False, default=0) # Cards that partner well
# Mechanic/archetype counts
total_mechanics = Column(Integer, nullable=False, default=0)
total_archetypes = Column(Integer, nullable=False, default=0)
total_themes = Column(Integer, nullable=False, default=0)
# Synergy strength metrics
avg_synergy_strength = Column(Float, nullable=False, default=0.0)
max_synergy_strength = Column(Integer, nullable=False, default=0)
# Primary archetype and theme
primary_archetype = Column(String(50), nullable=True)
primary_theme = Column(String(50), nullable=True)
# Metadata
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def __repr__(self):
return f"<CardInteractionStats(id={self.id}, card_id={self.card_id})>"
def create_interaction_tables(engine):
"""
Create all interaction tables in the database.
Args:
engine: SQLAlchemy engine
"""
Base.metadata.create_all(engine)
print("✅ Interaction tables created successfully")
def drop_interaction_tables(engine):
"""
Drop all interaction tables from the database.
Args:
engine: SQLAlchemy engine
"""
Base.metadata.drop_all(engine)
print("✅ Interaction tables dropped successfully")
if __name__ == "__main__":
# Example usage
from dotenv import load_dotenv
import os
load_dotenv()
db_url = os.getenv('MTG_DATABASE_URL', 'postgresql+psycopg2://mtgonline:mtgonline_pass@172.18.0.2:5432/mtgdata')
engine = create_engine(db_url)
# Create tables
create_interaction_tables(engine)
# Print table names
from sqlalchemy import inspect
inspector = inspect(engine)
print("\n📊 Tables created:")
for table in inspector.get_table_names():
if 'mtg_card_' in table:
print(f" - {table}")