
001package org.hl7.fhir.r4.terminologies; 002 003import org.hl7.fhir.exceptions.FHIRException; 004import org.hl7.fhir.exceptions.PathEngineException; 005import org.hl7.fhir.r4.context.IWorkerContext; 006import org.hl7.fhir.r4.elementmodel.Element; 007import org.hl7.fhir.r4.elementmodel.ObjectConverter; 008import org.hl7.fhir.r4.model.*; 009import org.hl7.fhir.r4.fhirpath.FHIRPathEngine; 010import org.hl7.fhir.r4.fhirpath.ExpressionNode; 011import org.hl7.fhir.r4.fhirpath.TypeDetails; 012import org.hl7.fhir.r4.fhirpath.FHIRPathFunctionDefinition; 013import org.hl7.fhir.r4.fhirpath.FHIRPathUtilityClasses; 014import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome; 015import org.hl7.fhir.utilities.FhirPublication; 016import org.hl7.fhir.utilities.i18n.I18nConstants; 017import org.hl7.fhir.utilities.validation.ValidationOptions; 018 019import java.util.ArrayList; 020import java.util.List; 021 022public class TerminologyFunctions { 023 024 025 public static abstract class TerminologyFunctionBase extends FHIRPathFunctionDefinition { 026 027 protected FHIRException makeExceptionPlural(FHIRPathEngine engine, Integer num, String constName, Object... args) { 028 String fmt = engine.getWorker().formatMessagePlural(num, constName, args); 029 return new PathEngineException(fmt, constName); 030 } 031 032 033 protected FHIRException makeException(FHIRPathEngine engine, ExpressionNode holder, String constName, Object... args) { 034 String fmt = engine.getWorker().formatMessage(constName, args); 035 return new PathEngineException(fmt, constName); 036 } 037 } 038 039 040 public static class TerminologiesObject extends Base { 041 @Override 042 public String fhirType() { 043 return "TerminologyServices"; 044 } 045 046 @Override 047 protected void listChildren(List<Property> result) { 048 049 } 050 051 @Override 052 public String getIdBase() { 053 return null; 054 } 055 056 @Override 057 public void setIdBase(String value) { 058 } 059 060 @Override 061 public Base copy() { 062 return this; 063 } 064 065 } 066 067 public static class ExpandFunction extends TerminologyFunctionBase { 068 069 @Override 070 public String name() { 071 return "expand"; 072 } 073 074 @Override 075 public FHIRPathUtilityClasses.FunctionDetails details() { 076 return new FHIRPathUtilityClasses.FunctionDetails("Perform a value set expansion", 1, 2); 077 } 078 079 @Override 080 public TypeDetails check(FHIRPathEngine engine, Object appContext, TypeDetails focus, List<TypeDetails> parameters) { 081 return new TypeDetails(ExpressionNode.CollectionStatus.SINGLETON, "Resource"); 082 } 083 084 @Override 085 public List<Base> execute(FHIRPathEngine engine, Object appContext, List<Base> focus, List<List<Base>> parameters) { 086 if (focus.size() == 0) { 087 return new ArrayList<Base>(); 088 } 089 if (focus.size() != 1) { 090 throw makeExceptionPlural(engine, focus.size(), I18nConstants.FHIRPATH_FOCUS, "expand", focus.size()); 091 } 092 Base base = focus.get(0); 093 List<Base> result = new ArrayList<Base>(); 094 if (base.fhirType().equals("TerminologyServices") && parameters.size() > 0) { 095 List<Base> param1 = parameters.get(0); 096 if (param1.size() != 1) { 097 throw makeExceptionPlural(engine, param1.size(), I18nConstants.FHIRPATH_PARAMETER_CARD, "valueSet", focus.size()); 098 } 099 ValueSet vs = null; 100 if (param1.get(0).isPrimitive()) { 101 vs = engine.getWorker().fetchResource(ValueSet.class, param1.get(0).primitiveValue()); 102 } else { 103 // nothing 104 } 105 if (vs != null) { 106 ValueSetExpansionOutcome exp = engine.getWorker().expandVS(vs, true, false); 107 if (exp.isOk() && exp.getValueset() != null) { 108 result.add(exp.getValueset()); 109 } 110 } else { 111 throw new Error("Not supported yet"); 112 } 113 } 114 return result; 115 } 116 } 117 118 public static class ValidateVSFunction extends TerminologyFunctionBase { 119 120 @Override 121 public String name() { 122 return "validateVS"; 123 } 124 125 @Override 126 public FHIRPathUtilityClasses.FunctionDetails details() { 127 return new FHIRPathUtilityClasses.FunctionDetails("Validate a code against a ValueSet", 2, 3); 128 } 129 130 @Override 131 public TypeDetails check(FHIRPathEngine engine, Object appContext, TypeDetails focus, List<TypeDetails> parameters) { 132 return new TypeDetails(ExpressionNode.CollectionStatus.SINGLETON, "Parameters"); 133 } 134 135 @Override 136 public List<Base> execute(FHIRPathEngine engine, Object appContext, List<Base> focus, List<List<Base>> parameters) { 137 if (focus.size() == 0) { 138 return new ArrayList<Base>(); 139 } 140 if (focus.size() != 1) { 141 throw makeExceptionPlural(engine, focus.size(), I18nConstants.FHIRPATH_FOCUS, "expand", focus.size()); 142 } 143 Base base = focus.get(0); 144 List<Base> result = new ArrayList<Base>(); 145 if (base.fhirType().equals("TerminologyServices") && parameters.size() > 1) { 146 List<Base> param1 = parameters.get(0); 147 if (param1.size() != 1) { 148 throw makeExceptionPlural(engine, param1.size(), I18nConstants.FHIRPATH_PARAMETER_CARD, "valueSet", focus.size()); 149 } 150 ValueSet vs = null; 151 if (param1.get(0).isPrimitive()) { 152 vs = engine.getWorker().fetchResource(ValueSet.class, param1.get(0).primitiveValue()); 153 } else { 154 // nothing 155 } 156 if (vs != null) { 157 List<Base> param2 = parameters.get(1); 158 if (param2.size() != 1) { 159 throw makeExceptionPlural(engine, param1.size(), I18nConstants.FHIRPATH_PARAMETER_CARD, "coded", focus.size()); 160 } 161 Base coded = param2.get(0); 162 if (coded.isPrimitive()) { 163 IWorkerContext.ValidationResult vr = engine.getWorker().validateCode(ValidationOptions.defaults(), coded.primitiveValue(), vs); 164 result.add(vr.getOrMakeParameters()); 165 } else if ("Coding".equals(coded.fhirType())) { 166 Coding coding = coded instanceof Coding ? (Coding) coded : ObjectConverter.readAsCoding((Element) coded); 167 IWorkerContext.ValidationResult vr = engine.getWorker().validateCode(ValidationOptions.defaults(), coded.primitiveValue(), vs); 168 result.add(vr.getOrMakeParameters()); 169 } else if ("CodeableConcept".equals(coded.fhirType())) { 170 CodeableConcept cc = coded instanceof CodeableConcept ? (CodeableConcept) coded : ObjectConverter.readAsCodeableConcept((Element) coded); 171 IWorkerContext.ValidationResult vr = engine.getWorker().validateCode(ValidationOptions.defaults(), coded.primitiveValue(), vs); 172 result.add(vr.getOrMakeParameters()); 173 } 174 } 175 } 176 return result; 177 } 178 } 179 180 181 public static class TranslateFunction extends TerminologyFunctionBase { 182 183 @Override 184 public String name() { 185 return "translate"; 186 } 187 188 @Override 189 public FHIRPathUtilityClasses.FunctionDetails details() { 190 return new FHIRPathUtilityClasses.FunctionDetails("Translate from terminology to another", 2, 3); 191 } 192 193 @Override 194 public TypeDetails check(FHIRPathEngine engine, Object appContext, TypeDetails focus, List<TypeDetails> parameters) { 195 return new TypeDetails(ExpressionNode.CollectionStatus.SINGLETON, "Parameters"); 196 } 197 198 @Override 199 public List<Base> execute(FHIRPathEngine engine, Object appContext, List<Base> focus, List<List<Base>> parameters) { 200 if (focus.size() == 0) { 201 return new ArrayList<Base>(); 202 } 203 if (focus.size() != 1) { 204 throw makeExceptionPlural(engine, focus.size(), I18nConstants.FHIRPATH_FOCUS, "expand", focus.size()); 205 } 206 Base base = focus.get(0); 207 List<Base> result = new ArrayList<Base>(); 208 if (base.fhirType().equals("TerminologyServices") && parameters.size() > 1) { 209 List<Base> param1 = parameters.get(0); 210 if (param1.size() != 1) { 211 throw makeExceptionPlural(engine, param1.size(), I18nConstants.FHIRPATH_PARAMETER_CARD, "valueSet", focus.size()); 212 } 213 ConceptMap cm = null; 214 if (param1.get(0).isPrimitive()) { 215 cm = engine.getWorker().fetchResource(ConceptMap.class, param1.get(0).primitiveValue()); 216 } else { 217 // nothing 218 } 219 if (cm != null) { 220 List<Base> param2 = parameters.get(1); 221 if (param2.size() != 1) { 222 throw makeExceptionPlural(engine, param1.size(), I18nConstants.FHIRPATH_PARAMETER_CARD, "coded", focus.size()); 223 } 224 Base coded = param2.get(0); 225 if (coded.isPrimitive()) { 226 Parameters p = new ConceptTranslationEngine(engine.getWorker()).translateCode(coded.primitiveValue(), cm); 227 result.add(p); 228 } else if ("Coding".equals(coded.fhirType())) { 229 Coding coding = coded instanceof Coding ? (Coding) coded : ObjectConverter.readAsCoding((Element) coded); 230 Parameters p = new ConceptTranslationEngine(engine.getWorker()).translateCoding(coding, cm); 231 result.add(p); 232 } 233 } 234 } 235 return result; 236 } 237 } 238 239}