Skip to content

Commit c1d2220

Browse files
nhsdevwsmfjarvis
authored andcommitted
VED-687 Search API bug RSV Not returned (#721)
implement pagination
1 parent fe00261 commit c1d2220

19 files changed

+317
-213
lines changed

backend/poetry.lock

Lines changed: 184 additions & 176 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/src/fhir_batch_repository.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import boto3
44
import time
55
import simplejson as json
6+
from clients import logger
67
from dataclasses import dataclass
78
import botocore.exceptions
89
from boto3.dynamodb.conditions import Key, Attr
@@ -34,7 +35,7 @@ def _query_identifier(table, index, pk, identifier, is_present):
3435
return queryresponse
3536

3637
if retries > 6:
37-
print(f"{identifier}: Crossed {retries} retries")
38+
logger.info(f"{identifier}: Crossed {retries} retries")
3839

3940
retries += 1
4041
# Delay time in milliseconds

backend/src/fhir_controller.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from botocore.config import Config
1414
from fhir.resources.R4B.immunization import Immunization
1515
from boto3 import client as boto3_client
16+
from clients import logger
1617

1718
from authorization import Authorization, UnknownPermission
1819
from cache import Cache
@@ -640,7 +641,7 @@ def check_vaccine_type_permissions(self, aws_event):
640641
if len(supplier_system) == 0:
641642
raise UnauthorizedSystemError()
642643
imms_vax_type_perms = get_supplier_permissions(supplier_system)
643-
print(f" update imms = {imms_vax_type_perms}")
644+
logger.info(f" update imms = {imms_vax_type_perms}")
644645
if len(imms_vax_type_perms) == 0:
645646
raise UnauthorizedVaxError()
646647
# Return the values needed for later use

backend/src/fhir_repository.py

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from urllib import response
2+
from responses import logger
13
import simplejson as json
24
import os
35
import time
@@ -397,20 +399,46 @@ def find_immunizations(self, patient_identifier: str, vaccine_types: list):
397399
condition = Key("PatientPK").eq(_make_patient_pk(patient_identifier))
398400
is_not_deleted = Attr("DeletedAt").not_exists() | Attr("DeletedAt").eq("reinstated")
399401

400-
response = self.table.query(
401-
IndexName="PatientGSI",
402-
KeyConditionExpression=condition,
403-
FilterExpression=is_not_deleted,
404-
)
402+
raw_items = self.get_all_items(condition, is_not_deleted)
405403

406-
if "Items" in response:
404+
if raw_items:
407405
# Filter the response to contain only the requested vaccine types
408-
items = [x for x in response["Items"] if x["PatientSK"].split("#")[0] in vaccine_types]
406+
items = [x for x in raw_items if x["PatientSK"].split("#")[0] in vaccine_types]
409407

410408
# Return a list of the FHIR immunization resource JSON items
411-
return [json.loads(item["Resource"]) for item in items]
409+
final_resources = [json.loads(item["Resource"]) for item in items]
410+
411+
return final_resources
412412
else:
413-
raise UnhandledResponseError(message=f"Unhandled error. Query failed", response=response)
413+
logger.warning("no items matched patient_identifier filter!")
414+
return []
415+
416+
def get_all_items(self, condition, is_not_deleted):
417+
"""Query DynamoDB and paginate through all results."""
418+
all_items = []
419+
last_evaluated_key = None
420+
421+
while True:
422+
query_args = {
423+
"IndexName": "PatientGSI",
424+
"KeyConditionExpression": condition,
425+
"FilterExpression": is_not_deleted,
426+
}
427+
if last_evaluated_key:
428+
query_args["ExclusiveStartKey"] = last_evaluated_key
429+
430+
response = self.table.query(**query_args)
431+
if "Items" not in response:
432+
raise UnhandledResponseError(message="No Items in DynamoDB response", response=response)
433+
434+
items = response.get("Items", [])
435+
all_items.extend(items)
436+
437+
last_evaluated_key = response.get("LastEvaluatedKey")
438+
if not last_evaluated_key:
439+
break
440+
441+
return all_items
414442

415443
@staticmethod
416444
def _handle_dynamo_response(response):

backend/src/log_structure.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def function_info(func):
2020
@wraps(func)
2121
def wrapper(*args, **kwargs):
2222
event = args[0] if args else {}
23-
print(f"Event: {event}")
23+
logger.info(f"Event: {event}")
2424
headers = event.get("headers", {})
2525
correlation_id = headers.get("X-Correlation-ID", "X-Correlation-ID not passed")
2626
request_id = headers.get("X-Request-ID", "X-Request-ID not passed")
@@ -40,7 +40,7 @@ def wrapper(*args, **kwargs):
4040
start = time.time()
4141
try:
4242
result = func(*args, **kwargs)
43-
print(f"Result:{result}")
43+
logger.info(f"Result:{result}")
4444
end = time.time()
4545
log_data["time_taken"] = f"{round(end - start, 5)}s"
4646
status = "500"
@@ -56,7 +56,7 @@ def wrapper(*args, **kwargs):
5656
record = result_headers["Location"]
5757
if result.get("body"):
5858
ops_outcome = json.loads(result["body"])
59-
print(f"ops_outcome: {ops_outcome}")
59+
logger.info(f"ops_outcome: {ops_outcome}")
6060
if ops_outcome.get("issue"):
6161
outcome_body = ops_outcome["issue"][0]
6262
status_code = outcome_body["code"]

backend/src/models/utils/permission_checker.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from enum import StrEnum
2+
from clients import logger
23

34
class ApiOperationCode(StrEnum):
45
CREATE = "c"
@@ -22,7 +23,7 @@ def _expand_permissions(permissions: list[str]) -> dict[str, list[ApiOperationCo
2223

2324
def validate_permissions(permissions: list[str], operation: ApiOperationCode, vaccine_types: list[str]):
2425
expanded_permissions = _expand_permissions(permissions)
25-
print(f"operation: {operation}, expanded_permissions: {expanded_permissions}, vaccine_types: {vaccine_types}")
26+
logger.info(f"operation: {operation}, expanded_permissions: {expanded_permissions}, vaccine_types: {vaccine_types}")
2627
return all(
2728
operation in expanded_permissions.get(vaccine_type.lower(), [])
2829
for vaccine_type in vaccine_types

backend/src/parameter_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from typing import Optional
77
from urllib.parse import parse_qs, urlencode, quote
88

9-
from clients import redis_client
9+
from clients import redis_client, logger
1010
from models.errors import ParameterException
1111
from models.constants import Constants
1212

backend/src/search_imms_handler.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import json
33
import logging
44
import pprint
5-
import traceback
65
import uuid
76

87
from aws_lambda_typing import context as context_, events
@@ -53,9 +52,7 @@ def search_imms(event: events.APIGatewayProxyEventV1, controller: FhirController
5352
or body_has_immunization_element
5453
):
5554
return controller.get_immunization_by_identifier(event)
56-
response = controller.search_immunizations(event)
57-
else:
58-
response = controller.search_immunizations(event)
55+
response = controller.search_immunizations(event)
5956

6057
result_json = json.dumps(response)
6158
result_size = len(result_json.encode("utf-8"))

backend/tests/test_create_imms.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22
import unittest
3-
from unittest.mock import create_autospec
3+
from unittest.mock import create_autospec, patch
44

55
from create_imms_handler import create_immunization
66
from fhir_controller import FhirController
@@ -11,6 +11,13 @@
1111
class TestCreateImmunizationById(unittest.TestCase):
1212
def setUp(self):
1313
self.controller = create_autospec(FhirController)
14+
self.logger_info_patcher = patch("logging.Logger.info")
15+
self.mock_logger_info = self.logger_info_patcher.start()
16+
self.logger_exception_patcher = patch("logging.Logger.exception")
17+
self.mock_logger_exception = self.logger_exception_patcher.start()
18+
19+
def tearDown(self):
20+
patch.stopall()
1421

1522
def test_create_immunization(self):
1623
"""it should create Immunization"""
@@ -26,7 +33,7 @@ def test_create_immunization(self):
2633
self.controller.create_immunization.assert_called_once_with(lambda_event)
2734
self.assertDictEqual(exp_res, act_res)
2835

29-
def test_handle_exception(self):
36+
def test_create_handle_exception(self):
3037
"""unhandled exceptions should result in 500"""
3138
lambda_event = {"aws": "event"}
3239
error_msg = "an unhandled error"

backend/tests/test_delete_imms.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22
import unittest
3-
from unittest.mock import create_autospec
3+
from unittest.mock import create_autospec, patch
44

55
from delete_imms_handler import delete_immunization
66
from fhir_controller import FhirController
@@ -11,6 +11,11 @@
1111
class TestDeleteImmunizationById(unittest.TestCase):
1212
def setUp(self):
1313
self.controller = create_autospec(FhirController)
14+
self.logger_exception_patcher = patch("logging.Logger.exception")
15+
self.mock_logger_exception = self.logger_exception_patcher.start()
16+
17+
def tearDown(self):
18+
patch.stopall()
1419

1520
def test_delete_immunization(self):
1621
"""it should delete Immunization"""
@@ -26,7 +31,7 @@ def test_delete_immunization(self):
2631
self.controller.delete_immunization.assert_called_once_with(lambda_event)
2732
self.assertDictEqual(exp_res, act_res)
2833

29-
def test_handle_exception(self):
34+
def test_delete_handle_exception(self):
3035
"""unhandled exceptions should result in 500"""
3136
lambda_event = {"pathParameters": {"id": "an-id"}}
3237
error_msg = "an unhandled error"

0 commit comments

Comments
 (0)