diff --git a/cg/meta/upload/scout/uploadscoutapi.py b/cg/meta/upload/scout/uploadscoutapi.py index 57e6df049f..fd3c23d3b6 100644 --- a/cg/meta/upload/scout/uploadscoutapi.py +++ b/cg/meta/upload/scout/uploadscoutapi.py @@ -447,7 +447,7 @@ def create_rna_dna_collection(self, rna_sample: Sample) -> RNADNACollection: collaborators: set[Customer] = rna_sample.customer.collaborators subject_id_samples: list[Sample] = ( - self.status_db.get_samples_by_customer_id_list_and_subject_id_and_is_tumour( + self.status_db.get_samples_by_customer_ids_and_subject_id_and_is_tumour( customer_ids=[customer.id for customer in collaborators], subject_id=rna_sample.subject_id, is_tumour=rna_sample.is_tumour, diff --git a/cg/server/endpoints/samples.py b/cg/server/endpoints/samples.py index 819cd4bbaa..007a345782 100644 --- a/cg/server/endpoints/samples.py +++ b/cg/server/endpoints/samples.py @@ -1,13 +1,14 @@ from http import HTTPStatus + from flask import Blueprint, abort, g, jsonify, request -from cg.server.dto.samples.collaborator_samples_request import CollaboratorSamplesRequest -from cg.server.dto.samples.collaborator_samples_request import CollaboratorSamplesRequest +from cg.server.dto.samples.collaborator_samples_request import ( + CollaboratorSamplesRequest, +) from cg.server.dto.samples.samples_response import SamplesResponse from cg.server.endpoints.utils import before_request -from cg.server.ext import sample_service +from cg.server.ext import db, sample_service from cg.store.models import Customer, Sample -from cg.server.ext import db SAMPLES_BLUEPRINT = Blueprint("samples", __name__, url_prefix="/api/v1") SAMPLES_BLUEPRINT.before_request(before_request) @@ -57,7 +58,7 @@ def get_samples(): customers: list[Customer] | None = ( None if g.current_user.is_admin else g.current_user.customers ) - samples: list[Sample] = db.get_samples_by_customer_id_and_pattern( + samples: list[Sample] = db.get_samples_by_customers_and_pattern( pattern=request.args.get("enquiry"), customers=customers ) limit = int(request.args.get("limit", 50)) diff --git a/cg/store/crud/read.py b/cg/store/crud/read.py index 04cb7e9c27..d325729989 100644 --- a/cg/store/crud/read.py +++ b/cg/store/crud/read.py @@ -11,11 +11,19 @@ from cg.constants.constants import CaseActions, CustomerId, PrepCategory, SampleType from cg.exc import CaseNotFoundError, CgError, OrderNotFoundError, SampleNotFoundError from cg.server.dto.orders.orders_request import OrdersRequest -from cg.server.dto.samples.collaborator_samples_request import CollaboratorSamplesRequest +from cg.server.dto.samples.collaborator_samples_request import ( + CollaboratorSamplesRequest, +) from cg.store.base import BaseHandler from cg.store.exc import EntryNotFoundError -from cg.store.filters.status_analysis_filters import AnalysisFilter, apply_analysis_filter -from cg.store.filters.status_application_filters import ApplicationFilter, apply_application_filter +from cg.store.filters.status_analysis_filters import ( + AnalysisFilter, + apply_analysis_filter, +) +from cg.store.filters.status_application_filters import ( + ApplicationFilter, + apply_application_filter, +) from cg.store.filters.status_application_limitations_filters import ( ApplicationLimitationsFilter, apply_application_limitations_filter, @@ -25,14 +33,23 @@ apply_application_versions_filter, ) from cg.store.filters.status_bed_filters import BedFilter, apply_bed_filter -from cg.store.filters.status_bed_version_filters import BedVersionFilter, apply_bed_version_filter +from cg.store.filters.status_bed_version_filters import ( + BedVersionFilter, + apply_bed_version_filter, +) from cg.store.filters.status_case_filters import CaseFilter, apply_case_filter -from cg.store.filters.status_case_sample_filters import CaseSampleFilter, apply_case_sample_filter +from cg.store.filters.status_case_sample_filters import ( + CaseSampleFilter, + apply_case_sample_filter, +) from cg.store.filters.status_collaboration_filters import ( CollaborationFilter, apply_collaboration_filter, ) -from cg.store.filters.status_customer_filters import CustomerFilter, apply_customer_filter +from cg.store.filters.status_customer_filters import ( + CustomerFilter, + apply_customer_filter, +) from cg.store.filters.status_illumina_flow_cell_filters import ( IlluminaFlowCellFilter, apply_illumina_flow_cell_filters, @@ -47,10 +64,13 @@ ) from cg.store.filters.status_invoice_filters import InvoiceFilter, apply_invoice_filter from cg.store.filters.status_order_filters import OrderFilter, apply_order_filters -from cg.store.filters.status_organism_filters import OrganismFilter, apply_organism_filter +from cg.store.filters.status_organism_filters import ( + OrganismFilter, + apply_organism_filter, +) from cg.store.filters.status_pacbio_smrt_cell_filters import ( - apply_pac_bio_smrt_cell_filters, PacBioSMRTCellFilter, + apply_pac_bio_smrt_cell_filters, ) from cg.store.filters.status_panel_filters import PanelFilter, apply_panel_filter from cg.store.filters.status_pool_filters import PoolFilter, apply_pool_filter @@ -73,12 +93,12 @@ Invoice, Order, Organism, + PacBioSMRTCell, Panel, Pool, Sample, SampleRunMetrics, User, - PacBioSMRTCell, ) LOG = logging.getLogger(__name__) @@ -540,13 +560,12 @@ def new_invoice_id(self) -> int: ids = [inv.id for inv in query] return max(ids) + 1 if ids else 0 - def get_pools_by_customer_id(self, *, customers: list[Customer] | None = None) -> list[Pool]: - """Return all the pools for a customer.""" - customer_ids = [customer.id for customer in customers] + def get_pools_by_customers(self, *, customers: list[Customer] | None = None) -> list[Pool]: + """Return all the pools for a list of customers.""" return apply_pool_filter( pools=self._get_query(table=Pool), - customer_ids=customer_ids, - filter_functions=[PoolFilter.BY_CUSTOMER_ID], + customers=customers, + filter_functions=[PoolFilter.BY_CUSTOMERS], ).all() def get_pools_by_name_enquiry(self, *, name_enquiry: str = None) -> list[Pool]: @@ -580,7 +599,7 @@ def get_pools_to_render( self, customers: list[Customer] | None = None, enquiry: str = None ) -> list[Pool]: pools: list[Pool] = ( - self.get_pools_by_customer_id(customers=customers) if customers else self.get_pools() + self.get_pools_by_customers(customers=customers) if customers else self.get_pools() ) if enquiry: pools: list[Pool] = list( @@ -603,24 +622,22 @@ def get_ready_made_library_expected_reads(self, case_id: str) -> int: ) return application.expected_reads - def get_samples_by_customer_id_and_pattern( + def get_samples_by_customers_and_pattern( self, *, customers: list[Customer] | None = None, pattern: str = None ) -> list[Sample]: """Get samples by customer and sample internal id or sample name pattern.""" samples: Query = self._get_query(table=Sample) - customer_entry_ids: list[int] = [] filter_functions: list[SampleFilter] = [] if customers: if not isinstance(customers, list): customers = list(customers) - customer_entry_ids = [customer.id for customer in customers] - filter_functions.append(SampleFilter.BY_CUSTOMER_ENTRY_IDS) + filter_functions.append(SampleFilter.BY_CUSTOMERS) if pattern: filter_functions.extend([SampleFilter.BY_INTERNAL_ID_OR_NAME_SEARCH]) filter_functions.append(SampleFilter.ORDER_BY_CREATED_AT_DESC) return apply_sample_filter( samples=samples, - customer_entry_ids=customer_entry_ids, + customers=customers, search_pattern=pattern, filter_functions=filter_functions, ).all() @@ -667,7 +684,7 @@ def get_samples_by_customer_and_subject_id( customer_internal_id=customer_internal_id, subject_id=subject_id ).all() - def get_samples_by_customer_id_list_and_subject_id_and_is_tumour( + def get_samples_by_customer_ids_and_subject_id_and_is_tumour( self, customer_ids: list[int], subject_id: str, is_tumour: bool ) -> list[Sample]: """Return a list of samples matching a list of customers with given subject id and is a tumour or not.""" diff --git a/cg/store/filters/status_pool_filters.py b/cg/store/filters/status_pool_filters.py index b27464e510..8fc5d5b443 100644 --- a/cg/store/filters/status_pool_filters.py +++ b/cg/store/filters/status_pool_filters.py @@ -6,7 +6,7 @@ from cg.store.models import Customer, Pool -def filter_pools_by_customer_id(pools: Query, customer_ids: list[int], **kwargs) -> Query: +def filter_pools_by_customer_ids(pools: Query, customer_ids: list[int], **kwargs) -> Query: """Return pools by customer id.""" return pools.filter(Pool.customer_id.in_(customer_ids)) @@ -71,6 +71,12 @@ def filter_pools_by_customer(pools: Query, customer: Customer, **kwargs) -> Quer return pools.filter(Pool.customer == customer) +def filter_pools_by_customers(pools: Query, customers: list[Customer], **kwargs) -> Query: + """Return pools by customers.""" + customer_ids = [customer.id for customer in customers] + return pools.filter(Pool.customer_id.in_(customer_ids)) + + def apply_pool_filter( filter_functions: list[Callable], pools: Query, @@ -78,6 +84,7 @@ def apply_pool_filter( entry_id: int | None = None, name: str | None = None, customer_ids: list[int] | None = None, + customers: list[Customer] | None = None, name_enquiry: str | None = None, order_enquiry: str | None = None, customer: Customer | None = None, @@ -94,6 +101,7 @@ def apply_pool_filter( name_enquiry=name_enquiry, order_enquiry=order_enquiry, customer=customer, + customers=customers, ) return pools @@ -110,7 +118,8 @@ class PoolFilter(Enum): BY_INVOICE_ID: Callable = filter_pools_by_invoice_id WITHOUT_INVOICE_ID: Callable = filter_pools_without_invoice_id DO_INVOICE: Callable = filter_pools_do_invoice - BY_CUSTOMER_ID: Callable = filter_pools_by_customer_id + BY_CUSTOMER_IDS: Callable = filter_pools_by_customer_ids BY_NAME_ENQUIRY: Callable = filter_pools_by_name_enquiry BY_ORDER_ENQUIRY: Callable = filter_pools_by_order_enquiry BY_CUSTOMER: Callable = filter_pools_by_customer + BY_CUSTOMERS: Callable = filter_pools_by_customers diff --git a/cg/store/filters/status_sample_filters.py b/cg/store/filters/status_sample_filters.py index 64855bc9ac..1a182d6f43 100644 --- a/cg/store/filters/status_sample_filters.py +++ b/cg/store/filters/status_sample_filters.py @@ -147,6 +147,12 @@ def filter_samples_by_customer(samples: Query, customer: Customer, **kwargs) -> return samples.filter(Sample.customer == customer) +def filter_samples_by_customers(samples: Query, customers: list[Customer], **kwargs) -> Query: + """Return samples by customers.""" + customer_ids = [customer.id for customer in customers] + return samples.filter(Sample.customer_id.in_(customer_ids)) + + def order_samples_by_created_at_desc(samples: Query, **kwargs) -> Query: """Return samples ordered by created_at descending.""" return samples.order_by(Sample.created_at.desc()) @@ -179,6 +185,7 @@ def apply_sample_filter( subject_id: str | None = None, name: str | None = None, customer: Customer | None = None, + customers: list[Customer] | None = None, name_pattern: str | None = None, internal_id_pattern: str | None = None, search_pattern: str | None = None, @@ -200,6 +207,7 @@ def apply_sample_filter( subject_id=subject_id, name=name, customer=customer, + customers=customers, name_pattern=name_pattern, internal_id_pattern=internal_id_pattern, search_pattern=search_pattern, @@ -214,6 +222,7 @@ class SampleFilter(Enum): """Define Sample filter functions.""" BY_CUSTOMER: Callable = filter_samples_by_customer + BY_CUSTOMERS: Callable = filter_samples_by_customers BY_CUSTOMER_ENTRY_IDS: Callable = filter_samples_by_entry_customer_ids BY_ENTRY_ID: Callable = filter_samples_by_entry_id BY_IDENTIFIER_NAME_AND_VALUE: Callable = filter_samples_by_identifier_name_and_value diff --git a/tests/services/orders/test_validate_order_service/test_validate_pacbio_order_service.py b/tests/services/orders/test_validate_order_service/test_validate_pacbio_order_service.py index d4f3a9cd5d..872ccc2a64 100644 --- a/tests/services/orders/test_validate_order_service/test_validate_pacbio_order_service.py +++ b/tests/services/orders/test_validate_order_service/test_validate_pacbio_order_service.py @@ -51,7 +51,7 @@ def test_validate_pacbio_order_reused_sample_name( # GIVEN a PacBio order with a reused sample name status_db: Store = validate_pacbio_order_service.status_db customer = status_db.get_customer_by_internal_id(pacbio_order.customer) - old_sample_name: str = status_db.get_samples_by_customer_id_and_pattern(customers=[customer])[ + old_sample_name: str = status_db.get_samples_by_customers_and_pattern(customers=[customer])[ 0 ].name pacbio_order.samples[0].name = old_sample_name diff --git a/tests/store/crud/read/test_read.py b/tests/store/crud/read/test_read.py index f113366664..a7f7c651bd 100644 --- a/tests/store/crud/read/test_read.py +++ b/tests/store/crud/read/test_read.py @@ -950,7 +950,7 @@ def test_get_pools_by_customer_id(store_with_multiple_pools_for_customer: Store) # GIVEN a database with two pools # WHEN getting pools by customer id - pools: list[Pool] = store_with_multiple_pools_for_customer.get_pools_by_customer_id( + pools: list[Pool] = store_with_multiple_pools_for_customer.get_pools_by_customers( customers=store_with_multiple_pools_for_customer.get_customers() ) diff --git a/tests/store/crud/read/test_read_sample.py b/tests/store/crud/read/test_read_sample.py index ce9f808ab9..dc2955a960 100644 --- a/tests/store/crud/read/test_read_sample.py +++ b/tests/store/crud/read/test_read_sample.py @@ -130,7 +130,7 @@ def test_get_samples_by_customer_id_list_and_subject_id_and_is_tumour( ) # WHEN fetching the samples by customer ID list, subject ID, and tumour status - samples = store_with_samples_customer_id_and_subject_id_and_tumour_status.get_samples_by_customer_id_list_and_subject_id_and_is_tumour( + samples = store_with_samples_customer_id_and_subject_id_and_tumour_status.get_samples_by_customer_ids_and_subject_id_and_is_tumour( customer_ids=customer_ids, subject_id=subject_id, is_tumour=is_tumour ) @@ -170,7 +170,7 @@ def test_get_samples_by_customer_id_list_and_subject_id_and_is_tumour_with_non_e # WHEN fetching the samples by customer ID list, subject ID, and tumour status non_existing_customer_id = [3] - samples = store_with_samples_customer_id_and_subject_id_and_tumour_status.get_samples_by_customer_id_list_and_subject_id_and_is_tumour( + samples = store_with_samples_customer_id_and_subject_id_and_tumour_status.get_samples_by_customer_ids_and_subject_id_and_is_tumour( customer_ids=non_existing_customer_id, subject_id="test_subject", is_tumour=True ) @@ -590,7 +590,7 @@ def test_get_samples_by_customer_id_and_pattern_with_collaboration( # WHEN getting the samples for a customer samples: list[Sample] = ( - store_with_samples_for_multiple_customers.get_samples_by_customer_id_and_pattern( + store_with_samples_for_multiple_customers.get_samples_by_customers_and_pattern( customers=customer, pattern="sample", ) diff --git a/tests/store/filters/test_status_pool_filters.py b/tests/store/filters/test_status_pool_filters.py index 0ee1f928dd..83592d6a88 100644 --- a/tests/store/filters/test_status_pool_filters.py +++ b/tests/store/filters/test_status_pool_filters.py @@ -1,7 +1,7 @@ from sqlalchemy.orm import Query from cg.store.filters.status_pool_filters import ( - filter_pools_by_customer_id, + filter_pools_by_customer_ids, filter_pools_by_invoice_id, filter_pools_by_name_enquiry, filter_pools_by_order_enquiry, @@ -263,7 +263,7 @@ def test_filter_pools_by_customer_id( # GIVEN a store with two pools of with the same customer # WHEN getting pools with customer id - pools: Query = filter_pools_by_customer_id( + pools: Query = filter_pools_by_customer_ids( pools=store_with_a_pool_with_and_without_attributes._get_query(table=Pool), customer_ids=[1], )