voice-notes / app /db.py
osina's picture
Build Voice Notes demo Space
64c1bdf verified
Raw History Blame Contribute Delete
1.88 kB
from __future__ import annotations
from datetime import UTC, datetime
from pathlib import Path
from sqlalchemy import DateTime, Engine, create_engine, event
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker
from sqlalchemy.types import TypeDecorator
class Base(DeclarativeBase):
pass
class UTCDateTime(TypeDecorator[datetime]):
"""Store datetimes as naive UTC and return timezone-aware UTC values."""
impl = DateTime
cache_ok = True
def process_bind_param(self, value: datetime | None, dialect):
if value is None:
return None
if value.tzinfo is None:
value = value.replace(tzinfo=UTC)
return value.astimezone(UTC).replace(tzinfo=None)
def process_result_value(self, value: datetime | None, dialect):
if value is None:
return None
return value.replace(tzinfo=UTC)
def create_db_engine(database_url: str) -> Engine:
if database_url.startswith("sqlite:///") and ":memory:" not in database_url:
path = database_url.removeprefix("sqlite:///")
Path(path).parent.mkdir(parents=True, exist_ok=True)
connect_args = {"check_same_thread": False} if database_url.startswith("sqlite") else {}
engine = create_engine(database_url, connect_args=connect_args, future=True)
if database_url.startswith("sqlite"):
@event.listens_for(engine, "connect")
def _set_sqlite_pragma(dbapi_connection, connection_record):
cursor = dbapi_connection.cursor()
cursor.execute("PRAGMA foreign_keys=ON")
cursor.close()
return engine
def create_session_factory(engine: Engine) -> sessionmaker[Session]:
return sessionmaker(bind=engine, expire_on_commit=False, class_=Session)
def init_db(engine: Engine) -> None:
from app import models # noqa: F401
Base.metadata.create_all(engine)