from __future__ import annotations import uuid from datetime import datetime from sqlalchemy import CheckConstraint, DateTime, ForeignKey, Integer, String from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from core.db.base import Base, TimestampMixin from core.db.types import json_jsonb from schemas.enums import InviteCodeStatus __all__ = ["InviteCode", "InviteCodeStatus"] class InviteCode(TimestampMixin, Base): __tablename__: str = "invite_codes" __table_args__ = ( CheckConstraint( "status IN ('active', 'disabled', 'expired')", name="invite_codes_status_check", ), CheckConstraint("used_count >= 0", name="invite_codes_used_count_check"), CheckConstraint( "max_uses IS NULL OR max_uses >= 1", name="invite_codes_max_uses_check", ), {"extend_existing": True}, ) id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, ) code: Mapped[str] = mapped_column( String(6), nullable=False, unique=True, index=True, ) owner_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("profiles.id", ondelete="SET NULL"), nullable=True, index=True, ) status: Mapped[str] = mapped_column( String(20), nullable=False, default=InviteCodeStatus.ACTIVE.value, ) used_count: Mapped[int] = mapped_column( Integer, nullable=False, default=0, ) max_uses: Mapped[int | None] = mapped_column( Integer, nullable=True, ) expires_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, ) reward_config: Mapped[dict[str, object]] = mapped_column( json_jsonb, nullable=False, server_default="{}", )