from __future__ import annotations from collections.abc import Mapping from datetime import datetime from typing import Any from fansifter_common.adapters.db.types import ChoiceType, SafeJSONType from fansifter_common.auth.account import Account from fansifter_common.utils import timezone from fansifter_common.utils.uuid import uuid_string from sqlalchemy.orm import Mapped, foreign, mapped_column, relationship from dmp.adapters.db import ReportingModel from dmp.app_connections.enums import AppConnectionStatus from dmp.config import settings class ShopifyShop(ReportingModel, kw_only=True): __tablename__ = "shopify_shop" __table_args__ = {"schema": settings.snowflake_shopify_schema} source_schema: Mapped[str] = mapped_column(primary_key=True) id: Mapped[int] name: Mapped[str | None] domain: Mapped[str | None] myshopify_domain: Mapped[str | None] products_count: Mapped[int] collections_count: Mapped[int] created_at: Mapped[datetime] = mapped_column(default_factory=timezone.now) class ShopifyStoreAssociation(ReportingModel, kw_only=True): __tablename__ = "shopify_store_association" id: Mapped[str] = mapped_column(primary_key=True, default_factory=uuid_string) shop_domain: Mapped[str] fivetran_connector_id: Mapped[str] fivetran_schema: Mapped[str] = mapped_column() status: Mapped[AppConnectionStatus] = mapped_column( ChoiceType(AppConnectionStatus), default=AppConnectionStatus.PENDING, ) errors: Mapped[list[Mapping[str, Any]] | None] = mapped_column( SafeJSONType, default=None ) vendor_id: Mapped[int] subaccount_id: Mapped[int] global_participant_id: Mapped[str | None] initial_email_sent: Mapped[bool] = mapped_column(default=False) synced_at: Mapped[datetime | None] = mapped_column(default=None) created_at: Mapped[datetime] = mapped_column(default_factory=timezone.now) created_by: Mapped[str] updated_at: Mapped[datetime] = mapped_column( default_factory=timezone.now, onupdate=timezone.now, ) # relationship shop: Mapped[ShopifyShop | None] = relationship( primaryjoin=fivetran_schema == foreign(ShopifyShop.source_schema), # ty: ignore[invalid-argument-type] viewonly=True, uselist=False, lazy="raise", default=None, ) @property def account(self) -> Account: return Account(vendor_id=self.vendor_id, subaccount_id=self.subaccount_id) @property def name(self) -> str | None: if not self.shop: return None return self.shop.name @property def custom_domain(self) -> str | None: if not self.shop or self.shop.domain == self.shop.myshopify_domain: return None return self.shop.domain @property def collections_count(self) -> int | None: if not self.shop: return None return self.shop.collections_count @property def products_count(self) -> int | None: if not self.shop: return None return self.shop.products_count @property def is_single_artist_store(self) -> bool: return self.global_participant_id is not None @property def is_multi_artist_store(self) -> bool: return self.global_participant_id is None @property def is_processed(self) -> bool: return self.shop is not None class ShopifyCollectionArtist(ReportingModel, kw_only=True): __tablename__ = "shopify_collection_artist" association_id: Mapped[str] = mapped_column(primary_key=True) collection_id: Mapped[int] = mapped_column(primary_key=True) global_participant_id: Mapped[str] class ShopifyCollection(ReportingModel, kw_only=True): __tablename__ = "shopify_collection" __table_args__ = {"schema": settings.snowflake_shopify_schema} id: Mapped[int] = mapped_column(primary_key=True) source_schema: Mapped[str] title: Mapped[str] products_count: Mapped[int] class ShopifyCollectionProduct(ReportingModel, kw_only=True): __tablename__ = "shopify_collection_product" __table_args__ = {"schema": settings.snowflake_shopify_schema} source_schema: Mapped[str] = mapped_column(primary_key=True) collection_id: Mapped[int] = mapped_column(primary_key=True) product_id: Mapped[int] = mapped_column(primary_key=True)