from sqlalchemy import ( Boolean, Column, Date, DateTime, Enum, Float, ForeignKey, Integer, MetaData, String, Table, func, ) from app.core.dto.user import UserRole metadata = MetaData() trainings = Table( "trainings", metadata, Column("id", Integer, primary_key=True), Column("date", Date, nullable=False, index=True), # RESTRICT: a user who has trainings can't be deleted by accident Column("trainee_id", ForeignKey("users.id", ondelete="RESTRICT"), nullable=False, index=True), # No trainer means a solo training Column("trainer_id", ForeignKey("users.id", ondelete="RESTRICT"), index=True), Column("created_at", DateTime(timezone=True), nullable=False, server_default=func.now()), ) exercises = Table( "exercises", metadata, Column("id", Integer, primary_key=True), Column( "training_id", ForeignKey("trainings.id", ondelete="CASCADE"), nullable=False, index=True, ), Column("name", String(255), nullable=False, index=True), Column("splitted_weight", Boolean, nullable=False, server_default="false"), Column("created_at", DateTime(timezone=True), nullable=False, server_default=func.now()), ) approaches = Table( "approaches", metadata, Column("id", Integer, primary_key=True), Column( "exercise_id", ForeignKey("exercises.id", ondelete="CASCADE"), nullable=False, index=True, ), Column("weight", Float, nullable=False), Column("reps", Integer, nullable=False), Column("created_at", DateTime(timezone=True), nullable=False, server_default=func.now()), ) users = Table( "users", metadata, Column("id", Integer, primary_key=True), Column("email", String(254), nullable=False, unique=True, index=True), Column("password_hash", String(255), nullable=False), Column("first_name", String(100), nullable=False, server_default=""), Column("last_name", String(100), nullable=False, server_default=""), # VARCHAR + CHECK instead of a native PostgreSQL enum: adding a role is a plain migration Column( "role", Enum( UserRole, name="user_role", native_enum=False, length=20, create_constraint=True, values_callable=lambda roles: [role.value for role in roles], ), nullable=False, server_default=UserRole.trainee.value, ), Column("is_active", Boolean, nullable=False, server_default="true"), Column("is_superuser", Boolean, nullable=False, server_default="false"), Column("created_at", DateTime(timezone=True), nullable=False, server_default=func.now()), Column("last_login", DateTime(timezone=True)), ) refresh_tokens = Table( "refresh_tokens", metadata, Column("id", Integer, primary_key=True), Column("user_id", ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True), # Tokens issued by rotation from one login share a family: a reused token revokes it all Column("family_id", String(32), nullable=False, index=True), Column("token_hash", String(64), nullable=False, unique=True), Column("expires_at", DateTime(timezone=True), nullable=False), Column("revoked_at", DateTime(timezone=True)), Column("created_at", DateTime(timezone=True), nullable=False, server_default=func.now()), )