US01-02: Establish Application and Database Foundation (#47)
This commit was merged in pull request #47.
This commit is contained in:
9
photo_pipeline/models/__init__.py
Normal file
9
photo_pipeline/models/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
"""SQLAlchemy persistence models.
|
||||
|
||||
Importing this package registers every model on ``Base.metadata``, which the
|
||||
Alembic environment relies on.
|
||||
"""
|
||||
|
||||
from photo_pipeline.models.assets import Asset, AssetPath
|
||||
|
||||
__all__ = ["Asset", "AssetPath"]
|
||||
59
photo_pipeline/models/assets.py
Normal file
59
photo_pipeline/models/assets.py
Normal file
@@ -0,0 +1,59 @@
|
||||
"""Stable asset identity and path history.
|
||||
|
||||
A file path is mutable metadata, never identity: ``assets.id`` is a generated
|
||||
UUID that never changes across moves, renames, or archival. ``asset_paths``
|
||||
records every path an asset has occupied. ``state_version`` supports optimistic
|
||||
concurrency; ``created_at``/``updated_at`` are the audit timestamps.
|
||||
|
||||
Later-stage columns (canonical link, safety score, archive location) are added by
|
||||
the migrations of the stories that own them, not speculatively here.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, Integer, String, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from photo_pipeline.db import Base
|
||||
|
||||
|
||||
class Asset(Base):
|
||||
__tablename__ = "assets"
|
||||
|
||||
id: Mapped[str] = mapped_column(String, primary_key=True)
|
||||
original_path: Mapped[str] = mapped_column(String, nullable=False)
|
||||
current_path: Mapped[str | None] = mapped_column(String, unique=True)
|
||||
|
||||
current_sha256: Mapped[str | None] = mapped_column(String)
|
||||
pixel_sha256: Mapped[str | None] = mapped_column(String)
|
||||
phash: Mapped[str | None] = mapped_column(String)
|
||||
hash_version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||||
byte_size: Mapped[int | None] = mapped_column(Integer)
|
||||
|
||||
discovered_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
||||
missing_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
availability_state: Mapped[str] = mapped_column(String, nullable=False, default="active")
|
||||
|
||||
state_version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
|
||||
class AssetPath(Base):
|
||||
__tablename__ = "asset_paths"
|
||||
|
||||
asset_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("assets.id"), primary_key=True
|
||||
)
|
||||
path: Mapped[str] = mapped_column(String, primary_key=True)
|
||||
valid_from: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), primary_key=True
|
||||
)
|
||||
valid_until: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
reason: Mapped[str | None] = mapped_column(String)
|
||||
Reference in New Issue
Block a user