from typing import Any, Dict from db_schema.common import ActivityStatusEnum from db_schema.schemas.apps import CompletenessStatusEnum as AppsCompletenessStatusEnum from db_schema.schemas.apps import UnitOfWork as AppsUnitOfWork from db_schema.schemas.apps import UnitOfWorkTypeEnum as AppsUnitOfWorkTypeEnum from sqlalchemy import and_, case, extract from sqlalchemy.orm import Query, Session from sqlalchemy.sql.functions import count, func from delphi_slz_admin.modelviews import BaseModelView class BackfillProgressBaseModelView(BaseModelView): group_by_statement: Dict[str, Any] = {} column_default_sort = None # type: ignore column_labels = { 'completed_pct': 'Completed %', } # pylint: disable=no-self-use def _format_completed_pct(self, _: Any, model: Any, __: Any) -> str: return str(model.completed * 100.0 / model.total_backfill_uows) column_formatters = {'completed_pct': _format_completed_pct} @staticmethod def _build_filter_clause() -> bool: return AppsUnitOfWork.unit_of_work_type == AppsUnitOfWorkTypeEnum.BACKFILL @staticmethod def _build_sum_case( label: str, completeness_status: AppsCompletenessStatusEnum, activity_status: ActivityStatusEnum ) -> str: return func.sum( case([( and_( AppsUnitOfWork.completeness_status == completeness_status, AppsUnitOfWork.activity_status == activity_status, ), 1, )], else_=0) ).label(label) def get_query(self) -> Query: query_args = list(self.group_by_statement.values()) + [ count(1).label('total_backfill_uows'), self._build_sum_case( 'in_progress', AppsCompletenessStatusEnum.QUEUED, ActivityStatusEnum.IN_PROGRESS ), self._build_sum_case( 'queued', AppsCompletenessStatusEnum.QUEUED, ActivityStatusEnum.NOT_IN_PROGRESS ), self._build_sum_case( 'completed', AppsCompletenessStatusEnum.COMPLETE, ActivityStatusEnum.NOT_IN_PROGRESS ), self._build_sum_case( 'failed', AppsCompletenessStatusEnum.FAILED, ActivityStatusEnum.NOT_IN_PROGRESS ), ] return self.session.query(*query_args).filter( self._build_filter_clause() ).group_by(*self.group_by_statement.keys()).order_by(*self.group_by_statement.keys()) def get_count_query(self) -> Query: subquery = self.session.query(*self.group_by_statement.values()).filter( self._build_filter_clause() ).group_by(*self.group_by_statement.keys()) return self.session.query(func.count('*')).select_from(subquery.selectable) # pylint: disable=too-many-ancestors class BackfillProgressYearDspModelView(BackfillProgressBaseModelView): column_list = [ 'year', 'dsp', 'total_backfill_uows', 'in_progress', 'queued', 'completed', 'failed', 'completed_pct' ] group_by_statement = { 'year': extract('YEAR', AppsUnitOfWork.report_date).label('year'), 'dsp': func.split_part(AppsUnitOfWork.unit_of_work_code, '-', 1).label('dsp'), } def __init__(self, session: Session, **kwargs: Any) -> None: self.model = AppsUnitOfWork self.name = 'Backfill (Year / DSP)' self.endpoint = 'backfill_year_dsp' super().__init__(self.model, session, name=self.name, endpoint=self.endpoint, **kwargs) # pylint: disable=too-many-ancestors class BackfillProgressYearDspReportModelView(BackfillProgressBaseModelView): column_list = [ 'year', 'dsp', 'report_', 'total_backfill_uows', 'in_progress', 'queued', 'completed', 'failed', 'completed_pct' ] group_by_statement = { 'year': extract('YEAR', AppsUnitOfWork.report_date).label('year'), 'dsp': func.split_part(AppsUnitOfWork.unit_of_work_code, '-', 1).label('dsp'), 'report_': func.split_part(AppsUnitOfWork.unit_of_work_code, '-', 3).label('report_'), } def __init__(self, session: Session, **kwargs: Any) -> None: self.model = AppsUnitOfWork self.name = 'Backfill (Year / DSP / Report)' self.endpoint = 'backfill_year_dsp_report' super().__init__(self.model, session, name=self.name, endpoint=self.endpoint, **kwargs)