Spaces:
Running
Running
File size: 7,008 Bytes
3222a21 1cff830 bfe88a9 3222a21 bfe88a9 4809b28 bfe88a9 4809b28 bfe88a9 3222a21 4809b28 3222a21 bfe88a9 3222a21 1cff830 3222a21 0f4be73 3222a21 bfe88a9 1cff830 3222a21 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# # app/database.py
# import os
# from databases import Database
# from dotenv import load_dotenv
# # --- Keep only these SQLAlchemy imports ---
# from sqlalchemy import MetaData, Table, Column, Integer, String
# import logging
# from urllib.parse import urlparse, urlunparse, parse_qs, urlencode
# load_dotenv()
# logger = logging.getLogger(__name__)
# # --- Database URL Configuration ---
# DEFAULT_DB_PATH = "/tmp/app.db" # Store DB in the temporary directory
# raw_db_url = os.getenv("DATABASE_URL", f"sqlite+aiosqlite:///{DEFAULT_DB_PATH}")
# final_database_url = raw_db_url
# if raw_db_url.startswith("sqlite+aiosqlite"):
# parsed_url = urlparse(raw_db_url)
# query_params = parse_qs(parsed_url.query)
# if 'check_same_thread' not in query_params:
# query_params['check_same_thread'] = ['False']
# new_query = urlencode(query_params, doseq=True)
# final_database_url = urlunparse(parsed_url._replace(query=new_query))
# logger.info(f"Using final async DB URL: {final_database_url}")
# else:
# logger.info(f"Using non-SQLite async DB URL: {final_database_url}")
# # --- Async Database Instance ---
# database = Database(final_database_url)
# # --- Metadata and Table Definition (Still needed for DDL generation) ---
# 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),
# )
# # --- REMOVE ALL SYNCHRONOUS ENGINE AND TABLE CREATION LOGIC ---
# # --- Keep and refine Async connect/disconnect functions ---
# async def connect_db():
# """Connects to the database, ensuring the parent directory exists."""
# try:
# # Ensure the directory exists just before connecting
# db_file_path = final_database_url.split("sqlite:///")[-1].split("?")[0]
# db_dir = os.path.dirname(db_file_path)
# if db_dir: # Only proceed if a directory path was found
# if not os.path.exists(db_dir):
# logger.info(f"Database directory {db_dir} does not exist. Attempting creation...")
# try:
# os.makedirs(db_dir, exist_ok=True)
# logger.info(f"Created database directory {db_dir}.")
# except Exception as mkdir_err:
# # Log error but proceed, connection might still work if path is valid but dir creation failed weirdly
# logger.error(f"Failed to create directory {db_dir}: {mkdir_err}")
# # Check writability after ensuring existence attempt
# if os.path.exists(db_dir) and not os.access(db_dir, os.W_OK):
# logger.error(f"CRITICAL: Directory {db_dir} exists but is not writable!")
# elif not os.path.exists(db_dir):
# logger.error(f"CRITICAL: Directory {db_dir} does not exist and could not be created!")
# # Now attempt connection
# await database.connect()
# logger.info(f"Database connection established (async): {final_database_url}")
# # Table creation will happen in main.py lifespan event using this connection
# except Exception as e:
# logger.exception(f"Failed to establish async database connection: {e}")
# raise # Reraise critical error during startup
# async def disconnect_db():
# """Disconnects from the database if connected."""
# try:
# if database.is_connected:
# await database.disconnect()
# logger.info("Database connection closed (async).")
# else:
# logger.info("Database already disconnected (async).")
# except Exception as e:
# logger.exception(f"Error closing async database connection: {e}")
# app/database.py
import os
# --- Keep only Sync SQLAlchemy ---
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String, text, exc as sqlalchemy_exc
from dotenv import load_dotenv
import logging
load_dotenv()
logger = logging.getLogger(__name__)
# Use /tmp for ephemeral storage in HF Space
DEFAULT_DB_PATH = "/tmp/app.db"
# Construct sync URL directly
DATABASE_URL = os.getenv("DATABASE_URL_SYNC", f"sqlite:///{DEFAULT_DB_PATH}")
logger.info(f"Using DB URL for sync operations: {DATABASE_URL}")
# SQLite specific args for sync engine
connect_args = {"check_same_thread": False} if DATABASE_URL.startswith("sqlite") else {}
engine = create_engine(DATABASE_URL, connect_args=connect_args, echo=False) # echo=True for debugging SQL
metadata = MetaData()
users_table = Table( # Renamed slightly to avoid confusion with Pydantic model name
"users",
metadata,
Column("id", Integer, primary_key=True),
Column("email", String, unique=True, index=True, nullable=False),
Column("hashed_password", String, nullable=False),
)
def ensure_db_and_table_exist():
"""Synchronously ensures DB file directory and users table exist."""
logger.info("Ensuring DB and table exist...")
try:
# Ensure directory exists
db_file_path = DATABASE_URL.split("sqlite:///")[-1]
db_dir = os.path.dirname(db_file_path)
if db_dir:
if not os.path.exists(db_dir):
logger.info(f"Creating DB directory: {db_dir}")
os.makedirs(db_dir, exist_ok=True)
if not os.access(db_dir, os.W_OK):
logger.error(f"CRITICAL: Directory {db_dir} not writable!")
return # Cannot proceed
# Check/Create table using the engine
with engine.connect() as connection:
try:
connection.execute(text("SELECT 1 FROM users LIMIT 1"))
logger.info("Users table already exists.")
except sqlalchemy_exc.OperationalError as e:
if "no such table" in str(e).lower():
logger.warning("Users table not found, creating...")
metadata.create_all(bind=connection) # Use connection
connection.commit()
logger.info("Users table created and committed.")
# Verify
try:
connection.execute(text("SELECT 1 FROM users LIMIT 1"))
logger.info("Users table verified post-creation.")
except Exception as verify_err:
logger.error(f"Verification failed after creating table: {verify_err}")
else:
logger.error(f"DB OperationalError checking table (not 'no such table'): {e}")
raise # Re-raise unexpected errors
except Exception as check_err:
logger.error(f"Unexpected error checking table: {check_err}")
raise # Re-raise unexpected errors
except Exception as e:
logger.exception(f"CRITICAL error during DB setup: {e}")
# Potentially raise to halt app start? |