from datetime import datetime from decimal import Decimal from typing import Any from uuid import UUID from sqlalchemy import ( CheckConstraint, DateTime, ForeignKey, ForeignKeyConstraint, Numeric, String, Text, UniqueConstraint, ) from sqlalchemy.dialects.postgresql import JSONB, UUID as PGUUID from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship class Base(DeclarativeBase): pass class AttributeDefinitionRecord(Base): __tablename__ = "attribute_definitions" __table_args__ = ( CheckConstraint( "value_type IN ('number', 'string', 'boolean', 'string_list')", name="ck_attribute_definitions_value_type", ), ) key: Mapped[str] = mapped_column(String(128), primary_key=True) value_type: Mapped[str] = mapped_column(String(32), nullable=False) canonical_unit: Mapped[str | None] = mapped_column(String(32)) minimum: Mapped[Decimal | None] = mapped_column(Numeric(12, 4)) maximum: Mapped[Decimal | None] = mapped_column(Numeric(12, 4)) description: Mapped[str | None] = mapped_column(Text) class SourceRecord(Base): __tablename__ = "sources" id: Mapped[str] = mapped_column(String(64), primary_key=True) name: Mapped[str] = mapped_column(String(128), nullable=False) adapter_type: Mapped[str] = mapped_column(String(64), nullable=False) class ScoringModelRecord(Base): __tablename__ = "scoring_models" version: Mapped[str] = mapped_column(String(64), primary_key=True) algorithm_id: Mapped[str] = mapped_column(String(128), nullable=False) definition: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) definition_hash: Mapped[str] = mapped_column(String(64), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) class ProductProfileRecord(Base): __tablename__ = "product_profiles" __table_args__ = ( CheckConstraint("version > 0", name="ck_product_profiles_version"), ) id: Mapped[str] = mapped_column(String(128), primary_key=True) version: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(256), nullable=False) category: Mapped[str] = mapped_column(String(128), nullable=False) scoring_version: Mapped[str] = mapped_column(ForeignKey("scoring_models.version"), nullable=False) definition: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) definition_hash: Mapped[str] = mapped_column(String(64), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) class ProductRecord(Base): __tablename__ = "products" id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) category: Mapped[str] = mapped_column(String(128), nullable=False) brand: Mapped[str] = mapped_column(String(128), nullable=False) name: Mapped[str] = mapped_column(String(256), nullable=False) model: Mapped[str | None] = mapped_column(String(128)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) variants: Mapped[list["ProductVariantRecord"]] = relationship(back_populates="product") class ProductVariantRecord(Base): __tablename__ = "product_variants" id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) product_id: Mapped[UUID] = mapped_column(ForeignKey("products.id"), nullable=False, index=True) name: Mapped[str] = mapped_column(String(256), nullable=False) manufacturer_sku: Mapped[str | None] = mapped_column(String(128)) identifiers: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False, default=dict) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) product: Mapped[ProductRecord] = relationship(back_populates="variants") class VariantAttributeRecord(Base): __tablename__ = "variant_attributes" __table_args__ = ( CheckConstraint("confidence >= 0 AND confidence <= 1", name="ck_variant_attributes_confidence"), CheckConstraint( "normalization_status IN ('normalized', 'unknown')", name="ck_variant_attributes_status", ), ) id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) variant_id: Mapped[UUID] = mapped_column(ForeignKey("product_variants.id"), nullable=False) attribute_key: Mapped[str] = mapped_column(ForeignKey("attribute_definitions.key"), nullable=False) source_id: Mapped[str] = mapped_column(ForeignKey("sources.id"), nullable=False) raw_value: Mapped[Any] = mapped_column(JSONB, nullable=False) normalized_value: Mapped[Any] = mapped_column(JSONB) unit: Mapped[str | None] = mapped_column(String(32)) normalization_status: Mapped[str] = mapped_column(String(32), nullable=False) normalizer_version: Mapped[str] = mapped_column(String(64), nullable=False) confidence: Mapped[Decimal] = mapped_column(Numeric(4, 3), nullable=False) source_reference: Mapped[str] = mapped_column(String(256), nullable=False) observed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) ingested_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) normalization_error: Mapped[str | None] = mapped_column(Text) class OfferRecord(Base): __tablename__ = "offers" __table_args__ = ( UniqueConstraint("source_id", "external_id", name="uq_offers_source_external"), CheckConstraint("currency ~ '^[A-Z]{3}$'", name="ck_offers_currency"), CheckConstraint("condition IN ('new', 'refurbished', 'used')", name="ck_offers_condition"), ) id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) variant_id: Mapped[UUID] = mapped_column(ForeignKey("product_variants.id"), nullable=False, index=True) source_id: Mapped[str] = mapped_column(ForeignKey("sources.id"), nullable=False) external_id: Mapped[str] = mapped_column(String(256), nullable=False) seller: Mapped[str] = mapped_column(String(256), nullable=False) url: Mapped[str | None] = mapped_column(Text) market: Mapped[str] = mapped_column(String(16), nullable=False) currency: Mapped[str] = mapped_column(String(3), nullable=False) condition: Mapped[str] = mapped_column(String(32), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) class PriceObservationRecord(Base): __tablename__ = "price_observations" __table_args__ = ( UniqueConstraint("offer_id", "external_observation_id", name="uq_price_obs_offer_external"), CheckConstraint("item_price > 0", name="ck_price_obs_item_price"), CheckConstraint("shipping_price IS NULL OR shipping_price >= 0", name="ck_price_obs_shipping"), CheckConstraint("confidence >= 0 AND confidence <= 1", name="ck_price_obs_confidence"), CheckConstraint( "availability IN ('in_stock', 'out_of_stock', 'unknown')", name="ck_price_obs_availability", ), CheckConstraint("currency ~ '^[A-Z]{3}$'", name="ck_price_obs_currency"), ) id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) offer_id: Mapped[UUID] = mapped_column(ForeignKey("offers.id"), nullable=False) source_id: Mapped[str] = mapped_column(ForeignKey("sources.id"), nullable=False) external_observation_id: Mapped[str] = mapped_column(String(256), nullable=False) observed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) ingested_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) item_price: Mapped[Decimal] = mapped_column(Numeric(12, 2), nullable=False) shipping_price: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) currency: Mapped[str] = mapped_column(String(3), nullable=False) availability: Mapped[str] = mapped_column(String(32), nullable=False) raw_payload: Mapped[Any] = mapped_column(JSONB, nullable=False) confidence: Mapped[Decimal] = mapped_column(Numeric(4, 3), nullable=False) class EvaluationRecord(Base): __tablename__ = "evaluations" __table_args__ = ( ForeignKeyConstraint( ["profile_id", "profile_version"], ["product_profiles.id", "product_profiles.version"], name="fk_evaluations_profile", ), CheckConstraint( "product_eligibility IN ('ELIGIBLE', 'INELIGIBLE', 'UNKNOWN')", name="ck_eval_product_eligibility", ), CheckConstraint( "offer_eligibility IN ('ELIGIBLE', 'INELIGIBLE', 'UNKNOWN')", name="ck_eval_offer_eligibility", ), CheckConstraint( "overall_eligibility IN ('ELIGIBLE', 'INELIGIBLE', 'UNKNOWN')", name="ck_eval_overall_eligibility", ), CheckConstraint( "product_score IS NULL OR (product_score >= 0 AND product_score <= 100)", name="ck_eval_product_score", ), CheckConstraint( "price_score IS NULL OR (price_score >= 0 AND price_score <= 100)", name="ck_eval_price_score", ), CheckConstraint( "deal_score IS NULL OR (deal_score >= 0 AND deal_score <= 100)", name="ck_eval_deal_score", ), ) id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) variant_id: Mapped[UUID] = mapped_column(ForeignKey("product_variants.id"), nullable=False, index=True) offer_id: Mapped[UUID] = mapped_column(ForeignKey("offers.id"), nullable=False) profile_id: Mapped[str] = mapped_column(String(128), nullable=False) profile_version: Mapped[int] = mapped_column(nullable=False) scoring_version: Mapped[str] = mapped_column(ForeignKey("scoring_models.version"), nullable=False) as_of: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) snapshot_cutoff: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) scoring_hash: Mapped[str] = mapped_column(String(64), nullable=False) engine_build: Mapped[str] = mapped_column(String(64), nullable=False) product_eligibility: Mapped[str] = mapped_column(String(16), nullable=False) offer_eligibility: Mapped[str] = mapped_column(String(16), nullable=False) overall_eligibility: Mapped[str] = mapped_column(String(16), nullable=False) product_score: Mapped[Decimal | None] = mapped_column(Numeric(6, 2)) price_score: Mapped[Decimal | None] = mapped_column(Numeric(6, 2)) deal_score: Mapped[Decimal | None] = mapped_column(Numeric(6, 2)) classification: Mapped[str] = mapped_column(String(32), nullable=False) price_reference_scope: Mapped[str] = mapped_column(String(32), nullable=False) input_snapshot: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) result_snapshot: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) components: Mapped[list["EvaluationComponentRecord"]] = relationship(back_populates="evaluation") class EvaluationComponentRecord(Base): __tablename__ = "evaluation_components" __table_args__ = ( UniqueConstraint("evaluation_id", "kind", "component_key", name="uq_eval_component"), ) id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) evaluation_id: Mapped[UUID] = mapped_column(ForeignKey("evaluations.id"), nullable=False) kind: Mapped[str] = mapped_column(String(64), nullable=False) component_key: Mapped[str] = mapped_column(String(128), nullable=False) raw_score: Mapped[Decimal | None] = mapped_column(Numeric(12, 6)) weight: Mapped[Decimal | None] = mapped_column(Numeric(12, 6)) contribution: Mapped[Decimal | None] = mapped_column(Numeric(12, 6)) details: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) evaluation: Mapped[EvaluationRecord] = relationship(back_populates="components")