927abe6111
Implements SQLAlchemy 2.0 async ORM models (Config, Subscription, ExportLog) with cascade delete-orphan relationships. Upgrades SQLAlchemy to 2.0.49 for Python 3.14 compatibility. Adds pytest conftest with in-memory SQLite fixture; all 4 TDD tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
67 lines
2.4 KiB
Python
67 lines
2.4 KiB
Python
from __future__ import annotations
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
from sqlalchemy import Integer, String, Text, Boolean, DateTime, ForeignKey
|
|
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
|
|
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
|
|
|
|
|
|
class Base(DeclarativeBase):
|
|
pass
|
|
|
|
|
|
class Config(Base):
|
|
__tablename__ = "configs"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String, nullable=False)
|
|
token: Mapped[str] = mapped_column(String, unique=True, nullable=False)
|
|
base_yaml: Mapped[str] = mapped_column(Text, nullable=False)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
|
)
|
|
|
|
subscriptions: Mapped[list["Subscription"]] = relationship(
|
|
back_populates="config", cascade="all, delete-orphan"
|
|
)
|
|
export_logs: Mapped[list["ExportLog"]] = relationship(
|
|
back_populates="config", cascade="all, delete-orphan"
|
|
)
|
|
|
|
|
|
class Subscription(Base):
|
|
__tablename__ = "subscriptions"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False)
|
|
name: Mapped[str] = mapped_column(String, nullable=False)
|
|
url: Mapped[str] = mapped_column(String, nullable=False)
|
|
last_fetched_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
|
|
|
|
config: Mapped["Config"] = relationship(back_populates="subscriptions")
|
|
|
|
|
|
class ExportLog(Base):
|
|
__tablename__ = "export_logs"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False)
|
|
fetched_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
node_count: Mapped[int] = mapped_column(Integer, default=0)
|
|
success: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
error_message: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
|
|
config: Mapped["Config"] = relationship(back_populates="export_logs")
|
|
|
|
|
|
def make_engine(database_url: str):
|
|
return create_async_engine(database_url)
|
|
|
|
|
|
def make_session_factory(engine):
|
|
return async_sessionmaker(engine, expire_on_commit=False)
|