Merge 12c05a0b3c
into 8358354d2f
This commit is contained in:
commit
50d19800f7
|
@ -25,6 +25,7 @@ import org.hl7.fhir.r5.model.StringType;
|
|||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
|
||||
public class Runner implements IEvaluationContext {
|
||||
|
@ -84,7 +85,14 @@ public class Runner implements IEvaluationContext {
|
|||
if (storage == null) {
|
||||
throw new FHIRException("No storage provided");
|
||||
}
|
||||
Validator validator = new Validator(context, fpe, prohibitedNames, storage.supportsArrays(), storage.supportsComplexTypes(), storage.needsName());
|
||||
Validator validator =
|
||||
new Validator(
|
||||
context,
|
||||
fpe,
|
||||
prohibitedNames,
|
||||
storage.supportsArrays() ? IssueSeverity.NULL : IssueSeverity.ERROR,
|
||||
storage.supportsComplexTypes() ? IssueSeverity.NULL : IssueSeverity.ERROR,
|
||||
storage.needsName() ? IssueSeverity.ERROR : IssueSeverity.NULL);
|
||||
validator.checkViewDefinition(path, viewDefinition);
|
||||
issues = validator.getIssues();
|
||||
validator.dump();
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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;
|
||||
|
@ -11,7 +10,6 @@ import org.hl7.fhir.r5.context.IWorkerContext;
|
|||
import org.hl7.fhir.r5.fhirpath.ExpressionNode;
|
||||
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine;
|
||||
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;
|
||||
|
@ -53,37 +51,48 @@ public class Validator {
|
|||
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 IssueSeverity checkArrays;
|
||||
private IssueSeverity checkComplexTypes;
|
||||
private IssueSeverity checkNames;
|
||||
|
||||
private String resourceName;
|
||||
private String name;
|
||||
|
||||
public Validator(IWorkerContext context, FHIRPathEngine fpe, List<String> prohibitedNames, Boolean arrays, Boolean complexTypes, Boolean needsName) {
|
||||
/** To turn off a check, use {@code IssueSeverity.NULL}. */
|
||||
public Validator(
|
||||
IWorkerContext context,
|
||||
FHIRPathEngine fpe,
|
||||
List<String> prohibitedNames,
|
||||
IssueSeverity checkArrays,
|
||||
IssueSeverity checkComplexTypes,
|
||||
IssueSeverity checkNames) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.fpe = fpe;
|
||||
this.prohibitedNames = prohibitedNames;
|
||||
this.arrays = arrays;
|
||||
this.complexTypes = complexTypes;
|
||||
this.needsName = needsName;
|
||||
this.checkArrays = checkArrays;
|
||||
this.checkComplexTypes = checkComplexTypes;
|
||||
this.checkNames = checkNames;
|
||||
}
|
||||
|
||||
public String getResourceName() {
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
|
||||
public void checkViewDefinition(String path, JsonObject viewDefinition) {
|
||||
checkProperties(viewDefinition, path, "resourceType", "url", "identifier", "name", "version", "title", "status", "experimental", "date", "publisher", "contact", "description", "useContext", "copyright", "resource", "constant", "select", "where");
|
||||
|
||||
JsonElement nameJ = viewDefinition.get("name");
|
||||
if (nameJ == null) {
|
||||
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);
|
||||
if (!checkNames.isError()) {
|
||||
addMessage(
|
||||
checkNames,
|
||||
path,
|
||||
viewDefinition,
|
||||
"No name provided. A name is required in many contexts where a ViewDefinition is used",
|
||||
IssueType.BUSINESSRULE);
|
||||
} else {
|
||||
addMessage(checkNames, path, viewDefinition, "No name provided", IssueType.REQUIRED);
|
||||
}
|
||||
} else if (!(nameJ instanceof JsonString)) {
|
||||
error(path, viewDefinition, "name must be a string", IssueType.INVALID);
|
||||
|
@ -279,6 +288,8 @@ public class Validator {
|
|||
TypeDetails td = null;
|
||||
ExpressionNode node = null;
|
||||
try {
|
||||
// TODO: Add support for `fhirVersion`.
|
||||
// TODO: Add support for `getReferenceKey`.
|
||||
node = fpe.parse(expr);
|
||||
column.setUserData("path", node);
|
||||
td = fpe.checkOnTypes(vd, resourceName, t, node, warnings);
|
||||
|
@ -317,6 +328,7 @@ public class Validator {
|
|||
// ok, name is sorted!
|
||||
if (columnName != null) {
|
||||
column.setUserData("name", columnName);
|
||||
// TODO: Fix this collection testing; it mis-categorizes many singletons as collections.
|
||||
boolean isColl = false;
|
||||
if (column.has("collection")) {
|
||||
JsonElement collectionJ = column.get("collection");
|
||||
|
@ -334,10 +346,24 @@ public class Validator {
|
|||
hint(path, column, "collection is true, but the path statement(s) can only return single values for the column '"+columnName+"'");
|
||||
}
|
||||
} else {
|
||||
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");
|
||||
} 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");
|
||||
if (!checkArrays.isError()) {
|
||||
addMessage(
|
||||
checkArrays,
|
||||
path,
|
||||
expression,
|
||||
"The column '"
|
||||
+ columnName
|
||||
+ "' appears to be a collection based on it's path. Collections are not supported in all execution contexts",
|
||||
IssueType.BUSINESSRULE);
|
||||
} else {
|
||||
addMessage(
|
||||
checkArrays,
|
||||
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",
|
||||
IssueType.INVALID);
|
||||
}
|
||||
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");
|
||||
|
@ -371,17 +397,19 @@ public class Validator {
|
|||
error(path, column, "Unable to determine a type (found "+td.describe()+")", IssueType.BUSINESSRULE);
|
||||
} else {
|
||||
String type = types.iterator().next();
|
||||
boolean ok = false;
|
||||
boolean ok = true;
|
||||
if (!isSimpleType(type) && !"null".equals(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;
|
||||
String message = "The column '"
|
||||
+ columnName
|
||||
+ "' is a complex type. This is not supported in some Runners";
|
||||
if (!checkComplexTypes.isError()) {
|
||||
message =
|
||||
"The column '"
|
||||
+ columnName
|
||||
+ "' is a complex type but this is not allowed in this context";
|
||||
ok = false;
|
||||
}
|
||||
} else {
|
||||
ok = true;
|
||||
addMessage(checkComplexTypes, path, expression, message, IssueType.BUSINESSRULE);
|
||||
}
|
||||
if (ok) {
|
||||
Column col = new Column(columnName, isColl, type, kindForType(type));
|
||||
|
@ -413,7 +441,27 @@ public class Validator {
|
|||
}
|
||||
|
||||
private boolean isSimpleType(String type) {
|
||||
return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time");
|
||||
return Utilities.existsInList(
|
||||
type,
|
||||
"dateTime",
|
||||
"boolean",
|
||||
"integer",
|
||||
"decimal",
|
||||
"string",
|
||||
"base64Binary",
|
||||
"uri",
|
||||
"url",
|
||||
"canonical",
|
||||
"code",
|
||||
"id",
|
||||
"instant",
|
||||
"integer64",
|
||||
"markdown",
|
||||
"oid",
|
||||
"positiveInt",
|
||||
"time",
|
||||
"unsignedInt",
|
||||
"uuid");
|
||||
}
|
||||
|
||||
private String simpleType(String type) {
|
||||
|
@ -652,34 +700,42 @@ public class Validator {
|
|||
}
|
||||
}
|
||||
|
||||
private void error(String path, JsonElement e, String issue, IssueType type) {
|
||||
ValidationMessage vm = new ValidationMessage(Source.InstanceValidator, type, e.getStart().getLine(), e.getStart().getCol(), path, issue, IssueSeverity.ERROR);
|
||||
private void addMessage(IssueSeverity severity, String path, JsonElement e, String issue, IssueType type) {
|
||||
if (severity == IssueSeverity.NULL) return;
|
||||
ValidationMessage vm =
|
||||
new ValidationMessage(
|
||||
Source.InstanceValidator,
|
||||
type,
|
||||
e.getStart().getLine(),
|
||||
e.getStart().getCol(),
|
||||
path,
|
||||
issue,
|
||||
severity);
|
||||
issues.add(vm);
|
||||
}
|
||||
|
||||
private void error(String path, JsonElement e, String issue, IssueType type) {
|
||||
addMessage(IssueSeverity.ERROR, path, e, issue, type);
|
||||
}
|
||||
|
||||
private void warning(String path, JsonElement e, String issue) {
|
||||
ValidationMessage vm = new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, e.getStart().getLine(), e.getStart().getCol(), path, issue, IssueSeverity.WARNING);
|
||||
issues.add(vm);
|
||||
addMessage(IssueSeverity.WARNING, path, e, issue, IssueType.BUSINESSRULE);
|
||||
}
|
||||
|
||||
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);
|
||||
addMessage(IssueSeverity.INFORMATION, path, e, issue, IssueType.BUSINESSRULE);
|
||||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -5935,7 +5935,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} 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);
|
||||
Validator sqlv = new Validator(context, fpe, new ArrayList<>(), IssueSeverity.WARNING, IssueSeverity.WARNING, IssueSeverity.WARNING);
|
||||
sqlv.checkViewDefinition(stack.getLiteralPath(), json);
|
||||
errors.addAll(sqlv.getIssues());
|
||||
ok = sqlv.isOk() && ok;
|
||||
|
|
Loading…
Reference in New Issue