@_linked/core 2.28.4 → 2.29.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/CHANGELOG.md +59 -0
- package/README.md +113 -1
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/ontologies/linked-core.d.ts +2 -0
- package/lib/esm/ontologies/linked-core.js +10 -0
- package/lib/esm/ontologies/linked-core.js.map +1 -1
- package/lib/esm/ontologies/shacl.d.ts +1 -0
- package/lib/esm/ontologies/shacl.js +2 -0
- package/lib/esm/ontologies/shacl.js.map +1 -1
- package/lib/esm/shapes/SHACL.d.ts +15 -2
- package/lib/esm/shapes/SHACL.js.map +1 -1
- package/lib/esm/shapes/singleOwnerConstraint.d.ts +27 -0
- package/lib/esm/shapes/singleOwnerConstraint.js +89 -0
- package/lib/esm/shapes/singleOwnerConstraint.js.map +1 -0
- package/lib/esm/shapes/syncShapes.js +48 -9
- package/lib/esm/shapes/syncShapes.js.map +1 -1
- package/lib/esm/sparql/SparqlDataset.d.ts +9 -1
- package/lib/esm/sparql/SparqlDataset.js +19 -0
- package/lib/esm/sparql/SparqlDataset.js.map +1 -1
- package/lib/esm/sparql/irToAlgebra.d.ts +34 -6
- package/lib/esm/sparql/irToAlgebra.js +271 -42
- package/lib/esm/sparql/irToAlgebra.js.map +1 -1
- package/lib/esm/sparql/ownedLinkCheck.d.ts +50 -0
- package/lib/esm/sparql/ownedLinkCheck.js +142 -0
- package/lib/esm/sparql/ownedLinkCheck.js.map +1 -0
- package/lib/esm/utils/Package.js +8 -0
- package/lib/esm/utils/Package.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SparqlDataset.js","sourceRoot":"","sources":["../../../src/sparql/SparqlDataset.ts"],"names":[],"mappings":"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","sourcesContent":["import type {IDataset} from '../interfaces/IDataset.js';\nimport type {SelectQuery} from '../queries/SelectQuery.js';\nimport type {AskQuery} from '../queries/AskQuery.js';\nimport type {CountQuery} from '../queries/CountQuery.js';\nimport type {CreateQuery} from '../queries/CreateQuery.js';\nimport type {UpdateQuery} from '../queries/UpdateQuery.js';\nimport type {DeleteQuery, DeleteResponse} from '../queries/DeleteQuery.js';\nimport type {\n IRSelectQuery,\n IRCountQuery,\n SelectResult,\n CreateResult,\n UpdateResult,\n} from '../queries/IntermediateRepresentation.js';\nimport type {SparqlQueryResults} from './resultMapping.js';\nimport {\n selectToSparql,\n askToSparql,\n countToSparql,\n createToSparql,\n updateToSparql,\n upsertToSparql,\n updateWhereToSparql,\n deleteToSparql,\n deleteAllToSparql,\n deleteWhereToSparql,\n} from './irToAlgebra.js';\nimport {\n mapSparqlSelectResult,\n mapSparqlAskResult,\n mapSparqlCountResult,\n mapSparqlCreateResult,\n mapSparqlUpdateResult,\n isSparqlSelectResults,\n} from './resultMapping.js';\nimport {generateEntityUri, type SparqlOptions} from './sparqlUtils.js';\nimport {lower} from '../queries/lower.js';\n\n/**\n * Abstract base class for SPARQL-backed datasets.\n *\n * Handles the full pipeline: IR query → SPARQL string → execute → map results.\n * Subclasses only need to implement the two transport methods:\n * - `executeSparqlSelect` — send a SPARQL SELECT and return JSON results\n * - `executeSparqlUpdate` — send a SPARQL UPDATE (INSERT DATA / DELETE..INSERT / etc.)\n *\n * Example subclass (Fuseki):\n * ```ts\n * class FusekiDataset extends SparqlDataset {\n * constructor(baseUrl: string, dataset: string) {\n * super({ dataRoot: 'http://data.example.org' });\n * this.queryEndpoint = `${baseUrl}/${dataset}/sparql`;\n * this.updateEndpoint = `${baseUrl}/${dataset}/update`;\n * }\n * protected async executeSparqlSelect(sparql: string) {\n * const res = await fetch(this.queryEndpoint, { ... });\n * return res.json();\n * }\n * protected async executeSparqlUpdate(sparql: string) {\n * await fetch(this.updateEndpoint, { ... });\n * }\n * }\n * ```\n */\nexport abstract class SparqlDataset implements IDataset {\n protected options?: SparqlOptions;\n\n constructor(options?: SparqlOptions) {\n this.options = options;\n }\n\n /**\n * Send a SPARQL SELECT/ASK/CONSTRUCT query and return the parsed\n * SPARQL JSON Results (application/sparql-results+json).\n *\n * The return type is the union of both response shapes a query endpoint can\n * produce: a SELECT result set (`results.bindings`) or an ASK answer\n * (`boolean`). A subclass may still declare the narrower `SparqlJsonResults` —\n * a return type is covariant, so existing implementations stay valid.\n */\n protected abstract executeSparqlSelect(\n sparql: string,\n ): Promise<SparqlQueryResults>;\n\n /**\n * Send a SPARQL UPDATE request (INSERT DATA, DELETE/INSERT, etc.).\n * No return value — the update is fire-and-forget at the SPARQL level.\n */\n protected abstract executeSparqlUpdate(sparql: string): Promise<void>;\n\n /**\n * Answer a select query — **and a count, which is a select.**\n *\n * A count is not a distinct query form the way an ask is. An ask really is\n * `ASK WHERE { … }` and needs its own method; a count is\n * `SELECT (COUNT(DISTINCT ?a0) AS ?count) WHERE { … }` — the same query form, the\n * same transport (`executeSparqlSelect`), the same result-set response, differing\n * only in its projection. `countToAlgebra` says so itself: it builds its plan by\n * calling `selectToAlgebra` and swapping the projection, and yields\n * `{type: 'select'}`.\n *\n * So a count rides this channel rather than a method of its own. That is not\n * tidiness: it is what lets a count reach a store through every router that\n * already forwards a select — `LinkedStorage.selectQuery`, a backend API store —\n * with no per-kind plumbing to add in each of them, and no optional `IDataset`\n * member that a third-party store silently lacks.\n *\n * The branch is on the LOWERED IR, as `updateQuery` and `deleteQuery` branch on\n * theirs: `lower()` is the one place that knows a count from a select, and a\n * rehydrated envelope (`fromJSON`) arrives here as a builder like any other.\n *\n * A count carries only a pattern, so there is nothing to normalise away on that\n * path: no projection, no ordering, and in particular no `LIMIT`/`OFFSET`, which\n * the builder dropped before the query ever reached the IR. Errors reject; a count\n * failure is never reported as `0`.\n */\n selectQuery(query: SelectQuery): Promise<SelectResult>;\n selectQuery(query: CountQuery): Promise<number>;\n async selectQuery(\n query: SelectQuery | CountQuery,\n ): Promise<SelectResult | number> {\n // Cast once for the call rather than lowering in each branch: `lower` is\n // overloaded per query kind and cannot resolve a union, and lowering twice\n // would be the thing this method most needs not to do.\n const ir = lower(query as SelectQuery) as IRSelectQuery | IRCountQuery;\n if (ir.kind === 'count') {\n const sparql = countToSparql(ir, this.options);\n const json = await this.executeSparqlSelect(sparql);\n // `mapSparqlCountResult` is strict in the same way the guard below is: it\n // refuses an ASK response, an empty result set and a non-integer binding\n // rather than answering `0`.\n return mapSparqlCountResult(json, ir);\n }\n const sparql = selectToSparql(ir, this.options);\n const json = await this.executeSparqlSelect(sparql);\n if (!isSparqlSelectResults(json)) {\n throw new Error(\n 'Expected a SPARQL SELECT result set, got an ASK response. The endpoint ' +\n 'did not answer the SELECT query that was sent.',\n );\n }\n return mapSparqlSelectResult(json, ir);\n }\n\n /**\n * Answer an ask query — emitted as `ASK WHERE { … }`.\n *\n * An {@link AskQuery} carries only a pattern, so there is nothing to normalise\n * away here. A query with no shape lowers to `ASK { <iri> ?p ?o }` — existence\n * of the node under any type or none. Errors reject; never reported as `false`.\n */\n async askQuery(query: AskQuery): Promise<boolean> {\n const ir = lower(query);\n const sparql = askToSparql(ir, this.options);\n const json = await this.executeSparqlSelect(sparql);\n return mapSparqlAskResult(json);\n }\n\n async createQuery(query: CreateQuery): Promise<CreateResult> {\n const ir = lower(query);\n const uri = ir.data.id || generateEntityUri(ir.data.shape, this.options);\n ir.data.id = uri;\n const sparql = createToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return mapSparqlCreateResult(uri, ir);\n }\n\n async updateQuery(query: UpdateQuery): Promise<UpdateResult> {\n const ir = lower(query);\n if (ir.kind === 'update_where') {\n const sparql = updateWhereToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return {id: ''} as UpdateResult;\n }\n const sparql =\n ir.kind === 'upsert'\n ? upsertToSparql(ir, this.options)\n : updateToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return mapSparqlUpdateResult(ir);\n }\n\n async deleteQuery(query: DeleteQuery): Promise<DeleteResponse> {\n const ir = lower(query);\n if (ir.kind === 'delete_all') {\n const sparql = deleteAllToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return {deleted: [], count: 0};\n }\n if (ir.kind === 'delete_where') {\n const sparql = deleteWhereToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return {deleted: [], count: 0};\n }\n const sparql = deleteToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return {\n deleted: ir.ids,\n count: ir.ids.length,\n };\n }\n\n /**\n * Execute a raw SPARQL query string directly against the dataset.\n * Defaults to SELECT; pass `'update'` for INSERT/DELETE operations.\n */\n async rawQuery(\n sparql: string,\n mode?: 'query' | 'update',\n ): Promise<SparqlQueryResults | void> {\n if (mode === 'update') {\n return this.executeSparqlUpdate(sparql);\n }\n return this.executeSparqlSelect(sparql);\n }\n}\n\n// Backwards-compatibility re-export — remove once all consumers are updated.\nexport {SparqlDataset as SparqlStore};\n"]}
|
|
1
|
+
{"version":3,"file":"SparqlDataset.js","sourceRoot":"","sources":["../../../src/sparql/SparqlDataset.ts"],"names":[],"mappings":"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","sourcesContent":["import type {IDataset} from '../interfaces/IDataset.js';\nimport type {SelectQuery} from '../queries/SelectQuery.js';\nimport type {AskQuery} from '../queries/AskQuery.js';\nimport type {CountQuery} from '../queries/CountQuery.js';\nimport type {CreateQuery} from '../queries/CreateQuery.js';\nimport type {UpdateQuery} from '../queries/UpdateQuery.js';\nimport type {DeleteQuery, DeleteResponse} from '../queries/DeleteQuery.js';\nimport type {\n IRSelectQuery,\n IRCountQuery,\n IRCreateMutation,\n IRUpdateMutation,\n IRUpdateWhereMutation,\n IRUpsertMutation,\n SelectResult,\n CreateResult,\n UpdateResult,\n} from '../queries/IntermediateRepresentation.js';\nimport type {SparqlQueryResults} from './resultMapping.js';\nimport {\n selectToSparql,\n askToSparql,\n countToSparql,\n createToSparql,\n updateToSparql,\n upsertToSparql,\n updateWhereToSparql,\n deleteToSparql,\n deleteAllToSparql,\n deleteWhereToSparql,\n} from './irToAlgebra.js';\nimport {\n mapSparqlSelectResult,\n mapSparqlAskResult,\n mapSparqlCountResult,\n mapSparqlCreateResult,\n mapSparqlUpdateResult,\n isSparqlSelectResults,\n} from './resultMapping.js';\nimport {generateEntityUri, type SparqlOptions} from './sparqlUtils.js';\nimport {lower} from '../queries/lower.js';\nimport {\n assertOwnedLinkTypes,\n collectOwnedLinks,\n ownedLinkTypesFromResults,\n ownedLinkTypesQuery,\n} from './ownedLinkCheck.js';\n\n/**\n * Abstract base class for SPARQL-backed datasets.\n *\n * Handles the full pipeline: IR query → SPARQL string → execute → map results.\n * Subclasses only need to implement the two transport methods:\n * - `executeSparqlSelect` — send a SPARQL SELECT and return JSON results\n * - `executeSparqlUpdate` — send a SPARQL UPDATE (INSERT DATA / DELETE..INSERT / etc.)\n *\n * Example subclass (Fuseki):\n * ```ts\n * class FusekiDataset extends SparqlDataset {\n * constructor(baseUrl: string, dataset: string) {\n * super({ dataRoot: 'http://data.example.org' });\n * this.queryEndpoint = `${baseUrl}/${dataset}/sparql`;\n * this.updateEndpoint = `${baseUrl}/${dataset}/update`;\n * }\n * protected async executeSparqlSelect(sparql: string) {\n * const res = await fetch(this.queryEndpoint, { ... });\n * return res.json();\n * }\n * protected async executeSparqlUpdate(sparql: string) {\n * await fetch(this.updateEndpoint, { ... });\n * }\n * }\n * ```\n */\nexport abstract class SparqlDataset implements IDataset {\n protected options?: SparqlOptions;\n\n constructor(options?: SparqlOptions) {\n this.options = options;\n }\n\n /**\n * Send a SPARQL SELECT/ASK/CONSTRUCT query and return the parsed\n * SPARQL JSON Results (application/sparql-results+json).\n *\n * The return type is the union of both response shapes a query endpoint can\n * produce: a SELECT result set (`results.bindings`) or an ASK answer\n * (`boolean`). A subclass may still declare the narrower `SparqlJsonResults` —\n * a return type is covariant, so existing implementations stay valid.\n */\n protected abstract executeSparqlSelect(\n sparql: string,\n ): Promise<SparqlQueryResults>;\n\n /**\n * Send a SPARQL UPDATE request (INSERT DATA, DELETE/INSERT, etc.).\n * No return value — the update is fire-and-forget at the SPARQL level.\n */\n protected abstract executeSparqlUpdate(sparql: string): Promise<void>;\n\n /**\n * Answer a select query — **and a count, which is a select.**\n *\n * A count is not a distinct query form the way an ask is. An ask really is\n * `ASK WHERE { … }` and needs its own method; a count is\n * `SELECT (COUNT(DISTINCT ?a0) AS ?count) WHERE { … }` — the same query form, the\n * same transport (`executeSparqlSelect`), the same result-set response, differing\n * only in its projection. `countToAlgebra` says so itself: it builds its plan by\n * calling `selectToAlgebra` and swapping the projection, and yields\n * `{type: 'select'}`.\n *\n * So a count rides this channel rather than a method of its own. That is not\n * tidiness: it is what lets a count reach a store through every router that\n * already forwards a select — `LinkedStorage.selectQuery`, a backend API store —\n * with no per-kind plumbing to add in each of them, and no optional `IDataset`\n * member that a third-party store silently lacks.\n *\n * The branch is on the LOWERED IR, as `updateQuery` and `deleteQuery` branch on\n * theirs: `lower()` is the one place that knows a count from a select, and a\n * rehydrated envelope (`fromJSON`) arrives here as a builder like any other.\n *\n * A count carries only a pattern, so there is nothing to normalise away on that\n * path: no projection, no ordering, and in particular no `LIMIT`/`OFFSET`, which\n * the builder dropped before the query ever reached the IR. Errors reject; a count\n * failure is never reported as `0`.\n */\n selectQuery(query: SelectQuery): Promise<SelectResult>;\n selectQuery(query: CountQuery): Promise<number>;\n async selectQuery(\n query: SelectQuery | CountQuery,\n ): Promise<SelectResult | number> {\n // Cast once for the call rather than lowering in each branch: `lower` is\n // overloaded per query kind and cannot resolve a union, and lowering twice\n // would be the thing this method most needs not to do.\n const ir = lower(query as SelectQuery) as IRSelectQuery | IRCountQuery;\n if (ir.kind === 'count') {\n const sparql = countToSparql(ir, this.options);\n const json = await this.executeSparqlSelect(sparql);\n // `mapSparqlCountResult` is strict in the same way the guard below is: it\n // refuses an ASK response, an empty result set and a non-integer binding\n // rather than answering `0`.\n return mapSparqlCountResult(json, ir);\n }\n const sparql = selectToSparql(ir, this.options);\n const json = await this.executeSparqlSelect(sparql);\n if (!isSparqlSelectResults(json)) {\n throw new Error(\n 'Expected a SPARQL SELECT result set, got an ASK response. The endpoint ' +\n 'did not answer the SELECT query that was sent.',\n );\n }\n return mapSparqlSelectResult(json, ir);\n }\n\n /**\n * Answer an ask query — emitted as `ASK WHERE { … }`.\n *\n * An {@link AskQuery} carries only a pattern, so there is nothing to normalise\n * away here. A query with no shape lowers to `ASK { <iri> ?p ?o }` — existence\n * of the node under any type or none. Errors reject; never reported as `false`.\n */\n async askQuery(query: AskQuery): Promise<boolean> {\n const ir = lower(query);\n const sparql = askToSparql(ir, this.options);\n const json = await this.executeSparqlSelect(sparql);\n return mapSparqlAskResult(json);\n }\n\n async createQuery(query: CreateQuery): Promise<CreateResult> {\n const ir = lower(query);\n const uri = ir.data.id || generateEntityUri(ir.data.shape, this.options);\n ir.data.id = uri;\n await this.checkOwnedLinks(ir);\n const sparql = createToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return mapSparqlCreateResult(uri, ir);\n }\n\n async updateQuery(query: UpdateQuery): Promise<UpdateResult> {\n const ir = lower(query);\n await this.checkOwnedLinks(ir);\n if (ir.kind === 'update_where') {\n const sparql = updateWhereToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return {id: ''} as UpdateResult;\n }\n const sparql =\n ir.kind === 'upsert'\n ? upsertToSparql(ir, this.options)\n : updateToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return mapSparqlUpdateResult(ir);\n }\n\n /**\n * Refuse a mutation that links a node of the wrong class into a `contains` property\n * (see `ownedLinkCheck.ts`). An owner deletes what it contains, so a Person linked into\n * an ImageObject slot would be deleted with its owner. Runs before the update is sent, so\n * a refused mutation writes nothing. With no such link no query is sent; otherwise one\n * SELECT covers every linked id.\n */\n protected async checkOwnedLinks(\n ir: IRCreateMutation | IRUpdateMutation | IRUpsertMutation | IRUpdateWhereMutation,\n ): Promise<void> {\n const links = collectOwnedLinks(ir);\n if (links.length === 0) return;\n const json = await this.executeSparqlSelect(\n ownedLinkTypesQuery(links.map((link) => link.id)),\n );\n assertOwnedLinkTypes(links, ownedLinkTypesFromResults(json));\n }\n\n async deleteQuery(query: DeleteQuery): Promise<DeleteResponse> {\n const ir = lower(query);\n if (ir.kind === 'delete_all') {\n const sparql = deleteAllToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return {deleted: [], count: 0};\n }\n if (ir.kind === 'delete_where') {\n const sparql = deleteWhereToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return {deleted: [], count: 0};\n }\n const sparql = deleteToSparql(ir, this.options);\n await this.executeSparqlUpdate(sparql);\n return {\n deleted: ir.ids,\n count: ir.ids.length,\n };\n }\n\n /**\n * Execute a raw SPARQL query string directly against the dataset.\n * Defaults to SELECT; pass `'update'` for INSERT/DELETE operations.\n */\n async rawQuery(\n sparql: string,\n mode?: 'query' | 'update',\n ): Promise<SparqlQueryResults | void> {\n if (mode === 'update') {\n return this.executeSparqlUpdate(sparql);\n }\n return this.executeSparqlSelect(sparql);\n }\n}\n\n// Backwards-compatibility re-export — remove once all consumers are updated.\nexport {SparqlDataset as SparqlStore};\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IRSelectQuery, IRAskQuery, IRCountQuery, IRCreateMutation, IRUpdateMutation, IRUpsertMutation, IRDeleteMutation, IRDeleteAllMutation, IRDeleteWhereMutation, IRUpdateWhereMutation } from '../queries/IntermediateRepresentation.js';
|
|
2
|
+
import type { NodeReferenceValue } from '../utils/NodeReference.js';
|
|
2
3
|
import type { SparqlSelectPlan, SparqlAskPlan, SparqlInsertDataPlan, SparqlDeleteInsertPlan, SparqlAlgebraNode, SparqlTriple, SparqlTerm } from './SparqlAlgebra.js';
|
|
3
4
|
import { type SparqlOptions } from './sparqlUtils.js';
|
|
4
5
|
/**
|
|
@@ -9,6 +10,8 @@ export declare function selectToAlgebra(query: IRSelectQuery, _options?: SparqlO
|
|
|
9
10
|
* Converts an IRCreateMutation to a SparqlInsertDataPlan.
|
|
10
11
|
*/
|
|
11
12
|
export declare function createToAlgebra(query: IRCreateMutation, options?: SparqlOptions): SparqlInsertDataPlan;
|
|
13
|
+
/** A bare `{id}` reference: a link to an existing node, not a nested create. */
|
|
14
|
+
export declare function isBareNodeReference(value: unknown): value is NodeReferenceValue;
|
|
12
15
|
/**
|
|
13
16
|
* Converts an IRUpdateMutation to a SparqlDeleteInsertPlan.
|
|
14
17
|
*/
|
|
@@ -23,6 +26,11 @@ export declare function updateToAlgebra(query: IRUpdateMutation, options?: Sparq
|
|
|
23
26
|
* needs no guard.
|
|
24
27
|
*/
|
|
25
28
|
export declare function upsertToAlgebra(query: IRUpsertMutation, options?: SparqlOptions): SparqlDeleteInsertPlan;
|
|
29
|
+
/** Gather contains-predicate IRIs and dependent targetClass IRIs from the registry. */
|
|
30
|
+
export declare function collectContainment(): {
|
|
31
|
+
containsPreds: string[];
|
|
32
|
+
dependentTypes: string[];
|
|
33
|
+
};
|
|
26
34
|
/**
|
|
27
35
|
* Build DELETE patterns + WHERE OPTIONAL blocks that cascade-delete the owned subtree
|
|
28
36
|
* reachable from `rootTerm` via `contains` edges. `varPrefix` keeps generated variables
|
|
@@ -30,8 +38,10 @@ export declare function upsertToAlgebra(query: IRUpsertMutation, options?: Sparq
|
|
|
30
38
|
*
|
|
31
39
|
* `anchor`, when given, leads every block: the triple that binds a variable root, so
|
|
32
40
|
* each block stays correct on its own (as a UNION branch) when no such root exists.
|
|
41
|
+
* `onlyTypes`, when given, restricts the blocks to those dependent types (a subject delete
|
|
42
|
+
* passes the types its shape can reach); by default every registered dependent type gets one.
|
|
33
43
|
*/
|
|
34
|
-
export declare function buildOwnedCascade(rootTerm: SparqlTerm, varPrefix: string, anchor?: SparqlTriple): {
|
|
44
|
+
export declare function buildOwnedCascade(rootTerm: SparqlTerm, varPrefix: string, anchor?: SparqlTriple, keep?: SparqlTerm[], onlyTypes?: string[]): {
|
|
35
45
|
deletePatterns: SparqlTriple[];
|
|
36
46
|
whereOptionals: SparqlAlgebraNode[];
|
|
37
47
|
};
|
|
@@ -43,12 +53,21 @@ export declare function buildOwnedCascade(rootTerm: SparqlTerm, varPrefix: strin
|
|
|
43
53
|
* does NOT require the child shape to be `dependent`: ownership via the edge is sufficient.
|
|
44
54
|
* Owned descendants *below* the old node are cascaded separately by `buildOwnedCascade`.
|
|
45
55
|
*
|
|
56
|
+
* Callers use it only for a property that declares a value shape. A shape-less `contains`
|
|
57
|
+
* slot (like `sh:path`) may hold a shared IRI, so its old value is left to
|
|
58
|
+
* `buildOwnedCascade`, which deletes it only when it is dependent-typed.
|
|
59
|
+
*
|
|
46
60
|
* The owning edge `<subject> <prop> ?old` is re-asserted INSIDE the WHERE group so `?old`
|
|
47
61
|
* is bound there: when no old value exists the group matches nothing and the DELETE is a
|
|
48
62
|
* no-op, rather than an unbound `?old` matching (and deleting) the whole graph. When
|
|
49
63
|
* `oldTerm` is a concrete IRI (set-remove), the guard just confirms the link still holds.
|
|
64
|
+
*
|
|
65
|
+
* `keep` lists the bare `{id}`s the mutation writes again (a re-sent current value, the
|
|
66
|
+
* retained ids of an array overwrite). With a variable `oldTerm` the block is wrapped in
|
|
67
|
+
* `FILTER(?old NOT IN (…))`, so a kept value is not deleted; its edge is deleted and
|
|
68
|
+
* re-inserted, a no-op. A nested create carrying an id is never kept: it rewrites that node.
|
|
50
69
|
*/
|
|
51
|
-
export declare function buildOwnedSelfDelete(subjectTerm: SparqlTerm, propertyTerm: SparqlTerm, oldTerm: SparqlTerm, varPrefix: string): {
|
|
70
|
+
export declare function buildOwnedSelfDelete(subjectTerm: SparqlTerm, propertyTerm: SparqlTerm, oldTerm: SparqlTerm, varPrefix: string, keep?: SparqlTerm[]): {
|
|
52
71
|
deletePatterns: SparqlTriple[];
|
|
53
72
|
whereOptionals: SparqlAlgebraNode[];
|
|
54
73
|
};
|
|
@@ -57,7 +76,12 @@ export declare function buildOwnedSelfDelete(subjectTerm: SparqlTerm, propertyTe
|
|
|
57
76
|
*
|
|
58
77
|
* The WHERE is the type guard of every id, joined with ONE UNION of independent
|
|
59
78
|
* blocks: per id its own triples, its incoming references and, for a shape that
|
|
60
|
-
* owns something, one block per
|
|
79
|
+
* owns something, one block per immediately-owned child (`<s> <p> ?dN . ?dN ?dN_p ?dN_o`,
|
|
80
|
+
* for each of the shape's own and inherited `contains` properties with a value shape and
|
|
81
|
+
* a simple path) and one block per dependent type its owned subtree can reach
|
|
82
|
+
* (`reachableDependentTypes`; none for a shape that owns only non-dependent values). The
|
|
83
|
+
* bulk deletes (`deleteAllToAlgebra`, `deleteWhereToAlgebra`) add the same owned blocks,
|
|
84
|
+
* rooted at the subject variable (see `bulkDeleteUnion`).
|
|
61
85
|
*
|
|
62
86
|
* The blocks must not be chained as OPTIONALs. A chain of OPTIONALs is a join, so
|
|
63
87
|
* the solutions multiply: own triples x incoming references x owned triples of each
|
|
@@ -75,14 +99,18 @@ export declare function deleteToAlgebra(query: IRDeleteMutation, _options?: Spar
|
|
|
75
99
|
/**
|
|
76
100
|
* Converts an IRDeleteAllMutation to a SparqlDeleteInsertPlan.
|
|
77
101
|
*
|
|
78
|
-
* Generates DELETE { ?a0 ?p ?o . [blank
|
|
79
|
-
* WHERE { ?a0 a <Shape> . ?a0 ?p ?o
|
|
102
|
+
* Generates DELETE { ?a0 ?p ?o . [blank-node and owned-cleanup wildcards] }
|
|
103
|
+
* WHERE { ?a0 a <Shape> . { ?a0 ?p ?o } UNION [one block per blank node,
|
|
104
|
+
* owned child and dependent type] }
|
|
105
|
+
* (see `bulkDeleteUnion`). Unlike a delete by id, incoming references are not deleted.
|
|
80
106
|
*/
|
|
81
107
|
export declare function deleteAllToAlgebra(query: IRDeleteAllMutation, _options?: SparqlOptions): SparqlDeleteInsertPlan;
|
|
82
108
|
/**
|
|
83
109
|
* Converts an IRDeleteWhereMutation to a SparqlDeleteInsertPlan.
|
|
84
110
|
*
|
|
85
|
-
* Like deleteAllToAlgebra but adds filter conditions from the where clause.
|
|
111
|
+
* Like deleteAllToAlgebra but adds filter conditions from the where clause. The cleanup
|
|
112
|
+
* UNION (blank nodes, owned children, dependent cascade) is joined with the filtered match,
|
|
113
|
+
* so only the matched subjects' children are deleted.
|
|
86
114
|
*/
|
|
87
115
|
export declare function deleteWhereToAlgebra(query: IRDeleteWhereMutation, _options?: SparqlOptions): SparqlDeleteInsertPlan;
|
|
88
116
|
/**
|