Files

321 lines
9.0 KiB
Python

#!/usr/bin/env python3
"""
MTG Card Search Script
Searches for Magic: The Gathering cards in the mtgdata database.
Supports searching by card name, partial name, and filters by set.
"""
import sys
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
def create_connection(db_url: str):
"""Create database connection."""
engine = create_engine(db_url)
session_factory = sessionmaker(bind=engine)
return engine, session_factory
def search_cards_by_name(session, card_name: str, set_code: str = None, limit: int = 10) -> list:
"""
Search for cards by name.
Args:
session: Database session
card_name: Card name to search for (partial matches supported)
set_code: Optional set code to filter by
limit: Maximum number of results
Returns:
List of card dictionaries
"""
# Build query based on whether set_code is provided
if set_code:
query = """
SELECT
c.id,
c.name,
c.type_line,
c.mana_cost,
c.oracle_text,
c.power,
c.toughness,
c.rarity,
c.layout,
c.artist,
c.flavor_text,
s.code as set_code,
s.name as set_name,
s.release_date as set_release_date
FROM mtg_cards c
JOIN mtg_sets s ON c.set_id = s.id
WHERE c.name LIKE :name
AND s.code = :set_code
ORDER BY c.name
LIMIT :limit
"""
params = {
"name": f"%{card_name}%",
"set_code": set_code.upper(),
"limit": limit
}
else:
query = """
SELECT
c.id,
c.name,
c.type_line,
c.mana_cost,
c.oracle_text,
c.power,
c.toughness,
c.rarity,
c.layout,
c.artist,
c.flavor_text,
s.code as set_code,
s.name as set_name,
s.release_date as set_release_date
FROM mtg_cards c
JOIN mtg_sets s ON c.set_id = s.id
WHERE c.name LIKE :name
ORDER BY c.name
LIMIT :limit
"""
params = {
"name": f"%{card_name}%",
"limit": limit
}
result = session.execute(text(query), params)
cards = []
for row in result:
card = {
"id": row[0],
"name": row[1],
"type_line": row[2],
"mana_cost": row[3],
"oracle_text": row[4],
"power": row[5],
"toughness": row[6],
"rarity": row[7],
"layout": row[8],
"artist": row[9],
"flavor_text": row[10],
"set_code": row[11],
"set_name": row[12],
"set_release_date": row[13]
}
cards.append(card)
return cards
def search_cards_by_set(session, set_code: str, limit: int = 100) -> list:
"""
Get all cards from a specific set.
Args:
session: Database session
set_code: Set code (e.g., '10E', '2ED')
limit: Maximum number of cards to return
Returns:
List of card dictionaries
"""
query = """
SELECT
c.id,
c.name,
c.type_line,
c.mana_cost,
c.oracle_text,
c.power,
c.toughness,
c.rarity,
c.layout,
c.artist,
c.flavor_text,
s.code as set_code,
s.name as set_name,
s.release_date as set_release_date
FROM mtg_cards c
JOIN mtg_sets s ON c.set_id = s.id
WHERE s.code = :set_code
ORDER BY c.name
LIMIT :limit
"""
params = {
"set_code": set_code.upper(),
"limit": limit
}
result = session.execute(text(query), params)
cards = []
for row in result:
card = {
"id": row[0],
"name": row[1],
"type_line": row[2],
"mana_cost": row[3],
"oracle_text": row[4],
"power": row[5],
"toughness": row[6],
"rarity": row[7],
"layout": row[8],
"artist": row[9],
"flavor_text": row[10],
"set_code": row[11],
"set_name": row[12],
"set_release_date": row[13]
}
cards.append(card)
return cards
def get_card_count(session, card_name: str = None, set_code: str = None) -> int:
"""
Get count of cards matching search criteria.
Args:
session: Database session
card_name: Optional card name filter
set_code: Optional set code filter
Returns:
Number of matching cards
"""
if card_name and set_code:
query = """
SELECT COUNT(*)
FROM mtg_cards c
JOIN mtg_sets s ON c.set_id = s.id
WHERE c.name LIKE :name
AND s.code = :set_code
"""
params = {
"name": f"%{card_name}%",
"set_code": set_code.upper()
}
elif card_name:
query = """
SELECT COUNT(*)
FROM mtg_cards
WHERE name LIKE :name
"""
params = {
"name": f"%{card_name}%"
}
elif set_code:
query = """
SELECT COUNT(*)
FROM mtg_cards
WHERE set_id = (SELECT id FROM mtg_sets WHERE code = :set_code)
"""
params = {
"set_code": set_code.upper()
}
else:
query = "SELECT COUNT(*) FROM mtg_cards"
params = {}
result = session.execute(text(query), params)
return result.fetchone()[0]
def format_card(card: dict) -> str:
"""Format a card dictionary for display."""
lines = [
f"Name: {card['name']}",
f"Type: {card['type_line'] or 'Unknown'}",
f"Mana Cost: {card['mana_cost'] or 'N/A'}",
f"Rarity: {card['rarity'] or 'N/A'}",
f"Set: {card['set_code']} - {card['set_name']}",
]
if card['oracle_text']:
lines.append(f"Oracle Text: {card['oracle_text']}")
if card['power'] and card['toughness']:
lines.append(f"Power/Toughness: {card['power']}/{card['toughness']}")
if card['artist']:
lines.append(f"Artist: {card['artist']}")
return "\n".join(lines)
def main():
"""Main entry point."""
# Database connection
db_url = "postgresql+psycopg2://mtgonline:mtgonline_pass@172.18.0.2:5432/mtgdata"
engine, session_factory = create_connection(db_url)
session = session_factory()
try:
# Get search parameters from command line
if len(sys.argv) < 2:
print("Usage: python search_cards.py <card_name> [set_code]")
print(" python search_cards.py --set <set_code>")
print(" python search_cards.py --count [card_name] [set_code]")
print("\nExamples:")
print(" python search_cards.py Lightning Bolt")
print(" python search_cards.py Lightning Bolt 10E")
print(" python search_cards.py --set 10E")
print(" python search_cards.py --count Lightning")
print(" python search_cards.py --count Lightning 10E")
return
# Parse arguments
if sys.argv[1] == "--set":
if len(sys.argv) < 3:
print("Error: --set requires a set code")
return
set_code = sys.argv[2]
print(f"Searching cards in set: {set_code}")
cards = search_cards_by_set(session, set_code)
print(f"\nFound {len(cards)} cards:\n")
for card in cards:
print(format_card(card))
print("-" * 60)
elif sys.argv[1] == "--count":
card_name = sys.argv[2] if len(sys.argv) > 2 else None
set_code = sys.argv[3] if len(sys.argv) > 3 else None
count = get_card_count(session, card_name, set_code)
print(f"Total cards matching criteria: {count}")
else:
card_name = sys.argv[1]
set_code = sys.argv[2] if len(sys.argv) > 2 else None
if set_code:
print(f"Searching for '{card_name}' in set {set_code}")
else:
print(f"Searching for '{card_name}'")
cards = search_cards_by_name(session, card_name, set_code)
if not cards:
print("No cards found.")
return
print(f"\nFound {len(cards)} card(s):\n")
for card in cards:
print(format_card(card))
print("-" * 60)
finally:
session.close()
engine.dispose()
if __name__ == "__main__":
main()