@_linked/core 2.28.1 → 2.28.3

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.28.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#322](https://github.com/linked-fw/core/pull/322) [`720e284`](https://github.com/linked-fw/core/commit/720e28438842cc8aa617a818c086b6279e87ade0) Thanks [@flyon](https://github.com/flyon)! - An update's WHERE, and a bulk delete's, no longer multiply their parts — the same fix [#318](https://github.com/linked-fw/core/issues/318) made for a delete by id. `update`, `upsert` and `updateWhere` chained the old value of every property and every owned-cleanup block as OPTIONALs, so the solutions were the product of all of them: updating two multi-valued properties gave one solution per pair of old values, and replacing a `contains` property gave the old node's own triples times every triple of its owned subtree. They are now one OPTIONAL over a UNION of those blocks, which deletes and inserts the same triples. Old values a computed field's BIND reads stay joined to it, as before. `deleteAll` and `deleteWhere` likewise join the root's triples and each blank-node subtree with a UNION instead of nested OPTIONALs.
8
+
9
+ Also fixes a data-loss bug: replacing a `contains` property that had no old value deleted the owned subtree of every other node in the graph, because the cascade block's `?old` variable was left unbound. Each cascade block now binds it through the owning edge.
10
+
11
+ ## 2.28.2
12
+
13
+ ### Patch Changes
14
+
15
+ - [#318](https://github.com/linked-fw/core/pull/318) [`2308490`](https://github.com/linked-fw/core/commit/2308490cdc6cc3c8d5a73e21d8ca763e0cbf5bab) Thanks [@flyon](https://github.com/flyon)! - A delete's WHERE no longer multiplies its parts. It chained the incoming references and every cascade block as OPTIONALs, so the solutions were the product of all of them; deleting one shape description during the shape sync gave ~27,000 solutions for ~130 triples and took over 30 seconds on Fuseki, which made an app's second boot (`syncShapesOnBoot`) take minutes. The WHERE is now the type guards joined with one UNION of the blocks, which deletes the same triples. A UNION chain is also serialized flat (`{a} UNION {b} UNION {c}`).
16
+
3
17
  ## 2.28.1
4
18
 
5
19
  ### Patch Changes
@@ -188,9 +188,18 @@ export function serializeAlgebraNode(node, collector) {
188
188
  return `${inner}\nFILTER(${expr})`;
189
189
  }
190
190
  case 'union': {
191
- const left = serializeAlgebraNode(node.left, collector);
192
- const right = serializeAlgebraNode(node.right, collector);
193
- return `{\n${indent(left)}\n}\nUNION\n{\n${indent(right)}\n}`;
191
+ // UNION is associative: write a left-nested chain flat, {a} UNION {b} UNION {c},
192
+ // instead of nesting every earlier branch one group deeper.
193
+ const branches = [node.right];
194
+ let head = node.left;
195
+ while (head.type === 'union') {
196
+ branches.unshift(head.right);
197
+ head = head.left;
198
+ }
199
+ branches.unshift(head);
200
+ return branches
201
+ .map((branch) => `{\n${indent(serializeAlgebraNode(branch, collector))}\n}`)
202
+ .join('\nUNION\n');
194
203
  }
195
204
  case 'minus': {
196
205
  const left = serializeAlgebraNode(node.left, collector);
@@ -1 +1 @@
1
- {"version":3,"file":"algebraToString.js","sourceRoot":"","sources":["../../../src/sparql/algebraToString.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n SparqlAlgebraNode,\n SparqlExpression,\n SparqlTerm,\n SparqlTriple,\n SparqlSelectPlan,\n SparqlAskPlan,\n SparqlInsertDataPlan,\n SparqlDeleteInsertPlan,\n SparqlDeleteWherePlan,\n} from './SparqlAlgebra.js';\nimport {\n type SparqlOptions,\n formatUri,\n formatLiteral,\n escapeSparqlString,\n collectPrefixes,\n assertSafeCallName,\n sanitizeVarName,\n} from './sparqlUtils.js';\n\n// ---------------------------------------------------------------------------\n// URI collector — gathers all IRIs encountered during serialization so that\n// the prefix block can be built afterwards.\n// ---------------------------------------------------------------------------\n\ntype UriCollector = {uris: Set<string>};\n\nfunction collectUri(collector: UriCollector, uri: string): void {\n collector.uris.add(uri);\n}\n\n// ---------------------------------------------------------------------------\n// Term serialization\n// ---------------------------------------------------------------------------\n\nexport function serializeTerm(\n term: SparqlTerm,\n collector?: UriCollector,\n): string {\n switch (term.kind) {\n case 'variable':\n return `?${sanitizeVarName(term.name)}`;\n case 'iri':\n if (collector) collectUri(collector, term.value);\n return formatUri(term.value);\n case 'literal': {\n if (term.language) {\n return `\"${escapeSparqlString(term.value)}\"@${term.language}`;\n }\n if (term.datatype) {\n if (collector) collectUri(collector, term.datatype);\n }\n return formatLiteral(term.value, term.datatype);\n }\n case 'path':\n if (collector && term.uris) {\n for (const uri of term.uris) collectUri(collector, uri);\n }\n return term.value;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Triple serialization\n// ---------------------------------------------------------------------------\n\nfunction serializeTriple(\n triple: SparqlTriple,\n collector?: UriCollector,\n): string {\n const s = serializeTerm(triple.subject, collector);\n const p = serializeTerm(triple.predicate, collector);\n const o = serializeTerm(triple.object, collector);\n return `${s} ${p} ${o}`;\n}\n\nfunction serializeTriples(\n triples: SparqlTriple[],\n collector?: UriCollector,\n): string {\n return triples\n .map((t) => serializeTriple(t, collector) + ' .')\n .join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Expression serialization\n// ---------------------------------------------------------------------------\n\n// SPARQL binary-operator precedence (higher binds tighter): multiplicative >\n// additive > relational. Used to parenthesize nested `binary_expr` operands so\n// arithmetic groups correctly (`(a+b)*c`, not `a+b*c`) and relational chains\n// (`a=b=c`, a non-associative syntax error) get parenthesized.\nconst RELATIONAL_OPS = new Set(['=', '!=', '<', '>', '<=', '>=']);\nfunction binaryPrecedence(op: string): number {\n if (op === '*' || op === '/') return 3;\n if (op === '+' || op === '-') return 2;\n if (RELATIONAL_OPS.has(op)) return 1;\n return 0;\n}\n\n/**\n * Serialize a `binary_expr` operand, wrapping it in parens when omitting them\n * would change how SPARQL parses the expression.\n */\nfunction wrapBinaryOperand(\n operand: SparqlExpression,\n parentOp: string,\n side: 'left' | 'right',\n collector?: UriCollector,\n): string {\n const s = serializeExpression(operand, collector);\n // Logical (&&/||) binds looser than any binary operator → always parenthesize.\n if (operand.kind === 'logical_expr') return `(${s})`;\n if (operand.kind !== 'binary_expr') return s;\n const parentIsRel = RELATIONAL_OPS.has(parentOp);\n const childIsRel = RELATIONAL_OPS.has(operand.op);\n // Relational is non-associative in SPARQL: any relational-in-relational needs parens.\n if (parentIsRel && childIsRel) return `(${s})`;\n const pc = binaryPrecedence(operand.op);\n const pp = binaryPrecedence(parentOp);\n const needs = side === 'left' ? pc < pp : pc <= pp;\n return needs ? `(${s})` : s;\n}\n\nexport function serializeExpression(\n expr: SparqlExpression,\n collector?: UriCollector,\n): string {\n switch (expr.kind) {\n case 'variable_expr':\n return `?${sanitizeVarName(expr.name)}`;\n\n case 'iri_expr':\n if (collector) collectUri(collector, expr.value);\n return formatUri(expr.value);\n\n case 'literal_expr': {\n if (expr.datatype && collector) collectUri(collector, expr.datatype);\n return formatLiteral(expr.value, expr.datatype);\n }\n\n case 'binary_expr': {\n const left = wrapBinaryOperand(expr.left, expr.op, 'left', collector);\n const right = wrapBinaryOperand(expr.right, expr.op, 'right', collector);\n return `${left} ${expr.op} ${right}`;\n }\n\n case 'logical_expr': {\n const op = expr.op === 'and' ? '&&' : '||';\n const parts = expr.exprs.map((e) => {\n const s = serializeExpression(e, collector);\n // Parenthesize OR children inside AND (AND binds tighter than OR)\n if (expr.op === 'and' && e.kind === 'logical_expr' && e.op === 'or') {\n return `(${s})`;\n }\n return s;\n });\n return parts.join(` ${op} `);\n }\n\n case 'not_expr':\n return `!(${serializeExpression(expr.inner, collector)})`;\n\n case 'function_expr': {\n assertSafeCallName(expr.name);\n const args = expr.args\n .map((a) => serializeExpression(a, collector))\n .join(', ');\n return `${expr.name}(${args})`;\n }\n\n case 'aggregate_expr': {\n assertSafeCallName(expr.name);\n const args = expr.args\n .map((a) => serializeExpression(a, collector))\n .join(', ');\n const distinctPrefix = expr.distinct ? 'DISTINCT ' : '';\n // Uppercased here rather than in the IR: this one line covers COUNT/SUM/AVG/\n // MIN/MAX and any aggregate added later, while the IR keeps carrying a plain\n // lowercase name (`'count'`) that other consumers can match on without\n // case-folding. It also puts the aggregate in the same voice as every other\n // keyword this file emits (SELECT, DISTINCT, GROUP BY, HAVING, …).\n // `function_expr` is deliberately left alone: its names arrive already in\n // their correct SPARQL spelling, which is not uniformly uppercase (`isBlank`,\n // `isIRI`), so case-folding there would corrupt them.\n return `${expr.name.toUpperCase()}(${distinctPrefix}${args})`;\n }\n\n case 'exists_expr': {\n const inner = serializeAlgebraNode(expr.pattern, collector);\n const prefix = expr.negated ? 'NOT EXISTS' : 'EXISTS';\n return `${prefix} {\\n${indent(inner)}\\n}`;\n }\n\n case 'bound_expr':\n return `BOUND(?${sanitizeVarName(expr.variable)})`;\n\n case 'in_expr': {\n // Empty list: `IN ()` matches nothing, `NOT IN ()` matches everything —\n // fold to a boolean constant rather than emit an empty parenthesis list.\n if (expr.list.length === 0) return expr.negated ? 'true' : 'false';\n const val = serializeExpression(expr.value, collector);\n const items = expr.list.map((e) => serializeExpression(e, collector)).join(', ');\n return `${val} ${expr.negated ? 'NOT IN' : 'IN'} (${items})`;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Algebra node serialization\n// ---------------------------------------------------------------------------\n\nexport function serializeAlgebraNode(\n node: SparqlAlgebraNode,\n collector?: UriCollector,\n): string {\n switch (node.type) {\n case 'bgp':\n return serializeTriples(node.triples, collector);\n\n case 'join': {\n const left = serializeAlgebraNode(node.left, collector);\n const right = serializeAlgebraNode(node.right, collector);\n return `${left}\\n${right}`;\n }\n\n case 'left_join': {\n const left = serializeAlgebraNode(node.left, collector);\n const right = serializeAlgebraNode(node.right, collector);\n let optionalBlock = `OPTIONAL {\\n${indent(right)}\\n}`;\n if (node.condition) {\n const cond = serializeExpression(node.condition, collector);\n // OPTIONAL with filter: OPTIONAL { pattern FILTER(cond) }\n // Re-build to include filter inside the OPTIONAL block\n optionalBlock = `OPTIONAL {\\n${indent(right)}\\n FILTER(${cond})\\n}`;\n }\n // If left side is empty (e.g. UPDATE WHERE with all-OPTIONAL triples),\n // omit the empty prefix to avoid blank lines\n return left ? `${left}\\n${optionalBlock}` : optionalBlock;\n }\n\n case 'filter': {\n const inner = serializeAlgebraNode(node.inner, collector);\n const expr = serializeExpression(node.expression, collector);\n return `${inner}\\nFILTER(${expr})`;\n }\n\n case 'union': {\n const left = serializeAlgebraNode(node.left, collector);\n const right = serializeAlgebraNode(node.right, collector);\n return `{\\n${indent(left)}\\n}\\nUNION\\n{\\n${indent(right)}\\n}`;\n }\n\n case 'minus': {\n const left = serializeAlgebraNode(node.left, collector);\n const right = serializeAlgebraNode(node.right, collector);\n return `${left}\\nMINUS {\\n${indent(right)}\\n}`;\n }\n\n case 'extend': {\n const inner = serializeAlgebraNode(node.inner, collector);\n const expr = serializeExpression(node.expression, collector);\n return `${inner}\\nBIND(${expr} AS ?${sanitizeVarName(node.variable)})`;\n }\n\n case 'graph': {\n if (collector) collectUri(collector, node.iri);\n const inner = serializeAlgebraNode(node.inner, collector);\n return `GRAPH ${formatUri(node.iri)} {\\n${indent(inner)}\\n}`;\n }\n\n case 'values': {\n const values = node.iris\n .map((iri) => {\n if (collector) collectUri(collector, iri);\n return formatUri(iri);\n })\n .join(' ');\n return `VALUES ?${sanitizeVarName(node.variable)} { ${values} }`;\n }\n\n case 'subselect': {\n const innerBody = serializeAlgebraNode(node.inner, collector);\n const projection = node.projection.map((v) => `?${sanitizeVarName(v)}`).join(' ');\n const lines: string[] = [`SELECT ${projection} WHERE {`];\n lines.push(indent(innerBody));\n lines.push('}');\n const trailing: string[] = [];\n if (node.orderBy && node.orderBy.length > 0) {\n const orderParts = node.orderBy.map((cond) => {\n const expr = serializeExpression(cond.expression, collector);\n return `${cond.direction}(${expr})`;\n });\n trailing.push(`ORDER BY ${orderParts.join(' ')}`);\n }\n if (node.limit !== undefined) {\n trailing.push(`LIMIT ${node.limit}`);\n }\n if (node.offset !== undefined) {\n trailing.push(`OFFSET ${node.offset}`);\n }\n const subSelectStr = trailing.length > 0\n ? `${lines.join('\\n')} ${trailing.join(' ')}`\n : lines.join('\\n');\n return `{\\n${indent(subSelectStr)}\\n}`;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction indent(text: string, level: number = 1): string {\n const prefix = ' '.repeat(level);\n return text\n .split('\\n')\n .map((line) => prefix + line)\n .join('\\n');\n}\n\nfunction buildPrefixBlock(usedUris: Set<string>): string {\n const prefixes = collectPrefixes([...usedUris]);\n const lines = Object.entries(prefixes)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([prefix, uri]) => `PREFIX ${prefix}: <${uri}>`);\n return lines.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Top-level plan serializers\n// ---------------------------------------------------------------------------\n\nexport function selectPlanToSparql(\n plan: SparqlSelectPlan,\n _options?: SparqlOptions,\n): string {\n const collector: UriCollector = {uris: new Set()};\n\n // 1. Serialize WHERE body\n const body = serializeAlgebraNode(plan.algebra, collector);\n\n // 2. Build SELECT line\n const projectionParts = plan.projection.map((item) => {\n if (item.kind === 'variable') {\n return `?${sanitizeVarName(item.name)}`;\n } else {\n // aggregate or expression projection: (expr AS ?alias)\n const expr = serializeExpression(item.expression, collector);\n return `(${expr} AS ?${sanitizeVarName(item.alias)})`;\n }\n });\n\n const distinctStr = plan.distinct ? 'DISTINCT ' : '';\n const selectLine = `SELECT ${distinctStr}${projectionParts.join(' ')}`;\n\n // 3. Build WHERE block\n const whereBlock = `WHERE {\\n${indent(body)}\\n}`;\n\n // 4. Build trailing clauses\n const clauses: string[] = [];\n\n if (plan.groupBy && plan.groupBy.length > 0) {\n clauses.push(\n `GROUP BY ${plan.groupBy.map((v) => `?${sanitizeVarName(v)}`).join(' ')}`,\n );\n }\n\n if (plan.having) {\n const havingExpr = serializeExpression(plan.having, collector);\n clauses.push(`HAVING(${havingExpr})`);\n }\n\n if (plan.orderBy && plan.orderBy.length > 0) {\n const orderParts = plan.orderBy.map((cond) => {\n const expr = serializeExpression(cond.expression, collector);\n return `${cond.direction}(${expr})`;\n });\n clauses.push(`ORDER BY ${orderParts.join(' ')}`);\n }\n\n if (plan.limit !== undefined) {\n clauses.push(`LIMIT ${plan.limit}`);\n }\n\n if (plan.offset !== undefined) {\n clauses.push(`OFFSET ${plan.offset}`);\n }\n\n // 5. Build PREFIX block (after collecting all URIs)\n const prefixBlock = buildPrefixBlock(collector.uris);\n\n // 6. Assemble\n const parts: string[] = [];\n if (prefixBlock) parts.push(prefixBlock);\n parts.push(selectLine);\n parts.push(whereBlock);\n parts.push(...clauses);\n\n return parts.join('\\n');\n}\n\n/**\n * Serializes a {@link SparqlAskPlan} to `ASK WHERE { … }`.\n *\n * The same WHERE body as {@link selectPlanToSparql}, with the projection line and\n * every solution modifier removed — `ASK` accepts none of them.\n */\nexport function askPlanToSparql(\n plan: SparqlAskPlan,\n _options?: SparqlOptions,\n): string {\n const collector: UriCollector = {uris: new Set()};\n\n // 1. Serialize WHERE body (collects the URIs the prefix block is built from)\n const body = serializeAlgebraNode(plan.algebra, collector);\n\n // 2. Build PREFIX block (after collecting all URIs)\n const prefixBlock = buildPrefixBlock(collector.uris);\n\n // 3. Assemble\n const parts: string[] = [];\n if (prefixBlock) parts.push(prefixBlock);\n parts.push(`ASK WHERE {\\n${indent(body)}\\n}`);\n\n return parts.join('\\n');\n}\n\nexport function insertDataPlanToSparql(\n plan: SparqlInsertDataPlan,\n _options?: SparqlOptions,\n): string {\n const collector: UriCollector = {uris: new Set()};\n\n let triplesStr: string;\n if (plan.graph) {\n if (collector) collectUri(collector, plan.graph);\n const innerTriples = serializeTriples(plan.triples, collector);\n triplesStr = `GRAPH ${formatUri(plan.graph)} {\\n${indent(innerTriples)}\\n}`;\n } else {\n triplesStr = serializeTriples(plan.triples, collector);\n }\n\n const body = `INSERT DATA {\\n${indent(triplesStr)}\\n}`;\n\n const prefixBlock = buildPrefixBlock(collector.uris);\n const parts: string[] = [];\n if (prefixBlock) parts.push(prefixBlock);\n parts.push(body);\n return parts.join('\\n');\n}\n\nexport function deleteInsertPlanToSparql(\n plan: SparqlDeleteInsertPlan,\n _options?: SparqlOptions,\n): string {\n const collector: UriCollector = {uris: new Set()};\n\n // DELETE block\n const deleteTriples = serializeTriples(plan.deletePatterns, collector);\n const deletePart = `DELETE {\\n${indent(deleteTriples)}\\n}`;\n\n // INSERT block (may be empty)\n let insertPart = '';\n if (plan.insertPatterns.length > 0) {\n const insertTriples = serializeTriples(plan.insertPatterns, collector);\n insertPart = `INSERT {\\n${indent(insertTriples)}\\n}\\n`;\n }\n\n // WHERE block\n const whereBody = serializeAlgebraNode(plan.whereAlgebra, collector);\n const wherePart = `WHERE {\\n${indent(whereBody)}\\n}`;\n\n const prefixBlock = buildPrefixBlock(collector.uris);\n const parts: string[] = [];\n if (prefixBlock) parts.push(prefixBlock);\n parts.push(deletePart);\n if (insertPart) parts.push(insertPart.trimEnd());\n parts.push(wherePart);\n return parts.join('\\n');\n}\n\nexport function deleteWherePlanToSparql(\n plan: SparqlDeleteWherePlan,\n _options?: SparqlOptions,\n): string {\n const collector: UriCollector = {uris: new Set()};\n\n const body = serializeAlgebraNode(plan.patterns, collector);\n\n let content: string;\n if (plan.graph) {\n if (collector) collectUri(collector, plan.graph);\n content = `GRAPH ${formatUri(plan.graph)} {\\n${indent(body)}\\n}`;\n } else {\n content = body;\n }\n\n const result = `DELETE WHERE {\\n${indent(content)}\\n}`;\n\n const prefixBlock = buildPrefixBlock(collector.uris);\n const parts: string[] = [];\n if (prefixBlock) parts.push(prefixBlock);\n parts.push(result);\n return parts.join('\\n');\n}\n"]}
1
+ {"version":3,"file":"algebraToString.js","sourceRoot":"","sources":["../../../src/sparql/algebraToString.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n SparqlAlgebraNode,\n SparqlExpression,\n SparqlTerm,\n SparqlTriple,\n SparqlSelectPlan,\n SparqlAskPlan,\n SparqlInsertDataPlan,\n SparqlDeleteInsertPlan,\n SparqlDeleteWherePlan,\n} from './SparqlAlgebra.js';\nimport {\n type SparqlOptions,\n formatUri,\n formatLiteral,\n escapeSparqlString,\n collectPrefixes,\n assertSafeCallName,\n sanitizeVarName,\n} from './sparqlUtils.js';\n\n// ---------------------------------------------------------------------------\n// URI collector — gathers all IRIs encountered during serialization so that\n// the prefix block can be built afterwards.\n// ---------------------------------------------------------------------------\n\ntype UriCollector = {uris: Set<string>};\n\nfunction collectUri(collector: UriCollector, uri: string): void {\n collector.uris.add(uri);\n}\n\n// ---------------------------------------------------------------------------\n// Term serialization\n// ---------------------------------------------------------------------------\n\nexport function serializeTerm(\n term: SparqlTerm,\n collector?: UriCollector,\n): string {\n switch (term.kind) {\n case 'variable':\n return `?${sanitizeVarName(term.name)}`;\n case 'iri':\n if (collector) collectUri(collector, term.value);\n return formatUri(term.value);\n case 'literal': {\n if (term.language) {\n return `\"${escapeSparqlString(term.value)}\"@${term.language}`;\n }\n if (term.datatype) {\n if (collector) collectUri(collector, term.datatype);\n }\n return formatLiteral(term.value, term.datatype);\n }\n case 'path':\n if (collector && term.uris) {\n for (const uri of term.uris) collectUri(collector, uri);\n }\n return term.value;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Triple serialization\n// ---------------------------------------------------------------------------\n\nfunction serializeTriple(\n triple: SparqlTriple,\n collector?: UriCollector,\n): string {\n const s = serializeTerm(triple.subject, collector);\n const p = serializeTerm(triple.predicate, collector);\n const o = serializeTerm(triple.object, collector);\n return `${s} ${p} ${o}`;\n}\n\nfunction serializeTriples(\n triples: SparqlTriple[],\n collector?: UriCollector,\n): string {\n return triples\n .map((t) => serializeTriple(t, collector) + ' .')\n .join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Expression serialization\n// ---------------------------------------------------------------------------\n\n// SPARQL binary-operator precedence (higher binds tighter): multiplicative >\n// additive > relational. Used to parenthesize nested `binary_expr` operands so\n// arithmetic groups correctly (`(a+b)*c`, not `a+b*c`) and relational chains\n// (`a=b=c`, a non-associative syntax error) get parenthesized.\nconst RELATIONAL_OPS = new Set(['=', '!=', '<', '>', '<=', '>=']);\nfunction binaryPrecedence(op: string): number {\n if (op === '*' || op === '/') return 3;\n if (op === '+' || op === '-') return 2;\n if (RELATIONAL_OPS.has(op)) return 1;\n return 0;\n}\n\n/**\n * Serialize a `binary_expr` operand, wrapping it in parens when omitting them\n * would change how SPARQL parses the expression.\n */\nfunction wrapBinaryOperand(\n operand: SparqlExpression,\n parentOp: string,\n side: 'left' | 'right',\n collector?: UriCollector,\n): string {\n const s = serializeExpression(operand, collector);\n // Logical (&&/||) binds looser than any binary operator → always parenthesize.\n if (operand.kind === 'logical_expr') return `(${s})`;\n if (operand.kind !== 'binary_expr') return s;\n const parentIsRel = RELATIONAL_OPS.has(parentOp);\n const childIsRel = RELATIONAL_OPS.has(operand.op);\n // Relational is non-associative in SPARQL: any relational-in-relational needs parens.\n if (parentIsRel && childIsRel) return `(${s})`;\n const pc = binaryPrecedence(operand.op);\n const pp = binaryPrecedence(parentOp);\n const needs = side === 'left' ? pc < pp : pc <= pp;\n return needs ? `(${s})` : s;\n}\n\nexport function serializeExpression(\n expr: SparqlExpression,\n collector?: UriCollector,\n): string {\n switch (expr.kind) {\n case 'variable_expr':\n return `?${sanitizeVarName(expr.name)}`;\n\n case 'iri_expr':\n if (collector) collectUri(collector, expr.value);\n return formatUri(expr.value);\n\n case 'literal_expr': {\n if (expr.datatype && collector) collectUri(collector, expr.datatype);\n return formatLiteral(expr.value, expr.datatype);\n }\n\n case 'binary_expr': {\n const left = wrapBinaryOperand(expr.left, expr.op, 'left', collector);\n const right = wrapBinaryOperand(expr.right, expr.op, 'right', collector);\n return `${left} ${expr.op} ${right}`;\n }\n\n case 'logical_expr': {\n const op = expr.op === 'and' ? '&&' : '||';\n const parts = expr.exprs.map((e) => {\n const s = serializeExpression(e, collector);\n // Parenthesize OR children inside AND (AND binds tighter than OR)\n if (expr.op === 'and' && e.kind === 'logical_expr' && e.op === 'or') {\n return `(${s})`;\n }\n return s;\n });\n return parts.join(` ${op} `);\n }\n\n case 'not_expr':\n return `!(${serializeExpression(expr.inner, collector)})`;\n\n case 'function_expr': {\n assertSafeCallName(expr.name);\n const args = expr.args\n .map((a) => serializeExpression(a, collector))\n .join(', ');\n return `${expr.name}(${args})`;\n }\n\n case 'aggregate_expr': {\n assertSafeCallName(expr.name);\n const args = expr.args\n .map((a) => serializeExpression(a, collector))\n .join(', ');\n const distinctPrefix = expr.distinct ? 'DISTINCT ' : '';\n // Uppercased here rather than in the IR: this one line covers COUNT/SUM/AVG/\n // MIN/MAX and any aggregate added later, while the IR keeps carrying a plain\n // lowercase name (`'count'`) that other consumers can match on without\n // case-folding. It also puts the aggregate in the same voice as every other\n // keyword this file emits (SELECT, DISTINCT, GROUP BY, HAVING, …).\n // `function_expr` is deliberately left alone: its names arrive already in\n // their correct SPARQL spelling, which is not uniformly uppercase (`isBlank`,\n // `isIRI`), so case-folding there would corrupt them.\n return `${expr.name.toUpperCase()}(${distinctPrefix}${args})`;\n }\n\n case 'exists_expr': {\n const inner = serializeAlgebraNode(expr.pattern, collector);\n const prefix = expr.negated ? 'NOT EXISTS' : 'EXISTS';\n return `${prefix} {\\n${indent(inner)}\\n}`;\n }\n\n case 'bound_expr':\n return `BOUND(?${sanitizeVarName(expr.variable)})`;\n\n case 'in_expr': {\n // Empty list: `IN ()` matches nothing, `NOT IN ()` matches everything —\n // fold to a boolean constant rather than emit an empty parenthesis list.\n if (expr.list.length === 0) return expr.negated ? 'true' : 'false';\n const val = serializeExpression(expr.value, collector);\n const items = expr.list.map((e) => serializeExpression(e, collector)).join(', ');\n return `${val} ${expr.negated ? 'NOT IN' : 'IN'} (${items})`;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Algebra node serialization\n// ---------------------------------------------------------------------------\n\nexport function serializeAlgebraNode(\n node: SparqlAlgebraNode,\n collector?: UriCollector,\n): string {\n switch (node.type) {\n case 'bgp':\n return serializeTriples(node.triples, collector);\n\n case 'join': {\n const left = serializeAlgebraNode(node.left, collector);\n const right = serializeAlgebraNode(node.right, collector);\n return `${left}\\n${right}`;\n }\n\n case 'left_join': {\n const left = serializeAlgebraNode(node.left, collector);\n const right = serializeAlgebraNode(node.right, collector);\n let optionalBlock = `OPTIONAL {\\n${indent(right)}\\n}`;\n if (node.condition) {\n const cond = serializeExpression(node.condition, collector);\n // OPTIONAL with filter: OPTIONAL { pattern FILTER(cond) }\n // Re-build to include filter inside the OPTIONAL block\n optionalBlock = `OPTIONAL {\\n${indent(right)}\\n FILTER(${cond})\\n}`;\n }\n // If left side is empty (e.g. UPDATE WHERE with all-OPTIONAL triples),\n // omit the empty prefix to avoid blank lines\n return left ? `${left}\\n${optionalBlock}` : optionalBlock;\n }\n\n case 'filter': {\n const inner = serializeAlgebraNode(node.inner, collector);\n const expr = serializeExpression(node.expression, collector);\n return `${inner}\\nFILTER(${expr})`;\n }\n\n case 'union': {\n // UNION is associative: write a left-nested chain flat, {a} UNION {b} UNION {c},\n // instead of nesting every earlier branch one group deeper.\n const branches: SparqlAlgebraNode[] = [node.right];\n let head: SparqlAlgebraNode = node.left;\n while (head.type === 'union') {\n branches.unshift(head.right);\n head = head.left;\n }\n branches.unshift(head);\n return branches\n .map((branch) => `{\\n${indent(serializeAlgebraNode(branch, collector))}\\n}`)\n .join('\\nUNION\\n');\n }\n\n case 'minus': {\n const left = serializeAlgebraNode(node.left, collector);\n const right = serializeAlgebraNode(node.right, collector);\n return `${left}\\nMINUS {\\n${indent(right)}\\n}`;\n }\n\n case 'extend': {\n const inner = serializeAlgebraNode(node.inner, collector);\n const expr = serializeExpression(node.expression, collector);\n return `${inner}\\nBIND(${expr} AS ?${sanitizeVarName(node.variable)})`;\n }\n\n case 'graph': {\n if (collector) collectUri(collector, node.iri);\n const inner = serializeAlgebraNode(node.inner, collector);\n return `GRAPH ${formatUri(node.iri)} {\\n${indent(inner)}\\n}`;\n }\n\n case 'values': {\n const values = node.iris\n .map((iri) => {\n if (collector) collectUri(collector, iri);\n return formatUri(iri);\n })\n .join(' ');\n return `VALUES ?${sanitizeVarName(node.variable)} { ${values} }`;\n }\n\n case 'subselect': {\n const innerBody = serializeAlgebraNode(node.inner, collector);\n const projection = node.projection.map((v) => `?${sanitizeVarName(v)}`).join(' ');\n const lines: string[] = [`SELECT ${projection} WHERE {`];\n lines.push(indent(innerBody));\n lines.push('}');\n const trailing: string[] = [];\n if (node.orderBy && node.orderBy.length > 0) {\n const orderParts = node.orderBy.map((cond) => {\n const expr = serializeExpression(cond.expression, collector);\n return `${cond.direction}(${expr})`;\n });\n trailing.push(`ORDER BY ${orderParts.join(' ')}`);\n }\n if (node.limit !== undefined) {\n trailing.push(`LIMIT ${node.limit}`);\n }\n if (node.offset !== undefined) {\n trailing.push(`OFFSET ${node.offset}`);\n }\n const subSelectStr = trailing.length > 0\n ? `${lines.join('\\n')} ${trailing.join(' ')}`\n : lines.join('\\n');\n return `{\\n${indent(subSelectStr)}\\n}`;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction indent(text: string, level: number = 1): string {\n const prefix = ' '.repeat(level);\n return text\n .split('\\n')\n .map((line) => prefix + line)\n .join('\\n');\n}\n\nfunction buildPrefixBlock(usedUris: Set<string>): string {\n const prefixes = collectPrefixes([...usedUris]);\n const lines = Object.entries(prefixes)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([prefix, uri]) => `PREFIX ${prefix}: <${uri}>`);\n return lines.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Top-level plan serializers\n// ---------------------------------------------------------------------------\n\nexport function selectPlanToSparql(\n plan: SparqlSelectPlan,\n _options?: SparqlOptions,\n): string {\n const collector: UriCollector = {uris: new Set()};\n\n // 1. Serialize WHERE body\n const body = serializeAlgebraNode(plan.algebra, collector);\n\n // 2. Build SELECT line\n const projectionParts = plan.projection.map((item) => {\n if (item.kind === 'variable') {\n return `?${sanitizeVarName(item.name)}`;\n } else {\n // aggregate or expression projection: (expr AS ?alias)\n const expr = serializeExpression(item.expression, collector);\n return `(${expr} AS ?${sanitizeVarName(item.alias)})`;\n }\n });\n\n const distinctStr = plan.distinct ? 'DISTINCT ' : '';\n const selectLine = `SELECT ${distinctStr}${projectionParts.join(' ')}`;\n\n // 3. Build WHERE block\n const whereBlock = `WHERE {\\n${indent(body)}\\n}`;\n\n // 4. Build trailing clauses\n const clauses: string[] = [];\n\n if (plan.groupBy && plan.groupBy.length > 0) {\n clauses.push(\n `GROUP BY ${plan.groupBy.map((v) => `?${sanitizeVarName(v)}`).join(' ')}`,\n );\n }\n\n if (plan.having) {\n const havingExpr = serializeExpression(plan.having, collector);\n clauses.push(`HAVING(${havingExpr})`);\n }\n\n if (plan.orderBy && plan.orderBy.length > 0) {\n const orderParts = plan.orderBy.map((cond) => {\n const expr = serializeExpression(cond.expression, collector);\n return `${cond.direction}(${expr})`;\n });\n clauses.push(`ORDER BY ${orderParts.join(' ')}`);\n }\n\n if (plan.limit !== undefined) {\n clauses.push(`LIMIT ${plan.limit}`);\n }\n\n if (plan.offset !== undefined) {\n clauses.push(`OFFSET ${plan.offset}`);\n }\n\n // 5. Build PREFIX block (after collecting all URIs)\n const prefixBlock = buildPrefixBlock(collector.uris);\n\n // 6. Assemble\n const parts: string[] = [];\n if (prefixBlock) parts.push(prefixBlock);\n parts.push(selectLine);\n parts.push(whereBlock);\n parts.push(...clauses);\n\n return parts.join('\\n');\n}\n\n/**\n * Serializes a {@link SparqlAskPlan} to `ASK WHERE { … }`.\n *\n * The same WHERE body as {@link selectPlanToSparql}, with the projection line and\n * every solution modifier removed — `ASK` accepts none of them.\n */\nexport function askPlanToSparql(\n plan: SparqlAskPlan,\n _options?: SparqlOptions,\n): string {\n const collector: UriCollector = {uris: new Set()};\n\n // 1. Serialize WHERE body (collects the URIs the prefix block is built from)\n const body = serializeAlgebraNode(plan.algebra, collector);\n\n // 2. Build PREFIX block (after collecting all URIs)\n const prefixBlock = buildPrefixBlock(collector.uris);\n\n // 3. Assemble\n const parts: string[] = [];\n if (prefixBlock) parts.push(prefixBlock);\n parts.push(`ASK WHERE {\\n${indent(body)}\\n}`);\n\n return parts.join('\\n');\n}\n\nexport function insertDataPlanToSparql(\n plan: SparqlInsertDataPlan,\n _options?: SparqlOptions,\n): string {\n const collector: UriCollector = {uris: new Set()};\n\n let triplesStr: string;\n if (plan.graph) {\n if (collector) collectUri(collector, plan.graph);\n const innerTriples = serializeTriples(plan.triples, collector);\n triplesStr = `GRAPH ${formatUri(plan.graph)} {\\n${indent(innerTriples)}\\n}`;\n } else {\n triplesStr = serializeTriples(plan.triples, collector);\n }\n\n const body = `INSERT DATA {\\n${indent(triplesStr)}\\n}`;\n\n const prefixBlock = buildPrefixBlock(collector.uris);\n const parts: string[] = [];\n if (prefixBlock) parts.push(prefixBlock);\n parts.push(body);\n return parts.join('\\n');\n}\n\nexport function deleteInsertPlanToSparql(\n plan: SparqlDeleteInsertPlan,\n _options?: SparqlOptions,\n): string {\n const collector: UriCollector = {uris: new Set()};\n\n // DELETE block\n const deleteTriples = serializeTriples(plan.deletePatterns, collector);\n const deletePart = `DELETE {\\n${indent(deleteTriples)}\\n}`;\n\n // INSERT block (may be empty)\n let insertPart = '';\n if (plan.insertPatterns.length > 0) {\n const insertTriples = serializeTriples(plan.insertPatterns, collector);\n insertPart = `INSERT {\\n${indent(insertTriples)}\\n}\\n`;\n }\n\n // WHERE block\n const whereBody = serializeAlgebraNode(plan.whereAlgebra, collector);\n const wherePart = `WHERE {\\n${indent(whereBody)}\\n}`;\n\n const prefixBlock = buildPrefixBlock(collector.uris);\n const parts: string[] = [];\n if (prefixBlock) parts.push(prefixBlock);\n parts.push(deletePart);\n if (insertPart) parts.push(insertPart.trimEnd());\n parts.push(wherePart);\n return parts.join('\\n');\n}\n\nexport function deleteWherePlanToSparql(\n plan: SparqlDeleteWherePlan,\n _options?: SparqlOptions,\n): string {\n const collector: UriCollector = {uris: new Set()};\n\n const body = serializeAlgebraNode(plan.patterns, collector);\n\n let content: string;\n if (plan.graph) {\n if (collector) collectUri(collector, plan.graph);\n content = `GRAPH ${formatUri(plan.graph)} {\\n${indent(body)}\\n}`;\n } else {\n content = body;\n }\n\n const result = `DELETE WHERE {\\n${indent(content)}\\n}`;\n\n const prefixBlock = buildPrefixBlock(collector.uris);\n const parts: string[] = [];\n if (prefixBlock) parts.push(prefixBlock);\n parts.push(result);\n return parts.join('\\n');\n}\n"]}
@@ -27,8 +27,11 @@ export declare function upsertToAlgebra(query: IRUpsertMutation, options?: Sparq
27
27
  * Build DELETE patterns + WHERE OPTIONAL blocks that cascade-delete the owned subtree
28
28
  * reachable from `rootTerm` via `contains` edges. `varPrefix` keeps generated variables
29
29
  * unique across multiple roots in one query. Returns empty when nothing is owned.
30
+ *
31
+ * `anchor`, when given, leads every block: the triple that binds a variable root, so
32
+ * each block stays correct on its own (as a UNION branch) when no such root exists.
30
33
  */
31
- export declare function buildOwnedCascade(rootTerm: SparqlTerm, varPrefix: string): {
34
+ export declare function buildOwnedCascade(rootTerm: SparqlTerm, varPrefix: string, anchor?: SparqlTriple): {
32
35
  deletePatterns: SparqlTriple[];
33
36
  whereOptionals: SparqlAlgebraNode[];
34
37
  };
@@ -51,6 +54,22 @@ export declare function buildOwnedSelfDelete(subjectTerm: SparqlTerm, propertyTe
51
54
  };
52
55
  /**
53
56
  * Converts an IRDeleteMutation to a SparqlDeleteInsertPlan (DELETE + WHERE).
57
+ *
58
+ * The WHERE is the type guard of every id, joined with ONE UNION of independent
59
+ * blocks: per id its own triples, its incoming references and, for a shape that
60
+ * owns something, one block per dependent type of its owned subtree.
61
+ *
62
+ * The blocks must not be chained as OPTIONALs. A chain of OPTIONALs is a join, so
63
+ * the solutions multiply: own triples x incoming references x owned triples of each
64
+ * dependent type. Deleting one shape description with the shape sync's cascade
65
+ * produced ~27,000 solutions for ~130 triples and took over 30 seconds on Fuseki,
66
+ * which re-evaluates the cascade property path for every left-hand row. A UNION
67
+ * yields each block's matches once, so the solutions add up instead, and it deletes
68
+ * exactly the same triples: a DELETE template triple whose variables a solution
69
+ * leaves unbound is skipped, as it was for an OPTIONAL that did not match.
70
+ *
71
+ * The guards stay required for every id, as before: when any id is not of the
72
+ * shape, the WHERE has no solution and nothing is deleted.
54
73
  */
55
74
  export declare function deleteToAlgebra(query: IRDeleteMutation, _options?: SparqlOptions): SparqlDeleteInsertPlan;
56
75
  /**