From 1b0c62bbec8e9fbf265153b520be405ccdb62fc1 Mon Sep 17 00:00:00 2001 From: Lee Surprenant Date: Mon, 21 Mar 2022 16:11:37 -0400 Subject: [PATCH] issue #3490 - patch us core 4.0 fhirpath expressions Add tests under com.ibm.fhir.ig.us.core.test.v400.ConformanceTest to show the issues. For Provenance: fix provenance-1 to handle multiple agents For Condition: fix us-core-1 to handle multiple categories Signed-off-by: Lee Surprenant --- conformance/fhir-ig-us-core/CHANGELOG | 4 +- ...StructureDefinition-us-core-condition.json | 4 +- ...tructureDefinition-us-core-provenance.json | 28 +++--- .../ig/us/core/test/v400/ConformanceTest.java | 96 +++++++++++++++++++ .../com/ibm/fhir/path/util/FHIRPathUtil.java | 3 +- 5 files changed, 117 insertions(+), 18 deletions(-) diff --git a/conformance/fhir-ig-us-core/CHANGELOG b/conformance/fhir-ig-us-core/CHANGELOG index 6716a175e77..a7b1eae1872 100644 --- a/conformance/fhir-ig-us-core/CHANGELOG +++ b/conformance/fhir-ig-us-core/CHANGELOG @@ -24,4 +24,6 @@ Source - http://hl7.org/fhir/us/core/STU3.1.1/ Source - https://www.hl7.org/fhir/us/core/stu4/ - Examples are under src/test/resources/JSON/400 - Replace all narrative text with minimal placeholder for space efficiency -- Revised Endpoint in the Practitioner endpoint so it points to relative path, not absolute path \ No newline at end of file +- Revised Endpoint in the Practitioner endpoint so it points to relative path, not absolute path +- Move provenance-1 constraint from Provenance.agent.onBehalfOf to Provenance.agent and fix the expression (https://jira.hl7.org/browse/FHIR-36328) +- Fix Condition constraint us-core-1 expression (https://jira.hl7.org/browse/FHIR-36336) \ No newline at end of file diff --git a/conformance/fhir-ig-us-core/src/main/resources/hl7/fhir/us/core/400/package/StructureDefinition-us-core-condition.json b/conformance/fhir-ig-us-core/src/main/resources/hl7/fhir/us/core/400/package/StructureDefinition-us-core-condition.json index 1ce501a61c0..92d2fe2de4b 100644 --- a/conformance/fhir-ig-us-core/src/main/resources/hl7/fhir/us/core/400/package/StructureDefinition-us-core-condition.json +++ b/conformance/fhir-ig-us-core/src/main/resources/hl7/fhir/us/core/400/package/StructureDefinition-us-core-condition.json @@ -183,7 +183,7 @@ "key": "us-core-1", "severity": "warning", "human": "A code in Condition.category SHOULD be from US Core Condition Category Codes value set.", - "expression": "where(category.memberOf('http://hl7.org/fhir/us/core/ValueSet/us-core-condition-category')).exists()", + "expression": "category.where(memberOf('http://hl7.org/fhir/us/core/ValueSet/us-core-condition-category')).exists()", "xpath": "(no xpath equivalent)" } ], @@ -2019,7 +2019,7 @@ "key": "us-core-1", "severity": "warning", "human": "A code in Condition.category SHOULD be from US Core Condition Category Codes value set.", - "expression": "where(category.memberOf('http://hl7.org/fhir/us/core/ValueSet/us-core-condition-category')).exists()", + "expression": "category.where(memberOf('http://hl7.org/fhir/us/core/ValueSet/us-core-condition-category')).exists()", "xpath": "(no xpath equivalent)" } ], diff --git a/conformance/fhir-ig-us-core/src/main/resources/hl7/fhir/us/core/400/package/StructureDefinition-us-core-provenance.json b/conformance/fhir-ig-us-core/src/main/resources/hl7/fhir/us/core/400/package/StructureDefinition-us-core-provenance.json index 38e9db55170..671da35f372 100644 --- a/conformance/fhir-ig-us-core/src/main/resources/hl7/fhir/us/core/400/package/StructureDefinition-us-core-provenance.json +++ b/conformance/fhir-ig-us-core/src/main/resources/hl7/fhir/us/core/400/package/StructureDefinition-us-core-provenance.json @@ -1149,6 +1149,12 @@ "expression": "hasValue() or (children().count() > id.count())", "xpath": "@value|f:*|h:div", "source": "http://hl7.org/fhir/StructureDefinition/Element" + }, + { + "key": "provenance-1", + "severity": "error", + "human": "onBehalfOf SHALL be present when Provenance.agent.who is a Practitioner or Device", + "expression": "((who.resolve() is Practitioner) or (who.resolve() is Device)) implies onBehalfOf.exists()" } ], "mustSupport": true, @@ -1537,12 +1543,6 @@ "expression": "hasValue() or (children().count() > id.count())", "xpath": "@value|f:*|h:div", "source": "http://hl7.org/fhir/StructureDefinition/Element" - }, - { - "key": "provenance-1", - "severity": "error", - "human": "onBehalfOf SHALL be present when Provenance.agent.who is a Practitioner or Device", - "expression": "((%resource.agent.who.resolve() is Practitioner) or (%resource.agent.who.resolve() is Device)) implies exists()" } ], "mustSupport": true, @@ -2796,6 +2796,14 @@ }, "min": 1, "max": "*", + "constraint": [ + { + "key": "provenance-1", + "severity": "error", + "human": "onBehalfOf SHALL be present when Provenance.agent.who is a Practitioner or Device", + "expression": "((who.resolve() is Practitioner) or (who.resolve() is Device)) implies onBehalfOf.exists()" + } + ], "mustSupport": true, "isModifier": false }, @@ -2885,14 +2893,6 @@ ] } ], - "constraint": [ - { - "key": "provenance-1", - "severity": "error", - "human": "onBehalfOf SHALL be present when Provenance.agent.who is a Practitioner or Device", - "expression": "((%resource.agent.who.resolve() is Practitioner) or (%resource.agent.who.resolve() is Device)) implies exists()" - } - ], "mustSupport": true, "isModifier": false }, diff --git a/conformance/fhir-ig-us-core/src/test/java/com/ibm/fhir/ig/us/core/test/v400/ConformanceTest.java b/conformance/fhir-ig-us-core/src/test/java/com/ibm/fhir/ig/us/core/test/v400/ConformanceTest.java index ac8cac479cd..b3506e9cc77 100644 --- a/conformance/fhir-ig-us-core/src/test/java/com/ibm/fhir/ig/us/core/test/v400/ConformanceTest.java +++ b/conformance/fhir-ig-us-core/src/test/java/com/ibm/fhir/ig/us/core/test/v400/ConformanceTest.java @@ -25,23 +25,34 @@ import com.ibm.fhir.model.format.Format; import com.ibm.fhir.model.parser.FHIRParser; +import com.ibm.fhir.model.patch.exception.FHIRPatchException; import com.ibm.fhir.model.resource.Bundle; import com.ibm.fhir.model.resource.CarePlan; +import com.ibm.fhir.model.resource.Condition; import com.ibm.fhir.model.resource.Observation; import com.ibm.fhir.model.resource.OperationOutcome.Issue; import com.ibm.fhir.model.resource.Patient; +import com.ibm.fhir.model.resource.Provenance; +import com.ibm.fhir.model.resource.Provenance.Agent; import com.ibm.fhir.model.resource.Resource; import com.ibm.fhir.model.type.Code; +import com.ibm.fhir.model.type.CodeableConcept; import com.ibm.fhir.model.type.Coding; import com.ibm.fhir.model.type.Extension; import com.ibm.fhir.model.type.HumanName; import com.ibm.fhir.model.type.Identifier; +import com.ibm.fhir.model.type.Instant; +import com.ibm.fhir.model.type.Narrative; +import com.ibm.fhir.model.type.Reference; import com.ibm.fhir.model.type.Uri; import com.ibm.fhir.model.type.code.AdministrativeGender; import com.ibm.fhir.model.type.code.IssueSeverity; import com.ibm.fhir.path.FHIRPathNode; import com.ibm.fhir.path.evaluator.FHIRPathEvaluator; +import com.ibm.fhir.path.exception.FHIRPathException; +import com.ibm.fhir.path.util.FHIRPathUtil; import com.ibm.fhir.validation.FHIRValidator; +import com.ibm.fhir.validation.exception.FHIRValidationException; public class ConformanceTest { @Test @@ -507,4 +518,89 @@ public void testUSCoreRaceExtension4() throws Exception { Assert.assertEquals(countInformation(issues), 1); } + @Test + void testConditionWithMultipleCategory() throws FHIRValidationException { + Condition condition = Condition.builder() + .text(Narrative.EMPTY) + .clinicalStatus(CodeableConcept.builder() + .coding(Coding.builder() + .system(Uri.of("http://terminology.hl7.org/CodeSystem/condition-clinical")) + .code(Code.of("active")) + .build()) + .build()) + .subject(Reference.builder() + .display("ref") + .build()) + .code(CodeableConcept.builder() + .coding(Coding.builder() + .system(Uri.of("http://snomed.info/sct")) + .code(Code.of("404684003")) + .build()) + .build()) + .category(CodeableConcept.builder() + .text("test") + .build()) + .category(CodeableConcept.builder() + .coding(Coding.builder() + .system(Uri.of("http://hl7.org/fhir/us/core/STU4/CodeSystem-condition-category.html")) + .code(Code.of("health-concern")) + .build()) + .build()) + .build(); + + FHIRValidator validator = FHIRValidator.validator(); + List issues = validator.validate(condition, "http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"); + + issues.forEach(System.out::println); + + Assert.assertEquals(countErrors(issues), 0); + // warning 1: us-core-1: A code in Condition.category SHOULD be from US Core Condition Category Codes value set. + // causedBy + // warning 2: Membership check was not performed: value set 'http://hl7.org/fhir/us/core/ValueSet/us-core-condition-code' is empty or could not be expanded + Assert.assertEquals(countWarnings(issues), 2); + } + + @Test + void testProvenanceWithMultipleAgent() throws FHIRValidationException, FHIRPathException, FHIRPatchException { + Provenance provenance = Provenance.builder() + .text(Narrative.EMPTY) + .target(Reference.builder() + .reference("Observation/123") + .build()) + .recorded(Instant.now()) + .agent(Agent.builder() + .who(Reference.builder() + .reference("Patient/123") + .build()) + .build()) + .agent(Agent.builder() + .who(Reference.builder() + .reference("Practitioner/abc") + .build()) + .build()) + .agent(Agent.builder() + .who(Reference.builder() + .reference("Device/xyz") + .build()) + .onBehalfOf(Reference.builder() + .reference("RelatedPerson/bleh") + .build()) + .build()) + .build(); + + FHIRValidator validator = FHIRValidator.validator(); + List issues = validator.validate(provenance, "http://hl7.org/fhir/us/core/StructureDefinition/us-core-provenance"); + + issues.forEach(System.out::println); + + Assert.assertEquals(countErrors(issues), 1); + Assert.assertEquals(countWarnings(issues), 0); + + Reference refToAdd = Reference.builder() + .reference("Organization/fix") + .build(); + provenance = FHIRPathUtil.add(provenance, "Provenance.agent[1]", "onBehalfOf", refToAdd); + issues = validator.validate(provenance, "http://hl7.org/fhir/us/core/StructureDefinition/us-core-provenance"); + Assert.assertEquals(countErrors(issues), 0); + } } \ No newline at end of file diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/util/FHIRPathUtil.java b/fhir-path/src/main/java/com/ibm/fhir/path/util/FHIRPathUtil.java index 2e4749735ce..96f12153e2b 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/util/FHIRPathUtil.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/util/FHIRPathUtil.java @@ -1,5 +1,5 @@ /* - * (C) Copyright IBM Corp. 2019, 2021 + * (C) Copyright IBM Corp. 2019, 2022 * * SPDX-License-Identifier: Apache-2.0 */ @@ -909,6 +909,7 @@ public static T delete(T elementOrResource, String fhirPat } /** + * @param elementOrResource * @param fhirPath * @param value * @throws FHIRPathException