Hello,
consider I have the following graph:
CREATE (n:A)-[:develops]->(m:B)
I'd like to enforce that A has at least one edge "develops" and that B has at least one edge "develops".
For A, this is easy enough:
@prefix neo4j: <neo4j://graph.schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
neo4j:AShape a sh:NodeShape ;
sh:targetClass neo4j:A ;
sh:property [
sh:minCount 1 ;
sh:path neo4j:develops;
sh:class neo4j:B;
sh:nodekind sh:IRI;
]
.
The graph is validated without error.
Now, for validating the constraint on B, I tried (in the same manner):
.
neo4j:BShape a sh:NodeShape ;
sh:targetClass neo4j:B ;
sh:property [
sh:minCount 1 ;
sh:path neo4j:develops;
sh:class neo4j:A;
sh:nodekind sh:IRI;
]
.
But that fails when validating:
╒═══════════╤══════════╤════════════════════════════╤════════════════════════════════════════════════════════╤════════════════╤════════════╤══════════════════════════════════════╤══════════════════════════════╕
│"focusNode"│"nodeType"│"shapeId" │"propertyShape" │"offendingValue"│"resultPath"│"severity" │"resultMessage" │
╞═══════════╪══════════╪════════════════════════════╪════════════════════════════════════════════════════════╪════════════════╪════════════╪══════════════════════════════════════╪══════════════════════════════╡
│109 │"B" │"bnode://id/node1fj1fn0bkx1"│"http://www.w3.org/ns/shacl#MinCountConstraintComponent"│null │"develops" │"http://www.w3.org/ns/shacl#Violation"│"unnacceptable cardinality: 0"│
└───────────┴──────────┴────────────────────────────┴────────────────────────────────────────────────────────┴────────────────┴────────────┴──────────────────────────────────────┴──────────────────────────────┘
It looks to me as if the first node in a relationship owns the edge. That would be bad for my use case, where I cannot really reverse the direction of the edge. I also tried
call n10s.validation.shacl.import.inline('
@prefix neo4j: <neo4j://graph.schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
neo4j:BShape a sh:NodeShape ;
sh:targetClass neo4j:B ;
sh:property [
sh:minCount 1 ;
sh:path [sh:inversePath neo4j:develops];
sh:class neo4j:A;
sh:nodekind sh:IRI;
]
.
', "Turtle")
but that would give me the following error:
Failed to invoke procedure `n10s.validation.shacl.validate`: Caused by: java.lang.ClassCastException: class org.neo4j.cypher.internal.expressions.HasDegreeLessThan cannot be cast to class org.neo4j.cypher.internal.expressions.InequalityExpression (org.neo4j.cypher.internal.expressions.HasDegreeLessThan and org.neo4j.cypher.internal.expressions.InequalityExpression are in unnamed module of loader 'app')
So, I guess my question is: How can I ensure that a node has at least one incoming edge of a certain type?