CONSTRUCT and DESCRIBE
CONSTRUCT builds new triples from a template. DESCRIBE returns the triples about a resource. Each form has its own function:
| Function | Runs |
|---|---|
pgrdf.construct(q) → SETOF jsonb | CONSTRUCT queries |
pgrdf.describe(q) → SETOF jsonb | DESCRIBE queries |
pgrdf.sparql() refuses both forms with an error, so call these functions instead.
Examples use the sample data.
Row shape
Each triple is one row. Every term says what kind it is (iri, literal or bnode), and literals carry their datatype:
{"subject": {"type": "iri", "value": "http://example.org/alice"},
"predicate": {"type": "iri", "value": "http://xmlns.com/foaf/0.1/name"},
"object": {"type": "literal", "value": "Alice",
"datatype": "http://www.w3.org/2001/XMLSchema#string"}}A literal with a language tag also carries language:
{"type": "literal", "value": "cat", "language": "en",
"datatype": "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString"}CONSTRUCT
Every foaf:Person becomes an ex:Agent, without changing the data:
SELECT * FROM pgrdf.construct($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX ex: <http://example.org/>
CONSTRUCT { ?p a ex:Agent }
WHERE { ?p a foaf:Person }
$$);
-- {"object": {"type": "iri", "value": "http://example.org/Agent"},
-- "subject": {"type": "iri", "value": "http://example.org/carol"},
-- "predicate": {"type": "iri", "value": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"}}
-- … one row each for bob and aliceTemplates can mix constants and variables:
SELECT t->'object'->>'value' AS mentioned
FROM pgrdf.construct($$
PREFIX ex: <http://example.org/>
CONSTRUCT { ex:report ex:mentions ?p }
WHERE { ?p ex:age ?a FILTER(?a > 30) }
$$) AS t
ORDER BY 1;
-- mentioned
-- --------------------------
-- http://example.org/alice
-- http://example.org/bobBlank nodes in the template
A blank node in the template becomes a new blank node for each solution. Within one solution, the same label is the same node:
SELECT * FROM pgrdf.construct($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX ex: <http://example.org/>
CONSTRUCT { ?p ex:contact _:c . _:c foaf:mbox ?m . }
WHERE { ?p foaf:mbox ?m }
$$);
-- {"object": {"type": "bnode", "value": "b1_1"}, "subject": {… "http://example.org/alice"}, "predicate": {… "http://example.org/contact"}}
-- {"object": {… "mailto:alice@example.org"}, "subject": {"type": "bnode", "value": "b1_1"}, …}
-- {"object": {"type": "bnode", "value": "b2_1"}, "subject": {… "http://example.org/carol"}, …}
-- {"object": {… "mailto:carol@example.org"}, "subject": {"type": "bnode", "value": "b2_1"}, …}CONSTRUCT WHERE
When the template is the same as the pattern, write it once:
SELECT * FROM pgrdf.construct($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
CONSTRUCT WHERE { ?s foaf:name ?n }
$$);
-- three rows: alice, bob and carol with their foaf:nameOne graph
Scope the pattern with GRAPH to copy a single graph out as triples:
SELECT count(*) FROM pgrdf.construct($$
CONSTRUCT { ?s ?p ?o }
WHERE { GRAPH <http://example.org/people> { ?s ?p ?o } }
$$);
-- 14Use the rows as a table
SELECT t->'subject'->>'value' AS subject,
t->'object'->>'value' AS object,
t->'object'->>'type' AS kind
FROM pgrdf.construct($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
CONSTRUCT WHERE { ?s foaf:name ?n }
$$) AS t
ORDER BY 1;
-- subject | object | kind
-- --------------------------+--------+---------
-- http://example.org/alice | Alice | literal
-- http://example.org/bob | Bob | literal
-- http://example.org/carol | Carol | literalThe same query works in a CREATE VIEW or CREATE TABLE … AS.
Keep the triples: INSERT … WHERE
CONSTRUCT only reads. To store the triples it would build, run the same template and pattern as a SPARQL UPDATE and name the target graph. The graph is created if it doesn't exist:
SELECT * FROM pgrdf.sparql($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX ex: <http://example.org/>
INSERT { GRAPH <http://example.org/agents> { ?p a ex:Agent } }
WHERE { ?p a foaf:Person }
$$);
-- {"_update": {"form": "INSERT_WHERE", ..., "graphs_touched": ["http://example.org/agents"],
-- "triples_deleted": 0, "triples_inserted": 3}}DESCRIBE
DESCRIBE returns the triples whose subject is the resource. When an object is a blank node, that node's triples are included too:
SELECT d->'predicate'->>'value' AS predicate,
d->'object'->>'value' AS object
FROM pgrdf.describe($$ DESCRIBE <http://example.org/bob> $$) AS d;
-- predicate | object
-- -------------------------------------------------+----------------------------------
-- http://xmlns.com/foaf/0.1/knows | http://example.org/carol
-- http://example.org/age | 41
-- http://www.w3.org/1999/02/22-rdf-syntax-ns#type | http://xmlns.com/foaf/0.1/Person
-- http://xmlns.com/foaf/0.1/name | BobTriples that point at the resource (Alice foaf:knows Bob) are not part of its description.
A pattern chooses the resources:
SELECT * FROM pgrdf.describe($$
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
DESCRIBE ?p WHERE { ?p foaf:name "Carol" }
$$);
-- four rows: carol's age, type, name and mailboxErrors
pgrdf.construct()given something other than aCONSTRUCTquery, a query that doesn't parse, or a template variable that theWHEREnever binds is refused with SQLSTATE22023.pgrdf.describe()given something other than aDESCRIBEquery is refused with an error.
See Errors and refusals.