from typing import List from sqlalchemy.orm.query import Query as SAQuery from sqlalchemy import asc, desc, nullslast, and_ from sqlalchemy.sql import func from db import db from models import Project, Campaign from models.campaign_ad import CampaignAd from campaign_ads.schemas import CampaignAdsQueryParams class CampaignAdsRepository: __sort_map = { "id": (CampaignAd.id,), "name": (CampaignAd.name, CampaignAd.id), "spend": (CampaignAd.budget_spend, CampaignAd.id), "startDate": (CampaignAd.start_date, CampaignAd.id), "endDate": (func.coalesce(CampaignAd.end_date, Project.end_date), CampaignAd.id), "remainingDays": ((CampaignAd.end_date - CampaignAd.start_date), CampaignAd.id), } def __filtered_campaign_ads_query(self, query: SAQuery, campaign_uuid: str, params: CampaignAdsQueryParams): query = query.filter(and_(Campaign.uuid == campaign_uuid, CampaignAd.campaign_id == Campaign.id)) filter_items = [] if params.freeText: found_ids = CampaignAd.search(expression=params.freeText) filter_items.append(CampaignAd.id.in_(found_ids)) for f in filter_items: query = query.filter(f) return query def get_filtered_campaign_ads_count(self, campaign_uuid: str, params: CampaignAdsQueryParams) -> int: count_query = db.session.query(func.count(CampaignAd.id)) query = self.__filtered_campaign_ads_query(count_query, campaign_uuid, params) return query.scalar() def get_filtered_campaign_ads(self, campaign_uuid: str, params: CampaignAdsQueryParams) -> List[CampaignAd]: campaign_ads_query = db.session.query(CampaignAd).join(Campaign).outerjoin(Project) query = self.__filtered_campaign_ads_query(campaign_ads_query, campaign_uuid, params) sort_dir = asc sort = params.sort if sort.startswith("-"): sort = sort[1:] sort_dir = desc order_expression = map(lambda x: nullslast(sort_dir(x)), self.__sort_map[sort]) return query.order_by(*order_expression).limit(params.limit).offset(params.offset).all()