From d2d29d14b616c8b6ff162246084976cfa62afea8 Mon Sep 17 00:00:00 2001 From: jameslinnell Date: Tue, 10 Feb 2026 14:42:28 +0000 Subject: [PATCH 01/10] [NDR-363] Search by default will only return NON-DELETED docs --- .../document_reference_search_service.py | 17 +++---- ...test_retrieve_document_fhir_api_failure.py | 6 +-- .../api/fhir/test_search_patient_fhir_api.py | 48 +++++++++++++++++++ 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/lambdas/services/document_reference_search_service.py b/lambdas/services/document_reference_search_service.py index a4046bb45..54fd0d002 100644 --- a/lambdas/services/document_reference_search_service.py +++ b/lambdas/services/document_reference_search_service.py @@ -126,12 +126,9 @@ def _search_tables_for_documents( def _get_filter_expression( self, filters: dict[str, str | None] = None, upload_completed=False ): - if filters: - return self._build_filter_expression(filters) - elif upload_completed: + if upload_completed: return UploadCompleted - else: - return None + return self._build_filter_expression(filters) def _create_fhir_bundle(self, document_resources: list[dict]) -> dict: entries = [ @@ -190,6 +187,9 @@ def _build_document_model(self, document: DocumentReference) -> dict: return document_formatted def _build_filter_expression(self, filter_values: dict[str, str]): + if not filter_values: + return NotDeleted + filter_builder = DynamoQueryFilterBuilder() for filter_key, filter_value in filter_values.items(): if filter_key == "custodian": @@ -215,11 +215,8 @@ def _build_filter_expression(self, filter_values: dict[str, str]): attr_operator=AttributeOperator.EQUAL, filter_value=filter_value, ) - if filter_values: - filter_expression = filter_builder.build() & NotDeleted - else: - filter_expression = NotDeleted - return filter_expression + + return filter_builder.build() & NotDeleted def create_document_reference_fhir_response( self, diff --git a/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py b/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py index 0640a412b..f280f25ac 100644 --- a/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py +++ b/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py @@ -20,7 +20,7 @@ def _assert_operation_outcome(body, code): @pytest.mark.parametrize( "doc_status, response_status", [ - ("deprecated", 200), # TODO Fix in NDR-363, this should return a 404 + ("deprecated", 404), ], ) def test_retrieval_of_deleted_document_reference( @@ -33,7 +33,7 @@ def test_retrieval_of_deleted_document_reference( pdm_record = create_and_store_pdm_record( test_data, doc_status=doc_status, - deleted=deletion_date.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), + Deleted=deletion_date.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), ttl=document_reference_ttl, ) @@ -41,7 +41,7 @@ def test_retrieval_of_deleted_document_reference( assert response.status_code == response_status response_json = response.json() - assert response_json.get("docStatus") == doc_status + _assert_operation_outcome(body=response_json, code="RESOURCE_NOT_FOUND") @pytest.mark.parametrize( diff --git a/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py b/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py index b2022432e..2681f0cc3 100644 --- a/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py +++ b/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py @@ -1,4 +1,6 @@ +from datetime import datetime, timezone import pytest +from enums.document_retention import DocumentRetentionDays from tests.e2e.api.fhir.conftest import ( MTLS_ENDPOINT, PDM_SNOMED, @@ -142,3 +144,49 @@ def test_search_invalid_resource_type(test_data): response = search_document_reference("9912003071", resource_type="FooBar") assert response.status_code == 400 + + +def test_search_patient_details_deleted_are_not_returned(test_data): + created_record_1 = create_and_store_pdm_record(test_data) + expected_record_id_1 = created_record_1["id"] + + deletion_date = datetime.now(timezone.utc) + document_ttl_days = DocumentRetentionDays.SOFT_DELETE + ttl_seconds = document_ttl_days * 24 * 60 * 60 + document_reference_ttl = int(deletion_date.timestamp() + ttl_seconds) + created_record_2 = create_and_store_pdm_record( + test_data, + doc_status="deprecated", + Deleted=deletion_date.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), + ttl=document_reference_ttl, + ) + expected_record_id_2 = created_record_2["id"] + + response = search_document_reference("9912003071") + assert response.status_code == 200 + + bundle = response.json() + assert bundle["total"] < 2 + entries = bundle.get("entry", []) + assert entries + + # Find the entry with the matching record_id + matching_entry = next( + ( + e + for e in entries + if e["resource"].get("id") == f"{PDM_SNOMED}~{expected_record_id_1}" + ), + None, + ) + assert matching_entry + # Assert deleted item doesn't exist + non_matching_entry = next( + ( + e + for e in entries + if e["resource"].get("id") == f"{PDM_SNOMED}~{expected_record_id_2}" + ), + None, + ) + assert non_matching_entry is None From e6b3662bb0a13ef39008f9ff9cc31cbc24833402 Mon Sep 17 00:00:00 2001 From: jameslinnell Date: Tue, 10 Feb 2026 15:24:51 +0000 Subject: [PATCH 02/10] [NDR-363] LG search tests e2e --- .../tests/e2e/api/test_search_patient_api.py | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/lambdas/tests/e2e/api/test_search_patient_api.py b/lambdas/tests/e2e/api/test_search_patient_api.py index ad7c7c79f..ce9fc126f 100644 --- a/lambdas/tests/e2e/api/test_search_patient_api.py +++ b/lambdas/tests/e2e/api/test_search_patient_api.py @@ -1,9 +1,11 @@ +from datetime import datetime, timezone import io import logging import uuid import requests from syrupy.filters import paths +from enums.document_retention import DocumentRetentionDays from tests.e2e.conftest import API_ENDPOINT, API_KEY, APIM_ENDPOINT, LLOYD_GEORGE_SNOMED from tests.e2e.helpers.data_helper import LloydGeorgeDataHelper @@ -128,3 +130,69 @@ def test_invalid_patient(snapshot_json): bundle = response.json() assert bundle == snapshot_json + + +def test_search_patient_details_deleted_are_not_returned(test_data): + lloyd_george_record = {} + test_data.append(lloyd_george_record) + + lloyd_george_record["id"] = str(uuid.uuid4()) + lloyd_george_record["nhs_number"] = "9449305943" + lloyd_george_record["data"] = io.BytesIO(b"Sample PDF Content") + + data_helper.create_metadata(lloyd_george_record) + data_helper.create_resource(lloyd_george_record) + + second_lloyd_george_record = {} + test_data.append(second_lloyd_george_record) + + deletion_date = datetime.now(timezone.utc) + document_ttl_days = DocumentRetentionDays.SOFT_DELETE + ttl_seconds = document_ttl_days * 24 * 60 * 60 + document_reference_ttl = int(deletion_date.timestamp() + ttl_seconds) + second_lloyd_george_record["id"] = str(uuid.uuid4()) + second_lloyd_george_record["nhs_number"] = "9449305943" + second_lloyd_george_record["data"] = io.BytesIO(b"Sample PDF Content") + second_lloyd_george_record["doc_status"] = "deprecated" + second_lloyd_george_record["Deleted"] = ( + deletion_date.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), + ) + second_lloyd_george_record["ttl"] = (document_reference_ttl,) + + data_helper.create_metadata(second_lloyd_george_record) + data_helper.create_resource(second_lloyd_george_record) + + url = f"https://{API_ENDPOINT}/FhirDocumentReference?subject:identifier=https://fhir.nhs.uk/Id/nhs-number|{lloyd_george_record['nhs_number']}" + headers = { + "Authorization": "Bearer 123", + "X-Api-Key": API_KEY, + "X-Correlation-Id": "1234", + } + response = requests.request("GET", url, headers=headers) + bundle = response.json() + assert bundle["total"] < 2 + entries = bundle.get("entry", []) + assert entries + + # Find the entry with the matching record_id + matching_entry = next( + ( + e + for e in entries + if e["resource"].get("id") + == f"{LLOYD_GEORGE_SNOMED}~{lloyd_george_record['id']}" + ), + None, + ) + assert matching_entry + # Assert deleted item doesn't exist + non_matching_entry = next( + ( + e + for e in entries + if e["resource"].get("id") + == f"{LLOYD_GEORGE_SNOMED}~{second_lloyd_george_record['id']}" + ), + None, + ) + assert non_matching_entry is None From fe855ef8586815909343adc7a7569d00ed58bf4c Mon Sep 17 00:00:00 2001 From: jameslinnell Date: Tue, 10 Feb 2026 15:35:00 +0000 Subject: [PATCH 03/10] [NDR-363] update LG e2e search test --- .../tests/e2e/api/test_search_patient_api.py | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lambdas/tests/e2e/api/test_search_patient_api.py b/lambdas/tests/e2e/api/test_search_patient_api.py index ce9fc126f..d1a1ba1e4 100644 --- a/lambdas/tests/e2e/api/test_search_patient_api.py +++ b/lambdas/tests/e2e/api/test_search_patient_api.py @@ -1,11 +1,9 @@ -from datetime import datetime, timezone import io import logging import uuid import requests from syrupy.filters import paths -from enums.document_retention import DocumentRetentionDays from tests.e2e.conftest import API_ENDPOINT, API_KEY, APIM_ENDPOINT, LLOYD_GEORGE_SNOMED from tests.e2e.helpers.data_helper import LloydGeorgeDataHelper @@ -146,22 +144,23 @@ def test_search_patient_details_deleted_are_not_returned(test_data): second_lloyd_george_record = {} test_data.append(second_lloyd_george_record) - deletion_date = datetime.now(timezone.utc) - document_ttl_days = DocumentRetentionDays.SOFT_DELETE - ttl_seconds = document_ttl_days * 24 * 60 * 60 - document_reference_ttl = int(deletion_date.timestamp() + ttl_seconds) second_lloyd_george_record["id"] = str(uuid.uuid4()) second_lloyd_george_record["nhs_number"] = "9449305943" second_lloyd_george_record["data"] = io.BytesIO(b"Sample PDF Content") - second_lloyd_george_record["doc_status"] = "deprecated" - second_lloyd_george_record["Deleted"] = ( - deletion_date.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), - ) - second_lloyd_george_record["ttl"] = (document_reference_ttl,) data_helper.create_metadata(second_lloyd_george_record) data_helper.create_resource(second_lloyd_george_record) + url = f"https://{API_ENDPOINT}/FhirDocumentReference?subject:identifier=https://fhir.nhs.uk/Id/nhs-number|{lloyd_george_record['nhs_number']}&_id={second_lloyd_george_record['id']}" + headers = { + "Authorization": "Bearer 123", + "X-Api-Key": API_KEY, + "X-Correlation-Id": "1234", + } + + delete_response = requests.request("DELETE", url, headers=headers) + assert delete_response.status_code == 204 + url = f"https://{API_ENDPOINT}/FhirDocumentReference?subject:identifier=https://fhir.nhs.uk/Id/nhs-number|{lloyd_george_record['nhs_number']}" headers = { "Authorization": "Bearer 123", From 839638c3ea942b82af6260fcda8c96d90c70d827 Mon Sep 17 00:00:00 2001 From: jameslinnell Date: Tue, 10 Feb 2026 15:55:33 +0000 Subject: [PATCH 04/10] [NDR-363] Make format --- .../document_reference_search_service.py | 16 ++++++++-------- .../test_retrieve_document_fhir_api_failure.py | 10 +++++----- .../e2e/api/fhir/test_search_patient_fhir_api.py | 5 +++-- lambdas/tests/e2e/api/test_search_patient_api.py | 12 ++++++------ 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/lambdas/services/document_reference_search_service.py b/lambdas/services/document_reference_search_service.py index 54fd0d002..f43207e12 100644 --- a/lambdas/services/document_reference_search_service.py +++ b/lambdas/services/document_reference_search_service.py @@ -43,7 +43,7 @@ def get_document_references( :return: List of document references or FHIR DocumentReferences. """ common_name = validate_common_name_in_mtls( - api_request_context=api_request_context + api_request_context=api_request_context, ) try: list_of_table_names = self._get_table_names(common_name) @@ -93,12 +93,12 @@ def _search_tables_for_documents( for table_name in table_names: logger.info(f"Searching for results in {table_name}") filter_expression = self._get_filter_expression( - filters, upload_completed=check_upload_completed + filters, upload_completed=check_upload_completed, ) if "coredocumentmetadata" not in table_name.lower(): documents = self.fetch_documents_from_table_with_nhs_number( - nhs_number, table_name, query_filter=filter_expression + nhs_number, table_name, query_filter=filter_expression, ) else: documents = self.fetch_documents_from_table( @@ -112,7 +112,7 @@ def _search_tables_for_documents( self._validate_upload_status(documents) processed_documents = self._process_documents( - documents, return_fhir=return_fhir + documents, return_fhir=return_fhir, ) document_resources.extend(processed_documents) @@ -124,7 +124,7 @@ def _search_tables_for_documents( return document_resources or None def _get_filter_expression( - self, filters: dict[str, str | None] = None, upload_completed=False + self, filters: dict[str, str | None] = None, upload_completed=False, ): if upload_completed: return UploadCompleted @@ -152,7 +152,7 @@ def _validate_upload_status(self, documents: list[DocumentReference]): raise DocumentRefSearchException(423, LambdaError.UploadInProgressError) def _process_documents( - self, documents: list[DocumentReference], return_fhir: bool + self, documents: list[DocumentReference], return_fhir: bool, ) -> list[dict]: results = [] for document in documents: @@ -210,7 +210,7 @@ def _build_filter_expression(self, filter_values: dict[str, str]): elif filter_key == "document_snomed_code": filter_builder.add_condition( attribute=str( - DocumentReferenceMetadataFields.DOCUMENT_SNOMED_CODE_TYPE.value + DocumentReferenceMetadataFields.DOCUMENT_SNOMED_CODE_TYPE.value, ), attr_operator=AttributeOperator.EQUAL, filter_value=filter_value, @@ -239,7 +239,7 @@ def create_document_reference_fhir_response( attachment=document_details, custodian=document_reference.current_gp_ods, snomed_code_doc_type=SnomedCodes.find_by_code( - document_reference.document_snomed_code_type + document_reference.document_snomed_code_type, ), ) .create_fhir_document_reference_object(document_reference) diff --git a/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py b/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py index f280f25ac..cc5336c35 100644 --- a/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py +++ b/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py @@ -1,5 +1,5 @@ -from datetime import datetime, timezone import uuid +from datetime import datetime, timezone import pytest from enums.document_retention import DocumentRetentionDays @@ -24,7 +24,7 @@ def _assert_operation_outcome(body, code): ], ) def test_retrieval_of_deleted_document_reference( - test_data, doc_status, response_status + test_data, doc_status, response_status, ): deletion_date = datetime.now(timezone.utc) document_ttl_days = DocumentRetentionDays.SOFT_DELETE @@ -51,7 +51,7 @@ def test_retrieval_of_deleted_document_reference( ], ) def test_retrieve_non_existant_document_reference( - record_id, expected_status, expected_code, expected_diagnostics + record_id, expected_status, expected_code, expected_diagnostics, ): response = get_pdm_document_reference(record_id) assert response.status_code == expected_status @@ -73,7 +73,7 @@ def test_forbidden_with_invalid_cert(test_data, temp_cert_and_key): cert_path, key_path = temp_cert_and_key response = get_pdm_document_reference( - pdm_record["id"], client_cert_path=cert_path, client_key_path=key_path + pdm_record["id"], client_cert_path=cert_path, client_key_path=key_path, ) body = response.json() @@ -103,7 +103,7 @@ def test_retrieve_invalid_resource_type(test_data): ], ) def test_incorrectly_formatted_path_param_id( - test_data, param, expected_status, expected_code + test_data, param, expected_status, expected_code, ): response = get_pdm_document_reference( endpoint_override=param, diff --git a/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py b/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py index 2681f0cc3..f0a3d88f4 100644 --- a/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py +++ b/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py @@ -1,4 +1,5 @@ from datetime import datetime, timezone + import pytest from enums.document_retention import DocumentRetentionDays from tests.e2e.api.fhir.conftest import ( @@ -110,7 +111,7 @@ def test_multiple_cancelled_search_patient_details(test_data): ], ) def test_search_edge_cases( - nhs_number, expected_status, expected_code, expected_diagnostics + nhs_number, expected_status, expected_code, expected_diagnostics, ): response = search_document_reference(nhs_number) assert response.status_code == expected_status @@ -131,7 +132,7 @@ def test_search_patient_unauthorized_mtls(test_data, temp_cert_and_key): cert_path, key_path = temp_cert_and_key response = search_document_reference( - "9912003071", client_cert_path=cert_path, client_key_path=key_path + "9912003071", client_cert_path=cert_path, client_key_path=key_path, ) body = response.json() diff --git a/lambdas/tests/e2e/api/test_search_patient_api.py b/lambdas/tests/e2e/api/test_search_patient_api.py index d1a1ba1e4..262354e05 100644 --- a/lambdas/tests/e2e/api/test_search_patient_api.py +++ b/lambdas/tests/e2e/api/test_search_patient_api.py @@ -43,7 +43,7 @@ def test_search_patient_details(test_data, snapshot_json): "entry.0.resource.date", "entry.0.resource.content.0.attachment.url", "timestamp", - ) + ), ) @@ -81,13 +81,13 @@ def test_multiple_cancelled_search_patient_details(test_data, snapshot_json): assert bundle["entry"][0] == snapshot_json( exclude=paths( - "resource.id", "resource.date", "resource.content.0.attachment.url" - ) + "resource.id", "resource.date", "resource.content.0.attachment.url", + ), ) assert bundle["entry"][1] == snapshot_json( exclude=paths( - "resource.id", "resource.date", "resource.content.0.attachment.url" - ) + "resource.id", "resource.date", "resource.content.0.attachment.url", + ), ) @@ -110,7 +110,7 @@ def test_no_records(snapshot_json): "entry.0.resource.date", "entry.0.resource.content.0.attachment.url", "timestamp", - ) + ), ) From 49f5c1360bc722341076f50aa1c425e45e1c21fd Mon Sep 17 00:00:00 2001 From: jameslinnell Date: Tue, 10 Feb 2026 16:19:35 +0000 Subject: [PATCH 05/10] [NDR-363] Make format... again! --- .../document_reference_search_service.py | 18 +++++++++++++----- .../test_retrieve_document_fhir_api_failure.py | 18 ++++++++++++++---- .../api/fhir/test_search_patient_fhir_api.py | 9 +++++++-- .../tests/e2e/api/test_search_patient_api.py | 8 ++++++-- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/lambdas/services/document_reference_search_service.py b/lambdas/services/document_reference_search_service.py index f43207e12..5a3e21a41 100644 --- a/lambdas/services/document_reference_search_service.py +++ b/lambdas/services/document_reference_search_service.py @@ -93,12 +93,15 @@ def _search_tables_for_documents( for table_name in table_names: logger.info(f"Searching for results in {table_name}") filter_expression = self._get_filter_expression( - filters, upload_completed=check_upload_completed, + filters, + upload_completed=check_upload_completed, ) if "coredocumentmetadata" not in table_name.lower(): documents = self.fetch_documents_from_table_with_nhs_number( - nhs_number, table_name, query_filter=filter_expression, + nhs_number, + table_name, + query_filter=filter_expression, ) else: documents = self.fetch_documents_from_table( @@ -112,7 +115,8 @@ def _search_tables_for_documents( self._validate_upload_status(documents) processed_documents = self._process_documents( - documents, return_fhir=return_fhir, + documents, + return_fhir=return_fhir, ) document_resources.extend(processed_documents) @@ -124,7 +128,9 @@ def _search_tables_for_documents( return document_resources or None def _get_filter_expression( - self, filters: dict[str, str | None] = None, upload_completed=False, + self, + filters: dict[str, str | None] = None, + upload_completed=False, ): if upload_completed: return UploadCompleted @@ -152,7 +158,9 @@ def _validate_upload_status(self, documents: list[DocumentReference]): raise DocumentRefSearchException(423, LambdaError.UploadInProgressError) def _process_documents( - self, documents: list[DocumentReference], return_fhir: bool, + self, + documents: list[DocumentReference], + return_fhir: bool, ) -> list[dict]: results = [] for document in documents: diff --git a/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py b/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py index cc5336c35..e1cfebe33 100644 --- a/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py +++ b/lambdas/tests/e2e/api/fhir/test_retrieve_document_fhir_api_failure.py @@ -24,7 +24,9 @@ def _assert_operation_outcome(body, code): ], ) def test_retrieval_of_deleted_document_reference( - test_data, doc_status, response_status, + test_data, + doc_status, + response_status, ): deletion_date = datetime.now(timezone.utc) document_ttl_days = DocumentRetentionDays.SOFT_DELETE @@ -51,7 +53,10 @@ def test_retrieval_of_deleted_document_reference( ], ) def test_retrieve_non_existant_document_reference( - record_id, expected_status, expected_code, expected_diagnostics, + record_id, + expected_status, + expected_code, + expected_diagnostics, ): response = get_pdm_document_reference(record_id) assert response.status_code == expected_status @@ -73,7 +78,9 @@ def test_forbidden_with_invalid_cert(test_data, temp_cert_and_key): cert_path, key_path = temp_cert_and_key response = get_pdm_document_reference( - pdm_record["id"], client_cert_path=cert_path, client_key_path=key_path, + pdm_record["id"], + client_cert_path=cert_path, + client_key_path=key_path, ) body = response.json() @@ -103,7 +110,10 @@ def test_retrieve_invalid_resource_type(test_data): ], ) def test_incorrectly_formatted_path_param_id( - test_data, param, expected_status, expected_code, + test_data, + param, + expected_status, + expected_code, ): response = get_pdm_document_reference( endpoint_override=param, diff --git a/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py b/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py index f0a3d88f4..92783b115 100644 --- a/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py +++ b/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py @@ -111,7 +111,10 @@ def test_multiple_cancelled_search_patient_details(test_data): ], ) def test_search_edge_cases( - nhs_number, expected_status, expected_code, expected_diagnostics, + nhs_number, + expected_status, + expected_code, + expected_diagnostics, ): response = search_document_reference(nhs_number) assert response.status_code == expected_status @@ -132,7 +135,9 @@ def test_search_patient_unauthorized_mtls(test_data, temp_cert_and_key): cert_path, key_path = temp_cert_and_key response = search_document_reference( - "9912003071", client_cert_path=cert_path, client_key_path=key_path, + "9912003071", + client_cert_path=cert_path, + client_key_path=key_path, ) body = response.json() diff --git a/lambdas/tests/e2e/api/test_search_patient_api.py b/lambdas/tests/e2e/api/test_search_patient_api.py index 262354e05..2a28349c6 100644 --- a/lambdas/tests/e2e/api/test_search_patient_api.py +++ b/lambdas/tests/e2e/api/test_search_patient_api.py @@ -81,12 +81,16 @@ def test_multiple_cancelled_search_patient_details(test_data, snapshot_json): assert bundle["entry"][0] == snapshot_json( exclude=paths( - "resource.id", "resource.date", "resource.content.0.attachment.url", + "resource.id", + "resource.date", + "resource.content.0.attachment.url", ), ) assert bundle["entry"][1] == snapshot_json( exclude=paths( - "resource.id", "resource.date", "resource.content.0.attachment.url", + "resource.id", + "resource.date", + "resource.content.0.attachment.url", ), ) From e50211d1721cd4a670c3cc6be83c62fa6dadf72f Mon Sep 17 00:00:00 2001 From: jameslinnell Date: Tue, 10 Feb 2026 16:51:54 +0000 Subject: [PATCH 06/10] [NDR-363] Filters before upload_completed --- .../services/document_reference_search_service.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lambdas/services/document_reference_search_service.py b/lambdas/services/document_reference_search_service.py index 5a3e21a41..b6910b187 100644 --- a/lambdas/services/document_reference_search_service.py +++ b/lambdas/services/document_reference_search_service.py @@ -132,9 +132,7 @@ def _get_filter_expression( filters: dict[str, str | None] = None, upload_completed=False, ): - if upload_completed: - return UploadCompleted - return self._build_filter_expression(filters) + return self._build_filter_expression(filters, upload_completed) def _create_fhir_bundle(self, document_resources: list[dict]) -> dict: entries = [ @@ -194,9 +192,13 @@ def _build_document_model(self, document: DocumentReference) -> dict: ) return document_formatted - def _build_filter_expression(self, filter_values: dict[str, str]): + def _build_filter_expression( + self, filter_values: dict[str, str], upload_completed=False + ): if not filter_values: - return NotDeleted + if not upload_completed: + return NotDeleted + return UploadCompleted filter_builder = DynamoQueryFilterBuilder() for filter_key, filter_value in filter_values.items(): From 180279cbc1b39857cafd86fddfe2eac87cfd3eeb Mon Sep 17 00:00:00 2001 From: jameslinnell Date: Tue, 10 Feb 2026 16:55:29 +0000 Subject: [PATCH 07/10] [NDR-363] Make format --- lambdas/services/document_reference_search_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambdas/services/document_reference_search_service.py b/lambdas/services/document_reference_search_service.py index b6910b187..9dc7636c4 100644 --- a/lambdas/services/document_reference_search_service.py +++ b/lambdas/services/document_reference_search_service.py @@ -193,7 +193,7 @@ def _build_document_model(self, document: DocumentReference) -> dict: return document_formatted def _build_filter_expression( - self, filter_values: dict[str, str], upload_completed=False + self, filter_values: dict[str, str], upload_completed=False, ): if not filter_values: if not upload_completed: From 362f1adc76a0989d0c7114a842cc19af1b439558 Mon Sep 17 00:00:00 2001 From: jameslinnell Date: Tue, 10 Feb 2026 16:58:51 +0000 Subject: [PATCH 08/10] [NDR-363] Make format again --- lambdas/services/document_reference_search_service.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lambdas/services/document_reference_search_service.py b/lambdas/services/document_reference_search_service.py index 9dc7636c4..901e5b046 100644 --- a/lambdas/services/document_reference_search_service.py +++ b/lambdas/services/document_reference_search_service.py @@ -193,7 +193,9 @@ def _build_document_model(self, document: DocumentReference) -> dict: return document_formatted def _build_filter_expression( - self, filter_values: dict[str, str], upload_completed=False, + self, + filter_values: dict[str, str], + upload_completed=False, ): if not filter_values: if not upload_completed: From 0ba95a740613a5aa51e22472849f2cd9c3b0e8e5 Mon Sep 17 00:00:00 2001 From: jameslinnell Date: Wed, 11 Feb 2026 11:06:19 +0000 Subject: [PATCH 09/10] [NDR-363] remove redundant function --- .../services/document_reference_search_service.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/lambdas/services/document_reference_search_service.py b/lambdas/services/document_reference_search_service.py index 901e5b046..2a765a53a 100644 --- a/lambdas/services/document_reference_search_service.py +++ b/lambdas/services/document_reference_search_service.py @@ -92,9 +92,8 @@ def _search_tables_for_documents( for table_name in table_names: logger.info(f"Searching for results in {table_name}") - filter_expression = self._get_filter_expression( - filters, - upload_completed=check_upload_completed, + filter_expression = self._build_filter_expression( + filters, check_upload_completed, ) if "coredocumentmetadata" not in table_name.lower(): @@ -127,13 +126,6 @@ def _search_tables_for_documents( return document_resources or None - def _get_filter_expression( - self, - filters: dict[str, str | None] = None, - upload_completed=False, - ): - return self._build_filter_expression(filters, upload_completed) - def _create_fhir_bundle(self, document_resources: list[dict]) -> dict: entries = [ BundleEntry(resource=doc_resource) for doc_resource in document_resources @@ -194,7 +186,7 @@ def _build_document_model(self, document: DocumentReference) -> dict: def _build_filter_expression( self, - filter_values: dict[str, str], + filter_values: dict[str, str] | None, upload_completed=False, ): if not filter_values: From e06c5eacbfea6d37c9406a5d9dbe4532e406a1d9 Mon Sep 17 00:00:00 2001 From: jameslinnell Date: Wed, 11 Feb 2026 11:50:52 +0000 Subject: [PATCH 10/10] [NDR-363] Make format --- lambdas/services/document_reference_search_service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lambdas/services/document_reference_search_service.py b/lambdas/services/document_reference_search_service.py index 2a765a53a..b40fa8b54 100644 --- a/lambdas/services/document_reference_search_service.py +++ b/lambdas/services/document_reference_search_service.py @@ -93,7 +93,8 @@ def _search_tables_for_documents( for table_name in table_names: logger.info(f"Searching for results in {table_name}") filter_expression = self._build_filter_expression( - filters, check_upload_completed, + filters, + check_upload_completed, ) if "coredocumentmetadata" not in table_name.lower():