import uuid from datetime import datetime from decimal import Decimal from sqlalchemy import ( BigInteger, Boolean, CheckConstraint, DateTime, ForeignKey, Identity, Index, Numeric, String, Text, UniqueConstraint, func, text, ) from sqlalchemy.orm import Mapped, mapped_column from app.db import Base class WebSession(Base): __tablename__ = "web_sessions" id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) class Category(Base): __tablename__ = "categories" id: Mapped[int] = mapped_column(BigInteger, Identity(always=True), primary_key=True) name: Mapped[str] = mapped_column(String(80), unique=True) class Product(Base): __tablename__ = "products" __table_args__ = ( CheckConstraint("price >= 0", name="products_price_nonnegative"), Index( "products_active_category_price_idx", "category_id", "price", "id", postgresql_where=text("is_active"), ), ) id: Mapped[int] = mapped_column(BigInteger, Identity(always=True), primary_key=True) category_id: Mapped[int] = mapped_column(ForeignKey("categories.id"), nullable=False) title: Mapped[str] = mapped_column(String(255), nullable=False) description: Mapped[str] = mapped_column(Text, nullable=False, default="") price: Mapped[Decimal] = mapped_column(Numeric(12, 2), nullable=False) is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, server_default=text("true")) image_key: Mapped[str | None] = mapped_column(String(255)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) class CartItem(Base): __tablename__ = "cart_items" __table_args__ = ( UniqueConstraint("owner_key", "product_id", name="uq_cart_owner_product"), CheckConstraint("qty > 0 AND qty <= 99", name="cart_qty_range"), Index("ix_cart_owner", "owner_key"), ) id: Mapped[int] = mapped_column(BigInteger, Identity(always=True), primary_key=True) owner_key: Mapped[str] = mapped_column(String(96), nullable=False) product_id: Mapped[int] = mapped_column(ForeignKey("products.id"), nullable=False) qty: Mapped[int] = mapped_column(nullable=False) class Order(Base): __tablename__ = "orders" __table_args__ = (Index("ix_orders_owner", "owner_key"),) id: Mapped[int] = mapped_column(BigInteger, Identity(always=True), primary_key=True) owner_key: Mapped[str] = mapped_column(String(96), nullable=False) customer_name: Mapped[str] = mapped_column(String(120), nullable=False) customer_phone: Mapped[str] = mapped_column(String(32), nullable=False) status: Mapped[str] = mapped_column(String(20), nullable=False, default="created", server_default="created") total: Mapped[Decimal] = mapped_column(Numeric(12, 2), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) class OrderItem(Base): __tablename__ = "order_items" id: Mapped[int] = mapped_column(BigInteger, Identity(always=True), primary_key=True) order_id: Mapped[int] = mapped_column(ForeignKey("orders.id", ondelete="CASCADE"), nullable=False) product_id: Mapped[int] = mapped_column(ForeignKey("products.id"), nullable=False) title: Mapped[str] = mapped_column(String(255), nullable=False) price: Mapped[Decimal] = mapped_column(Numeric(12, 2), nullable=False) qty: Mapped[int] = mapped_column(nullable=False) class BotDialog(Base): __tablename__ = "bot_dialogs" telegram_user_id: Mapped[int] = mapped_column(BigInteger, primary_key=True) step: Mapped[str] = mapped_column(String(16), nullable=False) name: Mapped[str | None] = mapped_column(String(120)) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) class TelegramUpdate(Base): __tablename__ = "telegram_updates" update_id: Mapped[int] = mapped_column(BigInteger, primary_key=True) processed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())