mirror of
https://github.com/hapifhir/org.hl7.fhir.core.git
synced 2025-03-01 17:09:08 +00:00
More improved FHIRPath checking when validating
This commit is contained in:
parent
5026ff3506
commit
b42c908328
@ -42,6 +42,7 @@ import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
|
||||
import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
|
||||
@ -115,6 +116,16 @@ public class TypeDetails {
|
||||
public boolean isSystemType() {
|
||||
return uri.startsWith(FP_NS);
|
||||
}
|
||||
|
||||
public String describeMin() {
|
||||
if (uri.startsWith(FP_NS)) {
|
||||
return "System."+uri.substring(FP_NS.length());
|
||||
}
|
||||
if (uri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
return "FHIR."+uri.substring("http://hl7.org/fhir/StructureDefinition/".length());
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -399,6 +410,12 @@ public class TypeDetails {
|
||||
public String describe() {
|
||||
return getTypes().toString();
|
||||
}
|
||||
public String describeMin() {
|
||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||
for (ProfiledType pt : types)
|
||||
b.append(pt.describeMin());
|
||||
return b.toString();
|
||||
}
|
||||
public String getType() {
|
||||
for (ProfiledType pt : types)
|
||||
return pt.uri;
|
||||
|
@ -3387,8 +3387,12 @@ public class FHIRPathEngine {
|
||||
return td;
|
||||
}
|
||||
case OfType : {
|
||||
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
|
||||
TypeDetails td = new TypeDetails(CollectionStatus.SINGLETON, exp.getParameters().get(0).getName());
|
||||
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
|
||||
String tn = exp.getParameters().get(0).getName();
|
||||
if (typeCastIsImpossible(focus, tn)) {
|
||||
typeWarnings.add(worker.formatMessage(I18nConstants.FHIRPATH_OFTYPE_IMPOSSIBLE, focus.describeMin(), tn, exp.toString()));
|
||||
}
|
||||
TypeDetails td = new TypeDetails(CollectionStatus.SINGLETON, tn);
|
||||
if (td.typesHaveTargets()) {
|
||||
td.addTargets(focus.getTargets());
|
||||
}
|
||||
@ -3707,6 +3711,10 @@ public class FHIRPathEngine {
|
||||
throw new Error("not Implemented yet");
|
||||
}
|
||||
|
||||
private boolean typeCastIsImpossible(TypeDetails focus, String tn) {
|
||||
return !focus.hasType(tn);
|
||||
}
|
||||
|
||||
private boolean isExpressionParameter(ExpressionNode exp, int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
|
@ -947,6 +947,8 @@ public class I18nConstants {
|
||||
public static final String FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT = "FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT";
|
||||
public static final String FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT = "FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT";
|
||||
public static final String ED_INVARIANT_KEY_ALREADY_USED = "ED_INVARIANT_KEY_ALREADY_USED";
|
||||
public static final String FHIRPATH_OFTYPE_IMPOSSIBLE = "FHIRPATH_OFTYPE_IMPOSSIBLE";
|
||||
public static final String ED_SEARCH_EXPRESSION_ERROR = "ED_SEARCH_EXPRESSION_ERROR";
|
||||
|
||||
|
||||
|
||||
|
@ -1003,3 +1003,5 @@ LIQUID_VARIABLE_ILLEGAL = Liquid Exception: The variable name ''{0}'' cannot be
|
||||
ED_INVARIANT_DIFF_NO_SOURCE = The invariant {0} defined in the differential must have no source, or the source must be the same as the profile
|
||||
FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT = The left side is inherently a collection, and so the expression ''{0}'' may fail or return false if there is more than one item in the content being evaluated
|
||||
FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT = The right side is inherently a collection, and so this expression ''{0}'' may fail or return false if there is more than one item in the content being evaluated
|
||||
FHIRPATH_OFTYPE_IMPOSSIBLE = The type specified in ofType is {1} which is not a possible candidate for the existing types ({0}) in the expression {2}. Check the paths and types to be sure this is what is intended
|
||||
ED_SEARCH_EXPRESSION_ERROR = Error in search expression ''{0}'': {1}
|
@ -46,9 +46,16 @@ public class SearchParameterValidator extends BaseValidator {
|
||||
|
||||
public boolean validateSearchParameter(List<ValidationMessage> errors, Element cs, NodeStack stack) {
|
||||
boolean ok = true;
|
||||
String url = cs.getNamedChildValue("url");
|
||||
String master = cs.getNamedChildValue("derivedFrom");
|
||||
// String url = cs.getNamedChildValue("url");
|
||||
|
||||
if (cs.hasChild("expression")) {
|
||||
List<String> bases = new ArrayList<>();
|
||||
for (Element b : cs.getChildrenByName("base")) {
|
||||
bases.add(b.primitiveValue());
|
||||
}
|
||||
ok = checkExpression(errors, stack.push(cs.getNamedChild("expression"), -1, null, null), cs.getNamedChildValue("expression"), bases) && ok;
|
||||
}
|
||||
String master = cs.getNamedChildValue("derivedFrom");
|
||||
if (!Utilities.noString(master)) {
|
||||
SearchParameter sp = context.fetchResource(SearchParameter.class, master);
|
||||
if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), sp != null, I18nConstants.SEARCHPARAMETER_NOTFOUND, master)) {
|
||||
@ -67,13 +74,33 @@ public class SearchParameterValidator extends BaseValidator {
|
||||
String expOther = canonicalise(sp.getExpression(), bases);
|
||||
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), expThis.equals(expOther), I18nConstants.SEARCHPARAMETER_EXP_WRONG, master, sp.getExpression(), cs.getNamedChildValue("expression"));
|
||||
}
|
||||
|
||||
// todo: check compositions
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private String canonicalise(String path, List<String> bases) {
|
||||
private boolean checkExpression(List<ValidationMessage> errors, NodeStack stack, String expression, List<String> bases) {
|
||||
boolean ok = true;
|
||||
try {
|
||||
List<String> warnings = new ArrayList<>();
|
||||
fpe.checkOnTypes(null, null, bases, fpe.parse(expression), warnings);
|
||||
for (String s : warnings) {
|
||||
warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, false, s);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (debug) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ok = rule(errors, "2023-06-19", IssueType.INVALID, stack, false, I18nConstants.ED_SEARCH_EXPRESSION_ERROR, expression, e.getMessage()) && ok;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private String canonicalise(String path, List<String> bases) {
|
||||
|
||||
|
||||
ExpressionNode exp = fpe.parse(path);
|
||||
List<ExpressionNode> pass = new ArrayList<>();
|
||||
while (exp != null) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user