Skip to content

Commit 4fdb3a3

Browse files
committed
Updated converter to handle urls. Added snomed validation
1 parent be10923 commit 4fdb3a3

File tree

7 files changed

+86
-23
lines changed

7 files changed

+86
-23
lines changed

delta_backend/poetry.lock

Lines changed: 18 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

delta_backend/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ python = "~3.10"
1313
boto3 = "~1.26.90"
1414
mypy-boto3-dynamodb = "^1.26.164"
1515
moto = "~4.2.11"
16+
python-stdnum = "^1.20"
1617

1718
[tool.poetry.group.dev.dependencies]
1819
coverage = "^7.8.0"

delta_backend/src/ConversionLayout.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@
153153
}
154154
},
155155
{
156-
"fieldNameFHIR": "extension|0|valueCodeableConcept|coding|0|code",
156+
"fieldNameFHIR": "extension|#:https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-VaccinationProcedure|valueCodeableConcept|coding|#:http://snomed.info/sct|code",
157157
"fieldNameFlat": "VACCINATION_PROCEDURE_CODE",
158158
"expression": {
159159
"expressionName": "Not Empty",
@@ -185,7 +185,7 @@
185185
"expression": {
186186
"expressionName": "Not Empty",
187187
"expressionType": "SNOMED",
188-
"expressionRule": ""
188+
"expressionRule": "validate-code"
189189
}
190190
},
191191
{

delta_backend/src/Converter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def _getSchemaParser(self, schemafile):
5252
return schemaParser
5353

5454
# Convert data against converter schema
55-
def _convertData(self, ConversionValidate, expression, dataParser, json_data):
55+
def _convertData(self, ConversionValidate: ConversionChecker, expression, dataParser: FHIRParser, json_data):
5656

5757
FHIRFieldName = expression["fieldNameFHIR"]
5858
FlatFieldName = expression["fieldNameFlat"]
@@ -61,7 +61,7 @@ def _convertData(self, ConversionValidate, expression, dataParser, json_data):
6161
expressionRule = expression["expression"]["expressionRule"]
6262

6363
try:
64-
conversionValues = dataParser.getKeyValue(FHIRFieldName)
64+
conversionValues = dataParser.getKeyValue(FHIRFieldName, expressionType, expressionRule)
6565
except Exception as e:
6666
message = "Data get value Unexpected exception [%s]: %s" % (e.__class__.__name__, e)
6767
error = self._log_error(message, code=ExceptionMessages.PARSING_ERROR)

delta_backend/src/FHIRParser.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# FHIR JSON importer and data access
22
import json
3-
3+
from utils import is_valid_simple_snomed
44

55
class FHIRParser:
66
# parser variables
@@ -10,6 +10,16 @@ class FHIRParser:
1010
def parseFHIRData(self, fhirData):
1111
self.FHIRFile = json.loads(fhirData) if isinstance(fhirData, str) else fhirData
1212

13+
def _validate_expression_rule(self, expression_type, expression_rule, key_value_pair):
14+
if not expression_rule:
15+
return True
16+
17+
elif expression_type == "SNOMED" and expression_rule == "validate-code":
18+
if key_value_pair.get("code"):
19+
return is_valid_simple_snomed(key_value_pair["code"])
20+
21+
return False
22+
1323
# scan for a key name or a value
1424
def _scanValuesForMatch(self, parent, matchValue):
1525
try:
@@ -21,18 +31,21 @@ def _scanValuesForMatch(self, parent, matchValue):
2131
return False
2232

2333
# locate an index for an item in a list
24-
def _locateListId(self, parent, locator):
25-
fieldList = locator.split(":")
34+
def _locateListId(self, parent, locator, expression_type, expression_rule: str = ""):
35+
fieldList = locator.split(":", 1)
2636
nodeId = 0
2737
index = 0
2838
try:
2939
while index < len(parent):
30-
for key in parent[index]:
31-
if (parent[index][key] == fieldList[1]) or (key == fieldList[1]):
40+
for key, value in parent[index].items():
41+
if (
42+
(value == fieldList[1] or key == fieldList[1])
43+
and self._validate_expression_rule(expression_type, expression_rule, parent[index])
44+
):
3245
nodeId = index
3346
break
3447
else:
35-
if self._scanValuesForMatch(parent[index][key], fieldList[1]):
48+
if self._scanValuesForMatch(value, fieldList[1]):
3649
nodeId = index
3750
break
3851
index += 1
@@ -54,26 +67,26 @@ def _getNode(self, parent, child):
5467
return result
5568

5669
# locate a value for a key
57-
def _scanForValue(self, FHIRFields):
70+
def _scanForValue(self, FHIRFields, expression_type, expression_rule: str = ""):
5871
fieldList = FHIRFields.split("|")
5972
# get root field before we iterate
6073
rootfield = self.FHIRFile[fieldList[0]]
6174
del fieldList[0]
6275
try:
6376
for field in fieldList:
6477
if field.startswith("#"):
65-
rootfield = self._locateListId(rootfield, field) # check here for default index??
78+
rootfield = self._locateListId(rootfield, field, expression_type, expression_rule) # check here for default index??
6679
else:
6780
rootfield = self._getNode(rootfield, field)
6881
except:
6982
rootfield = ""
7083
return rootfield
7184

7285
# get the value for a key
73-
def getKeyValue(self, fieldName):
86+
def getKeyValue(self, fieldName, expression_type, expression_rule: str = ""):
7487
value = []
7588
try:
76-
responseValue = self._scanForValue(fieldName)
89+
responseValue = self._scanForValue(fieldName, expression_type, expression_rule)
7790
except:
7891
responseValue = ""
7992

delta_backend/src/utils.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
from stdnum.verhoeff import validate
3+
4+
def is_valid_simple_snomed(simple_snomed: str) -> bool:
5+
"check the snomed code valid or not."
6+
min_snomed_length = 6
7+
max_snomed_length = 18
8+
try:
9+
return (
10+
simple_snomed is not None
11+
and simple_snomed.isdigit()
12+
and min_snomed_length <= len(simple_snomed) <= max_snomed_length
13+
and validate(simple_snomed)
14+
and (simple_snomed[-3:-1] in ("00", "10"))
15+
)
16+
except:
17+
return False

delta_backend/tests/sample_data/fhir_sample.json

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,25 @@
4343
{
4444
"url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-VaccinationProcedure",
4545
"valueCodeableConcept": {
46-
"coding": [
47-
{
48-
"system": "http://snomed.info/sct",
49-
"code": "13246810000001",
50-
"display": "Administration of first dose of severe acute respiratory syndrome coronavirus 2 vaccine (procedure)"
51-
}
52-
]
46+
"coding": [
47+
{
48+
"code": "956951000000105",
49+
"display": "Seasonal influenza vaccination (procedure)",
50+
"system": "http://snomed.info/test"
51+
},
52+
{
53+
"code": "956951000000104",
54+
"display": "Seasonal influenza vaccination (procedure)",
55+
"system": "http://snomed.info/sct"
56+
},
57+
{
58+
"code": "NEG",
59+
"display": "Seasonal influenza vaccination (procedure)",
60+
"system": "https://acme.lab/resultcodes"
61+
}
62+
]
63+
}
5364
}
54-
}
5565
],
5666
"identifier": [
5767
{
@@ -62,6 +72,11 @@
6272
"status": "completed",
6373
"vaccineCode": {
6474
"coding": [
75+
{
76+
"system": "http://snomed.info/sct",
77+
"code": "39114911000001104",
78+
"display": "COVID-19 Vaccine Vaxzevria (ChAdOx1 S [recombinant]) not less than 2.5x100,000,000 infectious units/0.5ml dose suspension for injection multidose vials (AstraZeneca UK Ltd) (product)"
79+
},
6580
{
6681
"system": "http://snomed.info/sct",
6782
"code": "39114911000001105",

0 commit comments

Comments
 (0)