|
import os |
|
from sqlalchemy import create_engine, text |
|
from sqlalchemy.ext.declarative import declarative_base |
|
from sqlalchemy.orm import sessionmaker |
|
from sqlalchemy.exc import SQLAlchemyError, OperationalError |
|
from dotenv import load_dotenv |
|
import logging |
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
load_dotenv() |
|
|
|
|
|
DEFAULT_DB_URL = os.getenv("AIVEN_DB_URL") |
|
|
|
|
|
DB_CONNECTION_MODE = os.getenv("DB_CONNECTION_MODE", "aiven") |
|
|
|
|
|
if DB_CONNECTION_MODE == "aiven": |
|
DATABASE_URL = os.getenv("AIVEN_DB_URL", DEFAULT_DB_URL) |
|
else: |
|
|
|
DATABASE_URL = os.getenv("AIVEN_DB_URL", DEFAULT_DB_URL) |
|
|
|
if not DATABASE_URL: |
|
logger.error("No database URL configured. Using default URL.") |
|
DATABASE_URL = DEFAULT_DB_URL |
|
|
|
|
|
try: |
|
engine = create_engine( |
|
DATABASE_URL, |
|
pool_size=10, |
|
max_overflow=5, |
|
pool_timeout=30, |
|
pool_recycle=300, |
|
pool_pre_ping=True, |
|
connect_args={ |
|
"connect_timeout": 5, |
|
"keepalives": 1, |
|
"keepalives_idle": 30, |
|
"keepalives_interval": 10, |
|
"keepalives_count": 5, |
|
"application_name": "pixagent_api" |
|
}, |
|
|
|
isolation_level="READ COMMITTED", |
|
echo=False, |
|
echo_pool=False, |
|
future=True, |
|
|
|
execution_options={ |
|
"compiled_cache": {}, |
|
"logging_token": "SQL", |
|
} |
|
) |
|
logger.info("PostgreSQL engine initialized with optimized settings") |
|
except Exception as e: |
|
logger.error(f"Failed to initialize PostgreSQL engine: {e}") |
|
|
|
|
|
|
|
SessionLocal = sessionmaker( |
|
autocommit=False, |
|
autoflush=False, |
|
bind=engine, |
|
expire_on_commit=False |
|
) |
|
|
|
|
|
from sqlalchemy.orm import declarative_base |
|
Base = declarative_base() |
|
|
|
|
|
def check_db_connection(): |
|
"""Check PostgreSQL connection status""" |
|
try: |
|
|
|
with engine.connect() as connection: |
|
connection.execute(text("SELECT 1")).fetchone() |
|
logger.info("PostgreSQL connection successful") |
|
return True |
|
except OperationalError as e: |
|
logger.error(f"PostgreSQL connection failed: {e}") |
|
return False |
|
except Exception as e: |
|
logger.error(f"Unknown error checking PostgreSQL connection: {e}") |
|
return False |
|
|
|
|
|
def get_db(): |
|
"""Get PostgreSQL database session""" |
|
db = SessionLocal() |
|
try: |
|
|
|
db.execute(text("SELECT 1")).fetchone() |
|
yield db |
|
except Exception as e: |
|
logger.error(f"DB connection error: {e}") |
|
raise |
|
finally: |
|
db.close() |
|
|
|
|
|
def create_tables(): |
|
"""Create tables in database""" |
|
try: |
|
Base.metadata.create_all(bind=engine) |
|
logger.info("Database tables created or already exist") |
|
return True |
|
except SQLAlchemyError as e: |
|
logger.error(f"Failed to create database tables (SQLAlchemy error): {e}") |
|
return False |
|
except Exception as e: |
|
logger.error(f"Failed to create database tables (unexpected error): {e}") |
|
return False |
|
|
|
|
|
def create_indexes(): |
|
"""Create indexes for better query performance""" |
|
try: |
|
with engine.connect() as conn: |
|
try: |
|
|
|
conn.execute(text(""" |
|
CREATE INDEX idx_event_featured |
|
ON event_item(featured) |
|
""")) |
|
except SQLAlchemyError: |
|
logger.info("Index idx_event_featured already exists") |
|
|
|
try: |
|
|
|
conn.execute(text(""" |
|
CREATE INDEX idx_event_active |
|
ON event_item(is_active) |
|
""")) |
|
except SQLAlchemyError: |
|
logger.info("Index idx_event_active already exists") |
|
|
|
try: |
|
|
|
conn.execute(text(""" |
|
CREATE INDEX idx_event_date_start |
|
ON event_item(date_start) |
|
""")) |
|
except SQLAlchemyError: |
|
logger.info("Index idx_event_date_start already exists") |
|
|
|
try: |
|
|
|
conn.execute(text(""" |
|
CREATE INDEX idx_event_featured_active |
|
ON event_item(featured, is_active) |
|
""")) |
|
except SQLAlchemyError: |
|
logger.info("Index idx_event_featured_active already exists") |
|
|
|
|
|
try: |
|
|
|
conn.execute(text(""" |
|
CREATE INDEX idx_faq_active |
|
ON faq_item(is_active) |
|
""")) |
|
except SQLAlchemyError: |
|
logger.info("Index idx_faq_active already exists") |
|
|
|
try: |
|
|
|
conn.execute(text(""" |
|
CREATE INDEX idx_emergency_active |
|
ON emergency_item(is_active) |
|
""")) |
|
except SQLAlchemyError: |
|
logger.info("Index idx_emergency_active already exists") |
|
|
|
try: |
|
conn.execute(text(""" |
|
CREATE INDEX idx_emergency_priority |
|
ON emergency_item(priority) |
|
""")) |
|
except SQLAlchemyError: |
|
logger.info("Index idx_emergency_priority already exists") |
|
|
|
conn.commit() |
|
|
|
logger.info("Database indexes created or verified") |
|
return True |
|
except SQLAlchemyError as e: |
|
logger.error(f"Failed to create indexes: {e}") |
|
return False |