This commit is contained in:
2025-01-31 13:05:48 -05:00
parent 9f1a73f49d
commit 780b274faf
17 changed files with 1556 additions and 0 deletions

0
db/__init__.py Normal file
View File

75
db/database.py Normal file
View File

@@ -0,0 +1,75 @@
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker, Session
from contextlib import contextmanager
from typing import Generator
import os
import logging
logger = logging.getLogger(__name__)
# Get database URL from environment variable with fallback
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///omegacard.db")
# Create engine with proper configuration
engine = create_engine(
DATABASE_URL,
pool_pre_ping=True, # Enable connection health checks
pool_size=5, # Set reasonable pool size
max_overflow=10 # Allow some overflow connections
)
# Create session factory
SessionLocal = sessionmaker(
bind=engine,
autocommit=False,
autoflush=False
)
@contextmanager
def get_db_session() -> Generator[Session, None, None]:
"""Context manager for database sessions"""
session = SessionLocal()
try:
yield session
except Exception as e:
logger.error(f"Database session error: {str(e)}")
session.rollback()
raise
finally:
session.close()
def get_db() -> Generator[Session, None, None]:
"""Dependency for FastAPI to get database sessions"""
with get_db_session() as session:
yield session
def init_db() -> None:
"""Initialize database tables"""
from .models import Base
try:
Base.metadata.create_all(bind=engine)
logger.info("Database tables created successfully")
except Exception as e:
logger.error(f"Failed to initialize database: {str(e)}")
raise
def check_db_connection() -> bool:
"""Check if database connection is working"""
try:
with get_db_session() as session:
session.execute(text("SELECT 1"))
return True
except Exception as e:
logger.error(f"Database connection check failed: {str(e)}")
return False
def destroy_db() -> None:
"""Destroy all database tables"""
from .models import Base
try:
Base.metadata.drop_all(bind=engine)
logger.info("Database tables dropped successfully")
except Exception as e:
logger.error(f"Failed to destroy database: {str(e)}")
raise

162
db/models.py Normal file
View File

@@ -0,0 +1,162 @@
from sqlalchemy import Column, Integer, String, Float, Boolean, DateTime, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from datetime import datetime
Base = declarative_base()
class Box(Base):
__tablename__ = "boxes"
id = Column(String, primary_key=True, index=True)
upload_id = Column(String, ForeignKey("upload_history.upload_id"))
set_name = Column(String)
set_code = Column(String)
type = Column(String)
cost = Column(Float)
date_purchased = Column(DateTime)
date_opened = Column(DateTime)
date_created = Column(DateTime, default=datetime.now)
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)
class ManaboxExportData(Base):
__tablename__ = "manabox_export_data"
id = Column(String, primary_key=True)
upload_id = Column(String)
box_id = Column(String, nullable=True)
name = Column(String)
set_code = Column(String)
set_name = Column(String)
collector_number = Column(String)
foil = Column(String)
rarity = Column(String)
quantity = Column(Integer)
manabox_id = Column(String)
scryfall_id = Column(String)
purchase_price = Column(Float)
misprint = Column(String)
altered = Column(String)
condition = Column(String)
language = Column(String)
purchase_price_currency = Column(String)
date_created = Column(DateTime, default=datetime.now)
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)
class UploadHistory(Base):
__tablename__ = "upload_history"
id = Column(String, primary_key=True)
upload_id = Column(String)
filename = Column(String)
date_created = Column(DateTime, default=datetime.now)
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)
status = Column(String)
class TCGPlayerGroups(Base):
__tablename__ = 'tcgplayer_groups'
id = Column(String, primary_key=True)
group_id = Column(Integer)
name = Column(String)
abbreviation = Column(String)
is_supplemental = Column(String)
published_on = Column(String)
modified_on = Column(String)
category_id = Column(Integer)
class TCGPlayerInventory(Base):
__tablename__ = 'tcgplayer_inventory'
# TCGplayer Id,Product Line,Set Name,Product Name,Title,Number,Rarity,Condition,TCG Market Price,TCG Direct Low,TCG Low Price With Shipping,TCG Low Price,Total Quantity,Add to Quantity,TCG Marketplace Price,Photo URL
id = Column(String, primary_key=True)
export_id = Column(String)
tcgplayer_product_id = Column(String, ForeignKey("tcgplayer_product.id"), nullable=True)
tcgplayer_id = Column(Integer)
product_line = Column(String)
set_name = Column(String)
product_name = Column(String)
title = Column(String)
number = Column(String)
rarity = Column(String)
condition = Column(String)
tcg_market_price = Column(Float)
tcg_direct_low = Column(Float)
tcg_low_price_with_shipping = Column(Float)
tcg_low_price = Column(Float)
total_quantity = Column(Integer)
add_to_quantity = Column(Integer)
tcg_marketplace_price = Column(Float)
photo_url = Column(String)
date_created = Column(DateTime, default=datetime.now)
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)
class TCGPlayerExportHistory(Base):
__tablename__ = 'tcgplayer_export_history'
id = Column(String, primary_key=True)
type = Column(String)
pricing_export_id = Column(String)
inventory_export_id = Column(String)
date_created = Column(DateTime, default=datetime.now)
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)
class TCGPlayerPricingHistory(Base):
__tablename__ = 'tcgplayer_pricing_history'
id = Column(String, primary_key=True)
tcgplayer_product_id = Column(String, ForeignKey("tcgplayer_product.id"))
export_id = Column(String)
group_id = Column(Integer)
tcgplayer_id = Column(Integer)
tcg_market_price = Column(Float)
tcg_direct_low = Column(Float)
tcg_low_price_with_shipping = Column(Float)
tcg_low_price = Column(Float)
tcg_marketplace_price = Column(Float)
date_created = Column(DateTime, default=datetime.now)
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)
class TCGPlayerProduct(Base):
__tablename__ = 'tcgplayer_product'
id = Column(String, primary_key=True)
group_id = Column(Integer)
tcgplayer_id = Column(Integer)
product_line = Column(String)
set_name = Column(String)
product_name = Column(String)
title = Column(String)
number = Column(String)
rarity = Column(String)
condition = Column(String)
date_created = Column(DateTime, default=datetime.now)
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)
class ManaboxTCGPlayerMapping(Base):
__tablename__ = 'manabox_tcgplayer_mapping'
id = Column(String, primary_key=True)
manabox_id = Column(String, ForeignKey("manabox_export_data.id"))
tcgplayer_id = Column(Integer, ForeignKey("tcgplayer_inventory.tcgplayer_id"))
date_created = Column(DateTime, default=datetime.now)
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)
class SetCodeGroupIdMapping(Base):
__tablename__ = 'set_code_group_id_mapping'
id = Column(String, primary_key=True)
set_code = Column(String)
group_id = Column(Integer)
date_created = Column(DateTime, default=datetime.now)
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)
class UnmatchedManaboxData(Base):
__tablename__ = 'unmatched_manabox_data'
id = Column(String, primary_key=True)
manabox_id = Column(String, ForeignKey("manabox_export_data.id"))
reason = Column(String)
date_created = Column(DateTime, default=datetime.now)
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)

23
db/utils.py Normal file
View File

@@ -0,0 +1,23 @@
from contextlib import contextmanager
from sqlalchemy.orm import Session
from exceptions import FailedUploadException
import logging
logger = logging.getLogger(__name__)
@contextmanager
def db_transaction(db: Session):
"""Simple context manager for database transactions"""
try:
yield
db.commit()
except FailedUploadException as failed_upload:
logger.error(f"Failed upload: {str(failed_upload.message)}")
db.rollback()
db.add(failed_upload.file_upload_record)
db.commit()
raise
except Exception as e:
logger.error(f"Database error: {str(e)}")
db.rollback()
raise