Skip to content

Commit da6cfd7

Browse files
committed
Implemented pagination and added more error handling logic to e2e search tests
1 parent 56a47a0 commit da6cfd7

24 files changed

+649
-109
lines changed

backend/src/fhir_repository.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -411,24 +411,48 @@ def delete_immunization(
411411
)
412412

413413
def find_immunizations(self, patient_identifier: str, vaccine_types: list):
414-
"""it should find all of the specified patient's Immunization events for all of the specified vaccine_types"""
414+
"""Find all of the specified patient's Immunization events for the given vaccine types, stopping after ~5MB of data."""
415415
condition = Key("PatientPK").eq(_make_patient_pk(patient_identifier))
416416
is_not_deleted = Attr("DeletedAt").not_exists() | Attr("DeletedAt").eq("reinstated")
417417

418-
response = self.table.query(
419-
IndexName="PatientGSI",
420-
KeyConditionExpression=condition,
421-
FilterExpression=is_not_deleted,
422-
)
418+
all_items = []
419+
last_evaluated_key = None
420+
MAX_ITEM_ESTIMATE = 2100 # TBC - Assuming 2.8KB per item, 6MB is upper limit
423421

424-
if "Items" in response:
425-
# Filter the response to contain only the requested vaccine types
426-
items = [x for x in response["Items"] if x["PatientSK"].split("#")[0] in vaccine_types]
422+
while len(all_items) <= MAX_ITEM_ESTIMATE:
423+
query_params = {
424+
"IndexName": "PatientGSI",
425+
"KeyConditionExpression": condition,
426+
"FilterExpression": is_not_deleted,
427+
}
428+
429+
if last_evaluated_key:
430+
query_params["ExclusiveStartKey"] = last_evaluated_key
431+
432+
response = self.table.query(**query_params)
433+
434+
if "Items" in response:
435+
# Filter for matching vaccine types
436+
filtered = [
437+
x for x in response["Items"]
438+
if x["PatientSK"].split("#")[0] in vaccine_types
439+
]
440+
all_items.extend(filtered)
441+
else:
442+
raise UnhandledResponseError(
443+
message="Unhandled error. Query failed",
444+
response=response
445+
)
446+
447+
last_evaluated_key = response.get("LastEvaluatedKey") # Paginating table query results
448+
if not last_evaluated_key:
449+
break
450+
451+
if len(all_items) >= MAX_ITEM_ESTIMATE:
452+
print(f"Stopped after reaching estimated 6MB limit ({len(all_items)} items).")
453+
454+
return [json.loads(item["Resource"]) for item in all_items]
427455

428-
# Return a list of the FHIR immunization resource JSON items
429-
return [json.loads(item["Resource"]) for item in items]
430-
else:
431-
raise UnhandledResponseError(message=f"Unhandled error. Query failed", response=response)
432456

433457
@staticmethod
434458
def _handle_dynamo_response(response):

delta_backend/.coverage

0 Bytes
Binary file not shown.

delta_backend/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
output.json
2+
output.csv

delta_backend/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@ package: build
55
mkdir -p build
66
docker run --rm -v $(shell pwd)/build:/build delta-lambda-build
77

8+
test:
9+
python -m unittest
10+
811
.PHONY: build package

delta_backend/README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# 🩺 FHIR to Flat JSON Conversion Engine
2+
3+
This project is designed to convert FHIR-compliant JSON data (e.g., Immunization records) into a flat JSON format based on a configurable schema layout. It is intended to support synchronization of Immunisation API generated data from external sources to DPS (Data Processing System) data system
4+
5+
---
6+
7+
## 📁 File Structure Overview
8+
9+
| File Name | What It Does |
10+
|------------------------|---------------|
11+
| **`converter.py`** | 🧠 The main brain — applies the schema, runs conversions, handles errors. |
12+
| **`FHIRParser.py`** | 🪜 Knows how to dig into nested FHIR structures and pull out values like dates, IDs, and patient names. |
13+
| **`SchemaParser.py`** | 📐 Reads your schema layout and tells the converter which FHIR fields to extract and how to rename/format them. |
14+
| **`ConversionLayout.py`** | ✍️ A plain Python list that defines which fields you want, and how they should be formatted (e.g. date format, renaming rules). |
15+
| **`ConversionChecker.py`** | 🔧 Handles transformation logic — e.g. turning a FHIR datetime into `YYYY-MM-DD`, applying lookups, gender codes, defaults, etc. |
16+
| **`Extractor.py`** | 🎣 Specialized logic to pull practitioner names, site codes, addresses, and apply time-aware rules. |
17+
| **`ExceptionMessages.py`** | 🚨 Holds reusable error messages and codes for clean debugging and validation feedback. |
18+
19+
---
20+
21+
22+
## 🛠️ Key Features
23+
24+
- Schema-driven field extraction and formatting
25+
- Support for custom date formats like `YYYYMMDD`, and CSV-safe UTC timestamps
26+
- Robust handling of patient, practitioner, and address data using time-aware logic
27+
- Extendable structure with static helper methods and modular architecture
28+
29+
---
30+
31+
## 📦 Example Use Case
32+
33+
- Input: FHIR `Immunization` resource (with nested fields)
34+
- Output: Flat JSON object with 34 standardized key-value pairs
35+
- Purpose: To export into CSV or push into downstream ETL systems
36+
37+
---
38+
39+
## ✅ Getting Started with `check_conversion.py`
40+
41+
To quickly test your conversion, use the provided `check_conversion.py` script.
42+
This script loads sample FHIR data, runs it through the converter, and automatically saves the output in both JSON and CSV formats.
43+
44+
### 🔄 How to Use It
45+
46+
1. Add your FHIR data (e.g., a dictionary or sample JSON) into the `fhir_sample` variable inside `check_conversion.py`
47+
2. Ensure the field mapping in `ConversionLayout.py` matches your desired output
48+
3. Run the script from the `tests` folder:
49+
50+
```bash
51+
python check_conversion.py
52+
```
53+
54+
### 📁 Output Location
55+
When the script runs, it will automatically:
56+
- Save a **flat JSON file** as `output.json`
57+
- Save a **CSV file** as `output.csv`
58+
59+
These will be located one level up from the `src/` folder:
60+
61+
```
62+
/mnt/c/Users/USER/desktop/shn/immunisation-fhir-api/delta_backend/output.json
63+
/mnt/c/Users/USER/desktop/shn/immunisation-fhir-api/delta_backend/output.csv
64+
```
65+
66+
### 👀 Visualization
67+
You can now:
68+
- Open `output.csv` in Excel or Google Sheets to view cleanly structured records
69+
- Inspect `output.json` to validate the flat key-value output programmatically
70+
71+
---

delta_backend/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)