Skip to content

Commit

Permalink
GH-1112 sh:closed (#4944)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmottestad committed Apr 15, 2024
2 parents 3afda22 + 1dc2438 commit 26be6a5
Show file tree
Hide file tree
Showing 180 changed files with 3,498 additions and 215 deletions.
2 changes: 1 addition & 1 deletion core/sail/shacl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<dependency>
<groupId>org.topbraid</groupId>
<artifactId>shacl</artifactId>
<version>1.3.2</version>
<version>1.4.3</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ public static List<IRI> getSupportedShaclPredicates() {
SHACL.EQUALS,
SHACL.LESS_THAN,
SHACL.LESS_THAN_OR_EQUALS,
SHACL.CLOSED,
SHACL.IGNORED_PROPERTIES,
DASH.hasValueIn,
RSX.targetShape,
RSX.dataGraph,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*******************************************************************************
* Copyright (c) 2024 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
******************************************************************************/

package org.eclipse.rdf4j.sail.shacl.ast;

public interface CanProduceValidationReport {

void setProducesValidationReport(boolean producesValidationReport);

boolean producesValidationReport();

}
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,6 @@ public ConstraintComponent deepClone() {
return nodeShape;
}

@Override
public boolean overrideValidationReport() {
return false;
}

@Override
public SparqlFragment buildSparqlValidNodes_rsx_targetShape(Variable<Value> subject,
Variable<Value> object,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ public PlanNode generateTransactionalValidationPlan(ConnectionsGroup connections
.generateTransactionalValidationPlan(connectionsGroup, validationSettings, overrideTargetNode,
Scope.propertyShape);

if (!(constraintComponent instanceof PropertyShape) && !constraintComponent.overrideValidationReport()) {
if (produceValidationReports) {
validationPlanNode = new ValidationReportNode(validationPlanNode, t -> {
return new ValidationResult(t.getActiveTarget(), t.getValue(), this,
constraintComponent, getSeverity(), t.getScope(), t.getContexts(),
Expand Down Expand Up @@ -315,11 +315,6 @@ public ConstraintComponent deepClone() {
return nodeShape;
}

@Override
public boolean overrideValidationReport() {
return false;
}

@Override
public SparqlFragment buildSparqlValidNodes_rsx_targetShape(Variable<Value> subject,
Variable<Value> object,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import org.eclipse.rdf4j.sail.shacl.ast.constraintcomponents.QualifiedMinCountConstraintComponent;
import org.eclipse.rdf4j.sail.shacl.ast.constraintcomponents.SparqlConstraintComponent;
import org.eclipse.rdf4j.sail.shacl.ast.constraintcomponents.UniqueLangConstraintComponent;
import org.eclipse.rdf4j.sail.shacl.ast.constraintcomponents.VoidConstraintComponent;
import org.eclipse.rdf4j.sail.shacl.ast.constraintcomponents.XoneConstraintComponent;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.EmptyNode;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.PlanNode;
Expand Down Expand Up @@ -295,7 +296,7 @@ List<ConstraintComponent> getConstraintComponents(ShaclProperties properties, Sh

if (properties.isClosed()) {
constraintComponent.add(new ClosedConstraintComponent(shapeSource, properties.getProperty(),
properties.getIgnoredProperties()));
properties.getIgnoredProperties(), this));
}

for (IRI iri : properties.getClazz()) {
Expand Down Expand Up @@ -379,6 +380,10 @@ List<ConstraintComponent> getConstraintComponents(ShaclProperties properties, Sh
constraintComponent.add(component);
}

if (constraintComponent.isEmpty()) {
constraintComponent.add(new VoidConstraintComponent());
}

return constraintComponent;
}

Expand Down Expand Up @@ -608,11 +613,17 @@ private static void calculateIfProducesValidationResult(List<Shape> split) {
}
}

propertyShape.produceValidationReports = true;
if (propertyShape.constraintComponents.get(0) instanceof CanProduceValidationReport) {
((CanProduceValidationReport) propertyShape.constraintComponents.get(0))
.setProducesValidationReport(true);
} else {
propertyShape.produceValidationReports = true;
}

} else if (shape instanceof NodeShape) {
if (shape.constraintComponents.get(0) instanceof SparqlConstraintComponent) {
((SparqlConstraintComponent) shape.constraintComponents.get(0)).produceValidationReports = true;
if (shape.constraintComponents.get(0) instanceof CanProduceValidationReport) {
((CanProduceValidationReport) shape.constraintComponents.get(0))
.setProducesValidationReport(true);
} else {
shape.produceValidationReports = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,22 @@ public int hashCode() {
return Objects.hash(subject, predicate, object);
}

private final static String VALUES_TARGET_0 = "VALUES ( ?target_0000000000 ){}\n";
private final static String VALUES_TARGET_0_AND_1 = "VALUES ( ?target_0000000000 ?target_0000000001 ){}\n";

public String getSparqlValuesDecl(Set<String> varNamesRestriction, boolean addInheritedVarNames,
Set<String> varNamesInQueryFragment) {

// EffectiveTarget interns all the first 1000 variable names, so we can use == to compare them
if (subject.name == "target_0000000000" && predicate.name == null && object.name == null
&& varNamesRestriction.contains(subject.name) && varNamesInQueryFragment.contains(subject.name)) {
return VALUES_TARGET_0;
} else if (subject.name == "target_0000000000" && predicate.name == null && object.name == "target_0000000001"
&& varNamesRestriction.contains(subject.name) && varNamesInQueryFragment.contains(subject.name)
&& varNamesRestriction.contains(object.name) && varNamesInQueryFragment.contains(object.name)) {
return VALUES_TARGET_0_AND_1;
}

StringBuilder sb = new StringBuilder("VALUES ( ");
if (subject.name != null && varNamesRestriction.contains(subject.name) ||
subject.baseName != null && varNamesRestriction.contains(subject.baseName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,27 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;

import org.eclipse.rdf4j.model.Namespace;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.sail.SailConnection;
import org.eclipse.rdf4j.sail.shacl.ast.StatementMatcher.Variable;
import org.eclipse.rdf4j.sail.shacl.ast.constraintcomponents.ConstraintComponent;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.EmptyNode;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.PlanNode;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.Select;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.ValidationReportNode;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.ValidationTuple;
import org.eclipse.rdf4j.sail.shacl.results.ValidationResult;

public class ValidationQuery {

private final Set<Namespace> namespaces = new HashSet<>();
private ValidationResultGenerator validationResultGenerator;
private String query;
private ConstraintComponent.Scope scope;
private ConstraintComponent.Scope scope_validationReport;
Expand All @@ -54,6 +57,7 @@ public class ValidationQuery {

private Severity severity;
private Shape shape;
private List<Variable<?>> extraVariables = List.of();

public ValidationQuery(Collection<Namespace> namespaces, String query, List<Variable<Value>> targets,
Variable<Value> value,
Expand Down Expand Up @@ -90,6 +94,8 @@ public ValidationQuery(Collection<Namespace> namespaces, String query, List<Vari
this.constraintComponent = constraintComponent;
this.severity = severity;
this.shape = shape;
this.validationResultGenerator = new ValidationResultGenerator();

}

public ValidationQuery(Set<Namespace> namespaces, String query, ConstraintComponent.Scope scope,
Expand All @@ -101,6 +107,7 @@ public ValidationQuery(Set<Namespace> namespaces, String query, ConstraintCompon
this.variables = Collections.unmodifiableList(variables);
this.targetIndex = targetIndex;
this.valueIndex = valueIndex;
this.validationResultGenerator = new ValidationResultGenerator();
}

/**
Expand Down Expand Up @@ -169,41 +176,78 @@ public PlanNode getValidationPlan(SailConnection baseConnection, Resource[] data

Select select = new Select(baseConnection, fullQueryString, bindings -> {

var validationResultFunction = validationResultGenerator.getValidationTupleValidationResultFunction(this,
shapesGraphs, bindings);

ValidationTuple validationTuple;

if (scope_validationReport == ConstraintComponent.Scope.propertyShape) {
if (propertyShapeWithValue_validationReport) {
return new ValidationTuple(bindings.getValue(getTargetVariable(true)),
validationTuple = new ValidationTuple(bindings.getValue(getTargetVariable(true)),
bindings.getValue(getValueVariable(true)),
scope_validationReport, true, dataGraph);
} else {
return new ValidationTuple(bindings.getValue(getTargetVariable(true)),
validationTuple = new ValidationTuple(bindings.getValue(getTargetVariable(true)),
scope_validationReport, false, dataGraph);
}

} else {
return new ValidationTuple(bindings.getValue(getTargetVariable(true)),
validationTuple = new ValidationTuple(bindings.getValue(getTargetVariable(true)),
scope_validationReport, true, dataGraph);
}

return validationTuple.addValidationResult(validationResultFunction);

}, dataGraph);

return new ValidationReportNode(select, t -> {
return new ValidationResult(t.getActiveTarget(), t.getValue(), shape,
constraintComponent_validationReport, severity, t.getScope(), t.getContexts(), shapesGraphs);
});
return select;

}

public static class ValidationResultGenerator {

public Function<ValidationTuple, ValidationResult> getValidationTupleValidationResultFunction(
ValidationQuery validationQuery, Resource[] shapesGraphs, BindingSet bindings) {
return t -> new ValidationResult(t.getActiveTarget(), t.getValue(), validationQuery.shape,
validationQuery.constraintComponent_validationReport, validationQuery.severity, t.getScope(),
t.getContexts(), shapesGraphs);
}

}

public void setValidationResultGenerator(List<Variable<?>> extraVariables,
ValidationResultGenerator validationResultGenerator) {
this.validationResultGenerator = validationResultGenerator;
this.extraVariables = extraVariables;
}

private String getFullQueryString() {
String extraVariablesString;
if (!extraVariables.isEmpty()) {
Optional<String> reduce = extraVariables.stream()
.map(Variable::asSparqlVariable)
.reduce((a, b) -> a + " " + b);
if (reduce.isPresent()) {
extraVariablesString = reduce.get() + " ";
} else {
extraVariablesString = "";
}
} else
extraVariablesString = "";

if (scope_validationReport == ConstraintComponent.Scope.propertyShape
&& propertyShapeWithValue_validationReport) {

return ShaclPrefixParser.toSparqlPrefixes(namespaces) + "\nSELECT DISTINCT " +
"?" + getTargetVariable(true) + " " +
"?" + getValueVariable(true) + " " +
extraVariablesString +
"WHERE {\n" + query + "\n}";

} else {
return ShaclPrefixParser.toSparqlPrefixes(namespaces) + "\nSELECT DISTINCT " +
"?" + getTargetVariable(true) + " " +
extraVariablesString +
"WHERE {\n" + query + "\n}";
}
}
Expand Down Expand Up @@ -267,6 +311,18 @@ public void makeCurrentStateValidationReport() {
propertyShapeWithValue_validationReport = propertyShapeWithValue;
}

public Shape getShape() {
return shape;
}

public Severity getSeverity() {
return severity;
}

public ConstraintComponent getConstraintComponent_validationReport() {
return constraintComponent_validationReport;
}

// used for sh:deactivated
public static class Deactivated extends ValidationQuery {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,4 @@ static PlanNode getAllTargetsIncludingThoseAddedByPath(ConnectionsGroup connecti
return allTargets;
}

@Override
public boolean overrideValidationReport() {
return false;
}
}
Loading

0 comments on commit 26be6a5

Please sign in to comment.