from __future__ import annotations import uuid from datetime import datetime from sqlalchemy import CheckConstraint, DateTime, Index, String, Text, text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from core.db.base import Base, SoftDeleteMixin, TimestampMixin from core.db.types import json_jsonb class Notification(TimestampMixin, SoftDeleteMixin, Base): __tablename__ = "notifications" __table_args__ = ( CheckConstraint( "status IN ('draft', 'published', 'revoked')", name="ck_notifications_status", ), CheckConstraint( "jsonb_typeof(payload) = 'object'", name="ck_notifications_payload_object", ), Index( "ix_notifications_status_created_at", "status", "created_at", ), Index( "ix_notifications_published_at", "published_at", ), Index( "uq_notifications_source_source_key", "source", "source_key", unique=True, postgresql_where=text("source_key IS NOT NULL"), ), ) id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) type: Mapped[str] = mapped_column( String(32), nullable=False, server_default=text("'system'") ) source: Mapped[str] = mapped_column( String(32), nullable=False, server_default=text("'manual'") ) source_key: Mapped[str | None] = mapped_column(String(128), nullable=True) source_version: Mapped[int | None] = mapped_column(nullable=True) content_hash: Mapped[str | None] = mapped_column(String(64), nullable=True) title: Mapped[str] = mapped_column(Text, nullable=False) body: Mapped[str] = mapped_column(Text, nullable=False) payload: Mapped[dict[str, object]] = mapped_column( json_jsonb, nullable=False, server_default=text("'{}'::jsonb"), default=dict, ) status: Mapped[str] = mapped_column( String(16), nullable=False, server_default=text("'published'") ) published_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) revoked_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True )