""" Photo model definition """ from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, Index from sqlalchemy.sql import func from datetime import datetime import uuid from app.database import Base class Photo(Base): __tablename__ = 'photos' # Primary key id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4())) # File information filepath = Column(String, unique=True, nullable=False) filename = Column(String, nullable=False) folder_id = Column(String, ForeignKey('folders.id')) file_hash = Column(String, index=True) # SHA-256 hash for duplicate detection # Media information media_type = Column(String, nullable=False) # 'photo' | 'video' | 'raw' | 'heic' original_format = Column(String) # 'CR3', 'NEF', 'HEIC', 'MP4', 'JPEG', etc. width = Column(Integer) height = Column(Integer) file_size = Column(Integer) # Timestamps taken_at = Column(DateTime) # from EXIF DateTimeOriginal, fallback to file mtime taken_at_source = Column(String) # 'exif' | 'filesystem' | 'manual' added_at = Column(DateTime, server_default=func.now()) updated_at = Column(DateTime, onupdate=func.now()) # Trash status is_trashed = Column(Boolean, default=False) trashed_at = Column(DateTime) # Thumbnail paths thumb_small = Column(String) # path to 240px thumb thumb_medium = Column(String) # path to 640px thumb thumb_large = Column(String) # path to 1280px thumb # Processing status processing_status = Column(String, default='pending') # 'pending' | 'processing' | 'completed' | 'failed' processing_error = Column(Text) # Metadata exif_json = Column(Text) # full EXIF/XMP blob as JSON # User-editable fields user_title = Column(String) user_notes = Column(Text) rating = Column(Integer, default=0) # 0-5 stars color_label = Column(String) # 'red'|'orange'|'yellow'|'green'|'blue'|'purple'|NULL is_picked = Column(Boolean, default=False) # Note: is_rejected was merged into is_trashed (a single soft "trashed" # concept). The DB column may still exist on legacy installs but is no # longer read or written. # Duplicate detection is_duplicate = Column(Boolean, default=False) # Live photo support live_photo_video_id = Column(String, ForeignKey('photos.id')) # Indexes for performance __table_args__ = ( Index('ix_photos_taken_at', 'taken_at'), Index('ix_photos_folder_id', 'folder_id'), Index('ix_photos_is_trashed', 'is_trashed'), Index('ix_photos_rating', 'rating'), Index('ix_photos_color_label', 'color_label'), Index('ix_photos_media_type', 'media_type'), Index('ix_photos_processing_status', 'processing_status'), )