From ce46eee731a1e4ee2e457eafe1c70128977042b8 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 8 May 2023 13:30:04 -0500 Subject: [PATCH] return codeableConcept from validate-code --- .../hl7/fhir/r5/context/IWorkerContext.java | 13 +++++++++- .../hl7/fhir/r5/model/CodeableConcept.java | 7 ++++++ .../validation/ValueSetValidator.java | 24 ++++++++++++++----- .../ExternalTerminologyServiceTests.java | 4 +++- .../tests/TerminologyServiceTests.java | 3 +++ 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java index 56db42573..4c084f5ac 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java @@ -122,6 +122,7 @@ public interface IWorkerContext { private String txLink; private String diagnostics; private List issues = new ArrayList<>(); + private CodeableConcept codeableConcept; @Override public String toString() { @@ -276,7 +277,17 @@ public interface IWorkerContext { public List getIssues() { return issues; } - + + public ValidationResult addCodeableConcept(CodeableConcept vcc) { + if (!vcc.isEmpty()) { + codeableConcept = vcc; + } + return this; + } + + public CodeableConcept getCodeableConcept() { + return codeableConcept; + } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CodeableConcept.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CodeableConcept.java index 2d2d12aab..b0263f178 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CodeableConcept.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CodeableConcept.java @@ -408,6 +408,13 @@ public boolean hasCoding(String system, String code) { @Override public String toString() { return hasCoding() ? getCoding().toString() : "["+getText()+"]"; + } + + public void removeCoding(String system, String version, String code) { + getCoding().removeIf(c -> + (system == null || system.equals(c.getSystem())) && + (version == null || version.equals(c.getVersion())) && + (code == null || code.equals(c.getCode()))); } // end addition diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java index f9b7989c2..c4f542171 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java @@ -158,6 +158,7 @@ public class ValueSetValidator { // first, we validate the codings themselves ValidationProcessInfo info = new ValidationProcessInfo(); + CodeableConcept vcc = new CodeableConcept(); if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) { int i = 0; for (Coding c : code.getCoding()) { @@ -183,7 +184,7 @@ public class ValueSetValidator { } } else { c.setUserData("cs", cs); - res = validateCode(path+".coding["+i+"]", c, cs); + res = validateCode(path+".coding["+i+"]", c, cs, vcc); } info.getIssues().addAll(res.getIssues()); i++; @@ -202,6 +203,12 @@ public class ValueSetValidator { } else if (ok) { result = true; foundCoding = c; + if (options.getValueSetMode() == ValueSetMode.CHECK_MEMERSHIP_ONLY) { + vcc.addCoding().setSystem(c.getSystem()).setVersion(c.getVersion()).setCode(c.getCode()); + } + } + if (ok == null || !ok) { + vcc.removeCoding(c.getSystem(), c.getVersion(), c.getCode()); } } if (result == null) { @@ -222,6 +229,7 @@ public class ValueSetValidator { res.setVersion(foundCoding.hasVersion() ? foundCoding.getVersion() : ((CodeSystem) foundCoding.getUserData("cs")).getVersion()); res.setDisplay(cd.getDisplay()); } + res.addCodeableConcept(vcc); return res; } else if (foundCoding == null) { return new ValidationResult(IssueSeverity.ERROR, "Internal Error that should not happen", makeIssue(IssueSeverity.FATAL, IssueType.EXCEPTION, path, "Internal Error that should not happen")); @@ -229,11 +237,11 @@ public class ValueSetValidator { String disp = lookupDisplay(foundCoding); ConceptDefinitionComponent cd = new ConceptDefinitionComponent(foundCoding.getCode()); cd.setDisplay(disp); - return new ValidationResult(IssueSeverity.WARNING, info.summary(), foundCoding.getSystem(), getVersion(foundCoding), cd, disp, info.getIssues()); + return new ValidationResult(IssueSeverity.WARNING, info.summary(), foundCoding.getSystem(), getVersion(foundCoding), cd, disp, info.getIssues()).addCodeableConcept(vcc); } else { ConceptDefinitionComponent cd = new ConceptDefinitionComponent(foundCoding.getCode()); cd.setDisplay(lookupDisplay(foundCoding)); - return new ValidationResult(foundCoding.getSystem(), getVersion(foundCoding), cd, getPreferredDisplay(cd, null)); + return new ValidationResult(foundCoding.getSystem(), getVersion(foundCoding), cd, getPreferredDisplay(cd, null)).addCodeableConcept(vcc); } } @@ -406,7 +414,7 @@ public class ValueSetValidator { // we can't validate that here. throw new FHIRException("Unable to evaluate based on empty code system"); } - res = validateCode(path, code, cs); + res = validateCode(path, code, cs, null); } else if (cs == null && valueset.hasExpansion() && inExpansion) { // we just take the value set as face value then res = new ValidationResult(system, wv, new ConceptDefinitionComponent().setCode(code.getCode()).setDisplay(code.getDisplay()), code.getDisplay()); @@ -589,7 +597,7 @@ public class ValueSetValidator { return false; } - private ValidationResult validateCode(String path, Coding code, CodeSystem cs) { + private ValidationResult validateCode(String path, Coding code, CodeSystem cs, CodeableConcept vcc) { ConceptDefinitionComponent cc = cs.hasUserData("tx.cs.special") ? ((SpecialCodeSystem) cs.getUserData("tx.cs.special")).findConcept(code) : findCodeInConcept(cs.getConcept(), code.getCode()); if (cc == null) { if (cs.getContent() == CodeSystemContentMode.FRAGMENT) { @@ -600,8 +608,12 @@ public class ValueSetValidator { return new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path+".code", msg)); } } + Coding vc = new Coding().setCode(code.getCode()).setSystem(cs.getUrl()).setVersion(cs.getVersion()).setDisplay(getPreferredDisplay(cc, cs)); + if (vcc != null) { + vcc.addCoding(vc); + } if (code.getDisplay() == null) { - return new ValidationResult(code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs)); + return new ValidationResult(code.getSystem(), cs.getVersion(), cc, vc.getDisplay()); } CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); if (cc.hasDisplay() && isOkLanguage(cs.getLanguage())) { diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/ExternalTerminologyServiceTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/ExternalTerminologyServiceTests.java index c8dd54694..744a08f0c 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/ExternalTerminologyServiceTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/ExternalTerminologyServiceTests.java @@ -49,8 +49,10 @@ public class ExternalTerminologyServiceTests implements ITxTesterLoader { } private static final String SERVER = FhirSettings.getTxFhirDevelopment(); -// private static final String SERVER = FhirSettings.getTxFhirLocal(); +// private static final String SERVER = FhirSettings.getTxFhirLocal(); +// private static final String SERVER = "https://r4.ontoserver.csiro.au/fhir"; + @Parameters(name = "{index}: id {0}") public static Iterable data() throws IOException { diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java index c167b2fd4..6f1afd246 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java @@ -274,6 +274,9 @@ public class TerminologyServiceTests { if (vm.getDisplay() != null) { res.addParameter("display", vm.getDisplay()); } + if (vm.getCodeableConcept() != null) { + res.addParameter("codeableConcept", vm.getCodeableConcept()); + } if (vm.getIssues().size() > 0) { OperationOutcome oo = new OperationOutcome(); oo.getIssue().addAll(vm.getIssues());