From 28cf47223025e1813c5cf67ce4b89b49c93adfad Mon Sep 17 00:00:00 2001 From: Sebastian Allard Date: Mon, 22 Jul 2024 10:35:00 +0200 Subject: [PATCH] Remove sequencing QC calculations in /orders endpoint (#3403) --- .../order_summary_service.py | 10 ++++----- .../orders/order_summary_service/utils.py | 15 ------------- cg/store/crud/read.py | 17 ++++++++++++++ .../filters/status_case_sample_filters.py | 22 +++++++++++++++++++ 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/cg/services/orders/order_summary_service/order_summary_service.py b/cg/services/orders/order_summary_service/order_summary_service.py index 1caef77ac7..5af8394e6d 100644 --- a/cg/services/orders/order_summary_service/order_summary_service.py +++ b/cg/services/orders/order_summary_service/order_summary_service.py @@ -1,10 +1,7 @@ from cg.apps.tb.api import TrailblazerAPI from cg.apps.tb.dto.summary_response import AnalysisSummary from cg.services.orders.order_summary_service.dto.order_summary import OrderSummary -from cg.services.orders.order_summary_service.utils import ( - _get_analysis_map, - get_cases_failed_sequencing_qc_count, -) +from cg.services.orders.order_summary_service.utils import _get_analysis_map from cg.store.models import Order from cg.store.store import Store @@ -47,9 +44,10 @@ def create_order_summary(self, order: Order, summary: AnalysisSummary) -> OrderS in_sequencing: int = self.store.get_case_in_sequencing_count( order_id=order_id, cases_to_exclude=counted_cases ) - failed_sequencing_qc: int = get_cases_failed_sequencing_qc_count( - order=order, cases_to_exclude=counted_cases + failed_sequencing_qc: int = self.store.get_case_failed_sequencing_count( + order_id=order_id, cases_to_exclude=counted_cases ) + return OrderSummary( order_id=order_id, total=len(order.cases), diff --git a/cg/services/orders/order_summary_service/utils.py b/cg/services/orders/order_summary_service/utils.py index 8e138dd72f..55b0bc3f53 100644 --- a/cg/services/orders/order_summary_service/utils.py +++ b/cg/services/orders/order_summary_service/utils.py @@ -1,20 +1,5 @@ from cg.apps.tb.dto.summary_response import AnalysisSummary -from cg.services.sequencing_qc_service import SequencingQCService -from cg.store.models import Case, Order def _get_analysis_map(analysis_summaries: list[AnalysisSummary]) -> dict: return {summary.order_id: summary for summary in analysis_summaries} - - -def _is_case_failed_sequencing_qc(case: Case) -> bool: - return case.are_all_samples_sequenced and not SequencingQCService.case_pass_sequencing_qc(case) - - -def get_cases_failed_sequencing_qc_count(order: Order, cases_to_exclude: list[str]) -> int: - cases: list[Case] = order.cases - return sum( - 1 - for case in cases - if _is_case_failed_sequencing_qc(case) and case.internal_id not in cases_to_exclude - ) diff --git a/cg/store/crud/read.py b/cg/store/crud/read.py index c7605b5a11..e6d3bd6b8d 100644 --- a/cg/store/crud/read.py +++ b/cg/store/crud/read.py @@ -1422,6 +1422,23 @@ def get_case_in_sequencing_count(self, order_id: int, cases_to_exclude: list[str cases_to_exclude=cases_to_exclude, ).count() + def get_case_failed_sequencing_count(self, order_id: int, cases_to_exclude: list[str]) -> int: + filters: list[CaseSampleFilter] = [ + CaseSampleFilter.BY_ORDER, + CaseSampleFilter.CASES_WITH_ALL_SAMPLES_RECEIVED, + CaseSampleFilter.CASES_WITH_ALL_SAMPLES_PREPARED, + CaseSampleFilter.CASES_WITH_ALL_SAMPLES_SEQUENCED, + CaseSampleFilter.CASES_FAILED_SEQUENCING_QC, + CaseSampleFilter.EXCLUDE_CASES, + ] + case_samples: Query = self._join_sample_and_case() + return apply_case_sample_filter( + case_samples=case_samples, + filter_functions=filters, + order_id=order_id, + cases_to_exclude=cases_to_exclude, + ).count() + def get_illumina_flow_cell_by_internal_id(self, internal_id: str) -> IlluminaFlowCell: """Return a flow cell by internal id.""" return apply_illumina_flow_cell_filters( diff --git a/cg/store/filters/status_case_sample_filters.py b/cg/store/filters/status_case_sample_filters.py index b5557c8491..508b98435d 100644 --- a/cg/store/filters/status_case_sample_filters.py +++ b/cg/store/filters/status_case_sample_filters.py @@ -3,6 +3,7 @@ from sqlalchemy.orm import Query +from cg.constants.constants import SequencingQCStatus from cg.store.models import Case, CaseSample, Order, Sample @@ -56,6 +57,25 @@ def get_not_sequenced_cases(case_samples: Query, **kwargs) -> Query: return case_samples.filter(Sample.last_sequenced_at == None).distinct() +def get_sequenced_cases(case_samples: Query, **kwargs) -> Query: + not_sequenced = ( + case_samples.filter(Sample.last_sequenced_at == None) + .with_entities(CaseSample.case_id) + .subquery() + ) + return ( + case_samples.outerjoin(not_sequenced, CaseSample.case_id == not_sequenced.c.case_id) + .filter(not_sequenced.c.case_id == None) + .distinct() + ) + + +def get_cases_failed_sequencing_qc(case_samples: Query, **kwargs) -> Query: + return case_samples.filter( + Case.aggregated_sequencing_qc == SequencingQCStatus.FAILED + ).distinct() + + def exclude_cases(case_samples: Query, cases_to_exclude: list[str], **kwargs) -> Query: return case_samples.filter(Case.internal_id.notin_(cases_to_exclude)) @@ -93,5 +113,7 @@ class CaseSampleFilter(Enum): CASES_WITH_SAMPLES_NOT_PREPARED: Callable = get_not_prepared_cases CASES_WITH_ALL_SAMPLES_PREPARED: Callable = get_prepared_cases CASES_WITH_SAMPLES_NOT_SEQUENCED: Callable = get_not_sequenced_cases + CASES_WITH_ALL_SAMPLES_SEQUENCED: Callable = get_sequenced_cases + CASES_FAILED_SEQUENCING_QC: Callable = get_cases_failed_sequencing_qc EXCLUDE_CASES: Callable = exclude_cases BY_ORDER: Callable = filter_by_order