Skip to content

Commit f5917e7

Browse files
committed
shema for all 34 fields
1 parent 32e2313 commit f5917e7

File tree

3 files changed

+130
-206
lines changed

3 files changed

+130
-206
lines changed

lambdas/shared/src/common/validator/expression_checker.py

Lines changed: 2 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import re
21
from datetime import datetime
32
from decimal import Decimal
43
from typing import Optional, Union
54

6-
from common.validator.constants.enums import MESSAGES, ExceptionLevels, MessageLabel
7-
from common.validator.error_report.record_error import ErrorReport, RecordError
5+
from common.validator.constants.enums import MESSAGES, ExceptionLevels
6+
from common.validator.error_report.record_error import ErrorReport
87
from common.validator.expression_rule import expression_rule_per_field
98
from common.validator.lookup_expressions.key_data import KeyData
109
from common.validator.lookup_expressions.lookup_data import LookUpData
@@ -44,10 +43,6 @@ def validate_expression(
4443
return self.validation_for_boolean(expression_rule, field_name, field_value)
4544
case "INTDECIMAL":
4645
return self.validation_for_integer_or_decimal(expression_rule, field_name, field_value)
47-
case "POSTCODE":
48-
return self._validate_post_code(expression_rule, field_name, field_value)
49-
case "GENDER":
50-
return self._validate_gender(expression_rule, field_name, field_value)
5146
case _:
5247
return "Schema expression not found! Check your expression type : " + expression_type
5348

@@ -150,27 +145,6 @@ def validation_for_unique_list(
150145

151146
found.append(item[unique_value_in_list])
152147

153-
# Regex Validate
154-
def _validate_regex(self, expression_rule: str, field_name: str, field_value: str, row: dict) -> ErrorReport:
155-
try:
156-
result = re.search(expression_rule, field_value)
157-
if not result:
158-
raise RecordError(
159-
ExceptionLevels.RECORD_CHECK_FAILED,
160-
"String REGEX check failed",
161-
"Value does not meet regex rules",
162-
)
163-
except RecordError as e:
164-
code = e.code if e.code is not None else ExceptionLevels.RECORD_CHECK_FAILED
165-
message = e.message if e.message is not None else MESSAGES[ExceptionLevels.RECORD_CHECK_FAILED]
166-
if e.details is not None:
167-
details = e.details
168-
return ErrorReport(code, message, row, field_name, details, self.summarise)
169-
except Exception as e:
170-
if self.report_unexpected_exception:
171-
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
172-
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, row, field_name, "", self.summarise)
173-
174148
def validation_for_boolean(self, expression_rule: str, field_name: str, field_value: str) -> ErrorReport:
175149
"""Apply pre-validation to a boolean field to ensure that it is a boolean"""
176150
try:
@@ -278,101 +252,6 @@ def validation_for_date_time(self, expression_rule: str, field_name: str, field_
278252
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
279253
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, None, field_name)
280254

281-
# Not Equal Validate
282-
def _validate_not_equal(self, expression_rule: str, field_name: str, field_value: str, row: dict) -> ErrorReport:
283-
try:
284-
if field_value == expression_rule:
285-
raise RecordError(
286-
ExceptionLevels.RECORD_CHECK_FAILED,
287-
"Value not equals check failed",
288-
"Value equals expected value when it should not, Expected- "
289-
+ expression_rule
290-
+ MessageLabel.FOUND_LABEL
291-
+ field_value,
292-
)
293-
except RecordError as e:
294-
code = e.code if e.code is not None else ExceptionLevels.RECORD_CHECK_FAILED
295-
message = e.message if e.message is not None else MESSAGES[ExceptionLevels.RECORD_CHECK_FAILED]
296-
if e.details is not None:
297-
details = e.details
298-
return ErrorReport(code, message, row, field_name, details, self.summarise)
299-
except Exception as e:
300-
if self.report_unexpected_exception:
301-
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
302-
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, row, field_name, "", self.summarise)
303-
304-
# Starts With Validate
305-
def _validate_starts_with(self, expression_rule: str, field_name: str, field_value: str, row: dict) -> ErrorReport:
306-
try:
307-
result = field_value.startswith(expression_rule)
308-
if not result:
309-
raise RecordError(
310-
ExceptionLevels.RECORD_CHECK_FAILED,
311-
"Value starts with failure",
312-
"Value does not start as expected, "
313-
+ MessageLabel.EXPECTED_LABEL
314-
+ expression_rule
315-
+ " "
316-
+ MessageLabel.FOUND_LABEL
317-
+ field_value,
318-
)
319-
except RecordError as e:
320-
code = e.code if e.code is not None else ExceptionLevels.RECORD_CHECK_FAILED
321-
message = e.message if e.message is not None else MESSAGES[ExceptionLevels.RECORD_CHECK_FAILED]
322-
if e.details is not None:
323-
details = e.details
324-
return ErrorReport(code, message, row, field_name, details, self.summarise)
325-
except Exception as e:
326-
if self.report_unexpected_exception:
327-
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
328-
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, row, field_name, "", self.summarise)
329-
330-
# Ends With Validate
331-
def _validate_ends_with(self, expression_rule: str, field_name: str, field_value: str, row: dict) -> ErrorReport:
332-
try:
333-
result = field_value.endswith(expression_rule)
334-
if not result:
335-
raise RecordError(
336-
ExceptionLevels.RECORD_CHECK_FAILED,
337-
"Value ends with failure",
338-
"Value does not end as expected, "
339-
+ MessageLabel.EXPECTED_LABEL
340-
+ expression_rule
341-
+ " "
342-
+ MessageLabel.FOUND_LABEL
343-
+ field_value,
344-
)
345-
except RecordError as e:
346-
code = e.code if e.code is not None else ExceptionLevels.RECORD_CHECK_FAILED
347-
message = e.message if e.message is not None else MESSAGES[ExceptionLevels.RECORD_CHECK_FAILED]
348-
if e.details is not None:
349-
details = e.details
350-
return ErrorReport(code, message, row, field_name, details, self.summarise)
351-
except Exception as e:
352-
if self.report_unexpected_exception:
353-
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
354-
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, row, field_name, "", self.summarise)
355-
356-
# Empty Validate
357-
def _validate_empty(self, _expression_rule: str, field_name: str, field_value: str, row: dict) -> ErrorReport:
358-
try:
359-
if field_value:
360-
raise RecordError(
361-
ExceptionLevels.RECORD_CHECK_FAILED,
362-
"Value is empty failure",
363-
"Value has data, not as expected, data- " + field_value,
364-
)
365-
except RecordError as e:
366-
code = e.code if e.code is not None else ExceptionLevels.RECORD_CHECK_FAILED
367-
message = e.message if e.message is not None else MESSAGES[ExceptionLevels.RECORD_CHECK_FAILED]
368-
if e.details is not None:
369-
details = e.details
370-
return ErrorReport(code, message, row, field_name, details, self.summarise)
371-
except Exception as e:
372-
if self.report_unexpected_exception:
373-
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
374-
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, row, field_name, "", self.summarise)
375-
376255
# String Pre-Validation
377256
def validation_for_string_values(self, expression_rule: str, field_name: str, field_value: str) -> ErrorReport:
378257
"""
@@ -419,86 +298,3 @@ def validation_for_string_values(self, expression_rule: str, field_name: str, fi
419298
if self.report_unexpected_exception:
420299
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
421300
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, None, field_name)
422-
423-
# Not Empty Validate
424-
def _validate_not_empty(self, _expression_rule: str, field_name: str, field_value: str) -> ErrorReport:
425-
try:
426-
if not field_value:
427-
raise RecordError(
428-
ExceptionLevels.RECORD_CHECK_FAILED, "Value not empty failure", "Value is empty, not as expected"
429-
)
430-
except RecordError as e:
431-
code = e.code if e.code is not None else ExceptionLevels.RECORD_CHECK_FAILED
432-
message = e.message if e.message is not None else MESSAGES[ExceptionLevels.RECORD_CHECK_FAILED]
433-
if e.details is not None:
434-
details = e.details
435-
return ErrorReport(code, message, None, field_name, details, self.summarise)
436-
except Exception as e:
437-
if self.report_unexpected_exception:
438-
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
439-
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, None, field_name)
440-
441-
# NHSNumber Validate
442-
def _validate_nhs_number(self, _expression_rule: str, field_name: str, field_value: str, row: dict) -> ErrorReport:
443-
try:
444-
regex_rule = r"^6\d{10}$"
445-
result = re.search(regex_rule, field_value)
446-
if not result:
447-
raise RecordError(
448-
ExceptionLevels.RECORD_CHECK_FAILED,
449-
"NHS Number check failed",
450-
"NHS Number does not meet regex rules, data- " + field_value,
451-
)
452-
except RecordError as e:
453-
code = e.code if e.code is not None else ExceptionLevels.RECORD_CHECK_FAILED
454-
message = e.message if e.message is not None else MESSAGES[ExceptionLevels.RECORD_CHECK_FAILED]
455-
if e.details is not None:
456-
details = e.details
457-
return ErrorReport(code, message, row, field_name, details, self.summarise)
458-
except Exception as e:
459-
if self.report_unexpected_exception:
460-
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
461-
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, row, field_name, "", self.summarise)
462-
463-
# Gender Validate
464-
def _validate_gender(self, _expression_rule: str, field_name: str, field_value: str) -> ErrorReport:
465-
try:
466-
rule_list = ["0", "1", "2", "9"]
467-
468-
if field_value not in rule_list:
469-
raise RecordError(
470-
ExceptionLevels.RECORD_CHECK_FAILED,
471-
"Gender check failed",
472-
"Gender value not found in array, data- " + field_value,
473-
)
474-
except RecordError as e:
475-
code = e.code if e.code is not None else ExceptionLevels.RECORD_CHECK_FAILED
476-
message = e.message if e.message is not None else MESSAGES[ExceptionLevels.RECORD_CHECK_FAILED]
477-
if e.details is not None:
478-
details = e.details
479-
return ErrorReport(code, message, None, field_name, details, self.summarise)
480-
except Exception as e:
481-
if self.report_unexpected_exception:
482-
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
483-
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, None, field_name)
484-
485-
# PostCode Validate
486-
def _validate_post_code(self, _expression_rule: str, field_name: str, field_value: str) -> ErrorReport:
487-
try:
488-
# UK postcode regex (allows optional space)
489-
regex_rule = r"^[A-Z]{1,2}\d[A-Z\d]?\s?\d[A-Z]{2}$"
490-
result = re.search(regex_rule, field_value)
491-
if not result:
492-
raise RecordError(
493-
ExceptionLevels.RECORD_CHECK_FAILED, "Postcode check failed", "Postcode does not meet regex rules"
494-
)
495-
except RecordError as e:
496-
code = e.code if e.code is not None else ExceptionLevels.RECORD_CHECK_FAILED
497-
message = e.message if e.message is not None else MESSAGES[ExceptionLevels.RECORD_CHECK_FAILED]
498-
if e.details is not None:
499-
details = e.details
500-
return ErrorReport(code, message, None, field_name, details, self.summarise)
501-
except Exception as e:
502-
if self.report_unexpected_exception:
503-
message = MESSAGES[ExceptionLevels.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)
504-
return ErrorReport(ExceptionLevels.UNEXPECTED_EXCEPTION, message, None, field_name, "", self.summarise)

lambdas/shared/tests/test_common/validator/test_expression_checker.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,82 @@ def test_dose_unit_code_string_valid_and_invalid(self):
357357
msg=f"fieldPath={field_path}",
358358
)
359359

360+
# STRING with DOSE_UNIT_TERM
361+
def test_dose_unit_term_string_valid_and_invalid(self):
362+
checker = self.make_checker()
363+
field_path = "doseQuantity|unit"
364+
self.assertIsNone(
365+
checker.validate_expression("STRING", "", field_path, "milliliter"),
366+
msg=f"fieldPath={field_path}",
367+
)
368+
self.assertIsInstance(
369+
checker.validate_expression("STRING", "", field_path, ""),
370+
ErrorReport,
371+
msg=f"fieldPath={field_path}",
372+
)
373+
self.assertIsInstance(
374+
checker.validate_expression("STRING", "", field_path, 1),
375+
ErrorReport,
376+
msg=f"fieldPath={field_path}",
377+
)
378+
379+
# STRING with INDICATION_CODE
380+
def test_indication_code_string_valid_and_invalid(self):
381+
checker = self.make_checker()
382+
field_path = "reasonCode|#:http://snomed.info/sct|coding|#:http://snomed.info/sct|code"
383+
self.assertIsNone(
384+
checker.validate_expression("STRING", "", field_path, "987654"),
385+
msg=f"fieldPath={field_path}",
386+
)
387+
self.assertIsInstance(
388+
checker.validate_expression("STRING", "", field_path, ""),
389+
ErrorReport,
390+
msg=f"fieldPath={field_path}",
391+
)
392+
self.assertIsInstance(
393+
checker.validate_expression("STRING", "", field_path, 987654),
394+
ErrorReport,
395+
msg=f"fieldPath={field_path}",
396+
)
397+
398+
# STRING with LOCATION_CODE
399+
def test_location_code_string_valid_and_invalid(self):
400+
checker = self.make_checker()
401+
field_path = "location|identifier|value"
402+
self.assertIsNone(
403+
checker.validate_expression("STRING", "", field_path, "LOC-123"),
404+
msg=f"fieldPath={field_path}",
405+
)
406+
self.assertIsInstance(
407+
checker.validate_expression("STRING", "", field_path, ""),
408+
ErrorReport,
409+
msg=f"fieldPath={field_path}",
410+
)
411+
self.assertIsInstance(
412+
checker.validate_expression("STRING", "", field_path, 321),
413+
ErrorReport,
414+
msg=f"fieldPath={field_path}",
415+
)
416+
417+
# STRING with LOCATION_CODE_TYPE_URI
418+
def test_location_code_type_uri_string_valid_and_invalid(self):
419+
checker = self.make_checker()
420+
field_path = "location|identifier|system"
421+
self.assertIsNone(
422+
checker.validate_expression("STRING", "", field_path, "https://example.org/location-code-system"),
423+
msg=f"fieldPath={field_path}",
424+
)
425+
self.assertIsInstance(
426+
checker.validate_expression("STRING", "", field_path, ""),
427+
ErrorReport,
428+
msg=f"fieldPath={field_path}",
429+
)
430+
self.assertIsInstance(
431+
checker.validate_expression("STRING", "", field_path, 0),
432+
ErrorReport,
433+
msg=f"fieldPath={field_path}",
434+
)
435+
360436
# LIST with PERFORMING_PROFESSIONAL_FORENAME (empty rule -> non-empty list)
361437
def test_practitioner_forename_list_valid_and_invalid(self):
362438
checker = self.make_checker()

lambdas/shared/tests/test_common/validator/test_schemas/test_schema.json

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,58 @@
380380
"expressionRule": ""
381381
},
382382
"errorGroup": "consistency"
383+
},
384+
{
385+
"expressionId": "01K8S2C3XTDW9RK9Y2FQ9YM5WJ",
386+
"fieldNameFHIR": "doseQuantity|unit",
387+
"fieldNameFlat": "DOSE_UNIT_TERM",
388+
"fieldNumber": 31,
389+
"errorLevel": 0,
390+
"expression": {
391+
"expressionName": "Dose Unit Term Not Empty Check",
392+
"expressionType": "STRING",
393+
"expressionRule": ""
394+
},
395+
"errorGroup": "completeness"
396+
},
397+
{
398+
"expressionId": "01K8S2CANK2PFNDANX3D04W2NR",
399+
"fieldNameFHIR": "reasonCode|#:http://snomed.info/sct|coding|#:http://snomed.info/sct|code",
400+
"fieldNameFlat": "INDICATION_CODE",
401+
"fieldNumber": 32,
402+
"errorLevel": 0,
403+
"expression": {
404+
"expressionName": "Indication Code Not Empty Check",
405+
"expressionType": "STRING",
406+
"expressionRule": ""
407+
},
408+
"errorGroup": "completeness"
409+
},
410+
{
411+
"expressionId": "01K8S2CKK8FCVJ6049EW5G563P",
412+
"fieldNameFHIR": "location|identifier|value",
413+
"fieldNameFlat": "LOCATION_CODE",
414+
"fieldNumber": 33,
415+
"errorLevel": 1,
416+
"expression": {
417+
"expressionName": "Location Code Default Check",
418+
"expressionType": "STRING",
419+
"expressionRule": ""
420+
},
421+
"errorGroup": "consistency"
422+
},
423+
{
424+
"expressionId": "01K8S2CSWYXJ5WDS7K59A045JR",
425+
"fieldNameFHIR": "location|identifier|system",
426+
"fieldNameFlat": "LOCATION_CODE_TYPE_URI",
427+
"fieldNumber": 34,
428+
"errorLevel": 1,
429+
"expression": {
430+
"expressionName": "Location Code Type URI Default Check",
431+
"expressionType": "STRING",
432+
"expressionRule": ""
433+
},
434+
"errorGroup": "consistency"
383435
}
384436
]
385437
}

0 commit comments

Comments
 (0)