get .ofType() working in discriminators (round #1!) + Improve Error message when snapshot can't be generated

This commit is contained in:
Grahame Grieve 2021-12-22 22:39:00 +11:00
parent c86b8114dd
commit 04c7111eb6
2 changed files with 88 additions and 55 deletions

View File

@ -208,6 +208,34 @@ public class FHIRPathEngine {
}
}
public static class TypedElementDefinition {
private ElementDefinition element;
private String type;
public TypedElementDefinition(ElementDefinition element, String type) {
super();
this.element = element;
this.type = type;
}
public TypedElementDefinition(ElementDefinition element) {
super();
this.element = element;
}
public ElementDefinition getElement() {
return element;
}
public String getType() {
return type;
}
public List<TypeRefComponent> getTypes() {
List<TypeRefComponent> res = new ArrayList<ElementDefinition.TypeRefComponent>();
for (TypeRefComponent tr : element.getType()) {
if (type == null || type.equals(tr.getCode())) {
res.add(tr);
}
}
return res;
}
}
private IWorkerContext worker;
private IEvaluationContext hostServices;
private StringBuilder log = new StringBuilder();
@ -5442,63 +5470,63 @@ public class FHIRPathEngine {
* @throws PathEngineException
* @throws DefinitionException
*/
public ElementDefinition evaluateDefinition(ExpressionNode expr, StructureDefinition profile, ElementDefinition element, StructureDefinition source) throws DefinitionException {
public TypedElementDefinition evaluateDefinition(ExpressionNode expr, StructureDefinition profile, TypedElementDefinition element, StructureDefinition source) throws DefinitionException {
StructureDefinition sd = profile;
ElementDefinition focus = null;
TypedElementDefinition focus = null;
boolean okToNotResolve = false;
if (expr.getKind() == Kind.Name) {
if (element.hasSlicing()) {
ElementDefinition slice = pickMandatorySlice(sd, element);
if (element.getElement().hasSlicing()) {
ElementDefinition slice = pickMandatorySlice(sd, element.getElement());
if (slice == null) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getId());
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getElement().getId());
}
element = slice;
element = new TypedElementDefinition(slice);
}
if (expr.getName().equals("$this")) {
focus = element;
} else {
List<ElementDefinition> childDefinitions;
childDefinitions = profileUtilities.getChildMap(sd, element);
childDefinitions = profileUtilities.getChildMap(sd, element.getElement());
// if that's empty, get the children of the type
if (childDefinitions.isEmpty()) {
sd = fetchStructureByType(element, expr);
if (sd == null) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getType().get(0).getProfile(), element.getId());
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getElement().getType().get(0).getProfile(), element.getElement().getId());
}
childDefinitions = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep());
}
for (ElementDefinition t : childDefinitions) {
if (tailMatches(t, expr.getName()) && !t.hasSlicing()) { // GG: slicing is a problem here. This is for an exetnsion with a fixed value (type slicing)
focus = t;
focus = new TypedElementDefinition(t);
break;
}
}
}
} else if (expr.getKind() == Kind.Function) {
if ("resolve".equals(expr.getName())) {
if (!element.hasType()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getId());
if (element.getTypes().size() == 0) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getElement().getId());
}
if (element.getType().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getId());
if (element.getTypes().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getElement().getId());
}
if (!element.getType().get(0).hasTarget()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getId(), element.getType().get(0).getCode()+")");
if (!element.getTypes().get(0).hasTarget()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getElement().getId(), element.getElement().getType().get(0).getCode()+")");
}
if (element.getType().get(0).getTargetProfile().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getId());
if (element.getTypes().get(0).getTargetProfile().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getElement().getId());
}
sd = worker.fetchResource(StructureDefinition.class, element.getType().get(0).getTargetProfile().get(0).getValue());
sd = worker.fetchResource(StructureDefinition.class, element.getTypes().get(0).getTargetProfile().get(0).getValue());
if (sd == null) {
throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getType().get(0).getTargetProfile(), element.getId());
throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getTypes().get(0).getTargetProfile(), element.getElement().getId());
}
focus = sd.getSnapshot().getElementFirstRep();
focus = new TypedElementDefinition(sd.getSnapshot().getElementFirstRep());
} else if ("extension".equals(expr.getName())) {
String targetUrl = expr.getParameters().get(0).getConstant().primitiveValue();
List<ElementDefinition> childDefinitions = profileUtilities.getChildMap(sd, element);
List<ElementDefinition> childDefinitions = profileUtilities.getChildMap(sd, element.getElement());
for (ElementDefinition t : childDefinitions) {
if (t.getPath().endsWith(".extension") && t.hasSliceName()) {
System.out.println("t: "+t.getId());
@ -5511,29 +5539,33 @@ public class FHIRPathEngine {
if (profileUtilities.getChildMap(sd, t).isEmpty()) {
sd = exsd;
}
focus = t;
focus = new TypedElementDefinition(t);
break;
}
}
}
if (focus == null) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND_EXTENSION, expr.toString(), targetUrl, element.getId(), sd.getUrl());
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND_EXTENSION, expr.toString(), targetUrl, element.getElement().getId(), sd.getUrl());
}
} else if ("ofType".equals(expr.getName())) {
if (!element.hasType()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getId());
if (!element.getElement().hasType()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getElement().getId());
}
if (element.getType().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE, element.getId());
List<String> atn = new ArrayList<>();
for (TypeRefComponent tr : element.getTypes()) {
if (!tr.hasCode()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getElement().getId());
}
atn.add(tr.getCode());
}
if (!element.getType().get(0).hasCode()) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getId());
}
String atn = element.getType().get(0).getCode();
String stn = expr.getParameters().get(0).getName();
okToNotResolve = true;
if ((atn.equals(stn))) {
focus = element;
if ((atn.contains(stn))) {
if (element.getTypes().size() > 1) {
focus = new TypedElementDefinition(element.getElement(), stn);
} else {
focus = element;
}
}
} else {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_NAME, expr.getName());
@ -5548,7 +5580,7 @@ public class FHIRPathEngine {
if (okToNotResolve) {
return null;
} else {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString(), source.getUrl(), element.getId(), profile.getUrl());
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString(), source.getUrl(), element.getElement().getId(), profile.getUrl());
}
} else if (expr.getInner() == null) {
return focus;
@ -5568,20 +5600,20 @@ public class FHIRPathEngine {
}
private StructureDefinition fetchStructureByType(ElementDefinition ed, ExpressionNode expr) throws DefinitionException {
if (ed.getType().size() == 0) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NOTYPE, ed.getId());
private StructureDefinition fetchStructureByType(TypedElementDefinition ed, ExpressionNode expr) throws DefinitionException {
if (ed.getTypes().size() == 0) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NOTYPE, ed.getElement().getId());
}
if (ed.getType().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES, ed.getId());
if (ed.getTypes().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES, ed.getElement().getId());
}
if (ed.getType().get(0).getProfile().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES, ed.getId());
if (ed.getTypes().get(0).getProfile().size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES, ed.getElement().getId());
}
if (ed.getType().get(0).hasProfile()) {
return worker.fetchResource(StructureDefinition.class, ed.getType().get(0).getProfile().get(0).getValue());
if (ed.getTypes().get(0).hasProfile()) {
return worker.fetchResource(StructureDefinition.class, ed.getTypes().get(0).getProfile().get(0).getValue());
} else {
return worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getType().get(0).getCode(), worker.getOverrideVersionNs()));
return worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getTypes().get(0).getCode(), worker.getOverrideVersionNs()));
}
}

View File

@ -135,6 +135,7 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorCla
import org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.FHIRPathEngine.TypedElementDefinition;
import org.hl7.fhir.r5.utils.validation.*;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
@ -3370,7 +3371,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
discriminator = discriminator.substring(0, discriminator.length() - 10);
}
ElementDefinition ed = null;
TypedElementDefinition ted = null;
String fp = fixExpr(discriminator, null);
ExpressionNode expr = null;
try {
@ -3380,10 +3381,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
throw new FHIRException(context.formatMessage(I18nConstants.DISCRIMINATOR_BAD_PATH, e.getMessage(), fp), e);
}
long t2 = System.nanoTime();
ed = fpe.evaluateDefinition(expr, profile, element, srcProfile);
ted = fpe.evaluateDefinition(expr, profile, new TypedElementDefinition(element), srcProfile);
timeTracker.sd(t2);
if (ed != null)
elements.add(ed);
if (ted != null)
elements.add(ted.getElement());
for (TypeRefComponent type : element.getType()) {
for (CanonicalType p : type.getProfile()) {
@ -3405,10 +3406,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
expr = fpe.parse(fp);
t2 = System.nanoTime();
ed = fpe.evaluateDefinition(expr, profile, element, srcProfile);
ted = fpe.evaluateDefinition(expr, profile, new TypedElementDefinition(element), srcProfile);
timeTracker.sd(t2);
if (ed != null)
elements.add(ed);
if (ted != null)
elements.add(ted.getElement());
}
}
return elements;
@ -4452,7 +4453,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
return;
}
if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), defn.hasSnapshot(), I18nConstants.VALIDATION_VAL_PROFILE_NOSNAPSHOT)) {
if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), defn.hasSnapshot(), I18nConstants.VALIDATION_VAL_PROFILE_NOSNAPSHOT, defn.getUrl())) {
List<ValidationMessage> localErrors = new ArrayList<ValidationMessage>();
resTracker.startValidating(defn);
trackUsage(defn, hostContext, element);
@ -4644,7 +4645,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
timeTracker.sd(t);
trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE, resourceName)) {
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_EXPL, special.toHuman(), resourceName, typeForResource.getProfile().get(0).asStringValue())) {
validateResource(hc, errors, resource, element, profile, idstatus, stack);
}
} else if (typeForResource.getProfile().isEmpty()) {
@ -4654,7 +4655,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
timeTracker.sd(t);
trackUsage(profile, hostContext, element);
if (rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE, resourceName)) {
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special.toHuman(), resourceName)) {
validateResource(hc, errors, resource, element, profile, idstatus, stack);
}
} else {
@ -4663,7 +4664,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
b.append(u.asStringValue());
}
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES, typeForResource.getCode(), b.toString());
false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES, special.toHuman(), typeForResource.getCode(), b.toString());
}
}
} else {