120 lines
4.2 KiB
Python
120 lines
4.2 KiB
Python
|
|
"""
|
||
|
|
Deck models for deck building and management
|
||
|
|
"""
|
||
|
|
|
||
|
|
from sqlalchemy import Column, Integer, String, DateTime, Boolean, ForeignKey, Text, Float
|
||
|
|
from sqlalchemy.orm import relationship
|
||
|
|
from sqlalchemy.sql import func
|
||
|
|
from app.database import Base
|
||
|
|
|
||
|
|
|
||
|
|
class Deck(Base):
|
||
|
|
__tablename__ = "decks"
|
||
|
|
|
||
|
|
id = Column(Integer, primary_key=True, index=True)
|
||
|
|
name = Column(String, nullable=False)
|
||
|
|
description = Column(Text)
|
||
|
|
format = Column(String) # Standard, Modern, Legacy, Commander, etc.
|
||
|
|
game = Column(String, nullable=False) # MTG, Pokemon, YuGiOh, etc.
|
||
|
|
|
||
|
|
# Deck status and sharing
|
||
|
|
is_public = Column(Boolean, default=False)
|
||
|
|
is_complete = Column(Boolean, default=False)
|
||
|
|
is_favorite = Column(Boolean, default=False)
|
||
|
|
|
||
|
|
# Commander/Partner info (for MTG)
|
||
|
|
commander_card_id = Column(Integer, ForeignKey("cards.id"))
|
||
|
|
partner_card_id = Column(Integer, ForeignKey("cards.id"))
|
||
|
|
|
||
|
|
# Deck statistics
|
||
|
|
total_cards = Column(Integer, default=0)
|
||
|
|
avg_mana_cost = Column(Float)
|
||
|
|
estimated_value = Column(Float)
|
||
|
|
|
||
|
|
# AI and optimization data
|
||
|
|
ai_suggestions = Column(Text) # JSON string of AI suggestions
|
||
|
|
win_rate = Column(Float) # If user tracks games
|
||
|
|
last_played = Column(DateTime)
|
||
|
|
|
||
|
|
# Ownership
|
||
|
|
owner_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||
|
|
|
||
|
|
# Metadata
|
||
|
|
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||
|
|
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||
|
|
|
||
|
|
# Relationships
|
||
|
|
owner = relationship("User", back_populates="decks")
|
||
|
|
commander = relationship("Card", foreign_keys=[commander_card_id])
|
||
|
|
partner = relationship("Card", foreign_keys=[partner_card_id])
|
||
|
|
deck_cards = relationship("DeckCard", back_populates="deck", cascade="all, delete-orphan")
|
||
|
|
|
||
|
|
@property
|
||
|
|
def mainboard_cards(self):
|
||
|
|
"""Get only mainboard cards"""
|
||
|
|
return [dc for dc in self.deck_cards if not dc.is_sideboard]
|
||
|
|
|
||
|
|
@property
|
||
|
|
def sideboard_cards(self):
|
||
|
|
"""Get only sideboard cards"""
|
||
|
|
return [dc for dc in self.deck_cards if dc.is_sideboard]
|
||
|
|
|
||
|
|
def calculate_stats(self):
|
||
|
|
"""Calculate deck statistics"""
|
||
|
|
mainboard = self.mainboard_cards
|
||
|
|
if not mainboard:
|
||
|
|
return
|
||
|
|
|
||
|
|
# Total cards
|
||
|
|
self.total_cards = sum(dc.quantity for dc in mainboard)
|
||
|
|
|
||
|
|
# Average mana cost
|
||
|
|
total_cmc = sum(dc.card.cmc * dc.quantity for dc in mainboard if dc.card.cmc)
|
||
|
|
self.avg_mana_cost = total_cmc / self.total_cards if self.total_cards > 0 else 0
|
||
|
|
|
||
|
|
# Estimated value
|
||
|
|
total_value = 0
|
||
|
|
for dc in self.deck_cards:
|
||
|
|
if dc.card.current_price:
|
||
|
|
total_value += dc.card.current_price * dc.quantity
|
||
|
|
self.estimated_value = total_value
|
||
|
|
|
||
|
|
def __repr__(self):
|
||
|
|
return f"<Deck(id={self.id}, name='{self.name}', format='{self.format}')>"
|
||
|
|
|
||
|
|
|
||
|
|
class DeckCard(Base):
|
||
|
|
__tablename__ = "deck_cards"
|
||
|
|
|
||
|
|
id = Column(Integer, primary_key=True, index=True)
|
||
|
|
deck_id = Column(Integer, ForeignKey("decks.id"), nullable=False)
|
||
|
|
card_id = Column(Integer, ForeignKey("cards.id"), nullable=False)
|
||
|
|
|
||
|
|
# Deck composition
|
||
|
|
quantity = Column(Integer, default=1)
|
||
|
|
is_sideboard = Column(Boolean, default=False)
|
||
|
|
is_commander = Column(Boolean, default=False) # For commander format
|
||
|
|
|
||
|
|
# Card preferences
|
||
|
|
preferred_printing = Column(String) # Specific set preference
|
||
|
|
foil_preference = Column(Boolean, default=False)
|
||
|
|
|
||
|
|
# Deck building notes
|
||
|
|
category = Column(String) # Removal, Ramp, Win-con, etc.
|
||
|
|
notes = Column(Text)
|
||
|
|
ai_suggestion = Column(Boolean, default=False) # Was this card suggested by AI?
|
||
|
|
|
||
|
|
# Ownership tracking
|
||
|
|
owned = Column(Boolean, default=False) # Does user own this card?
|
||
|
|
need_to_acquire = Column(Boolean, default=True)
|
||
|
|
|
||
|
|
# Metadata
|
||
|
|
added_at = Column(DateTime(timezone=True), server_default=func.now())
|
||
|
|
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||
|
|
|
||
|
|
# Relationships
|
||
|
|
deck = relationship("Deck", back_populates="deck_cards")
|
||
|
|
card = relationship("Card", back_populates="deck_cards")
|
||
|
|
|
||
|
|
def __repr__(self):
|
||
|
|
return f"<DeckCard(deck_id={self.deck_id}, card_id={self.card_id}, quantity={self.quantity})>"
|