Skip to content

Commit

Permalink
GH-4770 SHACL Property Pair Constraint Components (#4771)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmottestad authored Dec 25, 2023
2 parents a6ec965 + 72813eb commit a92ae7b
Show file tree
Hide file tree
Showing 158 changed files with 3,055 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class RSX {
public final static IRI valueConformsToXsdDatatypeFunction = create("valueConformsToXsdDatatypeFunction");

public final static IRI DataAndShapesGraphLink = create("DataAndShapesGraphLink");
public final static IRI actualPairwisePath = create("actualPairwisePath");

private static IRI create(String localName) {
return Vocabularies.createIRI(RSX.NAMESPACE, localName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,13 +320,21 @@ public static List<IRI> getSupportedShaclPredicates() {
SHACL.QUALIFIED_VALUE_SHAPE,
SHACL.SHAPES_GRAPH,
SHACL.MESSAGE,
SHACL.NAME,
SHACL.DESCRIPTION,
SHACL.DEFAULT_VALUE,
SHACL.ORDER,
SHACL.GROUP,
SHACL.DECLARE,
SHACL.SPARQL,
SHACL.SELECT,
SHACL.PREFIXES,
SHACL.PREFIX_PROP,
SHACL.NAMESPACE_PROP,
SHACL.SEVERITY_PROP,
SHACL.EQUALS,
SHACL.LESS_THAN,
SHACL.LESS_THAN_OR_EQUALS,
DASH.hasValueIn,
RSX.targetShape,
RSX.dataGraph,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@ 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 @@ -16,6 +16,7 @@
import java.util.stream.Collectors;

import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Value;
Expand Down Expand Up @@ -45,10 +46,11 @@
public class PropertyShape extends Shape {
private static final Logger logger = LoggerFactory.getLogger(PropertyShape.class);

List<String> name;
List<String> description;
Object defaultValue;
Object group;
List<Literal> name;
List<Literal> description;
Value defaultValue;
Value group;
Value order;

Path path;

Expand All @@ -62,6 +64,7 @@ public PropertyShape(PropertyShape propertyShape) {
this.defaultValue = propertyShape.defaultValue;
this.group = propertyShape.group;
this.path = propertyShape.path;
this.order = propertyShape.order;
}

public static PropertyShape getInstance(ShaclProperties properties, ShapeSource shapeSource,
Expand Down Expand Up @@ -93,6 +96,12 @@ public void populate(ShaclProperties properties, ShapeSource connection, ParseSe
throw new IllegalStateException(properties.getId() + " is a sh:PropertyShape without a sh:path!");
}

this.name = properties.getName();
this.description = properties.getDescription();
this.defaultValue = properties.getDefaultValue();
this.order = properties.getOrder();
this.group = properties.getGroup();

constraintComponents = getConstraintComponents(properties, connection, parseSettings, cache);
}

Expand All @@ -107,6 +116,26 @@ public void toModel(Resource subject, IRI predicate, Model model, Set<Resource>
super.toModel(subject, predicate, model, cycleDetection);
model.add(getId(), RDF.TYPE, SHACL.PROPERTY_SHAPE);

for (Literal literal : name) {
model.add(getId(), SHACL.NAME, literal);
}

for (Literal literal : description) {
model.add(getId(), SHACL.DESCRIPTION, literal);
}

if (defaultValue != null) {
model.add(getId(), SHACL.DEFAULT_VALUE, defaultValue);
}

if (order != null) {
model.add(getId(), SHACL.ORDER, order);
}

if (group != null) {
model.add(getId(), SHACL.GROUP, group);
}

if (subject != null) {
if (predicate == null) {
model.add(subject, SHACL.PROPERTY, getId());
Expand Down Expand Up @@ -202,7 +231,7 @@ public PlanNode generateTransactionalValidationPlan(ConnectionsGroup connections
.generateTransactionalValidationPlan(connectionsGroup, validationSettings, overrideTargetNode,
Scope.propertyShape);

if (!(constraintComponent instanceof PropertyShape)) {
if (!(constraintComponent instanceof PropertyShape) && !constraintComponent.overrideValidationReport()) {
validationPlanNode = new ValidationReportNode(validationPlanNode, t -> {
return new ValidationResult(t.getActiveTarget(), t.getValue(), this,
constraintComponent, getSeverity(), t.getScope(), t.getContexts(),
Expand Down Expand Up @@ -286,6 +315,11 @@ 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 @@ -96,6 +96,13 @@ public class ShaclProperties {
private final List<Literal> message = new ArrayList<>();
private IRI severity;

private final List<Literal> name = new ArrayList<>();
private final List<Literal> description = new ArrayList<>();

private Value defaultValue;
private Value order;
private Value group;

private final List<Resource> sparql = new ArrayList<>();

public ShaclProperties(Resource id, ShapeSource connection) {
Expand Down Expand Up @@ -173,6 +180,21 @@ public ShaclProperties(Resource id, ShapeSource connection) {
throw getExceptionForCastIssue(id, predicate, Literal.class, object);
}
break;
case "http://www.w3.org/ns/shacl#name":
try {
name.add((Literal) object);
} catch (ClassCastException e) {
throw getExceptionForCastIssue(id, predicate, Literal.class, object);
}
break;
case "http://www.w3.org/ns/shacl#description":
try {
description.add((Literal) object);
} catch (ClassCastException e) {
throw getExceptionForCastIssue(id, predicate, Literal.class, object);
}
break;

case "http://www.w3.org/ns/shacl#severity":
if (severity != null) {
throw getExceptionForAlreadyPopulated(id, predicate, severity, object);
Expand All @@ -183,6 +205,24 @@ public ShaclProperties(Resource id, ShapeSource connection) {
throw getExceptionForCastIssue(id, predicate, IRI.class, object);
}
break;
case "http://www.w3.org/ns/shacl#defaultValue":
if (defaultValue != null) {
throw getExceptionForAlreadyPopulated(id, predicate, defaultValue, object);
}
defaultValue = object;
break;
case "http://www.w3.org/ns/shacl#group":
if (group != null) {
throw getExceptionForAlreadyPopulated(id, predicate, group, object);
}
group = object;
break;
case "http://www.w3.org/ns/shacl#order":
if (order != null) {
throw getExceptionForAlreadyPopulated(id, predicate, order, object);
}
order = object;
break;
case "http://www.w3.org/ns/shacl#languageIn":
if (languageIn != null) {
throw getExceptionForAlreadyPopulated(id, predicate, languageIn, object);
Expand Down Expand Up @@ -592,8 +632,9 @@ private static ShaclShapeParsingException getExceptionForCastIssue(Resource id,
}

private static String getClassName(Value object) {
if (object == null)
if (object == null) {
return "null";
}
String actualClassName;
if (object.isIRI()) {
actualClassName = "IRI";
Expand Down Expand Up @@ -726,6 +767,26 @@ public IRI getSeverity() {
return severity;
}

public List<Literal> getName() {
return name;
}

public List<Literal> getDescription() {
return description;
}

public Value getDefaultValue() {
return defaultValue;
}

public Value getOrder() {
return order;
}

public Value getGroup() {
return group;
}

public List<Resource> getProperty() {
return property;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,23 +309,23 @@ List<ConstraintComponent> getConstraintComponents(ShaclProperties properties, Sh
}

for (IRI iri : properties.getEquals()) {
var equalsConstraintComponent = new EqualsConstraintComponent(iri);
var equalsConstraintComponent = new EqualsConstraintComponent(iri, this);
constraintComponent.add(equalsConstraintComponent);
}

for (IRI iri : properties.getDisjoint()) {
var disjointConstraintComponent = new DisjointConstraintComponent(iri);
var disjointConstraintComponent = new DisjointConstraintComponent(iri, this);
constraintComponent.add(disjointConstraintComponent);
}

for (IRI iri : properties.getLessThan()) {
var lessThanConstraintComponent = new LessThanConstraintComponent(iri);
var lessThanConstraintComponent = new LessThanConstraintComponent(iri, this);
constraintComponent.add(lessThanConstraintComponent);
}

for (IRI iri : properties.getLessThanOrEquals()) {
var lessThanOrEqualsConstraintComponent = new LessThanOrEqualsConstraintComponent(
iri);
iri, this);
constraintComponent.add(lessThanOrEqualsConstraintComponent);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,16 @@
import org.eclipse.rdf4j.sail.shacl.ast.StatementMatcher.Variable;
import org.eclipse.rdf4j.sail.shacl.ast.ValidationApproach;
import org.eclipse.rdf4j.sail.shacl.ast.ValidationQuery;
import org.eclipse.rdf4j.sail.shacl.ast.paths.Path;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.BufferedSplitter;
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.PlanNodeProvider;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.ReduceTargets;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.TrimToTarget;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.UnionNode;
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.Unique;
import org.eclipse.rdf4j.sail.shacl.ast.targets.EffectiveTarget;
import org.eclipse.rdf4j.sail.shacl.ast.targets.TargetChain;
import org.eclipse.rdf4j.sail.shacl.wrapper.data.ConnectionsGroup;
import org.eclipse.rdf4j.sail.shacl.wrapper.data.RdfsSubClassOfReasoner;
Expand Down Expand Up @@ -144,4 +151,31 @@ public String stringRepresentationOfValue(Value value) {
throw new IllegalStateException(value.getClass().getSimpleName());
}

static PlanNode getAllTargetsIncludingThoseAddedByPath(ConnectionsGroup connectionsGroup,
ValidationSettings validationSettings, Scope scope, EffectiveTarget effectiveTarget, Path path,
boolean includeTargetsAffectedByRemoval) {
PlanNode allTargets;
BufferedSplitter addedTargets = new BufferedSplitter(
effectiveTarget.getPlanNode(connectionsGroup, validationSettings.getDataGraph(),
scope, includeTargetsAffectedByRemoval, null));

PlanNode addedByPath = path.getAllAdded(connectionsGroup, validationSettings.getDataGraph(), null);

addedByPath = Unique.getInstance(new TrimToTarget(addedByPath), false);

addedByPath = new ReduceTargets(addedByPath, addedTargets.getPlanNode());

addedByPath = effectiveTarget.extend(addedByPath, connectionsGroup, validationSettings.getDataGraph(),
scope, EffectiveTarget.Extend.left,
false,
null);

allTargets = UnionNode.getInstance(addedTargets.getPlanNode(), addedByPath);
return allTargets;
}

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

0 comments on commit a92ae7b

Please sign in to comment.