@rdfc/sparql-ingest-processor-ts
Version:
SPARQL Update function to be within RDF-Connect pipelines
126 lines (125 loc) • 5.53 kB
JavaScript
import { SHACL } from "@treecg/types";
import { Writer as N3Writer, Parser } from "n3";
import { RdfStore } from "rdf-stores";
import { DataFactory } from "rdf-data-factory";
import { getObjects, splitStoreOnSize, splitStorePerNamedGraph } from "./Utils.js";
const df = new DataFactory();
export const CREATE = (store, forVirtuoso) => {
const queries = [];
const storesPerGraph = splitStorePerNamedGraph(store);
for (const { graph, store } of storesPerGraph) {
const subStores = splitStoreOnSize(store, forVirtuoso ? 500 : 50000);
subStores.forEach((s, i) => {
queries.push(`
INSERT DATA {
${graph.equals(df.defaultGraph()) ? "" : `GRAPH <${graph.value}> {`}
${new N3Writer().quadsToString(s.getQuads().map(q => {
return df.quad(q.subject, q.predicate, q.object, df.defaultGraph());
}))}
${graph.equals(df.defaultGraph()) ? "" : `}`}
}
`);
});
}
return queries;
};
export const UPDATE = (store, forVirtuoso) => {
const queries = [];
const storesPerGraph = splitStorePerNamedGraph(store);
for (const { graph, store } of storesPerGraph) {
const subStores = splitStoreOnSize(store, forVirtuoso ? 500 : 50000);
const formattedQuery = formatQuery(store);
const deleteInsertQuery = [`
${graph.equals(df.defaultGraph()) ? "" : `WITH <${graph.value}>`}
DELETE {
${formattedQuery[0]}
}
WHERE {
${formattedQuery[0]}
}
`];
subStores.forEach((s, i) => {
deleteInsertQuery.push(`
INSERT DATA {
${graph.equals(df.defaultGraph()) ? "" : `GRAPH <${graph.value}> {`}
${new N3Writer().quadsToString(s.getQuads().map(q => {
return df.quad(q.subject, q.predicate, q.object, df.defaultGraph());
}))}
${graph.equals(df.defaultGraph()) ? "" : `}`}
}
`);
});
queries.push(...deleteInsertQuery);
}
return queries;
};
export const DELETE = (store, memberIRI, memberShape) => {
const queries = [];
const storesPerGraph = splitStorePerNamedGraph(store);
for (const { graph, store } of storesPerGraph) {
const formatted = formatQuery(store, memberIRI, memberShape);
const deleteBuilder = formatted.length > 1 ? formatted[1] : formatted[0];
const whereBuilder = formatted[0];
queries.push(`
${graph.equals(df.defaultGraph()) ? "" : `WITH <${graph.value}>`}
DELETE {
${deleteBuilder}
} WHERE {
${whereBuilder}
}
`);
}
return queries;
};
function formatQuery(memberStore, memberIRI, memberShape, indexStart = 0) {
const subjectSet = new Set();
const blankNodeMap = new Map();
const queryBuilder = [];
let i = indexStart;
if (!memberShape) {
for (const quad of memberStore.getQuads()) {
if (!subjectSet.has(quad.subject.value)) {
subjectSet.add(quad.subject.value);
if (quad.subject.termType === "NamedNode") {
queryBuilder.push(`<${quad.subject.value}> ?p_${i} ?o_${i}.`);
}
else if (quad.subject.termType === "BlankNode") {
if (!blankNodeMap.has(quad.subject.value)) {
blankNodeMap.set(quad.subject.value, `?bn_${i}`);
}
if (quad.object.termType === "BlankNode") {
blankNodeMap.set(quad.object.value, `?bn_ref_${i}`);
}
queryBuilder.push(`${blankNodeMap.get(quad.subject.value)} <${quad.predicate.value}> ${quad.object.termType === "Literal"
? `"${quad.object.value}"^^<${quad.object.datatype.value}>`
: quad.object.termType === "BlankNode" ? `${blankNodeMap.get(quad.object.value)} `
: `<${quad.object.value}>`}.`);
queryBuilder.push(`${blankNodeMap.get(quad.subject.value)} ?p_${i} ?o_${i}.`);
queryBuilder.push(`?s_ref_${i} ?p_ref_${i} ${blankNodeMap.get(quad.subject.value)}.`);
}
i++;
}
}
return [queryBuilder.join("\n")];
}
else {
const shapeStore = RdfStore.createDefault();
new Parser().parse(memberShape).forEach(quad => shapeStore.addQuad(quad));
queryBuilder.push(`<${memberIRI}> ?p_${i} ?o_${i}.`);
const deleteQueryBuilder = [];
deleteQueryBuilder.push(`<${memberIRI}> ?p_${i} ?o_${i}.`);
i++;
const propShapes = getObjects(shapeStore, null, SHACL.terms.property, null);
queryBuilder.push(" OPTIONAL { ");
for (const propSh of propShapes) {
const pred = getObjects(shapeStore, propSh, SHACL.terms.path, null)[0];
queryBuilder.push(`<${memberIRI}> <${pred.value}> ?subEnt_${i}.`);
deleteQueryBuilder.push(`<${memberIRI}> <${pred.value}> ?subEnt_${i}.`);
queryBuilder.push(`?subEnt_${i} ?p_${i} ?o_${i}.`);
deleteQueryBuilder.push(`?subEnt_${i} ?p_${i} ?o_${i}.`);
i++;
}
queryBuilder.push(" }");
return [queryBuilder.join("\n"), deleteQueryBuilder.join("\n")];
}
}