diff --git a/apps/qbank/filters.py b/apps/qbank/filters.py index 6dcfb51..d975b9d 100644 --- a/apps/qbank/filters.py +++ b/apps/qbank/filters.py @@ -2,6 +2,27 @@ import strawberry_django from .models import QuestionBank, QBQuestion +from .enums import ( + QberPriorityLevelTypeEnum, + QberEnumeratorSkillTypeEnum, + QberDataCollectionMethodTypeEnum, +) + + +class QberMetaQuestionFilterMixin: + # QberMeta + priority_levels: list[QberPriorityLevelTypeEnum] + enumerator_skills: list[QberEnumeratorSkillTypeEnum] + data_collection_methods: list[QberDataCollectionMethodTypeEnum] + + def filter(self, queryset): + if self.priority_levels: + queryset = queryset.filter(priority_level__in=self.priority_levels) + if self.enumerator_skills: + queryset = queryset.filter(enumerator_skill__in=self.enumerator_skills) + if self.data_collection_methods: + queryset = queryset.filter(data_collection_method__in=self.data_collection_methods) + return queryset @strawberry_django.filters.filter(QuestionBank, lookups=True) @@ -11,7 +32,7 @@ class QuestionBankFilter: @strawberry_django.filters.filter(QBQuestion, lookups=True) -class QBQuestionFilter: +class QBQuestionFilter(QberMetaQuestionFilterMixin): id: strawberry.auto qbank: strawberry.auto leaf_group: strawberry.auto diff --git a/apps/questionnaire/dataloaders.py b/apps/questionnaire/dataloaders.py index 8c3bc90..4cf348b 100644 --- a/apps/questionnaire/dataloaders.py +++ b/apps/questionnaire/dataloaders.py @@ -76,6 +76,27 @@ def load_choices(keys: list[int]) -> list[list[Choice]]: return [_map.get(key, []) for key in keys] +def total_required_duration_by_questionnaire(keys: list[int]) -> list[float]: + qs = ( + Question.objects + .filter(questionnaire__in=keys) + .order_by().values('questionnaire') + .annotate( + total_required_duration=models.Sum( + 'required_duration', + filter=models.Q(is_hidden=False) & models.Q(leaf_group__is_hidden=False) + ) + ) + ) + _map = { + questionnaire_id: (total_required_duration or 0) + for questionnaire_id, total_required_duration in ( + qs.values_list('questionnaire', 'total_required_duration') + ) + } + return [_map.get(key, 0) for key in keys] + + class QuestionnaireDataLoader(): @cached_property def total_questions_by_questionnaire(self) -> list[QuestionCount]: @@ -92,3 +113,7 @@ def load_qbank(self) -> list[QuestionBank]: @cached_property def load_choices(self) -> list[list[Choice]]: return DataLoader(load_fn=sync_to_async(load_choices)) + + @cached_property + def total_required_duration_by_questionnaire(self) -> list[float]: + return DataLoader(load_fn=sync_to_async(total_required_duration_by_questionnaire)) diff --git a/apps/questionnaire/filters.py b/apps/questionnaire/filters.py index 8a57de9..9312669 100644 --- a/apps/questionnaire/filters.py +++ b/apps/questionnaire/filters.py @@ -1,6 +1,7 @@ import strawberry import strawberry_django +from apps.qbank.filters import QberMetaQuestionFilterMixin from .enums import ( QuestionTypeEnum, ) @@ -27,7 +28,7 @@ class QuestionChoiceCollectionFilter: @strawberry_django.filters.filter(Question, lookups=True) -class QuestionFilter: +class QuestionFilter(QberMetaQuestionFilterMixin): id: strawberry.auto questionnaire: strawberry.auto choice_collection: strawberry.auto diff --git a/apps/questionnaire/types.py b/apps/questionnaire/types.py index cbda21b..eca54a2 100644 --- a/apps/questionnaire/types.py +++ b/apps/questionnaire/types.py @@ -104,6 +104,10 @@ def get_queryset(_, queryset: models.QuerySet | None, info: Info): def project_id(self) -> strawberry.ID: return strawberry.ID(str(self.project_id)) + @strawberry.field + def total_required_duration(self, info: Info) -> float: + return info.context.dl.questionnaire.total_required_duration_by_questionnaire.load(self.pk) + @strawberry_django.field async def leaf_groups(self, info: Info) -> list[QuestionLeafGroupType]: queryset = QuestionLeafGroupType.get_queryset(None, None, info).filter(questionnaire=self.pk) diff --git a/schema.graphql b/schema.graphql index 4ebd8b4..14ae24b 100644 --- a/schema.graphql +++ b/schema.graphql @@ -464,6 +464,9 @@ type QBLeafGroupType { } input QBQuestionFilter { + priorityLevels: [QberMetaDataPriorityLevelTypeEnum!] + enumeratorSkills: [QberEnumeratorSkillTypeEnum!] + dataCollectionMethods: [QberDataCollectionMethodTypeEnum!] id: IDFilterLookup qbank: DjangoModelFilterInput leafGroup: DjangoModelFilterInput @@ -698,6 +701,9 @@ input QuestionCreateInput { } input QuestionFilter { + priorityLevels: [QberMetaDataPriorityLevelTypeEnum!] + enumeratorSkills: [QberEnumeratorSkillTypeEnum!] + dataCollectionMethods: [QberDataCollectionMethodTypeEnum!] id: IDFilterLookup questionnaire: DjangoModelFilterInput choiceCollection: DjangoModelFilterInput @@ -1073,6 +1079,7 @@ type QuestionnaireType { qbank: QuestionBankType! totalQbankQuestions: Int! totalQuestions: QuestionCount! + totalRequiredDuration: Float! } type QuestionnaireTypeCountList {