Update SQL-On-FHIR implementation for latest cases, and clone test cases to general test care repository

This commit is contained in:
Grahame Grieve 2024-09-09 17:48:46 +08:00
parent 810f4b8e31
commit cfdd1f9380
5 changed files with 157 additions and 88 deletions

View File

@ -554,6 +554,9 @@ public class RenderingContext extends RenderingI18nContext {
} }
public String fixReference(String ref) { public String fixReference(String ref) {
if (ref == null) {
return null;
}
if (!Utilities.isAbsoluteUrl(ref)) { if (!Utilities.isAbsoluteUrl(ref)) {
return (localPrefix == null ? "" : localPrefix)+ref; return (localPrefix == null ? "" : localPrefix)+ref;
} }

View File

@ -103,7 +103,7 @@ public class Runner implements IEvaluationContext {
for (JsonObject w : vd.getJsonObjects("where")) { for (JsonObject w : vd.getJsonObjects("where")) {
String expr = w.asString("path"); String expr = w.asString("path");
ExpressionNode node = fpe.parse(expr); ExpressionNode node = fpe.parse(expr);
boolean pass = fpe.evaluateToBoolean(null, b, b, b, node); boolean pass = fpe.evaluateToBoolean(vd, b, b, b, node);
if (!pass) { if (!pass) {
ok = false; ok = false;
break; break;
@ -114,7 +114,7 @@ public class Runner implements IEvaluationContext {
rows.add(new ArrayList<Cell>()); rows.add(new ArrayList<Cell>());
for (JsonObject select : vd.getJsonObjects("select")) { for (JsonObject select : vd.getJsonObjects("select")) {
executeSelect(select, b, rows); executeSelect(vd, select, b, rows);
} }
for (List<Cell> row : rows) { for (List<Cell> row : rows) {
storage.addRow(store, row); storage.addRow(store, row);
@ -124,14 +124,14 @@ public class Runner implements IEvaluationContext {
storage.finish(store); storage.finish(store);
} }
private void executeSelect(JsonObject select, Base b, List<List<Cell>> rows) { private void executeSelect(JsonObject vd, JsonObject select, Base b, List<List<Cell>> rows) {
List<Base> focus = new ArrayList<>(); List<Base> focus = new ArrayList<>();
if (select.has("forEach")) { if (select.has("forEach")) {
focus.addAll(executeForEach(select, b)); focus.addAll(executeForEach(vd, select, b));
} else if (select.has("forEachOrNull")) { } else if (select.has("forEachOrNull")) {
focus.addAll(executeForEachOrNull(select, b)); focus.addAll(executeForEachOrNull(vd, select, b));
if (focus.isEmpty()) { if (focus.isEmpty()) {
List<Column> columns = (List<Column>) select.getUserData("columns"); List<Column> columns = (List<Column>) select.getUserData("columns");
for (List<Cell> row : rows) { for (List<Cell> row : rows) {
@ -159,20 +159,20 @@ public class Runner implements IEvaluationContext {
List<List<Cell>> rowsToAdd = cloneRows(tempRows); List<List<Cell>> rowsToAdd = cloneRows(tempRows);
for (JsonObject column : select.getJsonObjects("column")) { for (JsonObject column : select.getJsonObjects("column")) {
executeColumn(column, f, rowsToAdd); executeColumn(vd, column, f, rowsToAdd);
} }
for (JsonObject sub : select.getJsonObjects("select")) { for (JsonObject sub : select.getJsonObjects("select")) {
executeSelect(sub, f, rowsToAdd); executeSelect(vd, sub, f, rowsToAdd);
} }
executeUnionAll(select.getJsonObjects("unionAll"), f, rowsToAdd); executeUnionAll(vd, select.getJsonObjects("unionAll"), f, rowsToAdd);
rows.addAll(rowsToAdd); rows.addAll(rowsToAdd);
} }
} }
private void executeUnionAll(List<JsonObject> unionList, Base b, List<List<Cell>> rows) { private void executeUnionAll(JsonObject vd, List<JsonObject> unionList, Base b, List<List<Cell>> rows) {
if (unionList.isEmpty()) { if (unionList.isEmpty()) {
return; return;
} }
@ -183,7 +183,7 @@ public class Runner implements IEvaluationContext {
for (JsonObject union : unionList) { for (JsonObject union : unionList) {
List<List<Cell>> tempRows = new ArrayList<>(); List<List<Cell>> tempRows = new ArrayList<>();
tempRows.addAll(sourceRows); tempRows.addAll(sourceRows);
executeSelect(union, b, tempRows); executeSelect(vd, union, b, tempRows);
rows.addAll(tempRows); rows.addAll(tempRows);
} }
} }
@ -204,25 +204,25 @@ public class Runner implements IEvaluationContext {
return list; return list;
} }
private List<Base> executeForEach(JsonObject focus, Base b) { private List<Base> executeForEach(JsonObject vd, JsonObject focus, Base b) {
ExpressionNode n = (ExpressionNode) focus.getUserData("forEach"); ExpressionNode n = (ExpressionNode) focus.getUserData("forEach");
List<Base> result = new ArrayList<>(); List<Base> result = new ArrayList<>();
result.addAll(fpe.evaluate(b, n)); result.addAll(fpe.evaluate(vd, b, n));
return result; return result;
} }
private List<Base> executeForEachOrNull(JsonObject focus, Base b) { private List<Base> executeForEachOrNull(JsonObject vd, JsonObject focus, Base b) {
ExpressionNode n = (ExpressionNode) focus.getUserData("forEachOrNull"); ExpressionNode n = (ExpressionNode) focus.getUserData("forEachOrNull");
List<Base> result = new ArrayList<>(); List<Base> result = new ArrayList<>();
result.addAll(fpe.evaluate(b, n)); result.addAll(fpe.evaluate(vd, b, n));
return result; return result;
} }
private void executeColumn(JsonObject column, Base b, List<List<Cell>> rows) { private void executeColumn(JsonObject vd, JsonObject column, Base b, List<List<Cell>> rows) {
ExpressionNode n = (ExpressionNode) column.getUserData("path"); ExpressionNode n = (ExpressionNode) column.getUserData("path");
List<Base> bl2 = new ArrayList<>(); List<Base> bl2 = new ArrayList<>();
if (b != null) { if (b != null) {
bl2.addAll(fpe.evaluate(b, n)); bl2.addAll(fpe.evaluate(vd, b, n));
} }
Column col = (Column) column.getUserData("column"); Column col = (Column) column.getUserData("column");
if (col == null) { if (col == null) {
@ -344,14 +344,43 @@ public class Runner implements IEvaluationContext {
@Override @Override
public List<Base> resolveConstant(FHIRPathEngine engine, Object appContext, String name, boolean beforeContext, boolean explicitConstant) throws PathEngineException { public List<Base> resolveConstant(FHIRPathEngine engine, Object appContext, String name, boolean beforeContext, boolean explicitConstant) throws PathEngineException {
throw new Error("Not implemented yet: resolveConstant"); List<Base> list = new ArrayList<Base>();
if (explicitConstant) {
JsonObject vd = (JsonObject) appContext;
JsonObject constant = findConstant(vd, name);
if (constant != null) {
Base b = (Base) constant.getUserData("value");
if (b != null) {
list.add(b);
}
}
}
return list;
} }
@Override @Override
public TypeDetails resolveConstantType(FHIRPathEngine engine, Object appContext, String name, boolean explicitConstant) throws PathEngineException { public TypeDetails resolveConstantType(FHIRPathEngine engine, Object appContext, String name, boolean explicitConstant) throws PathEngineException {
throw new Error("Not implemented yet: resolveConstantType"); if (explicitConstant) {
JsonObject vd = (JsonObject) appContext;
JsonObject constant = findConstant(vd, name.substring(1));
if (constant != null) {
Base b = (Base) constant.getUserData("value");
if (b != null) {
return new TypeDetails(CollectionStatus.SINGLETON, b.fhirType());
}
}
}
return null;
} }
private JsonObject findConstant(JsonObject vd, String name) {
for (JsonObject o : vd.getJsonObjects("constant")) {
if (name.equals(o.asString("name"))) {
return o;
}
}
return null;
}
@Override @Override
public boolean log(String argument, List<Base> focus) { public boolean log(String argument, List<Base> focus) {
throw new Error("Not implemented yet: log"); throw new Error("Not implemented yet: log");

View File

@ -2,6 +2,7 @@ package org.hl7.fhir.r5.utils.sql;
import java.util.List; import java.util.List;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonArray;
import org.hl7.fhir.utilities.json.model.JsonBoolean; import org.hl7.fhir.utilities.json.model.JsonBoolean;
@ -33,16 +34,16 @@ public class StorageJson implements Storage {
JsonObject row = new JsonObject(); JsonObject row = new JsonObject();
rows.add(row); rows.add(row);
for (Cell cell : cells) { for (Cell cell : cells) {
if (cell.getValues().size() == 0) { if (cell.getColumn().isColl() || cell.getValues().size() > 1) {
row.add(cell.getColumn().getName(), new JsonNull());
} else if (cell.getValues().size() == 1) {
row.add(cell.getColumn().getName(), makeJsonNode(cell.getValues().get(0)));
} else {
JsonArray arr = new JsonArray(); JsonArray arr = new JsonArray();
row.add(cell.getColumn().getName(), arr); row.add(cell.getColumn().getName(), arr);
for (Value value : cell.getValues()) { for (Value value : cell.getValues()) {
arr.add(makeJsonNode(value)); arr.add(makeJsonNode(value));
} }
} else if (cell.getValues().size() == 0) {
row.add(cell.getColumn().getName(), new JsonNull());
} else {
row.add(cell.getColumn().getName(), makeJsonNode(cell.getValues().get(0)));
} }
} }
} }
@ -87,7 +88,7 @@ public class StorageJson implements Storage {
@Override @Override
public String getKeyForSourceResource(Base res) { public String getKeyForSourceResource(Base res) {
return res.getIdBase(); return res.fhirType()+"/"+res.getIdBase();
} }
@Override @Override

View File

@ -11,6 +11,27 @@ import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.fhirpath.ExpressionNode; import org.hl7.fhir.r5.fhirpath.ExpressionNode;
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine; import org.hl7.fhir.r5.fhirpath.FHIRPathEngine;
import org.hl7.fhir.r5.fhirpath.TypeDetails; import org.hl7.fhir.r5.fhirpath.TypeDetails;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.model.Base64BinaryType;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.DateTimeType;
import org.hl7.fhir.r5.model.DateType;
import org.hl7.fhir.r5.model.DecimalType;
import org.hl7.fhir.r5.model.IdType;
import org.hl7.fhir.r5.model.InstantType;
import org.hl7.fhir.r5.model.Integer64Type;
import org.hl7.fhir.r5.model.IntegerType;
import org.hl7.fhir.r5.model.OidType;
import org.hl7.fhir.r5.model.PositiveIntType;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.TimeType;
import org.hl7.fhir.r5.model.UnsignedIntType;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.UrlType;
import org.hl7.fhir.r5.model.UuidType;
import org.hl7.fhir.r5.fhirpath.ExpressionNode.CollectionStatus; import org.hl7.fhir.r5.fhirpath.ExpressionNode.CollectionStatus;
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine.IssueMessage; import org.hl7.fhir.r5.fhirpath.FHIRPathEngine.IssueMessage;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
@ -99,7 +120,7 @@ public class Validator {
i = 0; i = 0;
if (checkAllObjects(path, viewDefinition, "where")) { if (checkAllObjects(path, viewDefinition, "where")) {
for (JsonObject where : viewDefinition.getJsonObjects("where")) { for (JsonObject where : viewDefinition.getJsonObjects("where")) {
checkWhere(path+".where["+i+"]", where); checkWhere(viewDefinition, path+".where["+i+"]", where);
i++; i++;
} }
} }
@ -108,7 +129,7 @@ public class Validator {
i = 0; i = 0;
if (checkAllObjects(path, viewDefinition, "select")) { if (checkAllObjects(path, viewDefinition, "select")) {
for (JsonObject select : viewDefinition.getJsonObjects("select")) { for (JsonObject select : viewDefinition.getJsonObjects("select")) {
columns.addAll(checkSelect(path+".select["+i+"]", select, t)); columns.addAll(checkSelect(viewDefinition, path+".select["+i+"]", select, t));
i++; i++;
} }
if (i == 0) { if (i == 0) {
@ -119,15 +140,15 @@ public class Validator {
} }
} }
private List<Column> checkSelect(String path, JsonObject select, TypeDetails t) { private List<Column> checkSelect(JsonObject vd, String path, JsonObject select, TypeDetails t) {
List<Column> columns = new ArrayList<>(); List<Column> columns = new ArrayList<>();
select.setUserData("columns", columns); select.setUserData("columns", columns);
checkProperties(select, path, "column", "select", "forEach", "forEachOrNull", "unionAll"); checkProperties(select, path, "column", "select", "forEach", "forEachOrNull", "unionAll");
if (select.has("forEach")) { if (select.has("forEach")) {
t = checkForEach(path, select, select.get("forEach"), t); t = checkForEach(vd, path, select, select.get("forEach"), t);
} else if (select.has("forEachOrNull")) { } else if (select.has("forEachOrNull")) {
t = checkForEachOrNull(path, select, select.get("forEachOrNull"), t); t = checkForEachOrNull(vd, path, select, select.get("forEachOrNull"), t);
} }
if (t != null) { if (t != null) {
@ -142,7 +163,7 @@ public class Validator {
if (!(e instanceof JsonObject)) { if (!(e instanceof JsonObject)) {
error(path+".column["+i+"]", a, "column["+i+"] is a "+e.type().toName()+" not an object", IssueType.INVALID); error(path+".column["+i+"]", a, "column["+i+"] is a "+e.type().toName()+" not an object", IssueType.INVALID);
} else { } else {
columns.add(checkColumn(path+".column["+i+"]", (JsonObject) e, t)); columns.add(checkColumn(vd, path+".column["+i+"]", (JsonObject) e, t));
} }
} }
} }
@ -158,14 +179,14 @@ public class Validator {
if (!(e instanceof JsonObject)) { if (!(e instanceof JsonObject)) {
error(path+".select["+i+"]", e, "select["+i+"] is not an object", IssueType.INVALID); error(path+".select["+i+"]", e, "select["+i+"] is not an object", IssueType.INVALID);
} else { } else {
columns.addAll(checkSelect(path+".select["+i+"]", (JsonObject) e, t)); columns.addAll(checkSelect(vd, path+".select["+i+"]", (JsonObject) e, t));
} }
} }
} }
} }
if (select.has("unionAll")) { if (select.has("unionAll")) {
columns.addAll(checkUnion(path, select, select.get("unionAll"), t)); columns.addAll(checkUnion(vd, path, select, select.get("unionAll"), t));
} }
if (columns.isEmpty()) { if (columns.isEmpty()) {
error(path, select, "The select has no columns or selects", IssueType.REQUIRED); error(path, select, "The select has no columns or selects", IssueType.REQUIRED);
@ -191,7 +212,7 @@ public class Validator {
} }
} }
private List<Column> checkUnion(String path, JsonObject focus, JsonElement expression, TypeDetails t) { private List<Column> checkUnion(JsonObject vd, String path, JsonObject focus, JsonElement expression, TypeDetails t) {
JsonElement a = focus.get("unionAll"); JsonElement a = focus.get("unionAll");
if (!(a instanceof JsonArray)) { if (!(a instanceof JsonArray)) {
error(path+".unionAll", a, "union is not an array", IssueType.INVALID); error(path+".unionAll", a, "union is not an array", IssueType.INVALID);
@ -203,7 +224,7 @@ public class Validator {
if (!(e instanceof JsonObject)) { if (!(e instanceof JsonObject)) {
error(path+".unionAll["+i+"]", e, "unionAll["+i+"] is not an object", IssueType.INVALID); error(path+".unionAll["+i+"]", e, "unionAll["+i+"] is not an object", IssueType.INVALID);
} else { } else {
unionColumns.add(checkSelect(path+".unionAll["+i+"]", (JsonObject) e, t)); unionColumns.add(checkSelect(vd, path+".unionAll["+i+"]", (JsonObject) e, t));
} }
i++; i++;
} }
@ -242,7 +263,7 @@ public class Validator {
} }
} }
private Column checkColumn(String path, JsonObject column, TypeDetails t) { private Column checkColumn(JsonObject vd, String path, JsonObject column, TypeDetails t) {
checkProperties(column, path, "path", "name", "description", "collection", "type", "tag"); checkProperties(column, path, "path", "name", "description", "collection", "type", "tag");
if (!column.has("path")) { if (!column.has("path")) {
@ -260,7 +281,7 @@ public class Validator {
try { try {
node = fpe.parse(expr); node = fpe.parse(expr);
column.setUserData("path", node); column.setUserData("path", node);
td = fpe.checkOnTypes(null, resourceName, t, node, warnings); td = fpe.checkOnTypes(vd, resourceName, t, node, warnings);
} catch (Exception e) { } catch (Exception e) {
error(path, expression, e.getMessage(), IssueType.INVALID); error(path, expression, e.getMessage(), IssueType.INVALID);
} }
@ -296,25 +317,31 @@ public class Validator {
// ok, name is sorted! // ok, name is sorted!
if (columnName != null) { if (columnName != null) {
column.setUserData("name", columnName); column.setUserData("name", columnName);
boolean isColl = (td.getCollectionStatus() != CollectionStatus.SINGLETON); boolean isColl = false;
if (column.has("collection")) { if (column.has("collection")) {
JsonElement collectionJ = column.get("collection"); JsonElement collectionJ = column.get("collection");
if (!(collectionJ instanceof JsonBoolean)) { if (!(collectionJ instanceof JsonBoolean)) {
error(path+".collection", collectionJ, "collection is not a boolean", IssueType.INVALID); error(path+".collection", collectionJ, "collection is not a boolean", IssueType.INVALID);
} else { } else {
boolean collection = collectionJ.asJsonBoolean().asBoolean(); boolean collection = collectionJ.asJsonBoolean().asBoolean();
if (!collection && isColl) { if (collection) {
isColl = false; isColl = true;
warning(path, column, "collection is false, but the path statement(s) might return multiple values for the column '"+columnName+"' some inputs");
} }
} }
} }
if (isColl) { if (isColl) {
if (td.getCollectionStatus() == CollectionStatus.SINGLETON) {
hint(path, column, "collection is true, but the path statement(s) can only return single values for the column '"+columnName+"'");
}
} else {
if (arrays == null) { if (arrays == null) {
warning(path, expression, "The column '"+columnName+"' appears to be a collection based on it's path. Collections are not supported in all execution contexts"); warning(path, expression, "The column '"+columnName+"' appears to be a collection based on it's path. Collections are not supported in all execution contexts");
} else if (!arrays) { } else if (!arrays) {
warning(path, expression, "The column '"+columnName+"' appears to be a collection based on it's path, but this is not allowed in the current execution context"); warning(path, expression, "The column '"+columnName+"' appears to be a collection based on it's path, but this is not allowed in the current execution context");
} }
if (td.getCollectionStatus() != CollectionStatus.SINGLETON) {
warning(path, column, "collection is not true, but the path statement(s) might return multiple values for the column '"+columnName+"' for some inputs");
}
} }
Set<String> types = new HashSet<>(); Set<String> types = new HashSet<>();
if (node.isNullSet()) { if (node.isNullSet()) {
@ -330,7 +357,7 @@ public class Validator {
if (typeJ instanceof JsonString) { if (typeJ instanceof JsonString) {
String type = typeJ.asString(); String type = typeJ.asString();
if (!td.hasType(type)) { if (!td.hasType(type)) {
error(path+".type", typeJ, "The path expression does not return a value of the type '"+type, IssueType.VALUE); error(path+".type", typeJ, "The path expression does not return a value of the type '"+type+"' - found "+td.describe(), IssueType.VALUE);
} else { } else {
types.clear(); types.clear();
types.add(simpleType(type)); types.add(simpleType(type));
@ -377,6 +404,8 @@ public class Validator {
case "integer": return ColumnKind.Integer; case "integer": return ColumnKind.Integer;
case "decimal": return ColumnKind.Decimal; case "decimal": return ColumnKind.Decimal;
case "string": return ColumnKind.String; case "string": return ColumnKind.String;
case "id": return ColumnKind.String;
case "code": return ColumnKind.String;
case "base64Binary": return ColumnKind.Binary; case "base64Binary": return ColumnKind.Binary;
case "time": return ColumnKind.Time; case "time": return ColumnKind.Time;
default: return ColumnKind.Complex; default: return ColumnKind.Complex;
@ -384,7 +413,7 @@ public class Validator {
} }
private boolean isSimpleType(String type) { private boolean isSimpleType(String type) {
return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary"); return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time");
} }
private String simpleType(String type) { private String simpleType(String type) {
@ -413,7 +442,7 @@ public class Validator {
return type; return type;
} }
private TypeDetails checkForEach(String path, JsonObject focus, JsonElement expression, TypeDetails t) { private TypeDetails checkForEach(JsonObject vd, String path, JsonObject focus, JsonElement expression, TypeDetails t) {
if (!(expression instanceof JsonString)) { if (!(expression instanceof JsonString)) {
error(path+".forEach", expression, "forEach is not a string", IssueType.INVALID); error(path+".forEach", expression, "forEach is not a string", IssueType.INVALID);
return null; return null;
@ -425,7 +454,7 @@ public class Validator {
try { try {
ExpressionNode n = fpe.parse(expr); ExpressionNode n = fpe.parse(expr);
focus.setUserData("forEach", n); focus.setUserData("forEach", n);
td = fpe.checkOnTypes(null, resourceName, t, n, warnings); td = fpe.checkOnTypes(vd, resourceName, t, n, warnings);
} catch (Exception e) { } catch (Exception e) {
error(path, expression, e.getMessage(), IssueType.INVALID); error(path, expression, e.getMessage(), IssueType.INVALID);
} }
@ -438,7 +467,7 @@ public class Validator {
} }
} }
private TypeDetails checkForEachOrNull(String path, JsonObject focus, JsonElement expression, TypeDetails t) { private TypeDetails checkForEachOrNull(JsonObject vd, String path, JsonObject focus, JsonElement expression, TypeDetails t) {
if (!(expression instanceof JsonString)) { if (!(expression instanceof JsonString)) {
error(path+".forEachOrNull", expression, "forEachOrNull is not a string", IssueType.INVALID); error(path+".forEachOrNull", expression, "forEachOrNull is not a string", IssueType.INVALID);
return null; return null;
@ -450,7 +479,7 @@ public class Validator {
try { try {
ExpressionNode n = fpe.parse(expr); ExpressionNode n = fpe.parse(expr);
focus.setUserData("forEachOrNull", n); focus.setUserData("forEachOrNull", n);
td = fpe.checkOnTypes(null, resourceName, t, n, warnings); td = fpe.checkOnTypes(vd, resourceName, t, n, warnings);
} catch (Exception e) { } catch (Exception e) {
error(path, expression, e.getMessage(), IssueType.INVALID); error(path, expression, e.getMessage(), IssueType.INVALID);
} }
@ -477,69 +506,79 @@ public class Validator {
} }
} }
if (constant.has("valueBase64Binary")) { if (constant.has("valueBase64Binary")) {
checkIsString(path, constant, "valueBase64Binary"); checkIsString(path, constant, "valueBase64Binary", new Base64BinaryType());
} else if (constant.has("valueBoolean")) { } else if (constant.has("valueBoolean")) {
checkIsBoolean(path, constant, "valueBoolean"); checkIsBoolean(path, constant, "valueBoolean", new BooleanType());
} else if (constant.has("valueCanonical")) { } else if (constant.has("valueCanonical")) {
checkIsString(path, constant, "valueCanonical"); checkIsString(path, constant, "valueCanonical", new CanonicalType());
} else if (constant.has("valueCode")) { } else if (constant.has("valueCode")) {
checkIsString(path, constant, "valueCode"); checkIsString(path, constant, "valueCode", new CodeType());
} else if (constant.has("valueDate")) { } else if (constant.has("valueDate")) {
checkIsString(path, constant, "valueDate"); checkIsString(path, constant, "valueDate", new DateType());
} else if (constant.has("valueDateTime")) { } else if (constant.has("valueDateTime")) {
checkIsString(path, constant, "valueDateTime"); checkIsString(path, constant, "valueDateTime", new DateTimeType());
} else if (constant.has("valueDecimal")) { } else if (constant.has("valueDecimal")) {
checkIsNumber(path, constant, "valueDecimal"); checkIsNumber(path, constant, "valueDecimal", new DecimalType());
} else if (constant.has("valueId")) { } else if (constant.has("valueId")) {
checkIsString(path, constant, "valueId"); checkIsString(path, constant, "valueId", new IdType());
} else if (constant.has("valueInstant")) { } else if (constant.has("valueInstant")) {
checkIsString(path, constant, "valueInstant"); checkIsString(path, constant, "valueInstant", new InstantType());
} else if (constant.has("valueInteger")) { } else if (constant.has("valueInteger")) {
checkIsNumber(path, constant, "valueInteger"); checkIsNumber(path, constant, "valueInteger", new IntegerType());
} else if (constant.has("valueInteger64")) { } else if (constant.has("valueInteger64")) {
checkIsNumber(path, constant, "valueInteger64"); checkIsNumber(path, constant, "valueInteger64", new Integer64Type());
} else if (constant.has("valueOid")) { } else if (constant.has("valueOid")) {
checkIsString(path, constant, "valueOid"); checkIsString(path, constant, "valueOid", new OidType());
} else if (constant.has("valueString")) { } else if (constant.has("valueString")) {
checkIsString(path, constant, "valueString"); checkIsString(path, constant, "valueString", new StringType());
} else if (constant.has("valuePositiveInt")) { } else if (constant.has("valuePositiveInt")) {
checkIsNumber(path, constant, "valuePositiveInt"); checkIsNumber(path, constant, "valuePositiveInt", new PositiveIntType());
} else if (constant.has("valueTime")) { } else if (constant.has("valueTime")) {
checkIsString(path, constant, "valueTime"); checkIsString(path, constant, "valueTime", new TimeType());
} else if (constant.has("valueUnsignedInt")) { } else if (constant.has("valueUnsignedInt")) {
checkIsNumber(path, constant, "valueUnsignedInt"); checkIsNumber(path, constant, "valueUnsignedInt", new UnsignedIntType());
} else if (constant.has("valueUri")) { } else if (constant.has("valueUri")) {
checkIsString(path, constant, "valueUri"); checkIsString(path, constant, "valueUri", new UriType());
} else if (constant.has("valueUrl")) { } else if (constant.has("valueUrl")) {
checkIsString(path, constant, "valueUrl"); checkIsString(path, constant, "valueUrl", new UrlType());
} else if (constant.has("valueUuid")) { } else if (constant.has("valueUuid")) {
checkIsString(path, constant, "valueUuid"); checkIsString(path, constant, "valueUuid", new UuidType());
} else { } else {
error(path, constant, "No value found", IssueType.REQUIRED); error(path, constant, "No value found", IssueType.REQUIRED);
} }
} }
private void checkIsString(String path, JsonObject constant, String name) { private void checkIsString(String path, JsonObject constant, String name, PrimitiveType<?> value) {
JsonElement j = constant.get(name); JsonElement j = constant.get(name);
if (!(j instanceof JsonString)) { if (!(j instanceof JsonString)) {
error(path+"."+name, j, name+" must be a string", IssueType.INVALID); error(path+"."+name, j, name+" must be a string", IssueType.INVALID);
} else {
value.setValueAsString(j.asString());
constant.setUserData("value", value);
} }
} }
private void checkIsBoolean(String path, JsonObject constant, String name) { private void checkIsBoolean(String path, JsonObject constant, String name, PrimitiveType<?> value) {
JsonElement j = constant.get(name); JsonElement j = constant.get(name);
if (!(j instanceof JsonBoolean)) { if (!(j instanceof JsonBoolean)) {
error(path+"."+name, j, name+" must be a boolean", IssueType.INVALID); error(path+"."+name, j, name+" must be a boolean", IssueType.INVALID);
} else {
value.setValueAsString(j.asString());
constant.setUserData("value", value);
} }
} }
private void checkIsNumber(String path, JsonObject constant, String name) { private void checkIsNumber(String path, JsonObject constant, String name, PrimitiveType<?> value) {
JsonElement j = constant.get(name); JsonElement j = constant.get(name);
if (!(j instanceof JsonNumber)) { if (!(j instanceof JsonNumber)) {
error(path+"."+name, j, name+" must be a number", IssueType.INVALID); error(path+"."+name, j, name+" must be a number", IssueType.INVALID);
} else {
value.setValueAsString(j.asString());
constant.setUserData("value", value);
} }
} }
private void checkWhere(String path, JsonObject where) {
private void checkWhere(JsonObject vd, String path, JsonObject where) {
checkProperties(where, path, "path", "description"); checkProperties(where, path, "path", "description");
String expr = where.asString("path"); String expr = where.asString("path");
@ -553,7 +592,7 @@ public class Validator {
try { try {
ExpressionNode n = fpe.parse(expr); ExpressionNode n = fpe.parse(expr);
where.setUserData("path", n); where.setUserData("path", n);
td = fpe.checkOnTypes(null, resourceName, types, n, warnings); td = fpe.checkOnTypes(vd, resourceName, types, n, warnings);
} catch (Exception e) { } catch (Exception e) {
error(path, where.get("path"), e.getMessage(), IssueType.INVALID); error(path, where.get("path"), e.getMessage(), IssueType.INVALID);
} }

View File

@ -83,16 +83,15 @@ public class SQLOnFhirTests {
this.resources = resources; this.resources = resources;
this.testCase = testCase; this.testCase = testCase;
} }
} }
public static Stream<Arguments> data() throws ParserConfigurationException, SAXException, IOException { public static Stream<Arguments> data() throws ParserConfigurationException, SAXException, IOException {
List<Arguments> objects = new ArrayList<>(); List<Arguments> objects = new ArrayList<>();
File dir = ManagedFileAccess.file("/Users/grahamegrieve/work/sql-on-fhir-v2/tests/content"); JsonArray testFiles = (JsonArray) JsonParser.parse(TestingUtilities.loadTestResourceStream("sql-on-fhir", "manifest.json"));
for (File f : dir.listFiles()) {
if (f.getName().endsWith(".json")) { for (String s : testFiles.asStrings()) {
JsonObject json = JsonParser.parseObject(f); JsonObject json = JsonParser.parseObject(TestingUtilities.loadTestResourceStream("sql-on-fhir", s));
String name1 = f.getName().replace(".json", ""); String name1 = s.replace(".json", "");
List<JsonObject> resources = json.getJsonObjects("resources"); List<JsonObject> resources = json.getJsonObjects("resources");
int i = 0; int i = 0;
for (JsonObject test : json.getJsonObjects("tests")) { for (JsonObject test : json.getJsonObjects("tests")) {
@ -101,7 +100,6 @@ public class SQLOnFhirTests {
i++; i++;
} }
} }
}
return objects.stream(); return objects.stream();
} }
@ -110,7 +108,6 @@ public class SQLOnFhirTests {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@ParameterizedTest(name = "{index}: file {0}") @ParameterizedTest(name = "{index}: file {0}")
@MethodSource("data") @MethodSource("data")
@Disabled
public void test(String name, TestDetails test) throws FileNotFoundException, IOException, FHIRException, org.hl7.fhir.exceptions.FHIRException, UcumException { public void test(String name, TestDetails test) throws FileNotFoundException, IOException, FHIRException, org.hl7.fhir.exceptions.FHIRException, UcumException {
this.details = test; this.details = test;
Runner runner = new Runner(); Runner runner = new Runner();
@ -137,8 +134,8 @@ public class SQLOnFhirTests {
rows.add("rows", results); rows.add("rows", results);
JsonObject exp = new JsonObject(); JsonObject exp = new JsonObject();
exp.add("rows", test.testCase.getJsonArray("expect")); exp.add("rows", test.testCase.getJsonArray("expect"));
sortResults(exp); // sortResults(exp);
sortResults(rows); // sortResults(rows);
String expS = JsonParser.compose(exp, true); String expS = JsonParser.compose(exp, true);
String rowS = JsonParser.compose(rows, true); String rowS = JsonParser.compose(rows, true);
String c = CompareUtilities.checkJsonSrcIsSame(name, expS, rowS, null); String c = CompareUtilities.checkJsonSrcIsSame(name, expS, rowS, null);