Skip to content

Worked example — minCount, datatype, nodeKind ​

A complete SHACL validation you can run in psql.

Setup: two graphs ​

sql
SELECT pgrdf.add_graph('http://example.org/data');
SELECT pgrdf.add_graph('http://example.org/shapes');

Load data: Bob has no mailbox ​

sql
SELECT pgrdf.parse_turtle('
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix ex:   <http://example.org/> .

ex:alice a foaf:Person ;
    foaf:name "Alice" ;
    foaf:mbox <mailto:alice@example.org> .

ex:bob a foaf:Person ;
    foaf:name "Bob" .
', pgrdf.graph_id('http://example.org/data'));
-- → 5

Load shapes ​

Every foaf:Person needs at least one foaf:name that is a string, and at least one foaf:mbox that is an IRI:

sql
SELECT pgrdf.parse_turtle('
@prefix sh:   <http://www.w3.org/ns/shacl#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix ex:   <http://example.org/> .
@prefix xsd:  <http://www.w3.org/2001/XMLSchema#> .

ex:PersonShape a sh:NodeShape ;
    sh:targetClass foaf:Person ;
    sh:property [
        sh:path foaf:name ;
        sh:minCount 1 ;
        sh:datatype xsd:string ;
    ] ;
    sh:property [
        sh:path foaf:mbox ;
        sh:minCount 1 ;
        sh:nodeKind sh:IRI ;
    ] .
', pgrdf.graph_id('http://example.org/shapes'));
-- → 10

Validate ​

sql
SELECT jsonb_pretty(pgrdf.validate(pgrdf.graph_id('http://example.org/data'),
                                   pgrdf.graph_id('http://example.org/shapes')));
json
{
    "mode": "native",
    "results": [
        {
            "value": null,
            "focusNode": "http://example.org/bob",
            "resultPath": "http://xmlns.com/foaf/0.1/mbox",
            "sourceShape": "_:e0426eab19040cf3a29413efb8e7cad7",
            "resultMessage": "MinCount(1) not satisfied",
            "resultSeverity": "sh:Violation",
            "sourceConstraintComponent": "http://www.w3.org/ns/shacl#MinCountConstraintComponent"
        }
    ],
    "conforms": false,
    "elapsed_ms": 1.423,
    "data_triples": 5,
    "data_graph_id": 5,
    "shapes_triples": 10,
    "shapes_graph_id": 6
}

Alice conforms. Bob doesn't, exactly as the shape declares. value is null because the violation is a missing value. sourceShape is a blank-node label because the property shape is written inline as [ … ]; its label and the graph ids will differ on your machine.

Fix the data and re-validate ​

sql
SELECT pgrdf.parse_turtle('
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix ex:   <http://example.org/> .
ex:bob foaf:mbox <mailto:bob@example.org> .
', pgrdf.graph_id('http://example.org/data'));

SELECT pgrdf.validate(pgrdf.graph_id('http://example.org/data'),
                      pgrdf.graph_id('http://example.org/shapes'));
-- {"mode": "native", "results": [], "conforms": true, "elapsed_ms": 0.717,
--  "data_triples": 6, "data_graph_id": 5, "shapes_triples": 10, "shapes_graph_id": 6}

Next steps ​

Next: SHACL Core components →

pgRDF is released under the MIT license. Documentation built with VitePress, served via GitHub Pages.