ShEx/Unique UNIQUE
Obsolete - please see the ShEx github wiki
UNIQUE
Proposed for 2.1
A UNIQUE constraint takes an optional scope (FOCUS|GRAPH, default: FOCUS) and 1+ predicates, e.g.:
<T> { :fname LITERAL; :lname LITERAL; :title LITERAL+; :homepage IRI UNIQUE(GRAPH, :fname, :lname) UNIQUE(LANGTAG(:title)) UNIQUE(GRAPH, :homepage) }
UNIQUEs can appear arbitrarily nested in expressions:
<PersonShape> { foaf:givenName .; foaf:familyName UNIQUE(foaf:given, foaf:family) | foaf:name . UNIQUE(foaf:name) }
UNIQUEs scoped to the FOCUSNODE can be dispatched immediately. Those scoped to the GRAPH or DATASET must have their values noted and associated with the UNIQUE constraint, noting any possible conflicts during insertion.
Shortcomings
It's possible we'd want uniques that span shapes, e.g. if the following data were permissible:
{ <s1> :code "1234"; :dept [ :code "5678" ] . <s2> :code "1234"; :dept [ :code "8765" ] }
but this were not:
{ <s1> :code "1234"; :dept [ :code "5678" ] . <s2> :code "1234"; :dept [ :code "5678" ] }
There's no way to stipulate uniqueness across repeated properties, e.g. if we wanted to make sure that creators from a.example were unique in the graph but creators from b.example were not:
schema: <S> { :creator PATTERN "^http://a\\.example/", :creator PATTERN "^http://b\\.example/" }
failing data: { <s1> :creator <http://a.example/1> ; :creator <http://b.example/2> . <s2> :creator <http://a.example/3> ; :creator <http://b.example/2> . }
Alternative Syntax - on shape
The UNIQUE constraints could go on the shape.
<T> UNIQUE(GRAPH, :fname, :lname) UNIQUE(LANGTAG(:title)) UNIQUE(GRAPH, :homepage) { :fname LITERAL; :lname LITERAL; :title LITERAL+; :homepage IRI }
This makes evaluation of predicates in disjuncts weird, e.g.
<PersonShape> UNIQUE(foaf:given, foaf:family) UNIQUE(foaf:name) { foaf:givenName .; foaf:familyName | foaf:name .}
where the semantics for enforcing UNIQUE(foaf:given, foaf:family) over the data
{ <s> :foaf:name "Bob Smith". }
are a bit weird and "NULL-y".