@rdfc/sparql-ingest-processor-ts 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +41 -0
- package/lib/SPARQLIngest.js +194 -0
- package/lib/SPARQLQueries.js +165 -0
- package/lib/Utils.js +31 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +42 -0
- package/processors.ttl +133 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Julian Rojas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# sparql-ingest-processor-ts
|
|
2
|
+
|
|
3
|
+
[](https://github.com/rdf-connect/sparql-ingest-processor-ts/actions/workflows/build-test.yml) [](https://npmjs.com/package/@rdfc/sparql-ingest-processor-ts)
|
|
4
|
+
|
|
5
|
+
Typescript [RDF-Connect](https://rdf-connect.github.io/rdfc.github.io/) processor for producing the corresponding SPARQL Update queries that write a stream of [SDS records](https://treecg.github.io/SmartDataStreams-Spec/) into a SPARQL triple store. Currently this repository exposes one function:
|
|
6
|
+
|
|
7
|
+
### [`js:SPARQLIngest`](https://github.com/rdf-connect/sparql-ingest-processor-ts/blob/main/processors.ttl#L9)
|
|
8
|
+
|
|
9
|
+
This processor is able to take an input stream of SDS records (described by the `sds:stream` and `sds:payload` properties) and produce corresponding [SPARQL Update](https://www.w3.org/TR/sparql11-update/) queries (`INSERT DATA`, `DELETE INSERT WHERE` and `DELETE WHERE`) to be executed over a graph store via the [SPARQL protocol](https://www.w3.org/TR/sparql11-protocol/).
|
|
10
|
+
|
|
11
|
+
By default, this processor will produce a `DELETE INSERT WHERE` query that will overwrite all the triples present in the payload of the received SDS record. However, specific query operations can be generated based on configurable change semantics that can be included in the SDS record payload. Next, an example of this processor is shown with a configuration that specifies the predicate `ex:changeType` and the values `as:Create`, `as:Update` and `as:Delete` as the expected values for generating `INSERT DATA`, `DELETE INSERT WHERE` ans `DELETE WHERE` queries respectively.
|
|
12
|
+
|
|
13
|
+
```turtle
|
|
14
|
+
[ ] a js:SPARQLIngest;
|
|
15
|
+
js:memberStream <inputStream>;
|
|
16
|
+
js:ingestConfig [
|
|
17
|
+
js:memberIsGraph false;
|
|
18
|
+
js:memberShape "Some SHACL shape", "Another SHACL shape";
|
|
19
|
+
js:changeSemantics [
|
|
20
|
+
js:changeTypePath "http://ex.org/changeType";
|
|
21
|
+
js:createValue "http://ex.org/Create";
|
|
22
|
+
js:updateValue "http://ex.org/Update";
|
|
23
|
+
js:deleteValue "http://ex.org/Delete"
|
|
24
|
+
];
|
|
25
|
+
js:targetNamedGraph "http://ex.org/myGraph";
|
|
26
|
+
js:transactionIdPath "http://ex.org/trancationId"
|
|
27
|
+
];
|
|
28
|
+
js:sparqlWriter <outputStream>.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For the case of delete operations, additional information can be provided depending on the content of the SDS record payload signaling a delete:
|
|
32
|
+
|
|
33
|
+
1. The payload is complete and contains all the triples that must be deleted from the triple store. In this case no additional information is needed.
|
|
34
|
+
2. The payload only contains the type of the payload's main entity (or member) via `rdf:type`. In this case one or more SHACL shapes can be configured via the `js:memberShape` property. The processor will identify the corresponding shape of an input SDS record (via the shape's target class) and the proper query pattern will be generated.
|
|
35
|
+
3. The payload does not contain the type of the payload's main entity (or member). In this case, is not possible to identify the corresponding SHACL shape, therefore a query reflecting all shapes via `OPTIONAL` clauses will be generated.
|
|
36
|
+
|
|
37
|
+
In case that the main entity (member) of the SDS record payload is always a named graph, this can be configured by setting the `js:memberIsGraph` to `true`. In this scenario, all resulting queries will be properly set with the `GRAPH` and the `WITH` clauses.
|
|
38
|
+
|
|
39
|
+
If a specific named graph should be targeted by all the resulting SPARQL Update queries, this can be configured via the `js:targetNamedGraph` property. This property will be ignored if the `js:memberIsGraph` property is `true`.
|
|
40
|
+
|
|
41
|
+
Lastly, the main entity (member) of SDS record payload may contain a transaction ID when the member is part of a larger group of members that must be updated altogether into the targeted triple store. This particular property can be indicated to the processor via the `js:transactionIdPath` configuration property. The processor will proceed to buffer all records containing the same transaction ID and execute the corresponding SPARQL Update query for all members at once.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { SDS } from "@treecg/types";
|
|
2
|
+
import { Store, Parser, DataFactory } from "n3";
|
|
3
|
+
import { CREATE, UPDATE, DELETE } from "./SPARQLQueries";
|
|
4
|
+
import { doSPARQLRequest, sanitizeQuads } from "./Utils";
|
|
5
|
+
const { quad, namedNode } = DataFactory;
|
|
6
|
+
export async function sparqlIngest(memberStream, config, sparqlWriter) {
|
|
7
|
+
let transactionMembers = [];
|
|
8
|
+
memberStream.data(async (rawQuads) => {
|
|
9
|
+
const quads = new Parser().parse(rawQuads);
|
|
10
|
+
const store = new Store(quads);
|
|
11
|
+
// Get member IRI form SDS description
|
|
12
|
+
const memberIRI = store.getObjects(null, SDS.payload, null)[0];
|
|
13
|
+
if (memberIRI) {
|
|
14
|
+
// Remove SDS wrapper
|
|
15
|
+
store.removeQuads(store.getQuads(null, SDS.stream, null, null));
|
|
16
|
+
store.removeQuads(store.getQuads(null, SDS.payload, null, null));
|
|
17
|
+
// Find if this member is part of a transaction
|
|
18
|
+
if (config.transactionConfig) {
|
|
19
|
+
const transactionId = store.getObjects(null, config.transactionConfig.transactionIdPath, null)[0];
|
|
20
|
+
if (transactionId) {
|
|
21
|
+
// Remove transactionId property
|
|
22
|
+
store.removeQuad(quad(memberIRI, namedNode(config.transactionConfig.transactionIdPath), transactionId));
|
|
23
|
+
// See if this is a finishing, new or ongoing transaction
|
|
24
|
+
const isLastOfTransaction = store.getObjects(null, config.transactionConfig.transactionEndPath, null)[0];
|
|
25
|
+
if (isLastOfTransaction) {
|
|
26
|
+
console.log(`[sparqlIngest] Last member of ${transactionId.value} received!`);
|
|
27
|
+
// Check this transaction is correct
|
|
28
|
+
verifyTransaction(transactionMembers.map(ts => ts.store), config.transactionConfig.transactionIdPath, transactionId);
|
|
29
|
+
// Remove is-last-of-transaction flag
|
|
30
|
+
store.removeQuad(quad(memberIRI, namedNode(config.transactionConfig.transactionEndPath), isLastOfTransaction));
|
|
31
|
+
// We copy all previous member quads into the current store
|
|
32
|
+
transactionMembers.push({
|
|
33
|
+
memberId: memberIRI.value,
|
|
34
|
+
transactionId: transactionId.value,
|
|
35
|
+
store
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
else if (transactionMembers.length > 0) {
|
|
39
|
+
// Check this transaction is correct
|
|
40
|
+
verifyTransaction(transactionMembers.map(ts => ts.store), config.transactionConfig.transactionIdPath, transactionId);
|
|
41
|
+
// Is an ongoing transaction, so we add this member's quads into the transaction store
|
|
42
|
+
transactionMembers.push({
|
|
43
|
+
memberId: memberIRI.value,
|
|
44
|
+
transactionId: transactionId.value,
|
|
45
|
+
store
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.log(`[sparqlIngest] New transaction ${transactionId.value} started!`);
|
|
51
|
+
if (transactionMembers.length > 0)
|
|
52
|
+
throw new Error(`[sparqlIngest] Received new transaction ${transactionId.value}, `
|
|
53
|
+
+ `but older transaction ${transactionMembers[0].transactionId} hasn't been finalized `);
|
|
54
|
+
// Is a new transaction, add it to the transaction store
|
|
55
|
+
transactionMembers.push({
|
|
56
|
+
memberId: memberIRI.value,
|
|
57
|
+
transactionId: transactionId.value,
|
|
58
|
+
store
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Variable that will hold the full query to be executed
|
|
65
|
+
let query;
|
|
66
|
+
let queryType;
|
|
67
|
+
if (config.changeSemantics) {
|
|
68
|
+
if (transactionMembers.length > 0) {
|
|
69
|
+
query = createTransactionQueries(transactionMembers, config);
|
|
70
|
+
// Clean up transaction stores
|
|
71
|
+
transactionMembers = [];
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Determine if we have a named graph (either explicitly configured or as the member itself)
|
|
75
|
+
const ng = getNamedGraphIfAny(memberIRI, config.memberIsGraph, config.targetNamedGraph);
|
|
76
|
+
// Get the type of change
|
|
77
|
+
const ctv = store.getQuads(null, config.changeSemantics.changeTypePath, null, null)[0];
|
|
78
|
+
// Remove change type quad from store
|
|
79
|
+
store.removeQuad(ctv);
|
|
80
|
+
// Sanitize quads to prevent issues on SPARQL queries
|
|
81
|
+
sanitizeQuads(store);
|
|
82
|
+
// Assemble corresponding SPARQL UPDATE query
|
|
83
|
+
if (ctv.object.value === config.changeSemantics.createValue) {
|
|
84
|
+
query = CREATE(store, ng);
|
|
85
|
+
queryType = "CREATE";
|
|
86
|
+
}
|
|
87
|
+
else if (ctv.object.value === config.changeSemantics.updateValue) {
|
|
88
|
+
query = UPDATE(store, ng);
|
|
89
|
+
queryType = "UPDATE";
|
|
90
|
+
}
|
|
91
|
+
else if (ctv.object.value === config.changeSemantics.deleteValue) {
|
|
92
|
+
query = DELETE(store, [memberIRI.value], config.memberShapes, ng);
|
|
93
|
+
queryType = "DELETE";
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
throw new Error(`[sparqlIngest] Unrecognized change type value: ${ctv.object.value}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
if (transactionMembers.length > 0) {
|
|
102
|
+
transactionMembers.forEach(ts => store.addQuads(ts.store.getQuads(null, null, null, null)));
|
|
103
|
+
query = UPDATE(store, config.targetNamedGraph);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Determine if we have a named graph (either explicitly configure or as the member itself)
|
|
107
|
+
const ng = getNamedGraphIfAny(memberIRI, config.memberIsGraph, config.targetNamedGraph);
|
|
108
|
+
// No change semantics are provided so we do a DELETE/INSERT query by default
|
|
109
|
+
query = UPDATE(store, ng);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Execute the update query
|
|
113
|
+
if (query) {
|
|
114
|
+
const outputPromises = [];
|
|
115
|
+
if (sparqlWriter) {
|
|
116
|
+
outputPromises.push(sparqlWriter.push(query));
|
|
117
|
+
}
|
|
118
|
+
if (config.graphStoreUrl) {
|
|
119
|
+
outputPromises.push(doSPARQLRequest(query, config.graphStoreUrl));
|
|
120
|
+
}
|
|
121
|
+
await Promise.all(outputPromises);
|
|
122
|
+
console.log(`[sparqlIngest] Executed ${queryType} on remote SPARQL server ${config.graphStoreUrl} - ${new Date().toISOString()}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
throw new Error(`[sparqlIngest] No member IRI found in received RDF data: \n${rawQuads}`);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
if (sparqlWriter) {
|
|
130
|
+
memberStream.on("end", async () => await sparqlWriter.end());
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function verifyTransaction(stores, transactionIdPath, transactionId) {
|
|
134
|
+
for (const store of stores) {
|
|
135
|
+
// Get all transaction IDs
|
|
136
|
+
const tIds = store.getObjects(null, transactionIdPath, null);
|
|
137
|
+
for (const tid of tIds) {
|
|
138
|
+
if (!tid.equals(transactionId)) {
|
|
139
|
+
throw new Error(`[sparqlIngest] Received non-matching transaction ID ${transactionId.value} `
|
|
140
|
+
+ `with previous transaction: ${tid.value}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function getNamedGraphIfAny(memberIRI, memberIsGraph, targetNamedGraph) {
|
|
146
|
+
let ng;
|
|
147
|
+
if (memberIsGraph) {
|
|
148
|
+
ng = memberIRI.value;
|
|
149
|
+
}
|
|
150
|
+
else if (targetNamedGraph) {
|
|
151
|
+
ng = targetNamedGraph;
|
|
152
|
+
}
|
|
153
|
+
return ng;
|
|
154
|
+
}
|
|
155
|
+
function createTransactionQueries(transactionMembers, config) {
|
|
156
|
+
console.log(`[sparqlIngest] Creating multi-operation SPARQL UPDATE query for ${transactionMembers.length}`
|
|
157
|
+
+ ` members of transaction ${transactionMembers[0].transactionId}`);
|
|
158
|
+
// This is a transaction query, we need to deal with possibly multiple types of queries
|
|
159
|
+
const createStore = new Store();
|
|
160
|
+
const updateStore = new Store();
|
|
161
|
+
const deleteStore = new Store();
|
|
162
|
+
const deleteMembers = [];
|
|
163
|
+
const transactionQueryBuilder = [];
|
|
164
|
+
for (const tsm of transactionMembers) {
|
|
165
|
+
const ctv = tsm.store.getQuads(null, config.changeSemantics.changeTypePath, null, null)[0];
|
|
166
|
+
// Remove change type quad from store
|
|
167
|
+
tsm.store.removeQuad(ctv);
|
|
168
|
+
if (ctv.object.value === config.changeSemantics.createValue) {
|
|
169
|
+
createStore.addQuads(tsm.store.getQuads(null, null, null, null));
|
|
170
|
+
}
|
|
171
|
+
else if (ctv.object.value === config.changeSemantics.updateValue) {
|
|
172
|
+
updateStore.addQuads(tsm.store.getQuads(null, null, null, null));
|
|
173
|
+
}
|
|
174
|
+
else if (ctv.object.value === config.changeSemantics.deleteValue) {
|
|
175
|
+
deleteStore.addQuads(tsm.store.getQuads(null, null, null, null));
|
|
176
|
+
deleteMembers.push(tsm.memberId);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
throw new Error(`[sparqlIngest] Unrecognized change type value: ${ctv.object.value}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// TODO: Handle case of members as Named Graphs
|
|
183
|
+
// Build multi-operation SPARQL query
|
|
184
|
+
if (createStore.size > 0) {
|
|
185
|
+
transactionQueryBuilder.push(CREATE(createStore, config.targetNamedGraph));
|
|
186
|
+
}
|
|
187
|
+
if (updateStore.size > 0) {
|
|
188
|
+
transactionQueryBuilder.push(UPDATE(updateStore, config.targetNamedGraph));
|
|
189
|
+
}
|
|
190
|
+
if (updateStore.size > 0) {
|
|
191
|
+
transactionQueryBuilder.push(DELETE(deleteStore, deleteMembers, config.memberShapes, config.targetNamedGraph));
|
|
192
|
+
}
|
|
193
|
+
return transactionQueryBuilder.join(";\n");
|
|
194
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { RDF, SHACL } from "@treecg/types";
|
|
2
|
+
import { Writer as N3Writer, Store, Parser } from "n3";
|
|
3
|
+
export const CREATE = (store, namedGraph, multipleNamedGraphs) => {
|
|
4
|
+
// TODO: Handle case of multiple members being Named Graphs
|
|
5
|
+
const content = new N3Writer().quadsToString(store.getQuads(null, null, null, null));
|
|
6
|
+
return `
|
|
7
|
+
INSERT DATA {
|
|
8
|
+
${namedGraph ? `GRAPH <${namedGraph}> {${content}}` : `${content}`}
|
|
9
|
+
}
|
|
10
|
+
`;
|
|
11
|
+
};
|
|
12
|
+
export const UPDATE = (store, namedGraph, multipleNamedGraphs) => {
|
|
13
|
+
// TODO: Handle case of multiple members being Named Graphs
|
|
14
|
+
const formattedQuery = formatDeleteQuery(store);
|
|
15
|
+
const content = new N3Writer().quadsToString(store.getQuads(null, null, null, null));
|
|
16
|
+
return `
|
|
17
|
+
${namedGraph ? `WITH <${namedGraph}>` : ""}
|
|
18
|
+
DELETE {
|
|
19
|
+
${formattedQuery[0]}
|
|
20
|
+
}
|
|
21
|
+
INSERT {
|
|
22
|
+
${content}
|
|
23
|
+
}
|
|
24
|
+
WHERE {
|
|
25
|
+
${formattedQuery[0]}
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
};
|
|
29
|
+
export const DELETE = (store, memberIRIs, memberShapes, namedGraph, multipleNamedGraphs) => {
|
|
30
|
+
// TODO: Handle case of multiple members being Named Graphs
|
|
31
|
+
const deleteBuilder = [];
|
|
32
|
+
const whereBuilder = [];
|
|
33
|
+
let indexStart = 0;
|
|
34
|
+
for (const memberIRI of memberIRIs) {
|
|
35
|
+
const formatted = formatDeleteQuery(store, memberIRI, memberShapes, indexStart);
|
|
36
|
+
deleteBuilder.push(formatted.length > 1 ? formatted[1] : formatted[0]);
|
|
37
|
+
whereBuilder.push(formatted[0]);
|
|
38
|
+
indexStart++;
|
|
39
|
+
}
|
|
40
|
+
return `
|
|
41
|
+
${namedGraph ? `WITH <${namedGraph}>` : ""}
|
|
42
|
+
DELETE {
|
|
43
|
+
${deleteBuilder.join("\n")}
|
|
44
|
+
} WHERE {
|
|
45
|
+
${whereBuilder.join("\n")}
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
};
|
|
49
|
+
function formatDeleteQuery(memberStore, memberIRI, memberShapes, indexStart = 0) {
|
|
50
|
+
const subjectSet = new Set();
|
|
51
|
+
const queryBuilder = [];
|
|
52
|
+
const formattedQueries = [];
|
|
53
|
+
let i = indexStart;
|
|
54
|
+
// Check if one or more member shapes were given.
|
|
55
|
+
// If not, we assume that all properties of the member are present
|
|
56
|
+
// and we use them to define its DELETE query pattern.
|
|
57
|
+
if (!memberShapes || memberShapes.length === 0) {
|
|
58
|
+
// Iterate over every BGP of the member to define a deletion pattern
|
|
59
|
+
for (const quad of memberStore.getQuads(null, null, null, null)) {
|
|
60
|
+
if (!subjectSet.has(quad.subject.value)) {
|
|
61
|
+
// Make sure every subject is processed only once
|
|
62
|
+
subjectSet.add(quad.subject.value);
|
|
63
|
+
if (quad.subject.termType === "NamedNode") {
|
|
64
|
+
// Define a pattern that covers every property and value of named nodes
|
|
65
|
+
queryBuilder.push(`<${quad.subject.value}> ?p_${i} ?o_${i}.`);
|
|
66
|
+
}
|
|
67
|
+
else if (quad.subject.termType === "BlankNode") {
|
|
68
|
+
// Define a pattern that covers the referencing BGP and every property and value of blank nodes
|
|
69
|
+
const bnQ = memberStore.getQuads(null, null, quad.subject, null)[0];
|
|
70
|
+
queryBuilder.push(`<${bnQ.subject.value}> <${bnQ.predicate.value}> ?bn_${i}.`);
|
|
71
|
+
queryBuilder.push(`?bn_${i} ?p_${i} ?o${i}.`);
|
|
72
|
+
}
|
|
73
|
+
i++;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
formattedQueries.push(queryBuilder.join("\n"));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Create a shape index per target class
|
|
80
|
+
const shapeIndex = new Map();
|
|
81
|
+
memberShapes.forEach(msh => {
|
|
82
|
+
const shapeStore = new Store(new Parser().parse(msh));
|
|
83
|
+
shapeIndex.set(extractMainTargetClass(shapeStore).value, shapeStore);
|
|
84
|
+
});
|
|
85
|
+
// Add basic DELETE query pattern for this member
|
|
86
|
+
queryBuilder.push(`<${memberIRI}> ?p_${i} ?o_${i}.`);
|
|
87
|
+
// See if the member has a defined rdf:type so that we create a query pattern
|
|
88
|
+
// for a specific shape, based on the sh:targetClass.
|
|
89
|
+
// Otherwise we have to include all shapes in the query pattern because we don't know
|
|
90
|
+
// exactly which is the shape of the received member.
|
|
91
|
+
const memberType = memberStore.getObjects(memberIRI, RDF.type, null)[0];
|
|
92
|
+
if (memberType) {
|
|
93
|
+
i++;
|
|
94
|
+
const mshStore = shapeIndex.get(memberType.value);
|
|
95
|
+
const propShapes = mshStore.getObjects(null, SHACL.property, null);
|
|
96
|
+
for (const propSh of propShapes) {
|
|
97
|
+
const pred = mshStore.getObjects(propSh, SHACL.path, null)[0];
|
|
98
|
+
queryBuilder.push(`<${memberIRI}> <${pred.value}> ?subEnt_${i}.`);
|
|
99
|
+
queryBuilder.push(`?subEnt_${i} ?p_${i} ?o_${i}.`);
|
|
100
|
+
i++;
|
|
101
|
+
}
|
|
102
|
+
formattedQueries.push(queryBuilder.join("\n"));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// We have to define a different but related query pattern for the delete clause without OPTIONAL
|
|
106
|
+
const deleteQueryBuilder = [];
|
|
107
|
+
deleteQueryBuilder.push(`<${memberIRI}> ?p_${i} ?o_${i}.`);
|
|
108
|
+
i++;
|
|
109
|
+
// Iterate over every declared member shape
|
|
110
|
+
shapeIndex.forEach(mshStore => {
|
|
111
|
+
const propShapes = mshStore.getObjects(null, SHACL.property, null);
|
|
112
|
+
queryBuilder.push(" OPTIONAL { ");
|
|
113
|
+
for (const propSh of propShapes) {
|
|
114
|
+
const pred = mshStore.getObjects(propSh, SHACL.path, null)[0];
|
|
115
|
+
queryBuilder.push(`<${memberIRI}> <${pred.value}> ?subEnt_${i}.`);
|
|
116
|
+
deleteQueryBuilder.push(`<${memberIRI}> <${pred.value}> ?subEnt_${i}.`);
|
|
117
|
+
queryBuilder.push(`?subEnt_${i} ?p_${i} ?o_${i}.`);
|
|
118
|
+
deleteQueryBuilder.push(`?subEnt_${i} ?p_${i} ?o_${i}.`);
|
|
119
|
+
i++;
|
|
120
|
+
}
|
|
121
|
+
queryBuilder.push(" }");
|
|
122
|
+
});
|
|
123
|
+
formattedQueries.push(queryBuilder.join("\n"));
|
|
124
|
+
formattedQueries.push(deleteQueryBuilder.join("\n"));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return formattedQueries;
|
|
128
|
+
}
|
|
129
|
+
// Find the main target class of a give Shape Graph.
|
|
130
|
+
// We determine this by assuming that the main node shape
|
|
131
|
+
// is not referenced by any other shape description.
|
|
132
|
+
// If more than one is found an exception is thrown.
|
|
133
|
+
function extractMainTargetClass(store) {
|
|
134
|
+
const nodeShapes = store.getSubjects(RDF.type, SHACL.NodeShape, null);
|
|
135
|
+
let mainNodeShape = null;
|
|
136
|
+
if (nodeShapes && nodeShapes.length > 0) {
|
|
137
|
+
for (const ns of nodeShapes) {
|
|
138
|
+
const isNotReferenced = store.getSubjects(null, ns, null).length === 0;
|
|
139
|
+
if (isNotReferenced) {
|
|
140
|
+
if (!mainNodeShape) {
|
|
141
|
+
mainNodeShape = ns;
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
throw new Error("There are multiple main node shapes in a given shape."
|
|
145
|
+
+ " Unrelated shapes must be given as separate member shapes");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (mainNodeShape) {
|
|
150
|
+
const tcq = store.getObjects(mainNodeShape, SHACL.targetClass, null)[0];
|
|
151
|
+
if (tcq) {
|
|
152
|
+
return tcq;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
throw new Error("No target class found in main SHACL Node Shapes");
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
throw new Error("No main SHACL Node Shapes found in given member shape");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
throw new Error("No SHACL Node Shapes found in given member shape");
|
|
164
|
+
}
|
|
165
|
+
}
|
package/lib/Utils.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { XSD } from "@treecg/types";
|
|
2
|
+
import { DataFactory as DF } from "n3";
|
|
3
|
+
export function sanitizeQuads(store) {
|
|
4
|
+
for (const q of store.getQuads(null, null, null, null)) {
|
|
5
|
+
// There is an issue with triples like <a> <b> +30.
|
|
6
|
+
// Virtuoso doesn't accept the implicit integer type including the + sign.
|
|
7
|
+
if (q.object.termType === "Literal" && q.object.datatype.value === XSD.integer) {
|
|
8
|
+
if (/\+\d+/.test(q.object.value) && q.object.value.startsWith("+")) {
|
|
9
|
+
store.removeQuad(q);
|
|
10
|
+
store.addQuad(q.subject, q.predicate, DF.literal(q.object.value.substring(1), DF.namedNode(XSD.integer)), q.graph);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export async function doSPARQLRequest(query, url) {
|
|
16
|
+
const res = await fetch(url, {
|
|
17
|
+
method: "POST",
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
20
|
+
},
|
|
21
|
+
body: `update=${fixedEncodeURIComponent(query)}`
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
throw new Error(`HTTP request failed with code ${res.status} and message: \n${await res.text()}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function fixedEncodeURIComponent(str) {
|
|
28
|
+
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
|
|
29
|
+
return '%' + c.charCodeAt(0).toString(16);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"program":{"fileNames":["../node_modules/typescript/lib/lib.es5.d.ts","../node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/typescript/lib/lib.es2021.d.ts","../node_modules/typescript/lib/lib.es2022.d.ts","../node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/typescript/lib/lib.es2016.intl.d.ts","../node_modules/typescript/lib/lib.es2017.date.d.ts","../node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/typescript/lib/lib.es2021.promise.d.ts","../node_modules/typescript/lib/lib.es2021.string.d.ts","../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../node_modules/typescript/lib/lib.es2021.intl.d.ts","../node_modules/typescript/lib/lib.es2022.array.d.ts","../node_modules/typescript/lib/lib.es2022.error.d.ts","../node_modules/typescript/lib/lib.es2022.intl.d.ts","../node_modules/typescript/lib/lib.es2022.object.d.ts","../node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2022.string.d.ts","../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../node_modules/typescript/lib/lib.esnext.intl.d.ts","../node_modules/typescript/lib/lib.decorators.d.ts","../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../node_modules/@types/node/assert.d.ts","../node_modules/@types/node/assert/strict.d.ts","../node_modules/buffer/index.d.ts","../node_modules/undici-types/header.d.ts","../node_modules/undici-types/readable.d.ts","../node_modules/undici-types/file.d.ts","../node_modules/undici-types/fetch.d.ts","../node_modules/undici-types/formdata.d.ts","../node_modules/undici-types/connector.d.ts","../node_modules/undici-types/client.d.ts","../node_modules/undici-types/errors.d.ts","../node_modules/undici-types/dispatcher.d.ts","../node_modules/undici-types/global-dispatcher.d.ts","../node_modules/undici-types/global-origin.d.ts","../node_modules/undici-types/pool-stats.d.ts","../node_modules/undici-types/pool.d.ts","../node_modules/undici-types/handlers.d.ts","../node_modules/undici-types/balanced-pool.d.ts","../node_modules/undici-types/agent.d.ts","../node_modules/undici-types/mock-interceptor.d.ts","../node_modules/undici-types/mock-agent.d.ts","../node_modules/undici-types/mock-client.d.ts","../node_modules/undici-types/mock-pool.d.ts","../node_modules/undici-types/mock-errors.d.ts","../node_modules/undici-types/proxy-agent.d.ts","../node_modules/undici-types/api.d.ts","../node_modules/undici-types/cookies.d.ts","../node_modules/undici-types/patch.d.ts","../node_modules/undici-types/filereader.d.ts","../node_modules/undici-types/diagnostics-channel.d.ts","../node_modules/undici-types/websocket.d.ts","../node_modules/undici-types/content-type.d.ts","../node_modules/undici-types/cache.d.ts","../node_modules/undici-types/interceptors.d.ts","../node_modules/undici-types/index.d.ts","../node_modules/@types/node/globals.d.ts","../node_modules/@types/node/async_hooks.d.ts","../node_modules/@types/node/buffer.d.ts","../node_modules/@types/node/child_process.d.ts","../node_modules/@types/node/cluster.d.ts","../node_modules/@types/node/console.d.ts","../node_modules/@types/node/constants.d.ts","../node_modules/@types/node/crypto.d.ts","../node_modules/@types/node/dgram.d.ts","../node_modules/@types/node/diagnostics_channel.d.ts","../node_modules/@types/node/dns.d.ts","../node_modules/@types/node/dns/promises.d.ts","../node_modules/@types/node/domain.d.ts","../node_modules/@types/node/dom-events.d.ts","../node_modules/@types/node/events.d.ts","../node_modules/@types/node/fs.d.ts","../node_modules/@types/node/fs/promises.d.ts","../node_modules/@types/node/http.d.ts","../node_modules/@types/node/http2.d.ts","../node_modules/@types/node/https.d.ts","../node_modules/@types/node/inspector.d.ts","../node_modules/@types/node/module.d.ts","../node_modules/@types/node/net.d.ts","../node_modules/@types/node/os.d.ts","../node_modules/@types/node/path.d.ts","../node_modules/@types/node/perf_hooks.d.ts","../node_modules/@types/node/process.d.ts","../node_modules/@types/node/punycode.d.ts","../node_modules/@types/node/querystring.d.ts","../node_modules/@types/node/readline.d.ts","../node_modules/@types/node/readline/promises.d.ts","../node_modules/@types/node/repl.d.ts","../node_modules/@types/node/sea.d.ts","../node_modules/@types/node/stream.d.ts","../node_modules/@types/node/stream/promises.d.ts","../node_modules/@types/node/stream/consumers.d.ts","../node_modules/@types/node/stream/web.d.ts","../node_modules/@types/node/string_decoder.d.ts","../node_modules/@types/node/test.d.ts","../node_modules/@types/node/timers.d.ts","../node_modules/@types/node/timers/promises.d.ts","../node_modules/@types/node/tls.d.ts","../node_modules/@types/node/trace_events.d.ts","../node_modules/@types/node/tty.d.ts","../node_modules/@types/node/url.d.ts","../node_modules/@types/node/util.d.ts","../node_modules/@types/node/v8.d.ts","../node_modules/@types/node/vm.d.ts","../node_modules/@types/node/wasi.d.ts","../node_modules/@types/node/worker_threads.d.ts","../node_modules/@types/node/zlib.d.ts","../node_modules/@types/node/globals.global.d.ts","../node_modules/@types/node/index.d.ts","../node_modules/@rdfjs/types/data-model.d.ts","../node_modules/@rdfjs/types/stream.d.ts","../node_modules/@rdfjs/types/dataset.d.ts","../node_modules/@rdfjs/types/query/common.d.ts","../node_modules/@rdfjs/types/query/queryable.d.ts","../node_modules/@rdfjs/types/query.d.ts","../node_modules/@rdfjs/types/index.d.ts","../node_modules/@rdfc/js-runner/dist/connectors/file.d.ts","../node_modules/@rdfc/js-runner/dist/connectors/ws.d.ts","../node_modules/kafkajs/types/index.d.ts","../node_modules/@rdfc/js-runner/dist/connectors/kafka.d.ts","../node_modules/@rdfc/js-runner/dist/connectors/http.d.ts","../node_modules/@treecg/types/dist/lib/Bucketizer.d.ts","../node_modules/@treecg/types/dist/lib/BucketizerOptions.d.ts","../node_modules/@treecg/types/dist/lib/Member.d.ts","../node_modules/@treecg/types/dist/lib/RelationParameters.d.ts","../node_modules/@treecg/types/dist/lib/Fragment.d.ts","../node_modules/@treecg/types/dist/lib/utils/Logger-Browser.d.ts","../node_modules/@treecg/types/dist/lib/Vocabularies.d.ts","../node_modules/@treecg/types/dist/index.d.ts","../node_modules/@rdfc/js-runner/dist/connectors.d.ts","../node_modules/rdf-lens/dist/lens.d.ts","../node_modules/rdf-lens/dist/shacl.d.ts","../node_modules/rdf-lens/dist/index.d.ts","../node_modules/@rdfc/js-runner/dist/index.d.ts","../node_modules/@types/n3/index.d.ts","../src/SPARQLQueries.ts","../src/Utils.ts","../src/SPARQLIngest.ts"],"fileInfos":[{"version":"44e584d4f6444f58791784f1d530875970993129442a847597db702a073ca68c","affectsGlobalScope":true},"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","5514e54f17d6d74ecefedc73c504eadffdeda79c7ea205cf9febead32d45c4bc",{"version":"6920e1448680767498a0b77c6a00a8e77d14d62c3da8967b171f1ddffa3c18e4","affectsGlobalScope":true},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true},{"version":"4443e68b35f3332f753eacc66a04ac1d2053b8b035a0e0ac1d455392b5e243b3","affectsGlobalScope":true},{"version":"bc47685641087c015972a3f072480889f0d6c65515f12bd85222f49a98952ed7","affectsGlobalScope":true},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true},{"version":"ea011c76963fb15ef1cdd7ce6a6808b46322c527de2077b6cfdf23ae6f5f9ec7","affectsGlobalScope":true},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true},{"version":"bb42a7797d996412ecdc5b2787720de477103a0b2e53058569069a0e2bae6c7e","affectsGlobalScope":true},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true},{"version":"61c37c1de663cf4171e1192466e52c7a382afa58da01b1dc75058f032ddf0839","affectsGlobalScope":true},{"version":"b541a838a13f9234aba650a825393ffc2292dc0fc87681a5d81ef0c96d281e7a","affectsGlobalScope":true},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true},{"version":"ae37d6ccd1560b0203ab88d46987393adaaa78c919e51acf32fb82c86502e98c","affectsGlobalScope":true},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true},{"version":"5e07ed3809d48205d5b985642a59f2eba47c402374a7cf8006b686f79efadcbd","affectsGlobalScope":true},{"version":"2b72d528b2e2fe3c57889ca7baef5e13a56c957b946906d03767c642f386bbc3","affectsGlobalScope":true},{"version":"479553e3779be7d4f68e9f40cdb82d038e5ef7592010100410723ceced22a0f7","affectsGlobalScope":true},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true},{"version":"d3d7b04b45033f57351c8434f60b6be1ea71a2dfec2d0a0c3c83badbb0e3e693","affectsGlobalScope":true},{"version":"956d27abdea9652e8368ce029bb1e0b9174e9678a273529f426df4b3d90abd60","affectsGlobalScope":true},{"version":"4fa6ed14e98aa80b91f61b9805c653ee82af3502dc21c9da5268d3857772ca05","affectsGlobalScope":true},{"version":"e6633e05da3ff36e6da2ec170d0d03ccf33de50ca4dc6f5aeecb572cedd162fb","affectsGlobalScope":true},{"version":"d8670852241d4c6e03f2b89d67497a4bbefe29ecaa5a444e2c11a9b05e6fccc6","affectsGlobalScope":true},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true},{"version":"caccc56c72713969e1cfe5c3d44e5bab151544d9d2b373d7dbe5a1e4166652be","affectsGlobalScope":true},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true},"2db0dd3aaa2ed285950273ce96ae8a450b45423aa9da2d10e194570f1233fa6b","7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","4967529644e391115ca5592184d4b63980569adf60ee685f968fd59ab1557188","5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","7180c03fd3cb6e22f911ce9ba0f8a7008b1a6ddbe88ccf16a9c8140ef9ac1686","25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","54cb85a47d760da1c13c00add10d26b5118280d44d58e6908d8e89abbd9d7725","3e4825171442666d31c845aeb47fcd34b62e14041bb353ae2b874285d78482aa","c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","a967bfe3ad4e62243eb604bf956101e4c740f5921277c60debaf325c1320bf88","e9775e97ac4877aebf963a0289c81abe76d1ec9a2a7778dbe637e5151f25c5f3","471e1da5a78350bc55ef8cef24eb3aca6174143c281b8b214ca2beda51f5e04a","cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","db3435f3525cd785bf21ec6769bf8da7e8a776be1a99e2e7efb5f244a2ef5fee","c3b170c45fc031db31f782e612adf7314b167e60439d304b49e704010e7bafe5","40383ebef22b943d503c6ce2cb2e060282936b952a01bea5f9f493d5fb487cc7","4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","3a84b7cb891141824bd00ef8a50b6a44596aded4075da937f180c90e362fe5f6","13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","33203609eba548914dc83ddf6cadbc0bcb6e8ef89f6d648ca0908ae887f9fcc5","0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","e53a3c2a9f624d90f24bf4588aacd223e7bec1b9d0d479b68d2f4a9e6011147f","339dc5265ee5ed92e536a93a04c4ebbc2128f45eeec6ed29f379e0085283542c","9f0a92164925aa37d4a5d9dd3e0134cff8177208dba55fd2310cd74beea40ee2","8bfdb79bf1a9d435ec48d9372dc93291161f152c0865b81fc0b2694aedb4578d","2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","d32275be3546f252e3ad33976caf8c5e842c09cb87d468cb40d5f4cf092d1acc","4a0c3504813a3289f7fb1115db13967c8e004aa8e4f8a9021b95285502221bd1",{"version":"e7be367719c613d580d4b27fdf8fe64c9736f48217f4b322c0d63b2971460918","affectsGlobalScope":true},"3d77c73be94570813f8cadd1f05ebc3dc5e2e4fdefe4d340ca20cd018724ee36",{"version":"392eadc2af403dd10b4debfbc655c089a7fa6a9750caeb770cfb30051e55e848","affectsGlobalScope":true},"62f1c00d3d246e0e3cf0224f91e122d560428ec1ccc36bb51d4574a84f1dbad0","53f0960fdcc53d097918adfd8861ffbe0db989c56ffc16c052197bf115da5ed6",{"version":"662163e5327f260b23ca0a1a1ad8a74078aabb587c904fcb5ef518986987eaff","affectsGlobalScope":true},"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb",{"version":"c48c503c6b3f63baf18257e9a87559b5602a4e960107c762586d2a6a62b64a18","affectsGlobalScope":true},"b0c0d1d13be149f790a75b381b413490f98558649428bb916fd2d71a3f47a134","3c884d9d9ec454bdf0d5a0b8465bf8297d2caa4d853851d92cc417ac6f30b969","0364f8bb461d6e84252412d4e5590feda4eb582f77d47f7a024a7a9ff105dfdc","5433f7f77cd1fd53f45bd82445a4e437b2f6a72a32070e907530a4fea56c30c8","d0ca5d7df114035258a9d01165be309371fcccf0cccd9d57b1453204686d1ed0",{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","affectsGlobalScope":true},{"version":"9a30b7fefd7f8abbca4828d481c61c18e40fe5ff107e113b1c1fcd2c8dcf2743","affectsGlobalScope":true},"173b6275a81ebdb283b180654890f46516c21199734fed01a773b1c168b8c45c","304f66274aa8119e8d65a49b1cff84cbf803def6afe1b2cc987386e9a9890e22","1b9adafe8a7fefaeaf9099a0e06f602903f6268438147b843a33a5233ac71745","98273274f2dbb79b0b2009b20f74eca4a7146a3447c912d580cd5d2d94a7ae30","c933f7ba4b201c98b14275fd11a14abb950178afd2074703250fe3654fc10cd2","2eaa31492906bc8525aff3c3ec2236e22d90b0dfeee77089f196cd0adf0b3e3b",{"version":"ea455cc68871b049bcecd9f56d4cf27b852d6dafd5e3b54468ca87cc11604e4d","affectsGlobalScope":true},"8f5814f29dbaf8bacd1764aebdf1c8a6eb86381f6a188ddbac0fcbaab855ce52","a63d03de72adfb91777784015bd3b4125abd2f5ef867fc5a13920b5649e8f52b","d20e003f3d518a7c1f749dbe27c6ab5e3be7b3c905a48361b04a9557de4a6900",{"version":"1d4d78c8b23c9ddaaaa49485e6adc2ec01086dfe5d8d4d36ca4cdc98d2f7e74a","affectsGlobalScope":true},{"version":"44fc16356b81c0463cc7d7b2b35dcf324d8144136f5bc5ce73ced86f2b3475b5","affectsGlobalScope":true},"575fb200043b11b464db8e42cc64379c5fd322b6d787638e005b5ee98a64486d","6de2f225d942562733e231a695534b30039bdf1875b377bb7255881f0df8ede8","56249fd3ef1f6b90888e606f4ea648c43978ef43a7263aafad64f8d83cd3b8aa","139ad1dc93a503da85b7a0d5f615bddbae61ad796bc68fedd049150db67a1e26","7b166975fdbd3b37afb64707b98bca88e46577bbc6c59871f9383a7df2daacd1","9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","81505c54d7cad0009352eaa21bd923ab7cdee7ec3405357a54d9a5da033a2084","269929a24b2816343a178008ac9ae9248304d92a8ba8e233055e0ed6dbe6ef71","93452d394fdd1dc551ec62f5042366f011a00d342d36d50793b3529bfc9bd633","3c1f19c7abcda6b3a4cf9438a15c7307a080bd3b51dfd56b198d9f86baf19447","2ee1645e0df9d84467cfe1d67b0ad3003c2f387de55874d565094464ee6f2927",{"version":"071d4b4af5755e1a081aa3b785b5526d09276af5a50e4725dea26edd4e7deb31","affectsGlobalScope":true},{"version":"9cf780e96b687e4bdfd1907ed26a688c18b89797490a00598fa8b8ab683335dd","affectsGlobalScope":true},"98e00f3613402504bc2a2c9a621800ab48e0a463d1eed062208a4ae98ad8f84c","9ae88ce9f73446c24b2d2452e993b676da1b31fca5ceb7276e7f36279f693ed1","e49d7625faff2a7842e4e7b9b197f972633fca685afcf6b4403400c97d087c36","b82c38abc53922b1b3670c3af6f333c21b735722a8f156e7d357a2da7c53a0a0",{"version":"b423f53647708043299ded4daa68d95c967a2ac30aa1437adc4442129d7d0a6c","affectsGlobalScope":true},{"version":"7245af181218216bacb01fbdf51095617a51661f20d77178c69a377e16fb69ed","affectsGlobalScope":true},"4f0fc7b7f54422bd97cfaf558ddb4bca86893839367b746a8f86b60ac7619673","4cdd8b6b51599180a387cc7c1c50f49eca5ce06595d781638fd0216520d98246","d91a7d8b5655c42986f1bdfe2105c4408f472831c8f20cf11a8c3345b6b56c8c",{"version":"8704423bf338bff381ebc951ed819935d0252d90cd6de7dffe5b0a5debb65d07","affectsGlobalScope":true},"7c6929fd7cbf38499b6a600b91c3b603d1d78395046dc3499b2b92d01418b94b",{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true},"a42be67ed1ddaec743582f41fc219db96a1b69719fccac6d1464321178d610fc","c0156ff6b3c5f5b6699fafa0e36635590651aa70a07314425cf212f11c2443f8","b1cac4e06205000177d05342bc524983550157a72fcf450b701e747deb19e6af","d2cdba5be077b28a91fd380157e423d093279590aedb605f51ed6b6f398657c1","0d278d3cf006676a7c6c30424326bd38aba8344c471b64289ab89e4dcdb6e799","8953bf122fc832d335954e3a9188cbe4766ee2ef9be51f577de52234cd8a630e","642970856d429003a8a04298231d0dedac726519411a8b88afd90e2ab689f094","25006341224db03de63a44dea009de6523428c1bfe214ce069d10d0748838f12","99f820b6aadd5b143178f4583e6d5c30e1b07c7cf8e305ff8ee3dd30110594b7","269840705433e32c1fc67c22ba74959321f9a81b14d1270b9b7d22020960ca24","c724034e22cbbde98550aca4ee32006f7f4c566885328949ac16ff9ff2f76e89","633de05744daa843cd74b6f68c73df25194f0324d74080c4f2f357e8b5c4af78","c95cb57532666384e7423ae20f47e0cda3d8e105e7928c92f687f05a28f4fddf","aa1196da64d7fb641934dbf9683d45c2feea84f8aed23795c7793564bb2b8e08","a8b9548c59b33326a9fe601dad0242350e801af3091d2cf8f29279bd3d766a84","691ca3c93dc4aa9e14880dfcaa141df361b8cff75a8d298ed026b3e342561e02","ad44c5b327076d4f9c1fa00aaa41a3a0d2858df3adfb8cd0cdd944e05dd4a86a","5ee0f472c2200c82722e5b0f33646ac2dc8529204d81a32ac74ec794a07758ac","4a7e35c3dca7a40e70c2eefd62458ba6d84fcac7e1a3ed7ffe90a76b576af6dd","7b4903e52d29404a1be01654d222dc5b4e69323c6dc1be4842ba1718eec364c5","588f0e8ab710dca145e2ea80f0ecad3a072b06c110c31728027aa23024b5d06d","97ec43b5b0e06c4b0fb78b2dd298e725ffa00892a826a5cd682ca1cd72f4c465","0df4c76f4dbf8986e9979ea8d4d9551d527bfe933c1d8d7c4c3743031455d469","1e7aa39114c8ecaec6292f8174d32cf8dfa2af491b29ce7b0d57b29063a3a21a","0231e5425f539b30c9665bbff15496ab31c7ce9f29fcfb834b988f790218fe87","46f16cb92afab0694926cfc5b46afe824704866ad6a35a41e5e1cb7ae46b3c66","74a4b426b437193f77a8ddcfa6059660403e0773f17f304b907542ebbb865b06","f201330c268c868e81f3369ea4812de5952f6efd8c5f718d0dc9040dedc1f116","38001d95e6773124fa250a93a5fedc11bc5ca44dfed631da2c3fcb83e0fad8b5","4d833b741f33ff788fd635945484f6f8863af2aa578ff816aead0b2d3bdecae8"],"root":[[173,175]],"options":{"allowSyntheticDefaultImports":true,"downlevelIteration":true,"esModuleInterop":true,"experimentalDecorators":true,"module":7,"outDir":"./","preserveConstEnums":true,"skipLibCheck":true,"strict":true,"strictFunctionTypes":false,"strictPropertyInitialization":false,"target":9},"fileIdsList":[[146,153,154,155,157,158,166],[167],[156,167],[153,167,170],[147,148],[146,147,148,149,152],[150,151],[108,147],[147,150],[108,127,147],[159,160,161,162,163,164,165],[153],[153,161,162],[108,127,146,153],[59],[95],[96,101,130],[97,102,108,109,116,127,138],[97,98,108,116],[99,139],[100,101,109,117],[101,127,135],[102,104,108,116],[95,103],[104,105],[108],[106,108],[95,108],[108,109,110,127,138],[108,109,110,123,127,130],[93,96,143],[104,108,111,116,127,138],[108,109,111,112,116,127,135,138],[111,113,127,135,138],[59,60,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145],[108,114],[115,138,143],[104,108,116,127],[117],[118],[95,119],[116,117,120,137,143],[121],[122],[108,123,124],[123,125,139,141],[96,108,127,128,129,130],[96,127,129],[127,128],[130],[131],[95,127],[108,133,134],[133,134],[101,116,127,135],[136],[116,137],[96,111,122,138],[101,139],[127,140],[115,141],[142],[96,101,108,110,119,127,138,141,143],[127,144],[116,135,146],[168,169],[153,168],[70,74,138],[70,127,138],[65],[67,70,135,138],[116,135],[146],[65,146],[67,70,116,138],[62,63,66,69,96,108,127,138],[62,68],[66,70,96,130,138,146],[96,146],[86,96,146],[64,65,146],[70],[64,65,66,67,68,69,70,71,72,74,75,76,77,78,79,80,81,82,83,84,85,87,88,89,90,91,92],[70,77,78],[68,70,78,79],[69],[62,65,70],[70,74,78,79],[74],[68,70,73,138],[62,67,68,70,74,77],[96,127],[65,70,86,96,143,146],[153,166,171,172,173,174],[153,166,172],[166,172]],"referencedMap":[[167,1],[154,2],[158,2],[157,3],[155,2],[171,4],[149,5],[153,6],[152,7],[150,8],[151,9],[148,10],[166,11],[159,12],[160,12],[163,13],[161,12],[162,12],[165,12],[172,14],[59,15],[60,15],[95,16],[96,17],[97,18],[98,19],[99,20],[100,21],[101,22],[102,23],[103,24],[104,25],[105,25],[107,26],[106,27],[108,28],[109,29],[110,30],[94,31],[111,32],[112,33],[113,34],[146,35],[114,36],[115,37],[116,38],[117,39],[118,40],[119,41],[120,42],[121,43],[122,44],[123,45],[124,45],[125,46],[127,47],[129,48],[128,49],[130,50],[131,51],[132,52],[133,53],[134,54],[135,55],[136,56],[137,57],[138,58],[139,59],[140,60],[141,61],[142,62],[143,63],[144,64],[156,65],[170,66],[168,12],[169,67],[77,68],[84,69],[76,68],[91,70],[68,71],[67,72],[90,73],[85,74],[88,75],[70,76],[69,77],[65,78],[64,79],[87,80],[66,81],[71,82],[75,82],[93,83],[92,82],[79,84],[80,85],[82,86],[78,87],[81,88],[86,73],[73,89],[74,90],[83,91],[63,92],[89,93],[175,94],[173,95],[174,96]]},"version":"5.5.2"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rdfc/sparql-ingest-processor-ts",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "SPARQL Update function to be within RDF-Connect pipelines",
|
|
5
|
+
"author": "Julián Rojas",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc && tsc-alias",
|
|
9
|
+
"prepublishOnly": "npm run build",
|
|
10
|
+
"test": "bun test",
|
|
11
|
+
"watch": "tsc -w"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"lib/**/*",
|
|
15
|
+
"./processors.ttl"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"SPARQL",
|
|
19
|
+
"RDF-Connect"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/rdf-connect/sparql-ingest-processor-ts.git"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@treecg/types": "^0.4.6",
|
|
28
|
+
"n3": "^1.17.4"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@jest/globals": "^29.7.0",
|
|
32
|
+
"@rdfc/js-runner": "^0.2.1",
|
|
33
|
+
"@rdfjs/types": "^1.1.0",
|
|
34
|
+
"@types/bun": "latest",
|
|
35
|
+
"@types/n3": "^1.16.4",
|
|
36
|
+
"memory-level": "^1.0.0",
|
|
37
|
+
"quadstore": "^13.1.1",
|
|
38
|
+
"quadstore-comunica": "^4.3.1",
|
|
39
|
+
"tsc-alias": "^1.8.10",
|
|
40
|
+
"typescript": "^5.5.2"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/processors.ttl
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
@prefix js: <https://w3id.org/conn/js#>.
|
|
2
|
+
@prefix fno: <https://w3id.org/function/ontology#>.
|
|
3
|
+
@prefix fnom: <https://w3id.org/function/vocabulary/mapping#>.
|
|
4
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
|
|
5
|
+
@prefix : <https://w3id.org/conn#>.
|
|
6
|
+
@prefix sh: <http://www.w3.org/ns/shacl#>.
|
|
7
|
+
@prefix dc: <http://purl.org/dc/terms/>.
|
|
8
|
+
|
|
9
|
+
js:SPARQLIngest a js:JsProcess;
|
|
10
|
+
js:file <./lib/SPARQLIngest.js>;
|
|
11
|
+
js:function "sparqlIngest";
|
|
12
|
+
js:location <./>;
|
|
13
|
+
js:mapping [
|
|
14
|
+
a fno:Mapping;
|
|
15
|
+
fno:parameterMapping [
|
|
16
|
+
a fnom:PositionParameterMapping;
|
|
17
|
+
fnom:functionParameter "memberStream";
|
|
18
|
+
fnom:implementationParameterPosition "0"^^xsd:integer;
|
|
19
|
+
], [
|
|
20
|
+
a fnom:PositionParameterMapping;
|
|
21
|
+
fnom:functionParameter "ingestConfig";
|
|
22
|
+
fnom:implementationParameterPosition "1"^^xsd:integer;
|
|
23
|
+
], [
|
|
24
|
+
a fnom:PositionParameterMapping;
|
|
25
|
+
fnom:functionParameter "sparqlWriter";
|
|
26
|
+
fnom:implementationParameterPosition "2"^^xsd:integer;
|
|
27
|
+
]
|
|
28
|
+
].
|
|
29
|
+
|
|
30
|
+
[ ] a sh:NodeShape;
|
|
31
|
+
sh:targetClass js:SPARQLIngest;
|
|
32
|
+
sh:property [
|
|
33
|
+
sh:path js:memberStream;
|
|
34
|
+
sh:name "memberStream";
|
|
35
|
+
sh:class :ReaderChannel;
|
|
36
|
+
sh:minCount 1;
|
|
37
|
+
sh:maxCount 1;
|
|
38
|
+
], [
|
|
39
|
+
sh:path js:ingestConfig;
|
|
40
|
+
sh:name "ingestConfig";
|
|
41
|
+
sh:class js:IngestConfig;
|
|
42
|
+
sh:minCount 1;
|
|
43
|
+
sh:maxCount 1;
|
|
44
|
+
], [
|
|
45
|
+
sh:path js:sparqlWriter;
|
|
46
|
+
sh:name "sparqlWriter";
|
|
47
|
+
sh:class :WriterChannel;
|
|
48
|
+
sh:minCount 1;
|
|
49
|
+
sh:maxCount 1;
|
|
50
|
+
].
|
|
51
|
+
|
|
52
|
+
[ ] a sh:NodeShape;
|
|
53
|
+
sh:targetClass js:IngestConfig;
|
|
54
|
+
sh:property [
|
|
55
|
+
sh:path js:memberIsGraph;
|
|
56
|
+
sh:datatype xsd:boolean;
|
|
57
|
+
sh:name "memberIsGraph";
|
|
58
|
+
sh:maxCount 1;
|
|
59
|
+
sh:minCount 1;
|
|
60
|
+
], [
|
|
61
|
+
sh:path js:memberShape;
|
|
62
|
+
sh:datatype xsd:string;
|
|
63
|
+
sh:name "memberShapes";
|
|
64
|
+
sh:minCount 0;
|
|
65
|
+
], [
|
|
66
|
+
sh:path js:changeSemantics;
|
|
67
|
+
sh:class js:ChangeSemantics;
|
|
68
|
+
sh:name "changeSemantics";
|
|
69
|
+
sh:maxCount 1;
|
|
70
|
+
sh:minCount 0;
|
|
71
|
+
], [
|
|
72
|
+
sh:path js:targetNamedGraph;
|
|
73
|
+
sh:datatype xsd:string;
|
|
74
|
+
sh:name "targetNamedGraph";
|
|
75
|
+
sh:maxCount 1;
|
|
76
|
+
sh:minCount 0;
|
|
77
|
+
], [
|
|
78
|
+
sh:path js:transactionConfig;
|
|
79
|
+
sh:class js:TransactionConfig;
|
|
80
|
+
sh:name "transactionConfig";
|
|
81
|
+
sh:maxCount 1;
|
|
82
|
+
sh:minCount 0;
|
|
83
|
+
], [
|
|
84
|
+
sh:path js:graphStoreUrl;
|
|
85
|
+
sh:datatype xsd:string;
|
|
86
|
+
sh:name "graphStoreUrl";
|
|
87
|
+
sh:maxCount 1;
|
|
88
|
+
sh:minCount 0;
|
|
89
|
+
].
|
|
90
|
+
|
|
91
|
+
[ ] a sh:NodeShape;
|
|
92
|
+
sh:targetClass js:ChangeSemantics;
|
|
93
|
+
sh:property [
|
|
94
|
+
sh:path js:changeTypePath;
|
|
95
|
+
sh:datatype xsd:string;
|
|
96
|
+
sh:name "changeTypePath";
|
|
97
|
+
sh:maxCount 1;
|
|
98
|
+
sh:minCount 1;
|
|
99
|
+
], [
|
|
100
|
+
sh:path js:createValue;
|
|
101
|
+
sh:datatype xsd:string;
|
|
102
|
+
sh:name "createValue";
|
|
103
|
+
sh:maxCount 1;
|
|
104
|
+
sh:minCount 1;
|
|
105
|
+
], [
|
|
106
|
+
sh:path js:updateValue;
|
|
107
|
+
sh:datatype xsd:string;
|
|
108
|
+
sh:name "updateValue";
|
|
109
|
+
sh:maxCount 1;
|
|
110
|
+
sh:minCount 1;
|
|
111
|
+
], [
|
|
112
|
+
sh:path js:deleteValue;
|
|
113
|
+
sh:datatype xsd:string;
|
|
114
|
+
sh:name "deleteValue";
|
|
115
|
+
sh:maxCount 1;
|
|
116
|
+
sh:minCount 1;
|
|
117
|
+
].
|
|
118
|
+
|
|
119
|
+
[ ] a sh:NodeShape;
|
|
120
|
+
sh:targetClass js:TransactionConfig;
|
|
121
|
+
sh:property [
|
|
122
|
+
sh:path js:transactionIdPath;
|
|
123
|
+
sh:datatype xsd:string;
|
|
124
|
+
sh:name "transactionIdPath";
|
|
125
|
+
sh:maxCount 1;
|
|
126
|
+
sh:minCount 1;
|
|
127
|
+
], [
|
|
128
|
+
sh:path js:transactionEndPath;
|
|
129
|
+
sh:datatype xsd:string;
|
|
130
|
+
sh:name "transactionEndPath";
|
|
131
|
+
sh:maxCount 1;
|
|
132
|
+
sh:minCount 1;
|
|
133
|
+
].
|