FarmerHelp / backend /app /database.py
Gankit12's picture
All Code
b64de39
Raw
History Blame Contribute Delete
3.85 kB
"""
Database Configuration and Session Management
"""
import logging
from contextlib import contextmanager
from sqlalchemy import create_engine, event, exc
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.pool import QueuePool, NullPool
from sqlalchemy.engine import Engine
from app.config import settings
logger = logging.getLogger(__name__)
# Determine pool class based on database type
# SQLite doesn't support connection pooling, use NullPool
if settings.DATABASE_URL.startswith("sqlite"):
poolclass = NullPool
connect_args = {"check_same_thread": False}
pool_pre_ping = False
else:
poolclass = QueuePool
connect_args = {}
pool_pre_ping = True
# Build engine kwargs; NullPool does not accept pool_size/max_overflow/pool_timeout
_engine_kwargs: dict = dict(
poolclass=poolclass,
pool_pre_ping=pool_pre_ping,
echo=settings.DEBUG,
connect_args=connect_args,
)
if poolclass is not NullPool:
_engine_kwargs.update(
pool_size=10,
max_overflow=20,
pool_recycle=3600,
pool_timeout=30,
)
engine = create_engine(settings.DATABASE_URL, **_engine_kwargs)
# Session factory
SessionLocal = sessionmaker(
autocommit=False,
autoflush=False,
bind=engine,
expire_on_commit=False
)
Base = declarative_base()
@event.listens_for(Engine, "connect")
def set_sqlite_pragma(dbapi_conn, connection_record):
"""
Set SQLite pragmas for better performance and foreign key support
"""
if settings.DATABASE_URL.startswith("sqlite"):
cursor = dbapi_conn.cursor()
cursor.execute("PRAGMA foreign_keys=ON")
cursor.execute("PRAGMA journal_mode=WAL")
cursor.execute("PRAGMA synchronous=NORMAL")
cursor.close()
@event.listens_for(Engine, "checkout")
def receive_checkout(dbapi_conn, connection_record, connection_proxy):
"""
Log connection checkout events
"""
if settings.DEBUG:
logger.debug("Connection checked out from pool")
def get_db():
"""
Database session dependency for FastAPI
Yields:
Session: SQLAlchemy database session
Example:
```python
@app.get("/items")
def get_items(db: Session = Depends(get_db)):
return db.query(Item).all()
```
"""
db = SessionLocal()
try:
yield db
except exc.SQLAlchemyError as e:
logger.error(f"Database error: {str(e)}")
db.rollback()
raise
finally:
db.close()
@contextmanager
def get_db_context():
"""
Context manager for database sessions (for use outside FastAPI)
Yields:
Session: SQLAlchemy database session
Example:
```python
with get_db_context() as db:
items = db.query(Item).all()
```
"""
db = SessionLocal()
try:
yield db
db.commit()
except exc.SQLAlchemyError as e:
logger.error(f"Database error: {str(e)}")
db.rollback()
raise
finally:
db.close()
def init_db():
"""
Initialize database by creating all tables
"""
try:
Base.metadata.create_all(bind=engine)
logger.info("Database tables created successfully")
except Exception as e:
logger.error(f"Error creating database tables: {str(e)}")
raise
def check_db_connection() -> bool:
"""
Check if database connection is healthy
Returns:
bool: True if connection is healthy, False otherwise
"""
try:
from sqlalchemy import text
with engine.connect() as conn:
conn.execute(text("SELECT 1"))
return True
except Exception as e:
logger.error(f"Database connection check failed: {str(e)}")
return False