from __future__ import annotations from datetime import datetime from typing import Any from sqlalchemy import CheckConstraint, DateTime, Index, Integer, JSON, String, Text from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import Mapped, mapped_column from app.models.base import Base, TimestampMixin JsonType = JSON().with_variant(JSONB, "postgresql") class ModelPricingRule(Base, TimestampMixin): __tablename__ = "model_pricing_rules" __table_args__ = ( Index( "uq_model_pricing_rules_provider_model_version", "provider", "model_name", "version_code", unique=True, ), Index( "ix_model_pricing_rules_resolve", "provider", "model_name", "publish_status", "effective_from", "effective_to", ), Index("ix_model_pricing_rules_category_status", "model_category", "publish_status"), CheckConstraint( "effective_to IS NULL OR effective_to >= effective_from", name="ck_model_pricing_rules_effective_range", ), ) id: Mapped[str] = mapped_column(String(32), primary_key=True) provider: Mapped[str] = mapped_column(String(32), nullable=False, index=True) model_name: Mapped[str] = mapped_column(String(128), nullable=False, index=True) model_category: Mapped[str] = mapped_column(String(16), nullable=False, index=True) billing_mode: Mapped[str] = mapped_column(String(48), nullable=False, index=True) calculator_version: Mapped[str] = mapped_column(String(64), nullable=False, index=True) version_code: Mapped[str] = mapped_column(String(64), nullable=False) effective_from: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, index=True) effective_to: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True) publish_status: Mapped[str] = mapped_column(String(16), nullable=False, default="draft", index=True) currency: Mapped[str] = mapped_column(String(8), nullable=False, default="CNY") rule_schema_version: Mapped[int] = mapped_column(Integer, nullable=False, default=1) # 规则 JSON 统一使用“构建新 dict 后整体赋值”,禁止嵌套原地修改。 rule_json: Mapped[dict[str, Any]] = mapped_column(JsonType, nullable=False, default=dict) rule_content_hash: Mapped[str] = mapped_column(String(64), nullable=False, index=True) source_url: Mapped[str | None] = mapped_column(Text, nullable=True) source_updated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) remark: Mapped[str | None] = mapped_column(Text, nullable=True) created_by: Mapped[str | None] = mapped_column(String(32), nullable=True) updated_by: Mapped[str | None] = mapped_column(String(32), nullable=True)