UNPKG

@jahed/sparql-engine

Version:

SPARQL query engine for servers and web browsers.

195 lines (186 loc) 5.88 kB
// SPDX-License-Identifier: MIT import type { BgpPattern, ClearDropOperation, CopyMoveAddOperation, GraphOrDefault, GraphPattern, GraphQuads, InsertDeleteOperation, Triple, } from "sparqljs"; import Dataset from "../../rdf/dataset.ts"; import { VARIABLE_o, VARIABLE_p, VARIABLE_s } from "../../utils/rdf.ts"; /** * Create a triple pattern that matches all RDF triples in a graph * @private * @return A triple pattern that matches all RDF triples in a graph */ function allPattern(): Triple { return { subject: VARIABLE_s, predicate: VARIABLE_p, object: VARIABLE_o, }; } /** * Create a BGP that matches all RDF triples in a graph * @private * @return A BGP that matches all RDF triples in a graph */ function allBGP(): BgpPattern { return { type: "bgp", triples: [allPattern()], }; } /** * Build a SPARQL GROUP that selects all RDF triples from the Default Graph or a Named Graph * @private * @param source - Source graph * @param dataset - RDF dataset used to select the source * @param isSilent - True if errors should not be reported * @param [isWhere=false] - True if the GROUP should belong to a WHERE clause * @return The SPARQL GROUP clasue */ function buildGroupClause( source: GraphOrDefault, dataset: Dataset, isSilent: boolean ): BgpPattern | GraphQuads { if (source.default) { return allBGP(); } else { // a SILENT modifier prevents errors when using an unknown graph if (!(source.name && dataset.hasNamedGraph(source.name)) && !isSilent) { throw new Error(`Unknown Source Graph in ADD query ${source.name}`); } return { type: "graph", name: source.name!, triples: [allPattern()], }; } } /** * Build a SPARQL WHERE that selects all RDF triples from the Default Graph or a Named Graph * @private * @param source - Source graph * @param dataset - RDF dataset used to select the source * @param isSilent - True if errors should not be reported * @param [isWhere=false] - True if the GROUP should belong to a WHERE clause * @return The SPARQL GROUP clasue */ function buildWhereClause( source: GraphOrDefault, dataset: Dataset, isSilent: boolean ): BgpPattern | GraphPattern { if (source.default) { return allBGP(); } else { // a SILENT modifier prevents errors when using an unknown graph if (!(source.name && dataset.hasNamedGraph(source.name)) && !isSilent) { throw new Error(`Unknown Source Graph in ADD query ${source.name}`); } const bgp: BgpPattern = { type: "bgp", triples: [allPattern()], }; return { type: "graph", name: source.name!, patterns: [bgp], }; } } /** * Rewrite an ADD query into a INSERT query * @see https://www.w3.org/TR/2013/REC-sparql11-update-20130321/#add * @param addQuery - Parsed ADD query * @param dataset - related RDF dataset * @return Rewritten ADD query */ export function rewriteAdd( addQuery: CopyMoveAddOperation, dataset: Dataset ): InsertDeleteOperation { return { updateType: "insertdelete", insert: [buildGroupClause(addQuery.destination, dataset, addQuery.silent)], where: [buildWhereClause(addQuery.source, dataset, addQuery.silent)], delete: [], }; } /** * Rewrite a COPY query into a CLEAR + INSERT/DELETE query * @see https://www.w3.org/TR/2013/REC-sparql11-update-20130321/#copy * @param copyQuery - Parsed COPY query * @param dataset - related RDF dataset * @return Rewritten COPY query, i.e., a sequence [CLEAR query, INSERT query] */ export function rewriteCopy( copyQuery: CopyMoveAddOperation, dataset: Dataset ): [ClearDropOperation, InsertDeleteOperation] { // first, build a CLEAR query to empty the destination const clear: ClearDropOperation = { type: "clear", silent: copyQuery.silent, graph: { type: "graph" }, }; if (copyQuery.destination.default) { clear.graph.default = true; } else { clear.graph.type = copyQuery.destination.type; clear.graph.name = copyQuery.destination.name; } // then, build an INSERT query to copy the data const update = rewriteAdd(copyQuery, dataset); return [clear, update]; } /** * Rewrite a MOVE query into a CLEAR + INSERT/DELETE + CLEAR query * @see https://www.w3.org/TR/2013/REC-sparql11-update-20130321/#move * @param moveQuery - Parsed MOVE query * @param dataset - related RDF dataset * @return Rewritten MOVE query, i.e., a sequence [CLEAR query, INSERT query, CLEAR query] */ export function rewriteMove( moveQuery: CopyMoveAddOperation, dataset: Dataset ): [ClearDropOperation, InsertDeleteOperation, ClearDropOperation] { // first, build a classic COPY query const [clearBefore, update] = rewriteCopy(moveQuery, dataset); // then, append a CLEAR query to clear the source graph const clearAfter: ClearDropOperation = { type: "clear", silent: moveQuery.silent, graph: { type: "graph" }, }; if (moveQuery.source.default) { clearAfter.graph.default = true; } else { clearAfter.graph.type = moveQuery.source.type; clearAfter.graph.name = moveQuery.source.name; } return [clearBefore, update, clearAfter]; } /** * Extract property paths triples and classic triples from a set of RDF triples. * It also performs a first rewriting of some property paths. * @param bgp - Set of RDF triples * @return A tuple [classic triples, triples with property paths, set of variables added during rewriting] */ export function extractPropertyPaths(bgp: BgpPattern): [Triple[], Triple[]] { const classicTriples: Triple[] = []; const pathTriples: Triple[] = []; for (const triple of bgp.triples) { if ("pathType" in triple.predicate) { pathTriples.push(triple); } else { classicTriples.push(triple); } } return [classicTriples, pathTriples]; }