191 lines
7.1 KiB
Python
191 lines
7.1 KiB
Python
"""
|
|
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}")
|