All examples are in 05-values.ttl, which compiles to 12 rules.
Datatypes
sh:property [ sh:path ex:age ; sh:datatype xsd:integer ] ;
SHACL uses XML Schema datatypes. shacl2cypher maps each one to the types your database actually stores:
| Datatype | Neo4j | LadybugDB column |
|---|---|---|
xsd:string | STRING | STRING |
xsd:integer | INTEGER | any integer type |
xsd:int, xsd:short, xsd:byte | INTEGER plus a range check | INT32/INT16/INT8 |
xsd:decimal, xsd:double | FLOAT | DECIMAL/DOUBLE/FLOAT |
xsd:boolean | BOOLEAN | BOOL |
xsd:date | DATE | DATE |
xsd:dateTime | ZONED DATETIME or LOCAL DATETIME | TIMESTAMP |
xsd:duration | DURATION | INTERVAL |
Need exactly one native type, such as only zoned date-times? Add s2c:datatype "ZONED_DATETIME" to the property shape.
On LadybugDB the schema often answers for you. If age is an INT64 column, sh:datatype xsd:integer can never fail, so the rule is guaranteed-by-schema and runs no query. If age is a STRING column, the rule can never pass: that is reported at compile time as a schema mismatch.
Ranges
sh:property [
sh:path ex:age ;
sh:datatype xsd:integer ;
sh:minInclusive 0 ;
sh:maxInclusive 130 ;
] ;
sh:property [
sh:path ex:hiredOn ;
sh:datatype xsd:date ;
sh:minInclusive "2000-01-01"^^xsd:date ;
] .
sh:minInclusive, sh:maxInclusive, sh:minExclusive and sh:maxExclusive compare each value with a typed constant. Dates compare with dates, numbers with numbers.
A wrong type is always a violation
What if age holds the string "forty"? In Cypher, "forty" >= 0 is null, and a naive WHERE NOT (p.age >= 0) would silently skip the row. shacl2cypher never lets that happen. Every value test is wrapped so that "can't compare" counts as "fails", and the row is reported with value: "forty". That is also what SHACL requires.
The flip side: value constraints ignore missing values. A person with no age passes every rule above. If age is required, add sh:minCount 1.
String length
sh:property [ sh:path ex:name ; sh:datatype xsd:string ; sh:minLength 2 ; sh:maxLength 80 ] ;
Lengths apply to strings, and to integers by their decimal digits. Any other value type fails a length constraint.
Patterns
sh:property [ sh:path ex:email ; sh:pattern "^[^@\\s]+@[^@\\s]+$" ] ;
sh:property [ sh:path ex:code ; sh:pattern "^emp-[0-9]{4}$" ; sh:flags "i" ] ;
Three things to know about sh:pattern:
- It matches anywhere in the string unless you anchor it.
"[0-9]"passes"abc1". Use^and$for a whole-string match. - Backslashes are doubled inside a Turtle string:
\\sin the file is\sin the regex. - Flags:
iignores case,slets.match newlines,mmakes^/$match at lines,xignores whitespace in the pattern, andqtreats the pattern as a literal string.
Patterns are XSD regular expressions. shacl2cypher parses each one and rewrites it for the engine, for example wrapping it as (?s:.*)(?:…)(?s:.*) for Neo4j's anchored =~. An invalid pattern is a compile error at its line in your file. Back-references such as (a)\1 work on Neo4j but are rejected for LadybugDB, whose regex engine can't evaluate them.
Allowed values
sh:property [ sh:path ex:status ; sh:in ( "active" "on-leave" "left" ) ] ;
Every value must be one of the list. IRIs in the list, such as ( ex:Active ex:Left ), compare by local name: "Active" and "Left".
A required value
ex:CompanyShape a sh:NodeShape ;
sh:targetClass ex:Company ;
sh:property [ sh:path ex:markets ; sh:hasValue "EU" ] .
sh:hasValue means "one of the values is this". It is the only value constraint besides counts that fails on an empty set. A company with no markets violates it.
Per-value results
Value constraints report one row per bad value, so a list with two bad elements gives two rows, each with its value:
failed Warning 1 3 PersonShape.name.pattern
- Person id=p1: ex:PersonShape violates sh:pattern on ex:name (value: "ann")
Takeaways
sh:datatypemaps XSD types onto native graph types; uses2c:datatypeto demand an exact one.- A value of the wrong type fails every value test. A missing value passes them all.
- Patterns match substrings unless anchored, and are validated at compile time.
sh:inrestricts values to a list;sh:hasValuerequires one particular value.