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