Merge pull request #1111 from hapifhir/gg-202302-comparable

FHIR-34417: implementations for comparable(), highBoundary(), lowBoun…
This commit is contained in:
Grahame Grieve 2023-02-10 17:23:52 +10:00 committed by GitHub
commit 63e1827a2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 149 additions and 4 deletions

View File

@ -1662,6 +1662,9 @@ public class ProfileUtilities extends TranslatingUtilities {
if (isLikelySourceURLReference(url, resourceNames, baseFilenames, localFilenames)) { if (isLikelySourceURLReference(url, resourceNames, baseFilenames, localFilenames)) {
b.append("]("); b.append("](");
b.append(basePath); b.append(basePath);
if (!Utilities.noString(basePath) && !basePath.endsWith("/")) {
b.append("/");
}
i = i + 1; i = i + 1;
} else { } else {
b.append("]("); b.append("](");
@ -1740,8 +1743,11 @@ public class ProfileUtilities extends TranslatingUtilities {
url.startsWith("loinc.html") || url.startsWith("loinc.html") ||
url.startsWith("http.html") || url.startsWith("http.html") ||
url.startsWith("references") || url.startsWith("references") ||
url.startsWith("license.html") ||
url.startsWith("narrative.html") || url.startsWith("narrative.html") ||
url.startsWith("search.html") || url.startsWith("search.html") ||
url.startsWith("security.html") ||
url.startsWith("versions.html") ||
url.startsWith("patient-operation-match.html") || url.startsWith("patient-operation-match.html") ||
(url.startsWith("extension-") && url.contains(".html")) || (url.startsWith("extension-") && url.contains(".html")) ||
url.startsWith("resource-definitions.html"); url.startsWith("resource-definitions.html");

View File

@ -1315,4 +1315,51 @@ public class Element extends Base {
throw new Error("Unrecognised name "+name+" on "+this.name); throw new Error("Unrecognised name "+name+" on "+this.name);
} }
@Override
public Base copy() {
Element element = new Element(this);
this.copyValues(element);
return element;
}
@Override
public void copyValues(Base dst) {
super.copyValues(dst);
Element dest = (Element) dst;
if (comments != null) {
dest.comments = new ArrayList<>();
dest.comments.addAll(comments);
} else {
dest.comments = null;
}
dest.value = value;
if (children != null) {
dest.children = new ArrayList<>();
dest.children.addAll(children);
} else {
dest.children = null;
}
dest.line = line;
dest.col = col;
dest.xhtml = xhtml;
dest.explicitType = explicitType;
dest.hasParentForValidator = false;
dest.path = path;
dest.messages = null;
dest.prohibited = prohibited;
dest.required = required;
dest.childMap = null;
dest.descendentCount = descendentCount;
dest.instanceId = instanceId;
dest.isNull = isNull;
dest.source = source;
}
public Base setProperty(String name, Base value) throws FHIRException {
setChildValue(name, value.primitiveValue());
return this;
}
} }

View File

@ -420,6 +420,8 @@ public abstract class Base implements Serializable, IBase, IElement {
return null; return null;
} }
public abstract Base copy();
public void copyValues(Base dst) { public void copyValues(Base dst) {
} }

View File

@ -56,7 +56,7 @@ public class ExpressionNode {
Encode, Decode, Escape, Unescape, Trim, Split, Join, LowBoundary, HighBoundary, Precision, Encode, Decode, Escape, Unescape, Trim, Split, Join, LowBoundary, HighBoundary, Precision,
// Local extensions to FHIRPath // Local extensions to FHIRPath
HtmlChecks1, HtmlChecks2, AliasAs, Alias; HtmlChecks1, HtmlChecks2, AliasAs, Alias, Comparable;
public static Function fromCode(String name) { public static Function fromCode(String name) {
if (name.equals("empty")) return Function.Empty; if (name.equals("empty")) return Function.Empty;
@ -118,6 +118,7 @@ public class ExpressionNode {
if (name.equals("htmlChecks")) return Function.HtmlChecks1; if (name.equals("htmlChecks")) return Function.HtmlChecks1;
if (name.equals("htmlchecks")) return Function.HtmlChecks1; // support change of care from R3 if (name.equals("htmlchecks")) return Function.HtmlChecks1; // support change of care from R3
if (name.equals("htmlChecks2")) return Function.HtmlChecks2; if (name.equals("htmlChecks2")) return Function.HtmlChecks2;
if (name.equals("comparable")) return Function.Comparable;
if (name.equals("encode")) return Function.Encode; if (name.equals("encode")) return Function.Encode;
if (name.equals("decode")) return Function.Decode; if (name.equals("decode")) return Function.Decode;
if (name.equals("escape")) return Function.Escape; if (name.equals("escape")) return Function.Escape;
@ -227,6 +228,7 @@ public class ExpressionNode {
case Join : return "join"; case Join : return "join";
case HtmlChecks1 : return "htmlChecks"; case HtmlChecks1 : return "htmlChecks";
case HtmlChecks2 : return "htmlChecks2"; case HtmlChecks2 : return "htmlChecks2";
case Comparable : return "comparable";
case OfType : return "ofType"; case OfType : return "ofType";
case Type : return "type"; case Type : return "type";
case ToInteger : return "toInteger"; case ToInteger : return "toInteger";

View File

@ -98,5 +98,12 @@ public class Tuple extends Base {
return getProperty(name.hashCode(), name, checkValid); return getProperty(name.hashCode(), name, checkValid);
} }
@Override
public Base copy() {
Tuple tuple = new Tuple();
copyValues(tuple);
return tuple;
}
} }

View File

@ -147,6 +147,11 @@ public class FHIRPathEngine {
public String primitiveValue() { public String primitiveValue() {
return value; return value;
} }
@Override
public Base copy() {
throw new Error("Not Implemented");
}
} }
private class ClassTypeInfo extends Base { private class ClassTypeInfo extends Base {
@ -205,6 +210,11 @@ public class FHIRPathEngine {
return instance.fhirType(); return instance.fhirType();
} }
} }
@Override
public Base copy() {
throw new Error("Not Implemented");
}
} }
public static class TypedElementDefinition { public static class TypedElementDefinition {
@ -1403,6 +1413,7 @@ public class FHIRPathEngine {
case Join: return checkParamCount(lexer, location, exp, 1); case Join: return checkParamCount(lexer, location, exp, 1);
case HtmlChecks1: return checkParamCount(lexer, location, exp, 0); case HtmlChecks1: return checkParamCount(lexer, location, exp, 0);
case HtmlChecks2: return checkParamCount(lexer, location, exp, 0); case HtmlChecks2: return checkParamCount(lexer, location, exp, 0);
case Comparable: return checkParamCount(lexer, location, exp, 1);
case ToInteger: return checkParamCount(lexer, location, exp, 0); case ToInteger: return checkParamCount(lexer, location, exp, 0);
case ToDecimal: return checkParamCount(lexer, location, exp, 0); case ToDecimal: return checkParamCount(lexer, location, exp, 0);
case ToString: return checkParamCount(lexer, location, exp, 0); case ToString: return checkParamCount(lexer, location, exp, 0);
@ -3335,6 +3346,8 @@ public class FHIRPathEngine {
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
case HtmlChecks2 : case HtmlChecks2 :
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
case Comparable :
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
case Alias : case Alias :
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return anything(CollectionStatus.SINGLETON); return anything(CollectionStatus.SINGLETON);
@ -3551,7 +3564,7 @@ public class FHIRPathEngine {
} }
private void checkContextContinuous(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { 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")) { if (!focus.hasNoTypes() && !focus.hasType("decimal") && !focus.hasType("date") && !focus.hasType("dateTime") && !focus.hasType("time") && !focus.hasType("Quantity")) {
throw makeException(expr, I18nConstants.FHIRPATH_CONTINUOUS_ONLY, name, focus.describe()); throw makeException(expr, I18nConstants.FHIRPATH_CONTINUOUS_ONLY, name, focus.describe());
} }
} }
@ -3641,6 +3654,7 @@ public class FHIRPathEngine {
case Alias : return funcAlias(context, focus, exp); case Alias : return funcAlias(context, focus, exp);
case HtmlChecks1 : return funcHtmlChecks1(context, focus, exp); case HtmlChecks1 : return funcHtmlChecks1(context, focus, exp);
case HtmlChecks2 : return funcHtmlChecks2(context, focus, exp); case HtmlChecks2 : return funcHtmlChecks2(context, focus, exp);
case Comparable : return funcComparable(context, focus, exp);
case ToInteger : return funcToInteger(context, focus, exp); case ToInteger : return funcToInteger(context, focus, exp);
case ToDecimal : return funcToDecimal(context, focus, exp); case ToDecimal : return funcToDecimal(context, focus, exp);
case ToString : return funcToString(context, focus, exp); case ToString : return funcToString(context, focus, exp);
@ -3880,7 +3894,10 @@ public class FHIRPathEngine {
} }
private List<Base> funcLowBoundary(ExecutionContext context, List<Base> focus, ExpressionNode expr) { private List<Base> funcLowBoundary(ExecutionContext context, List<Base> focus, ExpressionNode expr) {
if (focus.size() != 1) { if (focus.size() == 0) {
return makeNull();
}
if (focus.size() > 1) {
throw makeExceptionPlural(focus.size(), expr, I18nConstants.FHIRPATH_FOCUS, "lowBoundary", focus.size()); throw makeExceptionPlural(focus.size(), expr, I18nConstants.FHIRPATH_FOCUS, "lowBoundary", focus.size());
} }
int precision = 0; int precision = 0;
@ -3903,6 +3920,11 @@ public class FHIRPathEngine {
result.add(new DateTimeType(Utilities.lowBoundaryForDate(base.primitiveValue(), precision == 0 ? 17 : precision))); result.add(new DateTimeType(Utilities.lowBoundaryForDate(base.primitiveValue(), precision == 0 ? 17 : precision)));
} else if (base.hasType("time")) { } 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 == 0 ? 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)));
result.add(v);
} else { } else {
makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "decimal or date"); makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "decimal or date");
} }
@ -3910,7 +3932,10 @@ public class FHIRPathEngine {
} }
private List<Base> funcHighBoundary(ExecutionContext context, List<Base> focus, ExpressionNode expr) { private List<Base> funcHighBoundary(ExecutionContext context, List<Base> focus, ExpressionNode expr) {
if (focus.size() != 1) { if (focus.size() == 0) {
return makeNull();
}
if (focus.size() > 1) {
throw makeExceptionPlural(focus.size(), expr, I18nConstants.FHIRPATH_FOCUS, "highBoundary", focus.size()); throw makeExceptionPlural(focus.size(), expr, I18nConstants.FHIRPATH_FOCUS, "highBoundary", focus.size());
} }
int precision = 0; int precision = 0;
@ -3933,6 +3958,11 @@ public class FHIRPathEngine {
result.add(new DateTimeType(Utilities.highBoundaryForDate(base.primitiveValue(), precision == 0 ? 17 : precision))); result.add(new DateTimeType(Utilities.highBoundaryForDate(base.primitiveValue(), precision == 0 ? 17 : precision)));
} else if (base.hasType("time")) { } 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 == 0 ? 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)));
result.add(v);
} else { } else {
makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "decimal or date"); makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "decimal or date");
} }
@ -4167,6 +4197,47 @@ public class FHIRPathEngine {
return false; return false;
} }
private List<Base> funcComparable(ExecutionContext context, List<Base> focus, ExpressionNode exp) throws FHIRException {
if (focus.size() != 1 || !(focus.get(0).fhirType().equals("Quantity"))) {
return makeBoolean(false);
}
List<Base> nl = execute(context, focus, exp.getParameters().get(0), true);
if (nl.size() != 1 || !(nl.get(0).fhirType().equals("Quantity"))) {
return makeBoolean(false);
}
String s1 = getNamedValue(focus.get(0), "system");
String u1 = getNamedValue(focus.get(0), "code");
String s2 = getNamedValue(nl.get(0), "system");
String u2 = getNamedValue(nl.get(0), "code");
if (s1 == null || s2 == null || !s1.equals(s2)) {
return makeBoolean(false);
}
if (u1 == null || u2 == null) {
return makeBoolean(false);
}
if (u1.equals(u2)) {
return makeBoolean(true);
}
if (s1.equals("http://unitsofmeasure.org") && worker.getUcumService() != null) {
try {
return makeBoolean(worker.getUcumService().isComparable(u1, u2));
} catch (UcumException e) {
return makeBoolean(false);
}
} else {
return makeBoolean(false);
}
}
private String getNamedValue(Base base, String name) {
Property p = base.getChildByName(name);
if (p.hasValues() && p.getValues().size() == 1) {
return p.getValues().get(0).primitiveValue();
}
return null;
}
private boolean checkHtmlNames(XhtmlNode node) { private boolean checkHtmlNames(XhtmlNode node) {
if (node.getNodeType() == NodeType.Comment) { if (node.getNodeType() == NodeType.Comment) {

View File

@ -106,6 +106,11 @@ public class GraphQLEngine implements IGraphQLEngine {
default: return super.getNamedProperty(_hash, _name, _checkValid); default: return super.getNamedProperty(_hash, _name, _checkValid);
} }
} }
@Override
public Base copy() {
throw new Error("Not Implemented");
}
} }
public static class SearchWrapper extends Base { public static class SearchWrapper extends Base {
@ -195,6 +200,11 @@ public class GraphQLEngine implements IGraphQLEngine {
return null; return null;
} }
@Override
public Base copy() {
throw new Error("Not Implemented");
}
} }
private IWorkerContext context; private IWorkerContext context;