more work on sql-on-fhir implementation

This commit is contained in:
Grahame Grieve 2023-10-16 23:12:15 +11:00
parent 41eaad7356
commit 1e98e69338
10 changed files with 363 additions and 198 deletions

View File

@ -132,6 +132,7 @@ public class Element extends Base implements NamedItem {
private Base source;
private boolean ignorePropertyOrder;
private FhirFormat format;
private Object nativeObject;
public Element(String name) {
super();
@ -1478,4 +1479,13 @@ public class Element extends Base implements NamedItem {
return this;
}
public Object getNativeObject() {
return nativeObject;
}
public Element setNativeObject(Object nativeObject) {
this.nativeObject = nativeObject;
return this;
}
}

View File

@ -193,6 +193,7 @@ public class JsonParser extends ParserBase {
}
private void checkObject(List<ValidationMessage> errors, JsonObject object, Element b, String path) {
b.setNativeObject(object);
checkComments(errors, object, b, path);
if (policy == ValidationPolicy.EVERYTHING) {
if (object.getProperties().size() == 0) {

View File

@ -224,6 +224,12 @@ public abstract class ParserBase {
new ContextUtilities(context).generateSnapshot(sd);
return sd;
}
}
for (StructureDefinition sd : context.fetchResourcesByType(StructureDefinition.class)) {
if (name.equals(sd.getUrl()) && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
new ContextUtilities(context).generateSnapshot(sd);
return sd;
}
}
logError(errors, ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, name), IssueSeverity.FATAL);
return null;

View File

@ -302,7 +302,7 @@ public class XmlParser extends ParserBase {
public Element parse(List<ValidationMessage> errors, org.w3c.dom.Element base, String type) throws Exception {
StructureDefinition sd = getDefinition(errors, 0, 0, FormatUtilities.FHIR_NS, type);
Element result = new Element(base.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd)).setFormat(FhirFormat.XML);
Element result = new Element(base.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd)).setFormat(FhirFormat.XML).setNativeObject(base);
result.setPath(base.getLocalName());
String path = "/"+pathPrefix(base.getNamespaceURI())+base.getLocalName();
checkElement(errors, base, path, result.getProperty(), false);
@ -431,7 +431,7 @@ public class XmlParser extends ParserBase {
}
}
}
Element n = new Element(property.getName(), property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML);
Element n = new Element(property.getName(), property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML).setNativeObject(child);
n.setPath(element.getPath()+"."+property.getName());
element.getChildren().add(n);
} else {
@ -440,7 +440,7 @@ public class XmlParser extends ParserBase {
if (!property.isChoice() && !name.equals(property.getName())) {
name = property.getName();
}
Element n = new Element(name, property).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML);
Element n = new Element(name, property).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML).setNativeObject(child);
if (property.isList()) {
n.setPath(element.getPath()+"."+property.getName()+"["+repeatCount+"]");
} else {
@ -497,7 +497,7 @@ public class XmlParser extends ParserBase {
npath = npath+"/"+pathPrefix(child.getNamespaceURI())+child.getLocalName();
name = child.getLocalName();
Element n = new Element(name, property).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML);
Element n = new Element(name, property).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML).setNativeObject(child);
cgn.getChildren().add(n);
n.setPath(element.getPath()+"."+property.getName());
checkElement(errors, (org.w3c.dom.Element) child, npath, n.getProperty(), false);
@ -524,7 +524,7 @@ public class XmlParser extends ParserBase {
npath = npath+"/text()";
name = mtProp.getName();
Element n = new Element(name, mtProp, mtProp.getType(), child.getTextContent().trim()).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML);
Element n = new Element(name, mtProp, mtProp.getType(), child.getTextContent().trim()).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML).setNativeObject(child);
cgn.getChildren().add(n);
n.setPath(element.getPath()+"."+mtProp.getName());

View File

@ -111,7 +111,11 @@ public class Runner implements IEvaluationContext {
}
if (ok) {
List<List<Cell>> rows = new ArrayList<>();
generateCells(b, vd, rows);
rows.add(new ArrayList<Cell>());
for (JsonObject select : vd.getJsonObjects("select")) {
executeSelect(select, b, rows);
}
for (List<Cell> row : rows) {
storage.addRow(store, row);
}
@ -119,48 +123,47 @@ public class Runner implements IEvaluationContext {
}
storage.finish(store);
}
private void generateCells(Base bl, JsonObject vd, List<List<Cell>> rows) {
if (vd.has("forEach")) {
executeForEach(vd, bl, rows);
} else if (vd.has("forEachOrNull")) {
executeForEachOrNull(vd, bl, rows);
} else if (vd.has("union")) {
executeUnion(vd, bl, rows);
} else {
for (JsonObject select : vd.getJsonObjects("select")) {
executeSelect(select, bl, rows);
}
}
}
private void executeSelect(JsonObject select, Base bl, List<List<Cell>> rows) {
if (select.has("path")) {
executeSelectPath(select, bl, rows);
} else if (select.has("forEach")) {
executeForEach(select, bl, rows);
private void executeSelect(JsonObject select, Base b, List<List<Cell>> rows) {
List<Base> focus = new ArrayList<>();
if (select.has("forEach")) {
focus.addAll(executeForEach(select, b));
} else if (select.has("forEachOrNull")) {
executeForEachOrNull(select, bl, rows);
} else if (select.has("union")) {
executeUnion(select, bl, rows);
focus.addAll(executeForEachOrNull(select, b));
} else {
focus.add(b);
}
}
private void executeForEach(JsonObject focus, Base b, List<List<Cell>> rows) {
ExpressionNode n = (ExpressionNode) focus.getUserData("forEach");
List<Base> bl2 = fpe.evaluate(b, n);
// } else if (select.has("union")) {
// focus.addAll(executeUnion(select, b));
List<List<Cell>> tempRows = new ArrayList<>();
tempRows.addAll(rows);
rows.clear();
for (Base b2 : bl2) {
List<List<Cell>> rowsToAdd = cloneRows(tempRows);
for (JsonObject select : focus.getJsonObjects("select")) {
executeSelect(select, b2, rowsToAdd);
for (Base f : focus) {
List<List<Cell>> rowsToAdd = cloneRows(tempRows);
for (JsonObject column : select.getJsonObjects("column")) {
executeColumn(column, f, rowsToAdd);
}
for (JsonObject sub : select.getJsonObjects("union")) {
executeSelect(sub, f, rowsToAdd);
}
for (JsonObject sub : select.getJsonObjects("select")) {
executeSelect(sub, f, rowsToAdd);
}
rows.addAll(rowsToAdd);
}
}
private List<Base> executeUnion(JsonObject focus, Base b, List<List<Cell>> rows) {
throw new FHIRException("union is not supported");
}
private List<List<Cell>> cloneRows(List<List<Cell>> rows) {
List<List<Cell>> list = new ArrayList<>();
for (List<Cell> row : rows) {
@ -176,30 +179,38 @@ public class Runner implements IEvaluationContext {
}
return list;
}
private void executeForEachOrNull(JsonObject focus, Base b, List<List<Cell>> rows) {
throw new FHIRException("forEachOrNull is not supported");
private List<Base> executeForEach(JsonObject focus, Base b) {
ExpressionNode n = (ExpressionNode) focus.getUserData("forEach");
List<Base> result = new ArrayList<>();
result.addAll(fpe.evaluate(b, n));
return result;
}
private void executeUnion(JsonObject focus, Base b, List<List<Cell>> rows) {
throw new FHIRException("union is not supported");
private List<Base> executeForEachOrNull(JsonObject focus, Base b) {
ExpressionNode n = (ExpressionNode) focus.getUserData("forEachOrNull");
List<Base> result = new ArrayList<>();
result.addAll(fpe.evaluate(b, n));
if (result.size() == 0) {
result.add(null);
}
return result;
}
private void executeSelectPath(JsonObject select, Base b, List<List<Cell>> rows) {
ExpressionNode n = (ExpressionNode) select.getUserData("path");
List<Base> bl2 = fpe.evaluate(b, n);
String name = select.getUserString("name");
if (!bl2.isEmpty()) {
if (rows.isEmpty()) {
rows.add(new ArrayList<Cell>());
}
for (List<Cell> row : rows) {
Cell c = cell(row, name);
if (c == null) {
c = new Cell(column(name));
row.add(c);
}
private void executeColumn(JsonObject column, Base b, List<List<Cell>> rows) {
ExpressionNode n = (ExpressionNode) column.getUserData("path");
List<Base> bl2 = new ArrayList<>();
if (b != null) {
bl2.addAll(fpe.evaluate(b, n));
}
String name = column.getUserString("name");
for (List<Cell> row : rows) {
Cell c = cell(row, name);
if (c == null) {
c = new Cell(column(name));
row.add(c);
}
if (!bl2.isEmpty()) {
if (bl2.size() + c.getValues().size() > 1) {
// this is a problem if collection != true or if the storage can't deal with it
// though this should've been picked up before now - but there are circumstances where it wouldn't be
@ -211,14 +222,6 @@ public class Runner implements IEvaluationContext {
c.getValues().add(genValue(c.getColumn(), b2));
}
}
} else {
for (List<Cell> row : rows) {
Cell c = cell(row, name);
if (c == null) {
c = new Cell(column(name));
row.add(c);
}
}
}
}
@ -376,6 +379,9 @@ public class Runner implements IEvaluationContext {
String rt = null;
if (parameters.size() > 0) {
rt = parameters.get(0).get(0).primitiveValue();
if (rt.startsWith("FHIR.")) {
rt = rt.substring(5);
}
}
List<Base> base = new ArrayList<Base>();
if (focus.size() == 1) {
@ -427,6 +433,10 @@ public class Runner implements IEvaluationContext {
public ValueSet resolveValueSet(Object appContext, String url) {
throw new Error("Not implemented yet: resolveValueSet");
}
@Override
public boolean paramIsType(String name, int index) {
return "getReferenceKey".equals(name);
}
}

View File

@ -1,6 +1,7 @@
package org.hl7.fhir.r5.utils.sql;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -24,20 +25,20 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
public class Validator {
private IWorkerContext context;
private FHIRPathEngine fpe;
private List<String> prohibitedNames = new ArrayList<String>();
private List<ValidationMessage> issues = new ArrayList<ValidationMessage>();
private boolean arrays;
private boolean complexTypes;
private boolean needsName;
private Boolean arrays;
private Boolean complexTypes;
private Boolean needsName;
private String resourceName;
private List<Column> columns = new ArrayList<Column>();
private String name;
protected Validator(IWorkerContext context, FHIRPathEngine fpe, List<String> prohibitedNames, boolean arrays, boolean complexTypes, boolean needsName) {
public Validator(IWorkerContext context, FHIRPathEngine fpe, List<String> prohibitedNames, Boolean arrays, Boolean complexTypes, Boolean needsName) {
super();
this.context = context;
this.fpe = fpe;
@ -58,7 +59,9 @@ public class Validator {
public void checkViewDefinition(String path, JsonObject viewDefinition) {
JsonElement nameJ = viewDefinition.get("name");
if (nameJ == null) {
if (needsName) {
if (needsName == null) {
hint(path, viewDefinition, "No name provided. A name is required in many contexts where a ViewDefinition is used");
} else if (needsName) {
error(path, viewDefinition, "No name provided", IssueType.REQUIRED);
}
} else if (!(nameJ instanceof JsonString)) {
@ -122,119 +125,201 @@ public class Validator {
}
private void checkSelect(String path, JsonObject select, TypeDetails t) {
if (select.has("path")) {
checkSelectPath(path, select, select.get("path"), t);
} else if (select.has("forEach")) {
checkForEach(path, select, select.get("forEach"), t);
if (select.has("forEach")) {
t = checkForEach(path, select, select.get("forEach"), t);
} else if (select.has("forEachOrNull")) {
checkForEachOrNull(path, select, select.get("forEachOrNull"), t);
} else if (select.has("union")) {
checkUnion(path, select, select.get("union"), t);
} else {
error(path, select, "The select has neither a path, forEach, forEachOrNull, or union statement", IssueType.REQUIRED);
t = checkForEachOrNull(path, select, select.get("forEachOrNull"), t);
}
if (t != null) {
boolean content = false;
if (select.has("union")) {
content = checkUnion(path, select, select.get("union"), t);
}
if (select.has("column")) {
JsonElement a = select.get("column");
if (!(a instanceof JsonArray)) {
error(path+".column", a, "column is not an array", IssueType.INVALID);
} else {
content = true;
int i = 0;
for (JsonElement e : ((JsonArray) a)) {
if (!(e instanceof JsonObject)) {
error(path+".column["+i+"]", a, "column["+i+"] is a "+e.type().toName()+" not an object", IssueType.INVALID);
} else {
checkColumn(path+".column["+i+"]", (JsonObject) e, t);
}
}
}
}
if (select.has("select")) {
JsonElement a = select.get("select");
if (!(a instanceof JsonArray)) {
error(path+".select", a, "select is not an array", IssueType.INVALID);
} else {
content = true;
int i = 0;
for (JsonElement e : ((JsonArray) a)) {
if (!(e instanceof JsonObject)) {
error(path+".select["+i+"]", e, "select["+i+"] is not an object", IssueType.INVALID);
} else {
checkSelect(path+".select["+i+"]", (JsonObject) e, t);
}
}
}
}
if (!content) {
error(path, select, "The select has no columns or selects", IssueType.REQUIRED);
}
}
}
private void checkSelectPath(String path, JsonObject select, JsonElement expression, TypeDetails t) {
if (!(expression instanceof JsonString)) {
error(path+".forEach", expression, "forEach is not a string", IssueType.INVALID);
} else {
String expr = expression.asString();
List<String> warnings = new ArrayList<>();
TypeDetails td = null;
ExpressionNode node = null;
try {
node = fpe.parse(expr);
select.setUserData("path", node);
td = fpe.checkOnTypes(null, resourceName, t, node, warnings);
} catch (Exception e) {
error(path, expression, e.getMessage(), IssueType.INVALID);
private boolean checkUnion(String path, JsonObject focus, JsonElement expression, TypeDetails t) {
JsonElement a = focus.get("union");
if (!(a instanceof JsonArray)) {
error(path+".union", a, "union is not an array", IssueType.INVALID);
return false;
} else {
int i = 0;
for (JsonElement e : ((JsonArray) a)) {
if (!(e instanceof JsonObject)) {
error(path+".union["+i+"]", e, "union["+i+"] is not an object", IssueType.INVALID);
} else {
checkSelect(path+".union["+i+"]", (JsonObject) e, t);
}
}
if (i < 2) {
warning(path+".union", a, "union should have more than one item");
}
if (td != null && node != null) {
for (String s : warnings) {
warning(path+".path", expression, s);
}
String columnName = null;
JsonElement aliasJ = select.get("alias");
if (aliasJ != null) {
if (aliasJ instanceof JsonString) {
columnName = aliasJ.asString();
if (!isValidName(columnName)) {
error(path+".name", aliasJ, "The name '"+columnName+"' is not valid", IssueType.VALUE);
}
} else {
error(path+".alias", aliasJ, "alias must be a string", IssueType.INVALID);
}
}
if (columnName == null) {
List<String> names = node.getDistalNames();
if (names.size() == 1 && names.get(0) != null) {
columnName = names.get(0);
if (!isValidName(columnName)) {
error(path+".path", expression, "The name '"+columnName+"' found in the path expression is not a valid column name, so an alias is required", IssueType.INVARIANT);
}
} else {
error(path, select, "The path does not resolve to a name, so an alias is required", IssueType.REQUIRED);
}
}
// ok, name is sorted!
if (columnName != null) {
select.setUserData("name", columnName);
boolean isColl = (td.getCollectionStatus() != CollectionStatus.SINGLETON) || column(columnName) != null;
if (select.has("collection")) {
JsonElement collectionJ = select.get("collection");
if (!(collectionJ instanceof JsonBoolean)) {
error(path+".collection", collectionJ, "collection is not a boolean", IssueType.INVALID);
} else {
boolean collection = collectionJ.asJsonBoolean().asBoolean();
if (!collection && isColl) {
isColl = false;
warning(path, select, "collection is false, but the path statement(s) might return multiple values for the column '"+columnName+"' some inputs");
}
}
}
if (isColl && !arrays) {
warning(path, expression, "column appears to be a collection, but this is not allowed in this context");
}
// ok collection is sorted
Set<String> types = new HashSet<>();
for (String type : td.getTypes()) {
types.add(simpleType(type));
}
return true;
}
}
private void checkColumn(String path, JsonObject column, TypeDetails t) {
if (!column.has("path")) {
error(path, column, "no path found", IssueType.INVALID);
} else {
JsonElement expression = column.get("path");
if (!(expression instanceof JsonString)) {
error(path+".forEach", expression, "forEach is not a string", IssueType.INVALID);
} else {
String expr = expression.asString();
JsonElement typeJ = select.get("type");
if (typeJ != null) {
if (typeJ instanceof JsonString) {
String type = typeJ.asString();
if (!td.hasType(type)) {
error(path+".type", typeJ, "The path expression does not return a value of the type '"+type, IssueType.VALUE);
} else {
types.clear();
types.add(simpleType(type));
List<String> warnings = new ArrayList<>();
TypeDetails td = null;
ExpressionNode node = null;
try {
node = fpe.parse(expr);
column.setUserData("path", node);
td = fpe.checkOnTypes(null, resourceName, t, node, warnings);
} catch (Exception e) {
error(path, expression, e.getMessage(), IssueType.INVALID);
}
if (td != null && node != null) {
for (String s : warnings) {
warning(path+".path", expression, s);
}
String columnName = null;
JsonElement aliasJ = column.get("alias");
if (aliasJ != null) {
if (aliasJ instanceof JsonString) {
columnName = aliasJ.asString();
if (!isValidName(columnName)) {
error(path+".name", aliasJ, "The name '"+columnName+"' is not valid", IssueType.VALUE);
}
} else {
error(path+".type", typeJ, "type must be a string", IssueType.INVALID);
error(path+".alias", aliasJ, "alias must be a string", IssueType.INVALID);
}
}
if (types.size() != 1) {
error(path, select, "Unable to determine a type (found "+td.describe()+")", IssueType.BUSINESSRULE);
} else {
String type = types.iterator().next();
if (!isSimpleType(type) && !complexTypes) {
error(path, expression, "column is a complex type but this is not allowed in this context", IssueType.BUSINESSRULE);
if (columnName == null) {
List<String> names = node.getDistalNames();
if (names.size() == 1 && names.get(0) != null) {
columnName = names.get(0);
if (!isValidName(columnName)) {
error(path+".path", expression, "The name '"+columnName+"' found in the path expression is not a valid column name, so an alias is required", IssueType.INVARIANT);
}
} else {
Column col = column(columnName);
if (col != null) {
if (!col.getType().equals(type)) {
error(path, expression, "Duplicate definition for "+columnName+" has different types ("+col.getType()+" vs "+type+")", IssueType.BUSINESSRULE);
error(path, column, "The path does not resolve to a name, so an alias is required", IssueType.REQUIRED);
}
}
// ok, name is sorted!
if (columnName != null) {
column.setUserData("name", columnName);
boolean isColl = (td.getCollectionStatus() != CollectionStatus.SINGLETON) || column(columnName) != null;
if (column.has("collection")) {
JsonElement collectionJ = column.get("collection");
if (!(collectionJ instanceof JsonBoolean)) {
error(path+".collection", collectionJ, "collection is not a boolean", IssueType.INVALID);
} else {
boolean collection = collectionJ.asJsonBoolean().asBoolean();
if (!collection && isColl) {
isColl = false;
warning(path, column, "collection is false, but the path statement(s) might return multiple values for the column '"+columnName+"' some inputs");
}
if (col.isColl() != isColl) {
error(path, expression, "Duplicate definition for "+columnName+" has different status for collection ("+col.isColl()+" vs "+isColl+")", IssueType.BUSINESSRULE);
}
}
if (isColl) {
if (arrays == null) {
warning(path, expression, "column appears to be a collection. Collections are not supported in all Runners");
} else if (!arrays) {
warning(path, expression, "column appears to be a collection, but this is not allowed in this context");
}
}
// ok collection is sorted
Set<String> types = new HashSet<>();
for (String type : td.getTypes()) {
types.add(simpleType(type));
}
JsonElement typeJ = column.get("type");
if (typeJ != null) {
if (typeJ instanceof JsonString) {
String type = typeJ.asString();
if (!td.hasType(type)) {
error(path+".type", typeJ, "The path expression does not return a value of the type '"+type, IssueType.VALUE);
} else {
types.clear();
types.add(simpleType(type));
}
} else {
columns.add(new Column(columnName, isColl, type, kindForType(type)));
error(path+".type", typeJ, "type must be a string", IssueType.INVALID);
}
}
if (types.size() != 1) {
error(path, column, "Unable to determine a type (found "+td.describe()+")", IssueType.BUSINESSRULE);
} else {
String type = types.iterator().next();
boolean ok = false;
if (!isSimpleType(type)) {
if (complexTypes) {
warning(path, expression, "Column is a complex type. This is not supported in some Runners");
} else if (!complexTypes) {
error(path, expression, "Column is a complex type but this is not allowed in this context", IssueType.BUSINESSRULE);
} else {
ok = true;
}
} else {
ok = true;
}
if (ok) {
Column col = column(columnName);
if (col != null) {
if (!col.getType().equals(type)) {
error(path, expression, "Duplicate definition for "+columnName+" has different types ("+col.getType()+" vs "+type+")", IssueType.BUSINESSRULE);
}
if (col.isColl() != isColl) {
error(path, expression, "Duplicate definition for "+columnName+" has different status for collection ("+col.isColl()+" vs "+isColl+")", IssueType.BUSINESSRULE);
}
} else {
columns.add(new Column(columnName, isColl, type, kindForType(type)));
}
}
}
}
@ -295,9 +380,10 @@ public class Validator {
return type;
}
private void checkForEach(String path, JsonObject focus, JsonElement expression, TypeDetails t) {
private TypeDetails checkForEach(String path, JsonObject focus, JsonElement expression, TypeDetails t) {
if (!(expression instanceof JsonString)) {
error(path+".forEach", expression, "forEach is not a string", IssueType.INVALID);
return null;
} else {
String expr = expression.asString();
@ -312,28 +398,36 @@ public class Validator {
}
if (td != null) {
for (String s : warnings) {
warning(path+".path", expression, s);
}
int i = 0;
if (checkAllObjects(path, focus, "select")) {
for (JsonObject select : focus.getJsonObjects("select")) {
checkSelect(path+".select["+i+"]", select, td);
i++;
}
if (i == 0) {
error(path, focus, "No select statements found", IssueType.REQUIRED);
}
warning(path+".forEach", expression, s);
}
}
return td;
}
}
private void checkForEachOrNull(String path, JsonObject focus, JsonElement expression, TypeDetails t) {
error(path+".forEachOrNull", expression, "forEachOrNull is not supported", IssueType.BUSINESSRULE);
}
private TypeDetails checkForEachOrNull(String path, JsonObject focus, JsonElement expression, TypeDetails t) {
if (!(expression instanceof JsonString)) {
error(path+".forEachOrNull", expression, "forEachOrNull is not a string", IssueType.INVALID);
return null;
} else {
String expr = expression.asString();
private void checkUnion(String path, JsonObject focus, JsonElement expression, TypeDetails t) {
error(path+".union", focus.get("union"), "union is not supported", IssueType.BUSINESSRULE);
List<String> warnings = new ArrayList<>();
TypeDetails td = null;
try {
ExpressionNode n = fpe.parse(expr);
focus.setUserData("forEachOrNull", n);
td = fpe.checkOnTypes(null, resourceName, t, n, warnings);
} catch (Exception e) {
error(path, expression, e.getMessage(), IssueType.INVALID);
}
if (td != null) {
for (String s : warnings) {
warning(path+".forEachOrNull", expression, s);
}
}
return td;
}
}
private void checkConstant(String path, JsonObject constant) {
@ -481,27 +575,40 @@ public class Validator {
issues.add(vm);
}
public void dump() {
for (ValidationMessage vm : issues) {
System.out.println(vm.summary());
}
private void hint(String path, JsonElement e, String issue) {
ValidationMessage vm = new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, e.getStart().getLine(), e.getStart().getCol(), path, issue, IssueSeverity.INFORMATION);
issues.add(vm);
}
public void check() {
public void dump() {
for (ValidationMessage vm : issues) {
System.out.println(vm.summary());
}
}
public void check() {
if (!isOk()) {
throw new FHIRException("View Definition is not valid");
}
}
public String getName() {
return name;
}
public List<ValidationMessage> getIssues() {
return issues;
}
public boolean isOk() {
boolean ok = true;
for (ValidationMessage vm : issues) {
if (vm.isError()) {
ok = false;
}
}
if (!ok) {
throw new FHIRException("View Definition is not valid");
}
}
public String getName() {
return name;
return ok;
}
}

View File

@ -337,6 +337,11 @@ public class ValidatorCli {
res.add("5.0");
res.add("-ig");
res.add("hl7.cda.uv.core#2.1.0-draft1");
} else if (a.equals("-view-definition")) {
res.add("-version");
res.add("5.0");
res.add("-ig");
res.add("hl7.fhir.uv.sql-on-fhir#current");
} else {
res.add(a);
}

View File

@ -160,6 +160,7 @@ import org.hl7.fhir.r5.utils.FHIRPathUtilityClasses.TypedElementDefinition;
import org.hl7.fhir.r5.utils.ResourceUtilities;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.r5.utils.sql.Validator;
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
@ -429,6 +430,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return context.fetchResource(ValueSet.class, url);
}
@Override
public boolean paramIsType(String name, int index) {
return false;
}
}
private FHIRPathEngine fpe;
@ -5379,6 +5385,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(errors, element, stack) && ok;
} else if (element.getType().equals("ValueSet")) {
return new ValueSetValidator(this).validateValueSet(errors, element, stack) && ok;
} else if ("http://hl7.org/fhir/uv/sql-on-fhir/StructureDefinition/ViewDefinition".equals(element.getProperty().getStructure().getUrl())) {
if (element.getNativeObject() != null && element.getNativeObject() instanceof JsonObject) {
JsonObject json = (JsonObject) element.getNativeObject();
Validator sqlv = new Validator(context, fpe, new ArrayList<>(), null, null, null);
sqlv.checkViewDefinition(stack.getLiteralPath(), json);
errors.addAll(sqlv.getIssues());
ok = sqlv.isOk() && ok;
}
return ok;
} else {
return ok;
}

View File

@ -397,6 +397,10 @@ public class SnapShotGenerationXTests {
throw new Error("Not implemented yet");
}
@Override
public boolean paramIsType(String name, int index) {
return false;
}
}
private static FHIRPathEngine fp;
@ -577,4 +581,6 @@ public class SnapShotGenerationXTests {
}
return sd;
}
}

View File

@ -804,4 +804,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
}
}
@Override
public boolean paramIsType(String name, int index) {
return false;
}
}