FHIRPath fixes (string handling)

This commit is contained in:
Grahame Grieve 2022-07-27 22:38:32 +10:00
parent 816f1832d5
commit 7e8cace0fb
1 changed files with 71 additions and 41 deletions

View File

@ -2903,6 +2903,8 @@ public class FHIRPathEngine {
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity);
} else if (constant instanceof FHIRConstant) {
return resolveConstantType(context, ((FHIRConstant) constant).getValue(), expr);
} else if (constant == null) {
return new TypeDetails(CollectionStatus.SINGLETON);
} else {
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
@ -3140,60 +3142,60 @@ public class FHIRPathEngine {
return types;
}
case Lower : {
checkContextString(focus, "lower", exp);
checkContextString(focus, "lower", exp, true);
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
case Upper : {
checkContextString(focus, "upper", exp);
checkContextString(focus, "upper", exp, true);
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
case ToChars : {
checkContextString(focus, "toChars", exp);
checkContextString(focus, "toChars", exp, true);
return new TypeDetails(CollectionStatus.ORDERED, TypeDetails.FP_String);
}
case IndexOf : {
checkContextString(focus, "indexOf", exp);
checkContextString(focus, "indexOf", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer);
}
case Substring : {
checkContextString(focus, "subString", exp);
checkContextString(focus, "subString", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
case StartsWith : {
checkContextString(focus, "startsWith", exp);
checkContextString(focus, "startsWith", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
}
case EndsWith : {
checkContextString(focus, "endsWith", exp);
checkContextString(focus, "endsWith", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
}
case Matches : {
checkContextString(focus, "matches", exp);
checkContextString(focus, "matches", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
}
case MatchesFull : {
checkContextString(focus, "matches", exp);
checkContextString(focus, "matches", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
}
case ReplaceMatches : {
checkContextString(focus, "replaceMatches", exp);
checkContextString(focus, "replaceMatches", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
case Contains : {
checkContextString(focus, "contains", exp);
checkContextString(focus, "contains", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
}
case Replace : {
checkContextString(focus, "replace", exp);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, "string"), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
checkContextString(focus, "replace", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
case Length : {
@ -3427,37 +3429,39 @@ public class FHIRPathEngine {
}
private void checkContextString(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException {
if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "canonical") && !focus.hasType(worker, "id")) {
throw makeException(expr, I18nConstants.FHIRPATH_STRING_ONLY, name, focus.describe());
private void checkContextString(TypeDetails focus, String name, ExpressionNode expr, boolean sing) throws PathEngineException {
if (!focus.hasNoTypes() && !focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "canonical") && !focus.hasType(worker, "id")) {
throw makeException(expr, sing ? I18nConstants.FHIRPATH_STRING_SING_ONLY : I18nConstants.FHIRPATH_STRING_ORD_ONLY, name, focus.describe());
}
}
private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty, ExpressionNode expr) throws PathEngineException {
if (canQty) {
if (!focus.hasType(primitiveTypes) && !focus.hasType("Quantity")) {
throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), "Quantity, "+primitiveTypes.toString());
if (!focus.hasNoTypes()) {
if (canQty) {
if (!focus.hasType(primitiveTypes) && !focus.hasType("Quantity")) {
throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), "Quantity, "+primitiveTypes.toString());
}
} else if (!focus.hasType(primitiveTypes)) {
throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), primitiveTypes.toString());
}
} else if (!focus.hasType(primitiveTypes)) {
throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), primitiveTypes.toString());
}
}
private void checkContextNumerical(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException {
if (!focus.hasType("integer") && !focus.hasType("decimal") && !focus.hasType("Quantity")) {
if (!focus.hasNoTypes() && !focus.hasType("integer") && !focus.hasType("decimal") && !focus.hasType("Quantity")) {
throw makeException(expr, I18nConstants.FHIRPATH_NUMERICAL_ONLY, name, focus.describe());
}
}
private void checkContextDecimal(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException {
if (!focus.hasType("decimal") && !focus.hasType("integer")) {
if (!focus.hasNoTypes() && !focus.hasType("decimal") && !focus.hasType("integer")) {
throw makeException(expr, I18nConstants.FHIRPATH_DECIMAL_ONLY, name, focus.describe());
}
}
private void checkContextContinuous(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException {
if (!focus.hasType("decimal") && !focus.hasType("date") && !focus.hasType("dateTime") && !focus.hasType("time")) {
if (!focus.hasNoTypes() && !focus.hasType("decimal") && !focus.hasType("date") && !focus.hasType("dateTime") && !focus.hasType("time")) {
throw makeException(expr, I18nConstants.FHIRPATH_CONTINUOUS_ONLY, name, focus.describe());
}
}
@ -3672,7 +3676,10 @@ public class FHIRPathEngine {
private List<Base> funcExp(ExecutionContext context, List<Base> focus, ExpressionNode expr) {
if (focus.size() != 1) {
if (focus.size() == 0) {
return new ArrayList<Base>();
}
if (focus.size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "exp", focus.size());
}
Base base = focus.get(0);
@ -4218,15 +4225,19 @@ public class FHIRPathEngine {
private List<Base> funcReplace(ExecutionContext context, List<Base> focus, ExpressionNode expr) throws FHIRException, PathEngineException {
List<Base> result = new ArrayList<Base>();
List<Base> tB = execute(context, focus, expr.getParameters().get(0), true);
String t = convertToString(tB);
List<Base> rB = execute(context, focus, expr.getParameters().get(1), true);
String r = convertToString(rB);
if (focus.size() == 1) {
if (focus.size() == 0 || tB.size() == 0 || rB.size() == 0) {
//
} else if (focus.size() == 1) {
if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
String f = convertToString(focus.get(0));
if (Utilities.noString(f)) {
result.add(new StringType(""));
} else {
String t = convertToString(execute(context, focus, expr.getParameters().get(0), true));
String r = convertToString(execute(context, focus, expr.getParameters().get(1), true));
String n = f.replace(t, r);
result.add(new StringType(n));
}
@ -4240,10 +4251,14 @@ public class FHIRPathEngine {
private List<Base> funcReplaceMatches(ExecutionContext context, List<Base> focus, ExpressionNode exp) throws FHIRException {
List<Base> result = new ArrayList<Base>();
String regex = convertToString(execute(context, focus, exp.getParameters().get(0), true));
String repl = convertToString(execute(context, focus, exp.getParameters().get(1), true));
List<Base> regexB = execute(context, focus, exp.getParameters().get(0), true);
String regex = convertToString(regexB);
List<Base> replB = execute(context, focus, exp.getParameters().get(1), true);
String repl = convertToString(replB);
if (focus.size() == 1 && !Utilities.noString(regex)) {
if (focus.size() == 0 || regexB.size() == 0 || replB.size() == 0) {
//
} else if (focus.size() == 1 && !Utilities.noString(regex)) {
if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
result.add(new StringType(convertToString(focus.get(0)).replaceAll(regex, repl)).noExtensions());
}
@ -4256,10 +4271,13 @@ public class FHIRPathEngine {
private List<Base> funcEndsWith(ExecutionContext context, List<Base> focus, ExpressionNode exp) throws FHIRException {
List<Base> result = new ArrayList<Base>();
String sw = convertToString(execute(context, focus, exp.getParameters().get(0), true));
List<Base> swb = execute(context, focus, exp.getParameters().get(0), true);
String sw = convertToString(swb);
if (focus.size() == 0) {
result.add(new BooleanType(false).noExtensions());
//
} else if (swb.size() == 0) {
//
} else if (Utilities.noString(sw)) {
result.add(new BooleanType(true).noExtensions());
} else if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
@ -4929,9 +4947,12 @@ public class FHIRPathEngine {
private List<Base> funcMatches(ExecutionContext context, List<Base> focus, ExpressionNode exp) throws FHIRException {
List<Base> result = new ArrayList<Base>();
String sw = convertToString(execute(context, focus, exp.getParameters().get(0), true));
List<Base> swb = execute(context, focus, exp.getParameters().get(0), true);
String sw = convertToString(swb);
if (focus.size() == 1 && !Utilities.noString(sw)) {
if (focus.size() == 0 || swb.size() == 0) {
//
} else if (focus.size() == 1 && !Utilities.noString(sw)) {
if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
String st = convertToString(focus.get(0));
if (Utilities.noString(st)) {
@ -4973,10 +4994,13 @@ public class FHIRPathEngine {
private List<Base> funcContains(ExecutionContext context, List<Base> focus, ExpressionNode exp) throws FHIRException {
List<Base> result = new ArrayList<Base>();
String sw = convertToString(execute(context, baseToList(context.thisItem), exp.getParameters().get(0), true));
List<Base> swb = execute(context, baseToList(context.thisItem), exp.getParameters().get(0), true);
String sw = convertToString(swb);
if (focus.size() != 1) {
result.add(new BooleanType(false).noExtensions());
//
} else if (swb.size() != 1) {
//
} else if (Utilities.noString(sw)) {
result.add(new BooleanType(true).noExtensions());
} else if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
@ -5018,10 +5042,13 @@ public class FHIRPathEngine {
private List<Base> funcStartsWith(ExecutionContext context, List<Base> focus, ExpressionNode exp) throws FHIRException {
List<Base> result = new ArrayList<Base>();
String sw = convertToString(execute(context, focus, exp.getParameters().get(0), true));
List<Base> swb = execute(context, focus, exp.getParameters().get(0), true);
String sw = convertToString(swb);
if (focus.size() == 0) {
result.add(new BooleanType(false).noExtensions());
// no result
} else if (swb.size() == 0) {
// no result
} else if (Utilities.noString(sw)) {
result.add(new BooleanType(true).noExtensions());
} else if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
@ -5071,9 +5098,12 @@ public class FHIRPathEngine {
private List<Base> funcIndexOf(ExecutionContext context, List<Base> focus, ExpressionNode exp) throws FHIRException {
List<Base> result = new ArrayList<Base>();
String sw = convertToString(execute(context, focus, exp.getParameters().get(0), true));
List<Base> swb = execute(context, focus, exp.getParameters().get(0), true);
String sw = convertToString(swb);
if (focus.size() == 0) {
result.add(new IntegerType(0).noExtensions());
// no result
} else if (swb.size() == 0) {
// no result
} else if (Utilities.noString(sw)) {
result.add(new IntegerType(0).noExtensions());
} else if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {