from typing import cast from anydi import singleton from pydantic import TypeAdapter from dmp.adapters.db import ReportingDB from dmp.rosters.dtos import ( FanDataListCriteria, FanDataListDetail, FanDataListItem, SearchFanDataListCriteria, ) from dmp.rosters.types import FanDataListCIFields, FanDataListOrderBy FanDataListDetailList = TypeAdapter(list[FanDataListDetail]) FanDataListItemList = TypeAdapter(list[FanDataListItem]) @singleton class FanDataListRepository: def __init__(self, db: ReportingDB) -> None: self.db = db def count_by_criteria(self, criteria: FanDataListCriteria) -> int: if criteria.countries: template_name = "fandata-list/get-fandata-list-count-by-country.sql" else: template_name = "fandata-list/get-fandata-list-count.sql" query = self.db.query_from_template( template_name, context={ "criteria": criteria, }, ) result = self.db.session.execute(query) return cast(int, result.scalar_one()) def find_by_criteria( self, criteria: FanDataListCriteria, *, order_by: list[FanDataListOrderBy] | None = None, limit: int | None = None, offset: int | None = None, ) -> list[FanDataListDetail]: if criteria.countries: template_name = "fandata-list/get-fandata-list-by-country.sql" else: template_name = "fandata-list/get-fandata-list.sql" query = self.db.query_from_template( template_name, context={ "criteria": criteria, "order_by": self._build_order_by(order_by), "ci_fields": FanDataListCIFields, "limit": limit, "offset": offset, }, ) result = self.db.session.execute(query) return FanDataListDetailList.validate_python(result.mappings()) @staticmethod def _build_order_by( order_by: list[FanDataListOrderBy] | None, ) -> list[FanDataListOrderBy]: result: list[FanDataListOrderBy] = [] for o in order_by or []: field, _ = o.split(".", maxsplit=2) if field in ( "tiktokFollowers", "instagramFollowers", "spotifyMonthlyListeners", "spotifyFollowers", "facebookFollowers", "youtubeFollowers", "twitterFollowers", "soundcloudFollowers", "deezerFollowers", ): continue result.append(o) if not result: result = ["name.asc"] elif not any(o.startswith("name.") for o in result): name_order: FanDataListOrderBy = "name.asc" result = [*result, name_order] return result def search_by_criteria( self, criteria: SearchFanDataListCriteria, *, limit: int | None = None, ) -> list[FanDataListItem]: query = self.db.query_from_template( "fandata-list/search-fandata-list.sql", context={ "criteria": criteria, "limit": limit, }, ) result = self.db.session.execute(query) return FanDataListItemList.validate_python(result.mappings())