mirror of
https://github.com/hapifhir/org.hl7.fhir.core.git
synced 2025-02-09 06:14:45 +00:00
rework decimal lowBoundary() and highBoundary() after discussion on Zulip, and add extensive testing
This commit is contained in:
parent
db9d788a9a
commit
00ad185882
@ -3735,20 +3735,20 @@ public class FHIRPathEngine {
|
||||
|
||||
case LowBoundary:
|
||||
case HighBoundary: {
|
||||
checkContextContinuous(focus, exp.getFunction().toCode(), exp);
|
||||
checkContextContinuous(focus, exp.getFunction().toCode(), exp, true);
|
||||
if (paramTypes.size() > 0) {
|
||||
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer));
|
||||
}
|
||||
if (focus.hasType("decimal") && (focus.hasType("date") || focus.hasType("datetime") || focus.hasType("instant"))) {
|
||||
if ((focus.hasType("date") || focus.hasType("datetime") || focus.hasType("instant"))) {
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal, TypeDetails.FP_DateTime);
|
||||
} else if (focus.hasType("decimal")) {
|
||||
} else if (focus.hasType("decimal") || focus.hasType("integer")) {
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal);
|
||||
} else {
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime);
|
||||
}
|
||||
}
|
||||
case Precision: {
|
||||
checkContextContinuous(focus, exp.getFunction().toCode(), exp);
|
||||
checkContextContinuous(focus, exp.getFunction().toCode(), exp, false);
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer);
|
||||
}
|
||||
case hasTemplateIdOf: {
|
||||
@ -3897,8 +3897,8 @@ public class FHIRPathEngine {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkContextContinuous(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException {
|
||||
if (!focus.hasNoTypes() && !focus.hasType("decimal") && !focus.hasType("date") && !focus.hasType("dateTime") && !focus.hasType("time") && !focus.hasType("Quantity")) {
|
||||
private void checkContextContinuous(TypeDetails focus, String name, ExpressionNode expr, boolean allowInteger) throws PathEngineException {
|
||||
if (!focus.hasNoTypes() && !focus.hasType("decimal") && !focus.hasType("date") && !focus.hasType("dateTime") && !focus.hasType("time") && !focus.hasType("Quantity") && !(allowInteger && focus.hasType("integer"))) {
|
||||
throw makeException(expr, I18nConstants.FHIRPATH_CONTINUOUS_ONLY, name, focus.describe());
|
||||
}
|
||||
}
|
||||
@ -4295,7 +4295,7 @@ public class FHIRPathEngine {
|
||||
if (focus.size() > 1) {
|
||||
throw makeExceptionPlural(focus.size(), expr, I18nConstants.FHIRPATH_FOCUS, "lowBoundary", focus.size());
|
||||
}
|
||||
int precision = 0;
|
||||
Integer precision = null;
|
||||
if (expr.getParameters().size() > 0) {
|
||||
List<Base> n1 = execute(context, focus, expr.getParameters().get(0), true);
|
||||
if (n1.size() != 1) {
|
||||
@ -4308,17 +4308,23 @@ public class FHIRPathEngine {
|
||||
List<Base> result = new ArrayList<Base>();
|
||||
|
||||
if (base.hasType("decimal")) {
|
||||
result.add(new DecimalType(Utilities.lowBoundaryForDecimal(base.primitiveValue(), precision == 0 ? 8 : precision)));
|
||||
if (precision == null || (precision >= 0 && precision < 17)) {
|
||||
result.add(new DecimalType(Utilities.lowBoundaryForDecimal(base.primitiveValue(), precision == null ? 8 : precision)));
|
||||
}
|
||||
} else if (base.hasType("integer")) {
|
||||
if (precision == null || (precision >= 0 && precision < 17)) {
|
||||
result.add(new DecimalType(Utilities.lowBoundaryForDecimal(base.primitiveValue(), precision == null ? 8 : precision)));
|
||||
}
|
||||
} else if (base.hasType("date")) {
|
||||
result.add(new DateTimeType(Utilities.lowBoundaryForDate(base.primitiveValue(), precision == 0 ? 10 : precision)));
|
||||
result.add(new DateTimeType(Utilities.lowBoundaryForDate(base.primitiveValue(), precision == null ? 10 : precision)));
|
||||
} else if (base.hasType("dateTime")) {
|
||||
result.add(new DateTimeType(Utilities.lowBoundaryForDate(base.primitiveValue(), precision == 0 ? 17 : precision)));
|
||||
result.add(new DateTimeType(Utilities.lowBoundaryForDate(base.primitiveValue(), precision == null ? 17 : precision)));
|
||||
} else if (base.hasType("time")) {
|
||||
result.add(new TimeType(Utilities.lowBoundaryForTime(base.primitiveValue(), precision == 0 ? 9 : precision)));
|
||||
result.add(new TimeType(Utilities.lowBoundaryForTime(base.primitiveValue(), precision == null ? 9 : precision)));
|
||||
} else if (base.hasType("Quantity")) {
|
||||
String value = getNamedValue(base, "value");
|
||||
Base v = base.copy();
|
||||
v.setProperty("value", new DecimalType(Utilities.lowBoundaryForDecimal(value, precision == 0 ? 8 : precision)));
|
||||
v.setProperty("value", new DecimalType(Utilities.lowBoundaryForDecimal(value, precision == null ? 8 : precision)));
|
||||
result.add(v);
|
||||
} else {
|
||||
makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "decimal or date");
|
||||
@ -4333,7 +4339,7 @@ public class FHIRPathEngine {
|
||||
if (focus.size() > 1) {
|
||||
throw makeExceptionPlural(focus.size(), expr, I18nConstants.FHIRPATH_FOCUS, "highBoundary", focus.size());
|
||||
}
|
||||
int precision = 0;
|
||||
Integer precision = null;
|
||||
if (expr.getParameters().size() > 0) {
|
||||
List<Base> n1 = execute(context, focus, expr.getParameters().get(0), true);
|
||||
if (n1.size() != 1) {
|
||||
@ -4346,17 +4352,23 @@ public class FHIRPathEngine {
|
||||
Base base = focus.get(0);
|
||||
List<Base> result = new ArrayList<Base>();
|
||||
if (base.hasType("decimal")) {
|
||||
result.add(new DecimalType(Utilities.highBoundaryForDecimal(base.primitiveValue(), precision == 0 ? 8 : precision)));
|
||||
if (precision == null || (precision >= 0 && precision < 17)) {
|
||||
result.add(new DecimalType(Utilities.highBoundaryForDecimal(base.primitiveValue(), precision == null ? 8 : precision)));
|
||||
}
|
||||
} else if (base.hasType("integer")) {
|
||||
if (precision == null || (precision >= 0 && precision < 17)) {
|
||||
result.add(new DecimalType(Utilities.highBoundaryForDecimal(base.primitiveValue(), precision == null ? 8 : precision)));
|
||||
}
|
||||
} else if (base.hasType("date")) {
|
||||
result.add(new DateTimeType(Utilities.highBoundaryForDate(base.primitiveValue(), precision == 0 ? 10 : precision)));
|
||||
result.add(new DateTimeType(Utilities.highBoundaryForDate(base.primitiveValue(), precision == null ? 10 : precision)));
|
||||
} else if (base.hasType("dateTime")) {
|
||||
result.add(new DateTimeType(Utilities.highBoundaryForDate(base.primitiveValue(), precision == 0 ? 17 : precision)));
|
||||
result.add(new DateTimeType(Utilities.highBoundaryForDate(base.primitiveValue(), precision == null ? 17 : precision)));
|
||||
} else if (base.hasType("time")) {
|
||||
result.add(new TimeType(Utilities.highBoundaryForTime(base.primitiveValue(), precision == 0 ? 9 : precision)));
|
||||
result.add(new TimeType(Utilities.highBoundaryForTime(base.primitiveValue(), precision == null ? 9 : precision)));
|
||||
} else if (base.hasType("Quantity")) {
|
||||
String value = getNamedValue(base, "value");
|
||||
Base v = base.copy();
|
||||
v.setProperty("value", new DecimalType(Utilities.highBoundaryForDecimal(value, precision == 0 ? 8 : precision)));
|
||||
v.setProperty("value", new DecimalType(Utilities.highBoundaryForDecimal(value, precision == null ? 8 : precision)));
|
||||
result.add(v);
|
||||
} else {
|
||||
makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "decimal or date");
|
||||
|
@ -1695,31 +1695,47 @@ public class Utilities {
|
||||
value = value.substring(0, value.indexOf("e"));
|
||||
}
|
||||
if (isZero(value)) {
|
||||
return applyPrecision("-0.5000000000000000000000000", precision);
|
||||
return applyPrecision("-0.5000000000000000000000000", precision, true);
|
||||
} else if (value.startsWith("-")) {
|
||||
return "-"+highBoundaryForDecimal(value.substring(1), precision)+(e == null ? "" : e);
|
||||
} else {
|
||||
if (value.contains(".")) {
|
||||
return applyPrecision(minusOne(value)+"50000000000000000000000000000", precision)+(e == null ? "" : e);
|
||||
return applyPrecision(minusOne(value)+"50000000000000000000000000000", precision, true)+(e == null ? "" : e);
|
||||
} else {
|
||||
return applyPrecision(minusOne(value)+".50000000000000000000000000000", precision)+(e == null ? "" : e);
|
||||
return applyPrecision(minusOne(value)+".50000000000000000000000000000", precision, true)+(e == null ? "" : e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String applyPrecision(String v, int p) {
|
||||
private static String applyPrecision(String v, int p, boolean down) {
|
||||
String nv = v;
|
||||
int dp = -1;
|
||||
if (nv.contains(".")) {
|
||||
dp = nv.indexOf(".");
|
||||
nv = nv.substring(0, dp)+nv.substring(dp+1);
|
||||
}
|
||||
String s = null;
|
||||
int d = p - getDecimalPrecision(v);
|
||||
if (d == 0) {
|
||||
return v;
|
||||
s = nv;
|
||||
} else if (d > 0) {
|
||||
return v + padLeft("", '0', d);
|
||||
s = nv + padLeft("", '0', d);
|
||||
} else {
|
||||
if (v.charAt(v.length()+d) >= '6') {
|
||||
return v.substring(0, v.length()+d-1)+((char) (v.charAt(v.length()+d)+1));
|
||||
int l = v.length();
|
||||
int ld = l+d;
|
||||
if (dp > -1) {
|
||||
ld--;
|
||||
}
|
||||
if (nv.charAt(ld) >= '5' && !down) {
|
||||
s = nv.substring(0, ld-1)+((char) (nv.charAt(ld-1)+1));
|
||||
} else {
|
||||
return v.substring(0, v.length()+d);
|
||||
s = nv.substring(0, ld);
|
||||
}
|
||||
}
|
||||
if (s.endsWith(".")) {
|
||||
s = s.substring(0, s.length()-1);
|
||||
}
|
||||
return dp == -1 || dp >= s.length() ? s : s.substring(0, dp)+"."+s.substring(dp);
|
||||
}
|
||||
|
||||
private static String minusOne(String value) {
|
||||
@ -1831,14 +1847,14 @@ public class Utilities {
|
||||
value = value.substring(0, value.indexOf("e"));
|
||||
}
|
||||
if (isZero(value)) {
|
||||
return applyPrecision("0.50000000000000000000000000000", precision);
|
||||
return applyPrecision("0.50000000000000000000000000000", precision, false);
|
||||
} else if (value.startsWith("-")) {
|
||||
return "-"+lowBoundaryForDecimal(value.substring(1), precision)+(e == null ? "" : e);
|
||||
} else {
|
||||
if (value.contains(".")) {
|
||||
return applyPrecision(value+"50000000000000000000000000000", precision)+(e == null ? "" : e);
|
||||
return applyPrecision(value+"50000000000000000000000000000", precision, false)+(e == null ? "" : e);
|
||||
} else {
|
||||
return applyPrecision(value+".50000000000000000000000000000", precision)+(e == null ? "" : e);
|
||||
return applyPrecision(value+".50000000000000000000000000000", precision, false)+(e == null ? "" : e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user