AuthenticationApp / app /database.py
amaye15's picture
Debug - Change DB
1cff830
raw
history blame
3.6 kB
# app/database.py
import os
from databases import Database
from dotenv import load_dotenv
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String, text
import logging # Add logging
load_dotenv()
logger = logging.getLogger(__name__) # Add logger
# --- CHANGE THIS LINE ---
# Use an absolute path in a known writable directory like /data
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite+aiosqlite:////data/app.db")
# Note the four slashes for an absolute path: sqlite+aiosqlite:////path/to/db
# Use 'check_same_thread': False only for SQLite
connect_args = {"check_same_thread": False} if DATABASE_URL.startswith("sqlite") else {}
database = Database(DATABASE_URL, connect_args=connect_args)
metadata = MetaData()
users = Table(
"users",
metadata,
Column("id", Integer, primary_key=True),
Column("email", String, unique=True, index=True, nullable=False),
Column("hashed_password", String, nullable=False),
)
# Create the database and table if they don't exist (synchronous part)
# Derive the synchronous URL correctly from the potentially absolute DATABASE_URL
sync_db_url = DATABASE_URL.replace("+aiosqlite", "")
logger.info(f"Using synchronous DB URL for initial check/create: {sync_db_url}")
engine = create_engine(sync_db_url, connect_args=connect_args)
# Extract the directory path to ensure it exists
db_file_path = sync_db_url.split("sqlite:///")[-1] # Gets /data/app.db
if db_file_path: # Ensure we got a path
db_dir = os.path.dirname(db_file_path)
logger.info(f"Ensuring database directory exists: {db_dir}")
try:
if db_dir and not os.path.exists(db_dir):
os.makedirs(db_dir, exist_ok=True)
logger.info(f"Created database directory: {db_dir}")
except OSError as e:
logger.error(f"Error creating database directory {db_dir}: {e}")
# Proceed anyway, maybe permissions allow file creation but not dir listing/creation
# Now try connecting and creating the table
try:
logger.info("Attempting to connect with sync engine to check/create table...")
with engine.connect() as connection:
# Try a simple query to see if the table exists
try:
connection.execute(text("SELECT 1 FROM users LIMIT 1"))
logger.info("Users table already exists.")
except Exception: # Catch specific DB exceptions if possible, e.g., sqlalchemy.exc.ProgrammingError
logger.info("Users table not found or error checking, attempting creation...")
metadata.create_all(engine) # Create tables if check fails
logger.info("Users table created (or creation attempted).")
except Exception as e:
logger.exception(f"CRITICAL: Failed to connect/create database tables using sync engine: {e}")
# Application might fail to start properly here. Depending on requirements,
# you might raise the exception or just log it and hope the async part works.
# For now, just log it, as the async connection might still succeed later.
# Async connect/disconnect functions
async def connect_db():
try:
await database.connect()
logger.info(f"Database connection established (async): {DATABASE_URL}")
except Exception as e:
logger.exception(f"Failed to establish async database connection: {e}")
raise # Reraise critical error during startup lifespan
async def disconnect_db():
try:
await database.disconnect()
logger.info("Database connection closed (async).")
except Exception as e:
logger.exception(f"Error closing async database connection: {e}")