@undefineds.co/xpod 0.3.5 → 0.3.14

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.
Files changed (253) hide show
  1. package/config/cli.json +1 -1
  2. package/config/cloud.json +54 -22
  3. package/config/local.json +56 -12
  4. package/config/resolver.json +10 -2
  5. package/config/xpod.base.json +50 -0
  6. package/config/xpod.json +8 -8
  7. package/dist/agents/config/resolve.js +10 -10
  8. package/dist/agents/config/resolve.js.map +1 -1
  9. package/dist/api/chatkit/index.d.ts +1 -1
  10. package/dist/api/chatkit/index.js.map +1 -1
  11. package/dist/api/chatkit/pod-store.d.ts +14 -11
  12. package/dist/api/chatkit/pod-store.js +114 -78
  13. package/dist/api/chatkit/pod-store.js.map +1 -1
  14. package/dist/api/chatkit/runtime/AcpAgentRuntime.js +1 -1
  15. package/dist/api/chatkit/runtime/AcpAgentRuntime.js.map +1 -1
  16. package/dist/api/chatkit/service.js +1 -1
  17. package/dist/api/chatkit/service.js.map +1 -1
  18. package/dist/api/chatkit/types.d.ts +11 -11
  19. package/dist/api/chatkit/types.js +3 -3
  20. package/dist/api/chatkit/types.js.map +1 -1
  21. package/dist/api/container/cloud.js +0 -8
  22. package/dist/api/container/cloud.js.map +1 -1
  23. package/dist/api/container/index.js +2 -1
  24. package/dist/api/container/index.js.map +1 -1
  25. package/dist/api/container/local.js +0 -7
  26. package/dist/api/container/local.js.map +1 -1
  27. package/dist/api/container/routes.js +3 -17
  28. package/dist/api/container/routes.js.map +1 -1
  29. package/dist/api/container/types.d.ts +0 -2
  30. package/dist/api/container/types.js.map +1 -1
  31. package/dist/api/handlers/PodManagementHandler.d.ts +3 -0
  32. package/dist/api/handlers/PodManagementHandler.js +71 -1
  33. package/dist/api/handlers/PodManagementHandler.js.map +1 -1
  34. package/dist/api/handlers/RunHandler.js +5 -5
  35. package/dist/api/handlers/RunHandler.js.map +1 -1
  36. package/dist/api/runs/AgentRuntimeTypes.d.ts +7 -8
  37. package/dist/api/runs/AgentRuntimeTypes.js.map +1 -1
  38. package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
  39. package/dist/api/runs/ManagedRunWorker.d.ts +1 -1
  40. package/dist/api/runs/ManagedRunWorker.js +6 -6
  41. package/dist/api/runs/ManagedRunWorker.js.map +1 -1
  42. package/dist/api/runs/PiAgentRuntimeDriver.d.ts +16 -1
  43. package/dist/api/runs/PiAgentRuntimeDriver.js +182 -23
  44. package/dist/api/runs/PiAgentRuntimeDriver.js.map +1 -1
  45. package/dist/api/runs/RunStateCenter.d.ts +3 -3
  46. package/dist/api/runs/RunStateCenter.js +13 -13
  47. package/dist/api/runs/RunStateCenter.js.map +1 -1
  48. package/dist/api/runs/store.d.ts +4 -4
  49. package/dist/api/runs/store.js +2 -2
  50. package/dist/api/runs/store.js.map +1 -1
  51. package/dist/api/service/VectorStoreService.d.ts +1 -1
  52. package/dist/api/service/VectorStoreService.js +16 -16
  53. package/dist/api/service/VectorStoreService.js.map +1 -1
  54. package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
  55. package/dist/api/tasks/TaskMaterializer.d.ts +3 -3
  56. package/dist/api/tasks/TaskMaterializer.js +11 -11
  57. package/dist/api/tasks/TaskMaterializer.js.map +1 -1
  58. package/dist/api/tasks/TaskService.d.ts +3 -3
  59. package/dist/api/tasks/TaskService.js +11 -7
  60. package/dist/api/tasks/TaskService.js.map +1 -1
  61. package/dist/api/tasks/store.d.ts +10 -4
  62. package/dist/api/tasks/store.js +14 -4
  63. package/dist/api/tasks/store.js.map +1 -1
  64. package/dist/api/workspace/types.d.ts +3 -3
  65. package/dist/api/workspace/types.js +6 -6
  66. package/dist/api/workspace/types.js.map +1 -1
  67. package/dist/cli/commands/config.js +2 -2
  68. package/dist/cli/commands/config.js.map +1 -1
  69. package/dist/cli/commands/start.js +9 -3
  70. package/dist/cli/commands/start.js.map +1 -1
  71. package/dist/components/components.jsonld +8 -2
  72. package/dist/components/context.jsonld +302 -51
  73. package/dist/http/search/SearchHttpHandler.js +8 -8
  74. package/dist/http/search/SearchHttpHandler.js.map +1 -1
  75. package/dist/identity/drizzle/PodLookupRepository.d.ts +11 -1
  76. package/dist/identity/drizzle/PodLookupRepository.js +95 -4
  77. package/dist/identity/drizzle/PodLookupRepository.js.map +1 -1
  78. package/dist/identity/drizzle/db.js +4 -43
  79. package/dist/identity/drizzle/db.js.map +1 -1
  80. package/dist/identity/drizzle/schema.pg.d.ts +0 -5
  81. package/dist/identity/drizzle/schema.pg.js +2 -16
  82. package/dist/identity/drizzle/schema.pg.js.map +1 -1
  83. package/dist/identity/drizzle/schema.sqlite.d.ts +19 -176
  84. package/dist/identity/drizzle/schema.sqlite.js +2 -16
  85. package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
  86. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.d.ts +4 -4
  87. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js +7 -7
  88. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js.map +1 -1
  89. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.jsonld +6 -6
  90. package/dist/identity/oidc/AutoDetectOidcHandler.d.ts +4 -4
  91. package/dist/identity/oidc/AutoDetectOidcHandler.js +6 -6
  92. package/dist/identity/oidc/AutoDetectOidcHandler.js.map +1 -1
  93. package/dist/identity/oidc/AutoDetectOidcHandler.jsonld +6 -6
  94. package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +37 -0
  95. package/dist/identity/oidc/ScopedPickWebIdHandler.js +211 -0
  96. package/dist/identity/oidc/ScopedPickWebIdHandler.js.map +1 -0
  97. package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +158 -0
  98. package/dist/index.d.ts +12 -2
  99. package/dist/index.js +16 -4
  100. package/dist/index.js.map +1 -1
  101. package/dist/main.js +8 -2
  102. package/dist/main.js.map +1 -1
  103. package/dist/provision/ProvisionPodCreator.d.ts +3 -4
  104. package/dist/provision/ProvisionPodCreator.js +8 -13
  105. package/dist/provision/ProvisionPodCreator.js.map +1 -1
  106. package/dist/provision/ProvisionPodCreator.jsonld +7 -7
  107. package/dist/runtime/Proxy.d.ts +0 -1
  108. package/dist/runtime/Proxy.js +0 -9
  109. package/dist/runtime/Proxy.js.map +1 -1
  110. package/dist/runtime/bootstrap.d.ts +1 -0
  111. package/dist/runtime/bootstrap.js +5 -2
  112. package/dist/runtime/bootstrap.js.map +1 -1
  113. package/dist/runtime/css-process.d.ts +12 -4
  114. package/dist/runtime/css-process.js +61 -14
  115. package/dist/runtime/css-process.js.map +1 -1
  116. package/dist/runtime/oidc-issuer.d.ts +3 -2
  117. package/dist/runtime/oidc-issuer.js +3 -2
  118. package/dist/runtime/oidc-issuer.js.map +1 -1
  119. package/dist/runtime/runtime-types.d.ts +1 -0
  120. package/dist/runtime/runtime-types.js.map +1 -1
  121. package/dist/solidfs/LocalFirstRdfRepresentationResolver.d.ts +21 -0
  122. package/dist/solidfs/LocalFirstRdfRepresentationResolver.js +38 -0
  123. package/dist/solidfs/LocalFirstRdfRepresentationResolver.js.map +1 -0
  124. package/dist/solidfs/LocalSolidFS.d.ts +18 -0
  125. package/dist/solidfs/LocalSolidFS.js +539 -0
  126. package/dist/solidfs/LocalSolidFS.js.map +1 -0
  127. package/dist/solidfs/PodSolidFsHttpClient.d.ts +16 -0
  128. package/dist/solidfs/PodSolidFsHttpClient.js +93 -0
  129. package/dist/solidfs/PodSolidFsHttpClient.js.map +1 -0
  130. package/dist/solidfs/PodSolidFsHydrator.d.ts +27 -0
  131. package/dist/solidfs/PodSolidFsHydrator.js +127 -0
  132. package/dist/solidfs/PodSolidFsHydrator.js.map +1 -0
  133. package/dist/solidfs/PodSolidFsSyncer.d.ts +21 -0
  134. package/dist/solidfs/PodSolidFsSyncer.js +78 -0
  135. package/dist/solidfs/PodSolidFsSyncer.js.map +1 -0
  136. package/dist/solidfs/RdfIndexSolidFsSyncer.d.ts +22 -0
  137. package/dist/solidfs/RdfIndexSolidFsSyncer.js +131 -0
  138. package/dist/solidfs/RdfIndexSolidFsSyncer.js.map +1 -0
  139. package/dist/solidfs/index.d.ts +7 -0
  140. package/dist/solidfs/index.js +24 -0
  141. package/dist/solidfs/index.js.map +1 -0
  142. package/dist/solidfs/types.d.ts +131 -0
  143. package/dist/solidfs/types.js +19 -0
  144. package/dist/solidfs/types.js.map +1 -0
  145. package/dist/storage/RepresentationPartialConvertingStore.js +6 -13
  146. package/dist/storage/RepresentationPartialConvertingStore.js.map +1 -1
  147. package/dist/storage/SparqlUpdateResourceStore.d.ts +4 -0
  148. package/dist/storage/SparqlUpdateResourceStore.js +13 -0
  149. package/dist/storage/SparqlUpdateResourceStore.js.map +1 -1
  150. package/dist/storage/SparqlUpdateResourceStore.jsonld +26 -0
  151. package/dist/storage/accessors/MinioDataAccessor.d.ts +2 -0
  152. package/dist/storage/accessors/MinioDataAccessor.js +13 -7
  153. package/dist/storage/accessors/MinioDataAccessor.js.map +1 -1
  154. package/dist/storage/accessors/MinioDataAccessor.jsonld +8 -0
  155. package/dist/storage/accessors/MixDataAccessor.d.ts +85 -4
  156. package/dist/storage/accessors/MixDataAccessor.js +511 -16
  157. package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
  158. package/dist/storage/accessors/MixDataAccessor.jsonld +176 -1
  159. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.d.ts +7 -0
  160. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js +72 -4
  161. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js.map +1 -1
  162. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.jsonld +24 -0
  163. package/dist/storage/quint/BaseQuintStore.d.ts +3 -0
  164. package/dist/storage/quint/BaseQuintStore.js +51 -27
  165. package/dist/storage/quint/BaseQuintStore.js.map +1 -1
  166. package/dist/storage/quint/PgQuintStore.d.ts +1 -0
  167. package/dist/storage/quint/PgQuintStore.js +50 -32
  168. package/dist/storage/quint/PgQuintStore.js.map +1 -1
  169. package/dist/storage/quint/PgQuintStore.jsonld +4 -3
  170. package/dist/storage/quint/SqliteQuintStore.d.ts +5 -0
  171. package/dist/storage/quint/SqliteQuintStore.js +100 -0
  172. package/dist/storage/quint/SqliteQuintStore.js.map +1 -1
  173. package/dist/storage/quint/SqliteQuintStore.jsonld +20 -0
  174. package/dist/storage/quint/types.d.ts +16 -0
  175. package/dist/storage/quint/types.js.map +1 -1
  176. package/dist/storage/rdf/Rdf3xTripleIndex.d.ts +55 -0
  177. package/dist/storage/rdf/Rdf3xTripleIndex.js +1235 -0
  178. package/dist/storage/rdf/Rdf3xTripleIndex.js.map +1 -0
  179. package/dist/storage/rdf/RdfContentTypes.d.ts +9 -0
  180. package/dist/storage/rdf/RdfContentTypes.js +79 -0
  181. package/dist/storage/rdf/RdfContentTypes.js.map +1 -0
  182. package/dist/storage/rdf/RdfLocalQueryEngine.d.ts +76 -0
  183. package/dist/storage/rdf/RdfLocalQueryEngine.js +2636 -0
  184. package/dist/storage/rdf/RdfLocalQueryEngine.js.map +1 -0
  185. package/dist/storage/rdf/RdfQuadIndex.d.ts +98 -0
  186. package/dist/storage/rdf/RdfQuadIndex.js +1840 -0
  187. package/dist/storage/rdf/RdfQuadIndex.js.map +1 -0
  188. package/dist/storage/rdf/RdfQuadIndex.jsonld +416 -0
  189. package/dist/storage/rdf/RdfShadowComparator.d.ts +12 -0
  190. package/dist/storage/rdf/RdfShadowComparator.js +47 -0
  191. package/dist/storage/rdf/RdfShadowComparator.js.map +1 -0
  192. package/dist/storage/rdf/RdfSparqlAdapter.d.ts +147 -0
  193. package/dist/storage/rdf/RdfSparqlAdapter.js +2420 -0
  194. package/dist/storage/rdf/RdfSparqlAdapter.js.map +1 -0
  195. package/dist/storage/rdf/RdfSparqlAdapter.jsonld +414 -0
  196. package/dist/storage/rdf/RdfTermDictionary.d.ts +27 -0
  197. package/dist/storage/rdf/RdfTermDictionary.js +352 -0
  198. package/dist/storage/rdf/RdfTermDictionary.js.map +1 -0
  199. package/dist/storage/rdf/RdfTermDictionary.jsonld +114 -0
  200. package/dist/storage/rdf/RdfTermSemantics.d.ts +6 -0
  201. package/dist/storage/rdf/RdfTermSemantics.js +40 -0
  202. package/dist/storage/rdf/RdfTermSemantics.js.map +1 -0
  203. package/dist/storage/rdf/RdfTextIndex.d.ts +23 -0
  204. package/dist/storage/rdf/RdfTextIndex.js +569 -0
  205. package/dist/storage/rdf/RdfTextIndex.js.map +1 -0
  206. package/dist/storage/rdf/RdfVectorIndex.d.ts +22 -0
  207. package/dist/storage/rdf/RdfVectorIndex.js +631 -0
  208. package/dist/storage/rdf/RdfVectorIndex.js.map +1 -0
  209. package/dist/storage/rdf/RdfXmlSerializer.d.ts +2 -0
  210. package/dist/storage/rdf/RdfXmlSerializer.js +123 -0
  211. package/dist/storage/rdf/RdfXmlSerializer.js.map +1 -0
  212. package/dist/storage/rdf/ShadowRdfQuintStore.d.ts +58 -0
  213. package/dist/storage/rdf/ShadowRdfQuintStore.js +202 -0
  214. package/dist/storage/rdf/ShadowRdfQuintStore.js.map +1 -0
  215. package/dist/storage/rdf/ShadowRdfQuintStore.jsonld +308 -0
  216. package/dist/storage/rdf/SolidRdfEngine.d.ts +51 -0
  217. package/dist/storage/rdf/SolidRdfEngine.js +264 -0
  218. package/dist/storage/rdf/SolidRdfEngine.js.map +1 -0
  219. package/dist/storage/rdf/SolidRdfEngine.jsonld +338 -0
  220. package/dist/storage/rdf/SolidRdfSparqlEngine.d.ts +92 -0
  221. package/dist/storage/rdf/SolidRdfSparqlEngine.js +477 -0
  222. package/dist/storage/rdf/SolidRdfSparqlEngine.js.map +1 -0
  223. package/dist/storage/rdf/SolidRdfSparqlEngine.jsonld +257 -0
  224. package/dist/storage/rdf/index.d.ts +15 -0
  225. package/dist/storage/rdf/index.js +61 -0
  226. package/dist/storage/rdf/index.js.map +1 -0
  227. package/dist/storage/rdf/models-benchmark.d.ts +260 -0
  228. package/dist/storage/rdf/models-benchmark.js +1405 -0
  229. package/dist/storage/rdf/models-benchmark.js.map +1 -0
  230. package/dist/storage/rdf/types.d.ts +726 -0
  231. package/dist/storage/rdf/types.js +3 -0
  232. package/dist/storage/rdf/types.js.map +1 -0
  233. package/dist/storage/rdf/types.jsonld +316 -0
  234. package/dist/storage/vector/VectorIndexingListener.d.ts +5 -5
  235. package/dist/storage/vector/VectorIndexingListener.js +19 -19
  236. package/dist/storage/vector/VectorIndexingListener.js.map +1 -1
  237. package/package.json +3 -2
  238. package/templates/pod/acp/.acr.hbs +39 -0
  239. package/templates/pod/acp/README.acr +18 -0
  240. package/templates/pod/acp/profile/card.acr +22 -0
  241. package/templates/pod/base/README$.md.hbs +27 -0
  242. package/templates/pod/base/profile/card$.ttl.hbs +13 -0
  243. package/templates/pod/wac/.acl.hbs +26 -0
  244. package/templates/pod/wac/README.acl.hbs +14 -0
  245. package/templates/pod/wac/profile/card.acl.hbs +19 -0
  246. package/dist/api/handlers/WebIdProfileHandler.d.ts +0 -16
  247. package/dist/api/handlers/WebIdProfileHandler.js +0 -423
  248. package/dist/api/handlers/WebIdProfileHandler.js.map +0 -1
  249. package/dist/identity/drizzle/WebIdProfileRepository.d.ts +0 -63
  250. package/dist/identity/drizzle/WebIdProfileRepository.js +0 -168
  251. package/dist/identity/drizzle/WebIdProfileRepository.js.map +0 -1
  252. package/dist/identity/drizzle/WebIdProfileRepository.jsonld +0 -112
  253. package/dist/storage/quint/BaseQuintStore.jsonld +0 -257
@@ -0,0 +1,2420 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RdfSparqlAdapter = exports.DisabledSparqlFeatureError = exports.UnsupportedSparqlQueryError = void 0;
4
+ const n3_1 = require("n3");
5
+ const sparqljs_1 = require("sparqljs");
6
+ const RdfLocalQueryEngine_1 = require("./RdfLocalQueryEngine");
7
+ const PATH_JOIN_VARIABLE_PREFIX = '__rdf_path';
8
+ const XPATH_FUNCTION_NS = 'http://www.w3.org/2005/xpath-functions#';
9
+ class UnsupportedSparqlQueryError extends Error {
10
+ constructor(message) {
11
+ super(message);
12
+ this.name = 'UnsupportedSparqlQueryError';
13
+ }
14
+ }
15
+ exports.UnsupportedSparqlQueryError = UnsupportedSparqlQueryError;
16
+ class DisabledSparqlFeatureError extends Error {
17
+ constructor(message) {
18
+ super(message);
19
+ this.name = 'DisabledSparqlFeatureError';
20
+ }
21
+ }
22
+ exports.DisabledSparqlFeatureError = DisabledSparqlFeatureError;
23
+ class RdfSparqlAdapter {
24
+ compile(query, basePath) {
25
+ const parsed = typeof query === 'string'
26
+ ? new sparqljs_1.Parser({ baseIRI: basePath }).parse(query)
27
+ : query;
28
+ if (parsed.type === 'update') {
29
+ throw new UnsupportedSparqlQueryError('SPARQL UPDATE is handled by the compatibility engine');
30
+ }
31
+ const datasetScope = this.compileQueryDatasetScope(this.queryFromClause(parsed), basePath);
32
+ const state = new CompileState(basePath);
33
+ this.compilePatterns(parsed.where ?? [], datasetScope.defaultGraph, state, false, datasetScope.namedGraph);
34
+ this.compileValuesRows(parsed.values ?? [], state);
35
+ this.compileGroupBy(parsed.group ?? [], state);
36
+ if (parsed.queryType === 'SELECT') {
37
+ state.query.orderBy = this.compileOrder(parsed.order ?? [], state);
38
+ }
39
+ const variables = parsed.queryType === 'SELECT'
40
+ ? this.compileSelectVariables(parsed, state)
41
+ : [];
42
+ if (parsed.queryType === 'SELECT') {
43
+ state.query.having = this.compileHaving(parsed.having ?? [], state);
44
+ }
45
+ state.assertBindVariablesSafe();
46
+ state.assertValuesVariablesBoundByRequiredPatterns();
47
+ state.assertDependentGroupsShareRequiredVariables();
48
+ const constructTemplate = parsed.queryType === 'CONSTRUCT'
49
+ ? this.compileConstructTemplate(parsed)
50
+ : undefined;
51
+ const describeTargets = parsed.queryType === 'DESCRIBE'
52
+ ? this.compileDescribeTargets(parsed, state.query)
53
+ : undefined;
54
+ if (parsed.queryType === 'ASK') {
55
+ state.query.limit = 1;
56
+ }
57
+ else if (parsed.queryType === 'SELECT') {
58
+ state.query.select = variables.length > 0 ? variables : undefined;
59
+ state.query.distinct = Boolean(parsed.distinct);
60
+ state.query.limit = parsed.limit;
61
+ state.query.offset = parsed.offset;
62
+ }
63
+ return {
64
+ query: state.query,
65
+ variables,
66
+ queryType: parsed.queryType,
67
+ constructTemplate,
68
+ describeTargets,
69
+ };
70
+ }
71
+ compileUpdateDelta(query, basePath) {
72
+ const parsed = typeof query === 'string'
73
+ ? new sparqljs_1.Parser({ baseIRI: basePath }).parse(query)
74
+ : query;
75
+ if (parsed.type !== 'update') {
76
+ throw new UnsupportedSparqlQueryError('Only SPARQL UPDATE can compile into update delta');
77
+ }
78
+ const operations = [];
79
+ for (const update of parsed.updates) {
80
+ if (!('updateType' in update)) {
81
+ throw new UnsupportedSparqlQueryError('SPARQL UPDATE management operations fallback to compatibility engine');
82
+ }
83
+ switch (update.updateType) {
84
+ case 'insert':
85
+ if (update.graph) {
86
+ throw new UnsupportedSparqlQueryError('SPARQL UPDATE WITH/default graph scope fallback to compatibility engine');
87
+ }
88
+ operations.push({
89
+ type: 'insert',
90
+ quads: this.compileUpdateGraphQuads(update.insert, basePath),
91
+ });
92
+ break;
93
+ case 'delete':
94
+ if (update.graph) {
95
+ throw new UnsupportedSparqlQueryError('SPARQL UPDATE WITH/default graph scope fallback to compatibility engine');
96
+ }
97
+ operations.push({
98
+ type: 'delete',
99
+ quads: this.compileUpdateGraphQuads(update.delete, basePath),
100
+ });
101
+ break;
102
+ case 'deletewhere':
103
+ if (update.graph) {
104
+ throw new UnsupportedSparqlQueryError('SPARQL UPDATE WITH/default graph scope fallback to compatibility engine');
105
+ }
106
+ operations.push(this.compileDeleteWhere(update.delete, basePath));
107
+ break;
108
+ case 'insertdelete':
109
+ operations.push(this.compileInsertDeleteWhere(update, basePath));
110
+ break;
111
+ default:
112
+ throw new UnsupportedSparqlQueryError('Unsupported SPARQL UPDATE operation fallback to compatibility engine');
113
+ }
114
+ }
115
+ const inserts = operations
116
+ .filter((operation) => operation.type === 'insert')
117
+ .flatMap((operation) => operation.quads);
118
+ const deletes = operations
119
+ .filter((operation) => operation.type === 'delete')
120
+ .flatMap((operation) => operation.quads);
121
+ const deleteWhereCount = operations
122
+ .reduce((sum, operation) => {
123
+ if (operation.type === 'deleteWhere') {
124
+ return sum + operation.template.length;
125
+ }
126
+ if (operation.type === 'insertDeleteWhere') {
127
+ return sum + operation.deletes.length + operation.inserts.length;
128
+ }
129
+ if (operation.type === 'insertWhere') {
130
+ return sum + operation.inserts.length;
131
+ }
132
+ return sum;
133
+ }, 0);
134
+ if (inserts.length + deletes.length + deleteWhereCount === 0) {
135
+ throw new UnsupportedSparqlQueryError('SPARQL UPDATE without data quads fallback to compatibility engine');
136
+ }
137
+ return { operations, inserts, deletes };
138
+ }
139
+ compileDeleteWhere(items, basePath) {
140
+ const template = this.compileGraphQuadsTemplate(items, basePath, 'DELETE WHERE');
141
+ return {
142
+ type: 'deleteWhere',
143
+ query: this.queryFromUpdateTemplate(template, 'DELETE WHERE'),
144
+ template,
145
+ };
146
+ }
147
+ compileInsertDeleteWhere(update, basePath) {
148
+ const hasInsertTemplate = (update.insert?.length ?? 0) > 0;
149
+ const hasDeleteTemplate = (update.delete?.length ?? 0) > 0;
150
+ if (!hasInsertTemplate && !hasDeleteTemplate) {
151
+ throw new UnsupportedSparqlQueryError('DELETE/INSERT WHERE without DELETE or INSERT template fallback to compatibility engine');
152
+ }
153
+ const label = hasInsertTemplate && hasDeleteTemplate
154
+ ? 'DELETE/INSERT WHERE'
155
+ : hasInsertTemplate
156
+ ? 'INSERT WHERE'
157
+ : 'DELETE WHERE';
158
+ const withGraph = this.compileWithGraph(update.graph, basePath, label);
159
+ const using = this.compileUsingDatasetScope(update.using, basePath, label);
160
+ const queryDefaultGraph = using.hasUsing
161
+ ? using.defaultGraph ?? this.impossibleGraph(basePath)
162
+ : withGraph;
163
+ const queryNamedGraph = using.hasUsing
164
+ ? using.namedGraph ?? this.impossibleGraph(basePath)
165
+ : undefined;
166
+ const query = this.queryFromUpdateWhere(update.where ?? [], basePath, label, {
167
+ defaultGraph: queryDefaultGraph,
168
+ namedGraph: queryNamedGraph,
169
+ });
170
+ const inserts = hasInsertTemplate
171
+ ? this.compileGraphQuadsTemplate(update.insert ?? [], basePath, 'INSERT template', withGraph)
172
+ : [];
173
+ if (hasInsertTemplate && inserts.length === 0) {
174
+ throw new UnsupportedSparqlQueryError(`${label} without INSERT template fallback to compatibility engine`);
175
+ }
176
+ const deletes = hasDeleteTemplate
177
+ ? this.compileGraphQuadsTemplate(update.delete ?? [], basePath, 'DELETE template', withGraph)
178
+ : [];
179
+ if (hasDeleteTemplate && deletes.length === 0) {
180
+ throw new UnsupportedSparqlQueryError(`${label} without DELETE template fallback to compatibility engine`);
181
+ }
182
+ if (hasInsertTemplate && !hasDeleteTemplate) {
183
+ return {
184
+ type: 'insertWhere',
185
+ query,
186
+ inserts,
187
+ };
188
+ }
189
+ if (!hasInsertTemplate) {
190
+ return {
191
+ type: 'deleteWhere',
192
+ query,
193
+ template: deletes,
194
+ };
195
+ }
196
+ return {
197
+ type: 'insertDeleteWhere',
198
+ query,
199
+ deletes,
200
+ inserts,
201
+ };
202
+ }
203
+ compileUsingDatasetScope(using, basePath, label) {
204
+ if (!using) {
205
+ return { hasUsing: false };
206
+ }
207
+ const defaultGraphs = using.default ?? [];
208
+ const namedGraphs = using.named ?? [];
209
+ return {
210
+ hasUsing: true,
211
+ defaultGraph: this.compileUsingGraphs(defaultGraphs, basePath, label, 'USING'),
212
+ namedGraph: this.compileUsingGraphs(namedGraphs, basePath, label, 'USING NAMED'),
213
+ };
214
+ }
215
+ compileUsingGraphs(graphs, basePath, label, clause) {
216
+ if (graphs.length === 0) {
217
+ return undefined;
218
+ }
219
+ const compiledGraphs = graphs.map((graph) => {
220
+ const compiled = this.compileGraphTerm(graph, basePath);
221
+ if (compiled === null || isCompiledVariable(compiled)) {
222
+ throw new UnsupportedSparqlQueryError(`${label} ${clause} graph outside basePath fallback to compatibility engine`);
223
+ }
224
+ return compiled;
225
+ });
226
+ if (compiledGraphs.length === 1) {
227
+ return compiledGraphs[0];
228
+ }
229
+ return { $in: uniqueTerms(compiledGraphs) };
230
+ }
231
+ compileQueryDatasetScope(from, basePath) {
232
+ if (!from) {
233
+ return {};
234
+ }
235
+ const defaultGraphs = from.default ?? [];
236
+ const namedGraphs = from.named ?? [];
237
+ return {
238
+ defaultGraph: defaultGraphs.length > 0
239
+ ? this.compileQueryDatasetGraphs(defaultGraphs, basePath, 'FROM')
240
+ : namedGraphs.length > 0
241
+ ? this.impossibleGraph(basePath)
242
+ : undefined,
243
+ namedGraph: namedGraphs.length > 0
244
+ ? this.compileQueryDatasetGraphs(namedGraphs, basePath, 'FROM NAMED')
245
+ : undefined,
246
+ };
247
+ }
248
+ compileQueryDatasetGraphs(graphs, basePath, clause) {
249
+ const compiledGraphs = graphs.map((graph) => {
250
+ const compiled = this.compileGraphTerm(graph, basePath);
251
+ if (compiled === null || isCompiledVariable(compiled)) {
252
+ throw new DisabledSparqlFeatureError(`SPARQL ${clause} outside the server-owned Pod is disabled`);
253
+ }
254
+ return compiled;
255
+ });
256
+ if (compiledGraphs.length === 1) {
257
+ return compiledGraphs[0];
258
+ }
259
+ return { $in: uniqueTerms(compiledGraphs) };
260
+ }
261
+ queryFromClause(query) {
262
+ if (!('from' in query)) {
263
+ return undefined;
264
+ }
265
+ return query.from;
266
+ }
267
+ compileWithGraph(graph, basePath, label) {
268
+ if (!graph) {
269
+ return undefined;
270
+ }
271
+ const compiled = this.compileGraphTerm(graph, basePath);
272
+ if (compiled === null || isCompiledVariable(compiled)) {
273
+ throw new UnsupportedSparqlQueryError(`${label} WITH graph outside basePath fallback to compatibility engine`);
274
+ }
275
+ return compiled;
276
+ }
277
+ impossibleGraph(basePath) {
278
+ return n3_1.DataFactory.namedNode(`${basePath}__outside_graph_scope__`);
279
+ }
280
+ queryFromUpdateWhere(patterns, basePath, label, dataset = {}) {
281
+ if (patterns.length === 0) {
282
+ throw new UnsupportedSparqlQueryError(`${label} without WHERE patterns fallback to compatibility engine`);
283
+ }
284
+ const state = new CompileState(basePath);
285
+ this.assertScopedUpdateWherePatterns(patterns, basePath, label, Boolean(dataset.defaultGraph), dataset.namedGraph);
286
+ this.compilePatterns(patterns, dataset.defaultGraph, state, false, dataset.namedGraph);
287
+ state.assertBindVariablesSafe();
288
+ state.assertValuesVariablesBoundByRequiredPatterns();
289
+ state.assertDependentGroupsShareRequiredVariables();
290
+ if (state.query.patterns.length === 0 && (state.query.unions?.length ?? 0) === 0) {
291
+ throw new UnsupportedSparqlQueryError(`${label} without required graph BGP patterns fallback to compatibility engine`);
292
+ }
293
+ return state.query;
294
+ }
295
+ queryFromUpdateTemplate(template, label) {
296
+ if (template.length === 0) {
297
+ throw new UnsupportedSparqlQueryError(`${label} without WHERE patterns fallback to compatibility engine`);
298
+ }
299
+ return {
300
+ patterns: template.map((pattern) => ({
301
+ graph: pattern.graph,
302
+ subject: pattern.subject,
303
+ predicate: pattern.predicate,
304
+ object: pattern.object,
305
+ })),
306
+ optional: [],
307
+ filters: [],
308
+ };
309
+ }
310
+ compileGraphQuadsTemplate(items, basePath, label, defaultGraph) {
311
+ const template = [];
312
+ for (const item of items) {
313
+ let graph = defaultGraph;
314
+ if (item.type === 'graph') {
315
+ if (item.name.termType !== 'NamedNode') {
316
+ throw new UnsupportedSparqlQueryError(`${label} GRAPH variables fallback to compatibility engine`);
317
+ }
318
+ graph = this.compileGraphTerm(item.name, basePath) ?? undefined;
319
+ }
320
+ else if (!graph) {
321
+ throw new UnsupportedSparqlQueryError(`${label} default graph fallback to compatibility engine`);
322
+ }
323
+ if (!graph || graph === null || isCompiledVariable(graph)) {
324
+ throw new UnsupportedSparqlQueryError(`${label} graph outside basePath fallback to compatibility engine`);
325
+ }
326
+ const state = new CompileState(basePath);
327
+ for (const triple of item.triples) {
328
+ if (!isSimpleTerm(triple.predicate)) {
329
+ throw new UnsupportedSparqlQueryError(`${label} property path templates fallback to compatibility engine`);
330
+ }
331
+ const patterns = this.compileTriple(triple, graph, state);
332
+ if (patterns.length !== 1) {
333
+ throw new UnsupportedSparqlQueryError(`${label} property path templates fallback to compatibility engine`);
334
+ }
335
+ const pattern = patterns[0];
336
+ this.assertSafeUpdateTemplatePattern(pattern, label);
337
+ template.push({
338
+ graph,
339
+ subject: pattern.subject,
340
+ predicate: pattern.predicate,
341
+ object: pattern.object,
342
+ });
343
+ }
344
+ }
345
+ return template;
346
+ }
347
+ assertSafeUpdateTemplatePattern(pattern, label) {
348
+ const terms = [pattern.subject, pattern.predicate, pattern.object];
349
+ if (terms.some((term) => term && 'termType' in term && term.termType === 'BlankNode')) {
350
+ throw new UnsupportedSparqlQueryError(`${label} blank node templates fallback to compatibility engine`);
351
+ }
352
+ }
353
+ assertScopedUpdateWherePatterns(patterns, basePath, label, inGraph, namedGraph) {
354
+ if (patterns.length === 0) {
355
+ throw new UnsupportedSparqlQueryError(`${label} without WHERE patterns fallback to compatibility engine`);
356
+ }
357
+ for (const pattern of patterns) {
358
+ switch (pattern.type) {
359
+ case 'graph':
360
+ if (pattern.name.termType === 'Variable') {
361
+ if (!namedGraph) {
362
+ throw new UnsupportedSparqlQueryError(`${label} GRAPH variables fallback to compatibility engine`);
363
+ }
364
+ }
365
+ else if (pattern.name.termType !== 'NamedNode') {
366
+ throw new UnsupportedSparqlQueryError(`${label} GRAPH variables fallback to compatibility engine`);
367
+ }
368
+ else if (!pattern.name.value.startsWith(basePath)) {
369
+ throw new UnsupportedSparqlQueryError(`${label} graph outside basePath fallback to compatibility engine`);
370
+ }
371
+ this.assertScopedUpdateWherePatterns(pattern.patterns, basePath, label, true, namedGraph);
372
+ break;
373
+ case 'bgp':
374
+ if (!inGraph) {
375
+ throw new UnsupportedSparqlQueryError(`${label} default graph fallback to compatibility engine`);
376
+ }
377
+ break;
378
+ case 'optional':
379
+ case 'group':
380
+ this.assertScopedUpdateWherePatterns(pattern.patterns, basePath, label, inGraph, namedGraph);
381
+ break;
382
+ case 'union':
383
+ for (const branch of pattern.patterns) {
384
+ this.assertScopedUpdateWherePatterns(this.unionBranchPatterns(branch), basePath, label, inGraph, namedGraph);
385
+ }
386
+ break;
387
+ case 'filter':
388
+ case 'values':
389
+ break;
390
+ default:
391
+ if ('queryType' in pattern) {
392
+ throw new UnsupportedSparqlQueryError(`${label} subqueries fallback to compatibility engine`);
393
+ }
394
+ break;
395
+ }
396
+ }
397
+ }
398
+ compileUpdateGraphQuads(items, basePath) {
399
+ const quads = [];
400
+ for (const item of items) {
401
+ if (item.type !== 'graph') {
402
+ throw new UnsupportedSparqlQueryError('SPARQL UPDATE default graph fallback to compatibility engine');
403
+ }
404
+ if (item.name.termType !== 'NamedNode') {
405
+ throw new UnsupportedSparqlQueryError('SPARQL UPDATE GRAPH variables fallback to compatibility engine');
406
+ }
407
+ if (!item.name.value.startsWith(basePath)) {
408
+ throw new UnsupportedSparqlQueryError('SPARQL UPDATE graph outside basePath fallback to compatibility engine');
409
+ }
410
+ for (const triple of item.triples) {
411
+ quads.push(this.compileUpdateTriple(triple, item.name));
412
+ }
413
+ }
414
+ return quads;
415
+ }
416
+ compileUpdateTriple(triple, graph) {
417
+ const subject = this.compileUpdateNamedNode(triple.subject, 'subject');
418
+ const predicate = this.compileUpdateNamedNode(triple.predicate, 'predicate');
419
+ const object = this.compileUpdateObject(triple.object);
420
+ return n3_1.DataFactory.quad(subject, predicate, object, graph);
421
+ }
422
+ compileUpdateNamedNode(term, position) {
423
+ if (isNamedNodeTerm(term)) {
424
+ return term;
425
+ }
426
+ throw new UnsupportedSparqlQueryError(`SPARQL UPDATE ${position} must be a named node in embedded delta path`);
427
+ }
428
+ compileUpdateObject(term) {
429
+ if (isNamedNodeTerm(term) || isLiteralTerm(term)) {
430
+ return term;
431
+ }
432
+ throw new UnsupportedSparqlQueryError('SPARQL UPDATE object must be a named node or literal in embedded delta path');
433
+ }
434
+ compilePatterns(patterns, graph, state, optional, namedGraphScope) {
435
+ for (const pattern of patterns) {
436
+ switch (pattern.type) {
437
+ case 'bgp':
438
+ this.compileBgp(pattern, graph, state, optional);
439
+ break;
440
+ case 'graph':
441
+ this.compileGraphPattern(pattern, state, optional, namedGraphScope);
442
+ break;
443
+ case 'optional':
444
+ state.startOptional();
445
+ this.compilePatterns(pattern.patterns, graph, state, true, namedGraphScope);
446
+ state.finishOptional();
447
+ break;
448
+ case 'filter': {
449
+ const expression = pattern.expression;
450
+ const notExistsPatterns = this.notExistsPatterns(expression);
451
+ if (notExistsPatterns) {
452
+ if (optional) {
453
+ state.addOptionalMinus(this.compileAntiJoinGroup(notExistsPatterns, graph, state.basePath, 'FILTER NOT EXISTS', namedGraphScope));
454
+ break;
455
+ }
456
+ state.addMinus(this.compileAntiJoinGroup(notExistsPatterns, graph, state.basePath, 'FILTER NOT EXISTS', namedGraphScope));
457
+ break;
458
+ }
459
+ const existsPatterns = this.existsPatterns(expression);
460
+ if (existsPatterns) {
461
+ if (optional) {
462
+ state.addOptionalExists(this.compileExistsGroup(existsPatterns, graph, state.basePath, 'FILTER EXISTS', namedGraphScope));
463
+ break;
464
+ }
465
+ state.addExists(this.compileExistsGroup(existsPatterns, graph, state.basePath, 'FILTER EXISTS', namedGraphScope));
466
+ break;
467
+ }
468
+ if (optional) {
469
+ state.addOptionalFilters(this.compileFilter(expression));
470
+ break;
471
+ }
472
+ state.query.filters?.push(...this.compileFilter(expression));
473
+ break;
474
+ }
475
+ case 'group':
476
+ this.compilePatterns(pattern.patterns, graph, state, optional, namedGraphScope);
477
+ break;
478
+ case 'union':
479
+ if (optional) {
480
+ state.addOptionalUnion(this.compileUnionBranches(pattern.patterns, graph, state.basePath, namedGraphScope));
481
+ break;
482
+ }
483
+ state.addUnion(this.compileUnionBranches(pattern.patterns, graph, state.basePath, namedGraphScope));
484
+ break;
485
+ case 'service':
486
+ throw new DisabledSparqlFeatureError('SPARQL SERVICE federation is disabled for server-owned Pod queries');
487
+ case 'bind':
488
+ state.addBind(this.compileBind(pattern, state.basePath), optional);
489
+ break;
490
+ case 'minus':
491
+ if (optional) {
492
+ state.addOptionalMinus(this.compileMinusGroup(pattern, graph, state.basePath, namedGraphScope));
493
+ break;
494
+ }
495
+ state.addMinus(this.compileMinusGroup(pattern, graph, state.basePath, namedGraphScope));
496
+ break;
497
+ case 'values':
498
+ this.compileValuesRows(pattern.values, state, optional);
499
+ break;
500
+ default:
501
+ if ('queryType' in pattern) {
502
+ throw new UnsupportedSparqlQueryError('Subqueries fallback to compatibility engine');
503
+ }
504
+ throw new UnsupportedSparqlQueryError(`Unsupported SPARQL pattern: ${pattern.type ?? 'unknown'}`);
505
+ }
506
+ }
507
+ }
508
+ compileUnionBranches(branches, graph, basePath, namedGraphScope) {
509
+ if (branches.length < 2) {
510
+ throw new UnsupportedSparqlQueryError('UNION requires at least two branches locally');
511
+ }
512
+ const compiledBranches = [];
513
+ for (const branch of branches) {
514
+ compiledBranches.push(...this.compileUnionBranch(branch, graph, basePath, namedGraphScope));
515
+ }
516
+ return compiledBranches;
517
+ }
518
+ compileUnionBranch(branch, graph, basePath, namedGraphScope) {
519
+ if (branch.type === 'union') {
520
+ return branch.patterns.flatMap((nestedBranch) => (this.compileUnionBranch(nestedBranch, graph, basePath, namedGraphScope)));
521
+ }
522
+ const branchState = new CompileState(basePath);
523
+ this.compilePatterns(this.unionBranchPatterns(branch), graph, branchState, false, namedGraphScope);
524
+ branchState.assertBindVariablesSafe();
525
+ branchState.assertValuesVariablesBoundByRequiredPatterns();
526
+ if (branchState.query.unions?.length) {
527
+ throw new UnsupportedSparqlQueryError('Nested UNION fallback to compatibility engine');
528
+ }
529
+ if (branchState.query.patterns.length === 0) {
530
+ throw new UnsupportedSparqlQueryError('UNION branch without required BGP fallback to compatibility engine');
531
+ }
532
+ return [{
533
+ patterns: branchState.query.patterns,
534
+ ...(branchState.query.values?.length ? { values: branchState.query.values } : {}),
535
+ ...(branchState.query.optional?.length ? { optional: branchState.query.optional } : {}),
536
+ ...(branchState.query.binds?.length ? { binds: branchState.query.binds } : {}),
537
+ ...(branchState.query.filters?.length ? { filters: branchState.query.filters } : {}),
538
+ }];
539
+ }
540
+ compileMinusGroup(pattern, graph, basePath, namedGraphScope) {
541
+ return this.compileAntiJoinGroup(pattern.patterns, graph, basePath, 'MINUS', namedGraphScope);
542
+ }
543
+ compileAntiJoinGroup(patterns, graph, basePath, label, namedGraphScope) {
544
+ const minusState = new CompileState(basePath, true);
545
+ this.compilePatterns(patterns, graph, minusState, false, namedGraphScope);
546
+ minusState.assertBindVariablesSafe();
547
+ minusState.assertValuesVariablesBoundByRequiredPatterns();
548
+ if (minusState.query.minus?.length || minusState.query.exists?.length) {
549
+ throw new UnsupportedSparqlQueryError(`Nested ${label} fallback to compatibility engine`);
550
+ }
551
+ if (minusState.query.patterns.length === 0 && (minusState.query.unions?.length ?? 0) === 0) {
552
+ throw new UnsupportedSparqlQueryError(`${label} without required BGP fallback to compatibility engine`);
553
+ }
554
+ return {
555
+ patterns: minusState.query.patterns,
556
+ ...(minusState.query.values?.length ? { values: minusState.query.values } : {}),
557
+ ...(minusState.query.unions?.length ? { unions: minusState.query.unions } : {}),
558
+ ...(minusState.query.optional?.length ? { optional: minusState.query.optional } : {}),
559
+ ...(minusState.query.binds?.length ? { binds: minusState.query.binds } : {}),
560
+ ...(minusState.query.filters?.length ? { filters: minusState.query.filters } : {}),
561
+ };
562
+ }
563
+ compileExistsGroup(patterns, graph, basePath, label, namedGraphScope) {
564
+ const existsState = new CompileState(basePath, true);
565
+ this.compilePatterns(patterns, graph, existsState, false, namedGraphScope);
566
+ existsState.assertBindVariablesSafe();
567
+ existsState.assertValuesVariablesBoundByRequiredPatterns();
568
+ if (existsState.query.minus?.length || existsState.query.exists?.length) {
569
+ throw new UnsupportedSparqlQueryError(`Nested ${label} fallback to compatibility engine`);
570
+ }
571
+ if (existsState.query.patterns.length === 0 && (existsState.query.unions?.length ?? 0) === 0) {
572
+ throw new UnsupportedSparqlQueryError(`${label} without required BGP fallback to compatibility engine`);
573
+ }
574
+ return {
575
+ patterns: existsState.query.patterns,
576
+ ...(existsState.query.values?.length ? { values: existsState.query.values } : {}),
577
+ ...(existsState.query.unions?.length ? { unions: existsState.query.unions } : {}),
578
+ ...(existsState.query.optional?.length ? { optional: existsState.query.optional } : {}),
579
+ ...(existsState.query.binds?.length ? { binds: existsState.query.binds } : {}),
580
+ ...(existsState.query.filters?.length ? { filters: existsState.query.filters } : {}),
581
+ };
582
+ }
583
+ notExistsPatterns(expression) {
584
+ if (!isOperationExpression(expression) || expression.operator.toLowerCase() !== 'notexists') {
585
+ return null;
586
+ }
587
+ const pattern = expression.args[0];
588
+ if (!pattern || !isPattern(pattern)) {
589
+ throw new UnsupportedSparqlQueryError('FILTER NOT EXISTS without graph pattern fallback to compatibility engine');
590
+ }
591
+ return pattern.type === 'group'
592
+ ? pattern.patterns
593
+ : [pattern];
594
+ }
595
+ existsPatterns(expression) {
596
+ if (!isOperationExpression(expression) || expression.operator.toLowerCase() !== 'exists') {
597
+ return null;
598
+ }
599
+ const pattern = expression.args[0];
600
+ if (!pattern || !isPattern(pattern)) {
601
+ throw new UnsupportedSparqlQueryError('FILTER EXISTS without graph pattern fallback to compatibility engine');
602
+ }
603
+ return pattern.type === 'group'
604
+ ? pattern.patterns
605
+ : [pattern];
606
+ }
607
+ unionBranchPatterns(branch) {
608
+ return branch.type === 'group'
609
+ ? branch.patterns
610
+ : [branch];
611
+ }
612
+ compileBgp(pattern, graph, state, optional) {
613
+ for (const triple of pattern.triples) {
614
+ for (const queryPattern of this.compileTriple(triple, graph, state)) {
615
+ state.addPattern(queryPattern, optional);
616
+ }
617
+ }
618
+ }
619
+ compileGraphPattern(pattern, state, optional, namedGraphScope) {
620
+ const graph = this.compileScopedGraphTerm(pattern.name, state.basePath, namedGraphScope);
621
+ if (graph === null) {
622
+ state.addImpossibleGraphPattern(optional);
623
+ return;
624
+ }
625
+ if (pattern.name.termType === 'Variable') {
626
+ if (optional) {
627
+ throw new UnsupportedSparqlQueryError('OPTIONAL GRAPH variable scope fallback to compatibility engine');
628
+ }
629
+ if (namedGraphScope) {
630
+ state.query.filters?.push({
631
+ variable: pattern.name.value,
632
+ operator: '$in',
633
+ values: this.graphScopeFilterValues(namedGraphScope),
634
+ });
635
+ }
636
+ else {
637
+ state.query.filters?.push({
638
+ variable: pattern.name.value,
639
+ operator: '$startsWith',
640
+ value: state.basePath,
641
+ });
642
+ }
643
+ }
644
+ this.compilePatterns(pattern.patterns, graph, state, optional, namedGraphScope);
645
+ }
646
+ compileScopedGraphTerm(term, basePath, namedGraphScope) {
647
+ const graph = this.compileGraphTerm(term, basePath);
648
+ if (!namedGraphScope) {
649
+ return graph;
650
+ }
651
+ if (graph === null) {
652
+ return null;
653
+ }
654
+ if (term.termType === 'Variable') {
655
+ return graph;
656
+ }
657
+ return this.graphScopeContains(namedGraphScope, graph) ? graph : null;
658
+ }
659
+ graphScopeContains(scope, graph) {
660
+ if (isCompiledVariable(scope)) {
661
+ return false;
662
+ }
663
+ if (isRdfJsTerm(scope)) {
664
+ return (0, n3_1.termToId)(scope) === (0, n3_1.termToId)(graph);
665
+ }
666
+ const values = scope.$in;
667
+ return Array.isArray(values) && values.some((value) => (value && typeof value === 'object' && 'termType' in value && (0, n3_1.termToId)(value) === (0, n3_1.termToId)(graph)));
668
+ }
669
+ graphScopeFilterValues(scope) {
670
+ if (isCompiledVariable(scope)) {
671
+ throw new UnsupportedSparqlQueryError('GRAPH variable dataset scope fallback to compatibility engine');
672
+ }
673
+ if (isRdfJsTerm(scope)) {
674
+ return [scope];
675
+ }
676
+ const values = scope.$in;
677
+ if (Array.isArray(values) && values.every((value) => value && typeof value === 'object' && 'termType' in value)) {
678
+ return values;
679
+ }
680
+ throw new UnsupportedSparqlQueryError('GRAPH variable dataset scope fallback to compatibility engine');
681
+ }
682
+ compileBind(pattern, basePath) {
683
+ return {
684
+ variable: pattern.variable.value,
685
+ expression: this.compileBindExpression(pattern.expression, basePath),
686
+ };
687
+ }
688
+ compileBindExpression(expression, basePath) {
689
+ return this.compileBindLikeExpression(expression, basePath, 'BIND');
690
+ }
691
+ compileBindLikeExpression(expression, basePath, label) {
692
+ const normalized = this.normalizeFunctionCallExpression(expression);
693
+ if (isRdfTermExpression(normalized) && !isVariableTerm(normalized)) {
694
+ return {
695
+ type: 'term',
696
+ term: normalized,
697
+ };
698
+ }
699
+ if (isVariableTerm(normalized)) {
700
+ return {
701
+ type: 'variable',
702
+ variable: normalized.value,
703
+ };
704
+ }
705
+ if (!isOperationExpression(normalized)) {
706
+ throw new UnsupportedSparqlQueryError(`${label} expression fallback to compatibility engine`);
707
+ }
708
+ const operator = normalized.operator.toLowerCase();
709
+ if (operator === 'str') {
710
+ return {
711
+ type: 'stringValue',
712
+ variable: this.expressionVariable(this.expressionArg(normalized.args[0])),
713
+ };
714
+ }
715
+ if (operator === 'strlen') {
716
+ return {
717
+ type: 'stringLength',
718
+ variable: this.stringOperandVariable(this.expressionArg(normalized.args[0])).variable,
719
+ };
720
+ }
721
+ if (operator === 'lcase' || operator === 'lower-case') {
722
+ return {
723
+ type: 'lowerCase',
724
+ expression: this.compileBindExpression(this.expressionArg(normalized.args[0]), basePath),
725
+ };
726
+ }
727
+ if (operator === 'ucase' || operator === 'upper-case') {
728
+ return {
729
+ type: 'upperCase',
730
+ expression: this.compileBindExpression(this.expressionArg(normalized.args[0]), basePath),
731
+ };
732
+ }
733
+ if (operator === 'substr' || operator === 'substring') {
734
+ return {
735
+ type: 'substring',
736
+ expression: this.compileBindExpression(this.expressionArg(normalized.args[0]), basePath),
737
+ start: this.compileBindExpression(this.expressionArg(normalized.args[1]), basePath),
738
+ ...(normalized.args[2] === undefined
739
+ ? {}
740
+ : { length: this.compileBindExpression(this.expressionArg(normalized.args[2]), basePath) }),
741
+ };
742
+ }
743
+ if (operator === 'concat') {
744
+ return {
745
+ type: 'concat',
746
+ expressions: normalized.args.map((arg) => (this.compileBindExpression(this.expressionArg(arg), basePath))),
747
+ };
748
+ }
749
+ if (operator === 'iri' || operator === 'uri') {
750
+ return {
751
+ type: 'iri',
752
+ expression: this.compileBindExpression(this.expressionArg(normalized.args[0]), basePath),
753
+ base: basePath,
754
+ };
755
+ }
756
+ throw new UnsupportedSparqlQueryError(`${label} ${operator} fallback to compatibility engine`);
757
+ }
758
+ compileTriple(triple, graph, state) {
759
+ const subject = this.compileTerm(triple.subject);
760
+ const object = this.compileTerm(triple.object);
761
+ const pathPatterns = this.compilePropertyPath(triple.predicate, subject, object, graph, state);
762
+ if (pathPatterns) {
763
+ return pathPatterns;
764
+ }
765
+ if (!isSimpleTerm(triple.predicate)) {
766
+ throw new UnsupportedSparqlQueryError('Property paths fallback to compatibility engine');
767
+ }
768
+ return [{
769
+ graph,
770
+ subject,
771
+ predicate: this.compileTerm(triple.predicate),
772
+ object,
773
+ }];
774
+ }
775
+ compilePropertyPath(predicate, subject, object, graph, state) {
776
+ if (isSimpleTerm(predicate)) {
777
+ return null;
778
+ }
779
+ const alternative = this.flattenFixedAlternativePath(predicate);
780
+ if (alternative) {
781
+ const predicateMatch = { $in: alternative.predicates.map((entry) => entry) };
782
+ return [
783
+ alternative.inverse
784
+ ? {
785
+ graph,
786
+ subject: object,
787
+ predicate: predicateMatch,
788
+ object: subject,
789
+ }
790
+ : {
791
+ graph,
792
+ subject,
793
+ predicate: predicateMatch,
794
+ object,
795
+ },
796
+ ];
797
+ }
798
+ const segments = this.flattenFixedLengthPath(predicate);
799
+ if (!segments) {
800
+ throw new UnsupportedSparqlQueryError('Property paths fallback to compatibility engine');
801
+ }
802
+ if (segments.length === 0) {
803
+ throw new UnsupportedSparqlQueryError('Empty property paths fallback to compatibility engine');
804
+ }
805
+ const patterns = [];
806
+ let currentSubject = subject;
807
+ for (const [index, segment] of segments.entries()) {
808
+ const isLast = index === segments.length - 1;
809
+ const currentObject = isLast ? object : state.nextPathJoinVariable();
810
+ const predicate = this.compilePathSegmentPredicate(segment);
811
+ patterns.push(segment.inverse
812
+ ? {
813
+ graph,
814
+ subject: currentObject,
815
+ predicate,
816
+ object: currentSubject,
817
+ }
818
+ : {
819
+ graph,
820
+ subject: currentSubject,
821
+ predicate,
822
+ object: currentObject,
823
+ });
824
+ currentSubject = currentObject;
825
+ }
826
+ return patterns;
827
+ }
828
+ compilePathSegmentPredicate(segment) {
829
+ return segment.predicates.length === 1
830
+ ? segment.predicates[0]
831
+ : { $in: segment.predicates.map((entry) => entry) };
832
+ }
833
+ flattenFixedLengthPath(path) {
834
+ return this.flattenFixedLengthPathItem(path, false);
835
+ }
836
+ flattenFixedAlternativePath(path) {
837
+ return this.flattenFixedAlternativePathItem(path, false);
838
+ }
839
+ flattenFixedAlternativePathItem(item, inverse) {
840
+ if (isNamedNodeTerm(item)) {
841
+ return null;
842
+ }
843
+ if (item.pathType === '^' && item.items.length === 1) {
844
+ return this.flattenFixedAlternativePathItem(item.items[0], !inverse);
845
+ }
846
+ if (item.pathType !== '|') {
847
+ return null;
848
+ }
849
+ const predicates = [];
850
+ for (const nestedItem of item.items) {
851
+ if (!isNamedNodeTerm(nestedItem)) {
852
+ return null;
853
+ }
854
+ predicates.push(nestedItem);
855
+ }
856
+ return predicates.length > 0
857
+ ? { predicates, inverse }
858
+ : null;
859
+ }
860
+ flattenFixedLengthPathItem(item, inverse) {
861
+ if (isNamedNodeTerm(item)) {
862
+ return [{ predicates: [item], inverse }];
863
+ }
864
+ if (item.pathType === '^' && item.items.length === 1) {
865
+ return this.flattenFixedLengthPathItem(item.items[0], !inverse);
866
+ }
867
+ if (item.pathType === '|') {
868
+ const predicates = [];
869
+ for (const nestedItem of item.items) {
870
+ if (!isNamedNodeTerm(nestedItem)) {
871
+ return null;
872
+ }
873
+ predicates.push(nestedItem);
874
+ }
875
+ return predicates.length > 0
876
+ ? [{ predicates, inverse }]
877
+ : null;
878
+ }
879
+ if (item.pathType !== '/') {
880
+ return null;
881
+ }
882
+ const items = inverse ? [...item.items].reverse() : item.items;
883
+ const segments = [];
884
+ for (const nestedItem of items) {
885
+ const nested = this.flattenFixedLengthPathItem(nestedItem, inverse);
886
+ if (!nested) {
887
+ return null;
888
+ }
889
+ segments.push(...nested);
890
+ }
891
+ return segments;
892
+ }
893
+ compileGraphTerm(term, basePath) {
894
+ if (term.termType === 'Variable') {
895
+ return (0, RdfLocalQueryEngine_1.variable)(term.value);
896
+ }
897
+ if (!term.value.startsWith(basePath)) {
898
+ return null;
899
+ }
900
+ return term;
901
+ }
902
+ compileTerm(term) {
903
+ if (term.termType === 'Variable') {
904
+ return (0, RdfLocalQueryEngine_1.variable)(term.value);
905
+ }
906
+ if (term.termType === 'Quad') {
907
+ throw new UnsupportedSparqlQueryError('RDF-star terms fallback to compatibility engine');
908
+ }
909
+ return term;
910
+ }
911
+ materializeConstruct(template, rows, graph) {
912
+ return this.materializeTemplate(template.map((triple) => ({
913
+ ...triple,
914
+ graph: graph ?? n3_1.DataFactory.defaultGraph(),
915
+ })), rows);
916
+ }
917
+ materializeDeleteWhere(template, rows) {
918
+ return this.materializeTemplate(template, rows);
919
+ }
920
+ materializeTemplate(template, rows) {
921
+ const quads = [];
922
+ const seen = new Set();
923
+ for (const row of rows) {
924
+ for (const triple of template) {
925
+ const graph = this.resolveTemplateTerm(triple.graph, row);
926
+ const subject = this.resolveTemplateTerm(triple.subject, row);
927
+ const predicate = this.resolveTemplateTerm(triple.predicate, row);
928
+ const object = this.resolveTemplateTerm(triple.object, row);
929
+ if (!graph || !subject || !predicate || !object) {
930
+ continue;
931
+ }
932
+ if (graph.termType !== 'NamedNode' && graph.termType !== 'DefaultGraph') {
933
+ continue;
934
+ }
935
+ if (subject.termType !== 'NamedNode' && subject.termType !== 'BlankNode') {
936
+ continue;
937
+ }
938
+ if (predicate.termType !== 'NamedNode') {
939
+ continue;
940
+ }
941
+ if (object.termType === 'DefaultGraph') {
942
+ continue;
943
+ }
944
+ const quad = n3_1.DataFactory.quad(subject, predicate, object, graph);
945
+ const key = [quad.subject, quad.predicate, quad.object, quad.graph].map((term) => (0, n3_1.termToId)(term)).join('\u001f');
946
+ if (!seen.has(key)) {
947
+ seen.add(key);
948
+ quads.push(quad);
949
+ }
950
+ }
951
+ }
952
+ return quads;
953
+ }
954
+ compileConstructTemplate(query) {
955
+ if (!query.template || query.template.length === 0) {
956
+ throw new UnsupportedSparqlQueryError('CONSTRUCT without template fallback to compatibility engine');
957
+ }
958
+ return query.template.map((triple) => {
959
+ if (!isSimpleTerm(triple.predicate)) {
960
+ throw new UnsupportedSparqlQueryError('CONSTRUCT property paths fallback to compatibility engine');
961
+ }
962
+ if (triple.predicate.termType !== 'NamedNode' && triple.predicate.termType !== 'Variable') {
963
+ throw new UnsupportedSparqlQueryError('CONSTRUCT predicates must be IRIs or variables');
964
+ }
965
+ return {
966
+ subject: this.compileTerm(triple.subject),
967
+ predicate: this.compileTerm(triple.predicate),
968
+ object: this.compileTerm(triple.object),
969
+ };
970
+ });
971
+ }
972
+ compileDescribeTargets(query, localQuery) {
973
+ if (query.variables.length === 1 && query.variables[0] instanceof sparqljs_1.Wildcard) {
974
+ const variables = visibleSelectVariables(query);
975
+ if (variables.length === 0) {
976
+ throw new UnsupportedSparqlQueryError('DESCRIBE wildcard without visible variables fallback to compatibility engine');
977
+ }
978
+ const unboundVariable = variables.find((variable) => !queryBindsVariableInRequiredShape(localQuery, variable));
979
+ if (unboundVariable) {
980
+ throw new UnsupportedSparqlQueryError('DESCRIBE wildcard variables must be bound by required embedded query patterns');
981
+ }
982
+ return variables.map((variable) => (0, RdfLocalQueryEngine_1.variable)(variable));
983
+ }
984
+ const targets = query.variables.map((target) => {
985
+ if (target.termType === 'Variable') {
986
+ if (!queryBindsVariableInRequiredShape(localQuery, target.value)) {
987
+ throw new UnsupportedSparqlQueryError('DESCRIBE variables must be bound by required embedded query patterns');
988
+ }
989
+ return (0, RdfLocalQueryEngine_1.variable)(target.value);
990
+ }
991
+ if (target.termType === 'NamedNode') {
992
+ return target;
993
+ }
994
+ throw new UnsupportedSparqlQueryError('DESCRIBE targets must be IRIs or bound variables locally');
995
+ });
996
+ if (targets.length === 0) {
997
+ throw new UnsupportedSparqlQueryError('DESCRIBE without targets fallback to compatibility engine');
998
+ }
999
+ return targets;
1000
+ }
1001
+ resolveTemplateTerm(term, row) {
1002
+ if (isCompiledVariable(term)) {
1003
+ return row[term.variable];
1004
+ }
1005
+ return term;
1006
+ }
1007
+ compileSelectVariables(query, state) {
1008
+ const localQuery = state.query;
1009
+ if (query.variables.length === 1 && query.variables[0] instanceof sparqljs_1.Wildcard) {
1010
+ if ((localQuery.groupBy?.length ?? 0) > 0) {
1011
+ throw new UnsupportedSparqlQueryError('Wildcard grouped SELECT fallback to compatibility engine');
1012
+ }
1013
+ return visibleSelectVariables(query);
1014
+ }
1015
+ const variables = [];
1016
+ const visibleVariables = visibleSelectVariables(query);
1017
+ for (const variable of query.variables) {
1018
+ if (isSelectVariableTerm(variable)) {
1019
+ variables.push(variable.value);
1020
+ continue;
1021
+ }
1022
+ if (!isVariableExpression(variable)) {
1023
+ throw new UnsupportedSparqlQueryError('Wildcard mixed with explicit SELECT projections fallback to compatibility engine');
1024
+ }
1025
+ if (!isAggregateExpression(variable.expression)) {
1026
+ if ((localQuery.groupBy?.length ?? 0) > 0) {
1027
+ throw new UnsupportedSparqlQueryError('Grouped SELECT expression projection fallback to compatibility engine');
1028
+ }
1029
+ const alias = variable.variable.value;
1030
+ if (variables.includes(alias)
1031
+ || visibleVariables.includes(alias)
1032
+ || (localQuery.binds ?? []).some((bind) => bind.variable === alias)) {
1033
+ throw new UnsupportedSparqlQueryError('SELECT expression alias is already bound locally');
1034
+ }
1035
+ state.addBind({
1036
+ variable: alias,
1037
+ expression: this.compileSelectProjectionExpression(variable.expression, state.basePath),
1038
+ }, false);
1039
+ variables.push(alias);
1040
+ continue;
1041
+ }
1042
+ const aggregate = variable.expression;
1043
+ const compiledAggregate = this.compileAggregateProjection(aggregate, variable.variable.value, state);
1044
+ localQuery.aggregates = [...(localQuery.aggregates ?? []), compiledAggregate];
1045
+ localQuery.aggregate ??= compiledAggregate;
1046
+ variables.push(variable.variable.value);
1047
+ }
1048
+ this.assertGroupProjection(query, localQuery, variables);
1049
+ return variables;
1050
+ }
1051
+ compileAggregateProjection(aggregate, as, state) {
1052
+ const type = this.aggregateType(aggregate.aggregation);
1053
+ const aggregateExpression = aggregate.expression;
1054
+ if (type !== 'count' && isWildcardTerm(aggregateExpression)) {
1055
+ throw new UnsupportedSparqlQueryError(`${type.toUpperCase()}(*) fallback to compatibility engine`);
1056
+ }
1057
+ const variable = isWildcardTerm(aggregateExpression)
1058
+ ? undefined
1059
+ : this.expressionVariable(aggregateExpression);
1060
+ if (type !== 'count') {
1061
+ this.assertNumericAggregateSafe(variable, state);
1062
+ }
1063
+ return {
1064
+ type,
1065
+ as,
1066
+ variable,
1067
+ distinct: aggregate.distinct,
1068
+ };
1069
+ }
1070
+ aggregateType(aggregation) {
1071
+ switch (aggregation.toLowerCase()) {
1072
+ case 'count':
1073
+ case 'sum':
1074
+ case 'avg':
1075
+ case 'min':
1076
+ case 'max':
1077
+ return aggregation.toLowerCase();
1078
+ default:
1079
+ throw new UnsupportedSparqlQueryError(`Aggregate ${aggregation} fallback to compatibility engine`);
1080
+ }
1081
+ }
1082
+ assertNumericAggregateSafe(variable, state) {
1083
+ if (!variable) {
1084
+ throw new UnsupportedSparqlQueryError('Numeric aggregate requires a variable locally');
1085
+ }
1086
+ if (!queryBindsVariableInRequiredShape(state.query, variable)) {
1087
+ throw new UnsupportedSparqlQueryError('Numeric aggregate variable must be bound by required embedded query patterns');
1088
+ }
1089
+ if (!hasNumericGuard(state.query.filters ?? [], variable)) {
1090
+ throw new UnsupportedSparqlQueryError('Numeric aggregate requires FILTER(isNumeric(?var)) locally');
1091
+ }
1092
+ }
1093
+ compileSelectProjectionExpression(expression, basePath) {
1094
+ return this.compileBindLikeExpression(expression, basePath, 'SELECT projection');
1095
+ }
1096
+ compileGroupBy(group, state) {
1097
+ if (group.length === 0) {
1098
+ return undefined;
1099
+ }
1100
+ const groupBy = [];
1101
+ group.forEach((entry, index) => {
1102
+ if (isVariableTerm(entry.expression)) {
1103
+ const groupVariable = entry.variable?.value ?? entry.expression.value;
1104
+ groupBy.push(groupVariable);
1105
+ if (entry.variable && entry.variable.value !== entry.expression.value) {
1106
+ state.addBind({
1107
+ variable: entry.variable.value,
1108
+ expression: {
1109
+ type: 'variable',
1110
+ variable: entry.expression.value,
1111
+ },
1112
+ }, false);
1113
+ }
1114
+ return;
1115
+ }
1116
+ const groupVariable = entry.variable?.value ?? state.nextGroupVariable(index);
1117
+ state.addBind({
1118
+ variable: groupVariable,
1119
+ expression: this.compileGroupByExpression(entry.expression, state.basePath),
1120
+ }, false);
1121
+ groupBy.push(groupVariable);
1122
+ });
1123
+ state.query.groupBy = groupBy;
1124
+ return groupBy;
1125
+ }
1126
+ compileGroupByExpression(expression, basePath) {
1127
+ return this.compileBindLikeExpression(expression, basePath, 'GROUP BY');
1128
+ }
1129
+ compileHaving(having, state) {
1130
+ if (having.length === 0) {
1131
+ return undefined;
1132
+ }
1133
+ const localQuery = state.query;
1134
+ if ((localQuery.aggregates?.length ?? 0) === 0 && !localQuery.aggregate) {
1135
+ throw new UnsupportedSparqlQueryError('HAVING without aggregate fallback to compatibility engine');
1136
+ }
1137
+ const filters = having.flatMap((expression) => this.compileHavingFilter(expression, state));
1138
+ return filters.length > 0 ? filters : undefined;
1139
+ }
1140
+ compileHavingFilter(expression, state) {
1141
+ const normalized = this.normalizeFunctionCallExpression(expression);
1142
+ if (!isOperationExpression(normalized)) {
1143
+ throw new UnsupportedSparqlQueryError('Only simple HAVING operations are supported locally');
1144
+ }
1145
+ const operator = normalized.operator.toLowerCase();
1146
+ if (operator === '&&') {
1147
+ return normalized.args.flatMap((arg) => this.compileHavingFilter(this.expressionArg(arg), state));
1148
+ }
1149
+ const binary = this.binaryFilter(operator);
1150
+ if (!binary) {
1151
+ throw new UnsupportedSparqlQueryError(`HAVING ${operator} fallback to compatibility engine`);
1152
+ }
1153
+ return [this.compileHavingBinaryFilter(binary, normalized.args[0], normalized.args[1], state)];
1154
+ }
1155
+ compileHavingBinaryFilter(operator, left, right, state) {
1156
+ const leftExpression = this.expressionArg(left);
1157
+ const rightExpression = this.expressionArg(right);
1158
+ const leftAggregate = this.havingAggregateVariableOrUndefined(leftExpression, state);
1159
+ if (leftAggregate) {
1160
+ return {
1161
+ variable: leftAggregate,
1162
+ operator,
1163
+ value: this.filterValue(rightExpression),
1164
+ };
1165
+ }
1166
+ const rightAggregate = this.havingAggregateVariableOrUndefined(rightExpression, state);
1167
+ if (rightAggregate) {
1168
+ return {
1169
+ variable: rightAggregate,
1170
+ operator: this.reverseBinaryFilter(operator),
1171
+ value: this.filterValue(leftExpression),
1172
+ };
1173
+ }
1174
+ throw new UnsupportedSparqlQueryError('HAVING must compare one aggregate with one RDF term locally');
1175
+ }
1176
+ havingAggregateVariableOrUndefined(expression, state) {
1177
+ const localQuery = state.query;
1178
+ const aggregates = localQuery.aggregates ?? (localQuery.aggregate ? [localQuery.aggregate] : []);
1179
+ if (aggregates.length === 0) {
1180
+ return undefined;
1181
+ }
1182
+ if (isVariableExpressionTerm(expression)) {
1183
+ return aggregates.some((aggregate) => aggregate.as === expression.value) ? expression.value : undefined;
1184
+ }
1185
+ if (!isAggregateExpression(expression)) {
1186
+ return undefined;
1187
+ }
1188
+ const type = this.aggregateType(expression.aggregation);
1189
+ const aggregateExpression = expression.expression;
1190
+ const variable = isWildcardTerm(aggregateExpression)
1191
+ ? undefined
1192
+ : this.expressionVariable(aggregateExpression);
1193
+ const matchingAggregate = aggregates.find((aggregate) => (type === aggregate.type
1194
+ && variable === aggregate.variable
1195
+ && expression.distinct === Boolean(aggregate.distinct)));
1196
+ if (matchingAggregate) {
1197
+ return matchingAggregate.as;
1198
+ }
1199
+ if (type !== 'count') {
1200
+ this.assertNumericAggregateSafe(variable, state);
1201
+ }
1202
+ const hiddenAggregate = {
1203
+ type,
1204
+ as: state.nextHavingAggregateVariable(),
1205
+ variable,
1206
+ distinct: expression.distinct,
1207
+ };
1208
+ localQuery.aggregates = [...(localQuery.aggregates ?? []), hiddenAggregate];
1209
+ return hiddenAggregate.as;
1210
+ }
1211
+ assertGroupProjection(query, localQuery, variables) {
1212
+ const groupBy = localQuery.groupBy ?? [];
1213
+ if (groupBy.length === 0) {
1214
+ return;
1215
+ }
1216
+ const aggregates = localQuery.aggregates ?? (localQuery.aggregate ? [localQuery.aggregate] : []);
1217
+ if (aggregates.length === 0) {
1218
+ throw new UnsupportedSparqlQueryError('GROUP BY without aggregate fallback to compatibility engine');
1219
+ }
1220
+ const groupableVariables = new Set([
1221
+ ...localQuery.patterns.flatMap((pattern) => variablesInPattern(pattern)),
1222
+ ...(localQuery.binds ?? []).map((bind) => bind.variable),
1223
+ ]);
1224
+ if (groupBy.some((variableName) => !groupableVariables.has(variableName))) {
1225
+ throw new UnsupportedSparqlQueryError('GROUP BY variables must come from required BGP patterns or local binds');
1226
+ }
1227
+ const groupVariables = new Set(groupBy);
1228
+ const aggregateVariables = new Set();
1229
+ for (const variable of query.variables) {
1230
+ if (isSelectVariableTerm(variable)) {
1231
+ if (!groupVariables.has(variable.value)) {
1232
+ throw new UnsupportedSparqlQueryError('Grouped SELECT variables must be present in GROUP BY');
1233
+ }
1234
+ continue;
1235
+ }
1236
+ if (isVariableExpression(variable) && isAggregateExpression(variable.expression)) {
1237
+ aggregateVariables.add(variable.variable.value);
1238
+ }
1239
+ }
1240
+ const aggregateAliases = new Set(aggregates.map((aggregate) => aggregate.as));
1241
+ if (aggregateVariables.size !== aggregateAliases.size) {
1242
+ throw new UnsupportedSparqlQueryError('Grouped local queries require aggregate projections to be aggregate aliases');
1243
+ }
1244
+ if ([...aggregateVariables].some((variableName) => !aggregateAliases.has(variableName))) {
1245
+ throw new UnsupportedSparqlQueryError('Grouped local queries require aggregate projections to be aggregate aliases');
1246
+ }
1247
+ if (variables.some((variableName) => !groupVariables.has(variableName) && !aggregateAliases.has(variableName))) {
1248
+ throw new UnsupportedSparqlQueryError('Grouped SELECT projection fallback to compatibility engine');
1249
+ }
1250
+ }
1251
+ compileOrder(order, state) {
1252
+ if (order.length === 0) {
1253
+ return undefined;
1254
+ }
1255
+ return order.map((entry, index) => {
1256
+ if (isVariableTerm(entry.expression)) {
1257
+ return {
1258
+ variable: entry.expression.value,
1259
+ direction: entry.descending ? 'desc' : 'asc',
1260
+ };
1261
+ }
1262
+ const orderVariable = state.nextOrderVariable(index);
1263
+ state.addBind({
1264
+ variable: orderVariable,
1265
+ expression: this.compileOrderExpression(entry.expression, state.basePath),
1266
+ }, false);
1267
+ return {
1268
+ variable: orderVariable,
1269
+ direction: entry.descending ? 'desc' : 'asc',
1270
+ };
1271
+ });
1272
+ }
1273
+ compileOrderExpression(expression, basePath) {
1274
+ return this.compileBindLikeExpression(expression, basePath, 'ORDER BY');
1275
+ }
1276
+ compileFilter(expression) {
1277
+ const normalizedExpression = this.normalizeFunctionCallExpression(expression);
1278
+ if (!isOperationExpression(expression)) {
1279
+ if (!normalizedExpression || !isOperationExpression(normalizedExpression)) {
1280
+ throw new UnsupportedSparqlQueryError('Only simple FILTER operations are supported locally');
1281
+ }
1282
+ expression = normalizedExpression;
1283
+ }
1284
+ else {
1285
+ expression = normalizedExpression;
1286
+ }
1287
+ const operator = expression.operator.toLowerCase();
1288
+ if (operator === '&&') {
1289
+ return expression.args.flatMap((arg) => this.compileFilter(this.expressionArg(arg)));
1290
+ }
1291
+ if (operator === '||') {
1292
+ return [this.compileOrFilter(expression)];
1293
+ }
1294
+ if (operator === 'bound') {
1295
+ return [{
1296
+ variable: this.expressionVariable(this.expressionArg(expression.args[0])),
1297
+ operator: '$bound',
1298
+ value: true,
1299
+ }];
1300
+ }
1301
+ const termTest = this.compileTermTestFilter(operator, expression);
1302
+ if (termTest) {
1303
+ return [termTest];
1304
+ }
1305
+ if (operator === '!' || operator === 'not') {
1306
+ return this.compileNegatedFilter(this.expressionArg(expression.args[0]));
1307
+ }
1308
+ if (operator === 'langmatches') {
1309
+ return [this.compileLangMatchesFilter(expression)];
1310
+ }
1311
+ const binary = this.binaryFilter(operator);
1312
+ if (binary) {
1313
+ return [this.compileBinaryFilter(binary, expression.args[0], expression.args[1])];
1314
+ }
1315
+ if (operator === 'in' || operator === 'notin') {
1316
+ const values = expression.args[1];
1317
+ if (!Array.isArray(values)) {
1318
+ throw new UnsupportedSparqlQueryError('FILTER IN tuple fallback to compatibility engine');
1319
+ }
1320
+ const operand = this.stringOperandVariable(this.expressionArg(expression.args[0]));
1321
+ return [{
1322
+ variable: operand.variable,
1323
+ operator: operator === 'in' ? '$in' : '$notIn',
1324
+ operand: operand.operand,
1325
+ values: values.map((value) => this.filterValue(value)),
1326
+ }];
1327
+ }
1328
+ const stringOperator = this.stringFilter(operator);
1329
+ if (stringOperator) {
1330
+ const [left, right, flags] = expression.args;
1331
+ const leftOperand = this.stringOperandVariable(this.expressionArg(left));
1332
+ return [{
1333
+ variable: leftOperand.variable,
1334
+ operator: stringOperator,
1335
+ operand: leftOperand.operand,
1336
+ value: this.literalString(this.expressionArg(right)),
1337
+ flags: operator === 'regex' && flags ? this.literalString(this.expressionArg(flags)) : undefined,
1338
+ }];
1339
+ }
1340
+ throw new UnsupportedSparqlQueryError(`FILTER ${operator} fallback to compatibility engine`);
1341
+ }
1342
+ compileOrFilter(expression) {
1343
+ const branches = this.flattenOrExpressions(expression);
1344
+ let variable;
1345
+ let operand = undefined;
1346
+ let operandInitialized = false;
1347
+ const values = [];
1348
+ const seen = new Set();
1349
+ for (const branch of branches) {
1350
+ const filters = this.compileFilter(branch);
1351
+ if (filters.length !== 1) {
1352
+ throw new UnsupportedSparqlQueryError('FILTER OR only supports equality or IN branches on one variable locally');
1353
+ }
1354
+ const filter = filters[0];
1355
+ if (filter.operator !== '$eq' && filter.operator !== '$in') {
1356
+ throw new UnsupportedSparqlQueryError('FILTER OR only supports equality or IN branches on one variable locally');
1357
+ }
1358
+ if (variable && variable !== filter.variable) {
1359
+ throw new UnsupportedSparqlQueryError('FILTER OR branches must constrain the same variable locally');
1360
+ }
1361
+ if (operandInitialized && operand !== filter.operand) {
1362
+ throw new UnsupportedSparqlQueryError('FILTER OR branches must use the same operand locally');
1363
+ }
1364
+ variable = filter.variable;
1365
+ operand = filter.operand;
1366
+ operandInitialized = true;
1367
+ const branchValues = filter.operator === '$eq'
1368
+ ? filter.value === undefined ? [] : [filter.value]
1369
+ : filter.values ?? [];
1370
+ if (branchValues.length === 0) {
1371
+ throw new UnsupportedSparqlQueryError('FILTER OR branch without values fallback to compatibility engine');
1372
+ }
1373
+ for (const value of branchValues) {
1374
+ const key = this.filterValueKey(value);
1375
+ if (!seen.has(key)) {
1376
+ seen.add(key);
1377
+ values.push(value);
1378
+ }
1379
+ }
1380
+ }
1381
+ if (!variable || values.length === 0) {
1382
+ throw new UnsupportedSparqlQueryError('FILTER OR without equality branches fallback to compatibility engine');
1383
+ }
1384
+ return {
1385
+ variable,
1386
+ operator: '$in',
1387
+ operand,
1388
+ values,
1389
+ };
1390
+ }
1391
+ flattenOrExpressions(expression) {
1392
+ if (isOperationExpression(expression) && expression.operator.toLowerCase() === '||') {
1393
+ return expression.args.flatMap((arg) => this.flattenOrExpressions(this.expressionArg(arg)));
1394
+ }
1395
+ return [expression];
1396
+ }
1397
+ filterValueKey(value) {
1398
+ if (value && typeof value === 'object' && 'termType' in value) {
1399
+ return `term:${(0, n3_1.termToId)(value)}`;
1400
+ }
1401
+ return `${typeof value}:${String(value)}`;
1402
+ }
1403
+ compileBinaryFilter(operator, left, right) {
1404
+ const leftExpression = this.expressionArg(left);
1405
+ const rightExpression = this.expressionArg(right);
1406
+ const leftStringLengthVariable = this.stringLengthVariableOrUndefined(leftExpression);
1407
+ const rightStringLengthVariable = this.stringLengthVariableOrUndefined(rightExpression);
1408
+ if (leftStringLengthVariable && rightStringLengthVariable) {
1409
+ return {
1410
+ variable: leftStringLengthVariable,
1411
+ operator,
1412
+ operand: 'stringLength',
1413
+ variable2: rightStringLengthVariable,
1414
+ };
1415
+ }
1416
+ if (leftStringLengthVariable) {
1417
+ return {
1418
+ variable: leftStringLengthVariable,
1419
+ operator,
1420
+ operand: 'stringLength',
1421
+ value: this.filterValue(rightExpression),
1422
+ };
1423
+ }
1424
+ if (rightStringLengthVariable) {
1425
+ return {
1426
+ variable: rightStringLengthVariable,
1427
+ operator: this.reverseBinaryFilter(operator),
1428
+ operand: 'stringLength',
1429
+ value: this.filterValue(leftExpression),
1430
+ };
1431
+ }
1432
+ const leftFunction = this.compileFunctionComparisonFilter(operator, leftExpression, rightExpression);
1433
+ if (leftFunction) {
1434
+ return leftFunction;
1435
+ }
1436
+ const rightFunction = this.compileFunctionComparisonFilter(this.reverseBinaryFilter(operator), rightExpression, leftExpression);
1437
+ if (rightFunction) {
1438
+ return rightFunction;
1439
+ }
1440
+ const leftStringOperand = this.stringOperandVariableOrUndefined(leftExpression);
1441
+ const rightStringOperand = this.stringOperandVariableOrUndefined(rightExpression);
1442
+ if (leftStringOperand && rightStringOperand) {
1443
+ if (leftStringOperand.operand !== rightStringOperand.operand) {
1444
+ throw new UnsupportedSparqlQueryError('FILTER string expression comparison must use matching operands locally');
1445
+ }
1446
+ return {
1447
+ variable: leftStringOperand.variable,
1448
+ operator,
1449
+ operand: leftStringOperand.operand,
1450
+ variable2: rightStringOperand.variable,
1451
+ };
1452
+ }
1453
+ if (leftStringOperand) {
1454
+ return {
1455
+ variable: leftStringOperand.variable,
1456
+ operator,
1457
+ operand: leftStringOperand.operand,
1458
+ value: this.literalString(rightExpression),
1459
+ };
1460
+ }
1461
+ if (rightStringOperand) {
1462
+ return {
1463
+ variable: rightStringOperand.variable,
1464
+ operator: this.reverseBinaryFilter(operator),
1465
+ operand: rightStringOperand.operand,
1466
+ value: this.literalString(leftExpression),
1467
+ };
1468
+ }
1469
+ const leftVariable = this.expressionVariableOrUndefined(leftExpression);
1470
+ const rightVariable = this.expressionVariableOrUndefined(rightExpression);
1471
+ if (leftVariable && !rightVariable) {
1472
+ return {
1473
+ variable: leftVariable,
1474
+ operator,
1475
+ value: this.filterValue(rightExpression),
1476
+ };
1477
+ }
1478
+ if (leftVariable && rightVariable) {
1479
+ return {
1480
+ variable: leftVariable,
1481
+ operator,
1482
+ variable2: rightVariable,
1483
+ };
1484
+ }
1485
+ if (rightVariable && !leftVariable) {
1486
+ return {
1487
+ variable: rightVariable,
1488
+ operator: this.reverseBinaryFilter(operator),
1489
+ value: this.filterValue(leftExpression),
1490
+ };
1491
+ }
1492
+ throw new UnsupportedSparqlQueryError('FILTER comparison must compare one variable with one RDF term locally');
1493
+ }
1494
+ compileTermTestFilter(operator, expression) {
1495
+ switch (operator) {
1496
+ case 'isiri':
1497
+ case 'isuri':
1498
+ return {
1499
+ variable: this.expressionVariable(this.expressionArg(expression.args[0])),
1500
+ operator: '$termType',
1501
+ value: 'iri',
1502
+ };
1503
+ case 'isblank':
1504
+ return {
1505
+ variable: this.expressionVariable(this.expressionArg(expression.args[0])),
1506
+ operator: '$termType',
1507
+ value: 'blank',
1508
+ };
1509
+ case 'isliteral':
1510
+ return {
1511
+ variable: this.expressionVariable(this.expressionArg(expression.args[0])),
1512
+ operator: '$termType',
1513
+ value: 'literal',
1514
+ };
1515
+ case 'isnumeric':
1516
+ return {
1517
+ variable: this.expressionVariable(this.expressionArg(expression.args[0])),
1518
+ operator: '$termType',
1519
+ value: 'numeric',
1520
+ };
1521
+ case 'sameterm': {
1522
+ const leftExpression = this.expressionArg(expression.args[0]);
1523
+ const rightExpression = this.expressionArg(expression.args[1]);
1524
+ const leftVariable = this.expressionVariableOrUndefined(leftExpression);
1525
+ const rightVariable = this.expressionVariableOrUndefined(rightExpression);
1526
+ if (leftVariable && rightVariable) {
1527
+ return {
1528
+ variable: leftVariable,
1529
+ operator: '$sameTerm',
1530
+ variable2: rightVariable,
1531
+ };
1532
+ }
1533
+ if (leftVariable) {
1534
+ return {
1535
+ variable: leftVariable,
1536
+ operator: '$sameTerm',
1537
+ value: this.filterValue(rightExpression),
1538
+ };
1539
+ }
1540
+ if (rightVariable) {
1541
+ return {
1542
+ variable: rightVariable,
1543
+ operator: '$sameTerm',
1544
+ value: this.filterValue(leftExpression),
1545
+ };
1546
+ }
1547
+ throw new UnsupportedSparqlQueryError('sameTerm FILTER must compare at least one variable locally');
1548
+ }
1549
+ default:
1550
+ return null;
1551
+ }
1552
+ }
1553
+ compileFunctionComparisonFilter(operator, functionExpression, valueExpression) {
1554
+ if (operator !== '$eq' && operator !== '$ne') {
1555
+ return null;
1556
+ }
1557
+ if (!isOperationExpression(functionExpression)) {
1558
+ return null;
1559
+ }
1560
+ const functionOperator = functionExpression.operator.toLowerCase();
1561
+ if (functionOperator === 'lang') {
1562
+ return {
1563
+ variable: this.expressionVariable(this.expressionArg(functionExpression.args[0])),
1564
+ operator: operator === '$eq' ? '$lang' : '$notLang',
1565
+ value: this.literalString(valueExpression),
1566
+ };
1567
+ }
1568
+ if (functionOperator === 'datatype') {
1569
+ const value = this.filterValue(valueExpression);
1570
+ if (!isNamedNodeTerm(value)) {
1571
+ throw new UnsupportedSparqlQueryError('DATATYPE FILTER value must be an IRI locally');
1572
+ }
1573
+ return {
1574
+ variable: this.expressionVariable(this.expressionArg(functionExpression.args[0])),
1575
+ operator: operator === '$eq' ? '$datatype' : '$notDatatype',
1576
+ value,
1577
+ };
1578
+ }
1579
+ return null;
1580
+ }
1581
+ stringLengthVariableOrUndefined(expression) {
1582
+ const normalized = this.normalizeFunctionCallExpression(expression);
1583
+ if (!isOperationExpression(normalized) || normalized.operator.toLowerCase() !== 'strlen') {
1584
+ return undefined;
1585
+ }
1586
+ return this.stringOperandVariable(this.expressionArg(normalized.args[0])).variable;
1587
+ }
1588
+ stringValueVariableOrUndefined(expression) {
1589
+ const operand = this.stringOperandVariableOrUndefined(expression);
1590
+ return operand?.operand === 'stringValue' ? operand.variable : undefined;
1591
+ }
1592
+ stringOperandVariable(expression) {
1593
+ const stringOperand = this.stringOperandVariableOrUndefined(expression);
1594
+ if (stringOperand) {
1595
+ return stringOperand;
1596
+ }
1597
+ return {
1598
+ variable: this.expressionVariable(expression),
1599
+ };
1600
+ }
1601
+ stringOperandVariableOrUndefined(expression) {
1602
+ if (isStrOperation(expression)) {
1603
+ return {
1604
+ variable: this.expressionVariable(this.expressionArg(expression.args[0])),
1605
+ operand: 'stringValue',
1606
+ };
1607
+ }
1608
+ const normalized = this.normalizeFunctionCallExpression(expression);
1609
+ if (!isOperationExpression(normalized)) {
1610
+ return undefined;
1611
+ }
1612
+ const operator = normalized.operator.toLowerCase();
1613
+ if (operator !== 'lcase' && operator !== 'lower-case' && operator !== 'ucase' && operator !== 'upper-case') {
1614
+ return undefined;
1615
+ }
1616
+ const innerOperand = this.stringOperandVariableOrUndefined(this.expressionArg(normalized.args[0]));
1617
+ if (!innerOperand || innerOperand.operand !== 'stringValue') {
1618
+ return undefined;
1619
+ }
1620
+ return {
1621
+ variable: innerOperand.variable,
1622
+ operand: operator === 'lcase' || operator === 'lower-case' ? 'lowerStringValue' : 'upperStringValue',
1623
+ };
1624
+ }
1625
+ compileLangMatchesFilter(expression) {
1626
+ const langExpression = this.expressionArg(expression.args[0]);
1627
+ if (!isOperationExpression(langExpression) || langExpression.operator.toLowerCase() !== 'lang') {
1628
+ throw new UnsupportedSparqlQueryError('LANGMATCHES first argument must be LANG(?var) locally');
1629
+ }
1630
+ return {
1631
+ variable: this.expressionVariable(this.expressionArg(langExpression.args[0])),
1632
+ operator: '$langMatches',
1633
+ value: this.literalString(this.expressionArg(expression.args[1])),
1634
+ };
1635
+ }
1636
+ compileValuesRows(rows, state, optional = false) {
1637
+ if (rows.length === 0) {
1638
+ return;
1639
+ }
1640
+ const keys = unique(rows.flatMap((row) => Object.keys(row))).sort();
1641
+ if (keys.length === 0) {
1642
+ return;
1643
+ }
1644
+ const hasUnboundValues = rows.some((row) => keys.some((key) => !row[key]));
1645
+ if (!optional && keys.length === 1 && !hasUnboundValues) {
1646
+ const key = keys[0];
1647
+ state.query.filters?.push({
1648
+ variable: key.replace(/^\?/, ''),
1649
+ operator: '$in',
1650
+ values: rows.map((row) => this.filterValue(row[key])),
1651
+ source: 'values',
1652
+ });
1653
+ return;
1654
+ }
1655
+ const variables = keys.map((key) => key.replace(/^\?/, ''));
1656
+ state.addValuesSource({
1657
+ variables,
1658
+ rows: rows.map((row) => {
1659
+ const binding = {};
1660
+ keys.forEach((key, index) => {
1661
+ const expression = row[key];
1662
+ if (expression) {
1663
+ binding[variables[index]] = this.valuesTerm(expression);
1664
+ }
1665
+ });
1666
+ return binding;
1667
+ }),
1668
+ }, optional);
1669
+ }
1670
+ valuesTerm(expression) {
1671
+ const value = this.filterValue(expression);
1672
+ if (!isRdfJsTerm(value)) {
1673
+ throw new UnsupportedSparqlQueryError('VALUES rows must contain RDF terms locally');
1674
+ }
1675
+ return value;
1676
+ }
1677
+ compileNegatedFilter(expression) {
1678
+ if (!isOperationExpression(expression)) {
1679
+ throw new UnsupportedSparqlQueryError('Only safely negated FILTER operations are supported locally');
1680
+ }
1681
+ const operator = expression.operator.toLowerCase();
1682
+ if (operator === 'bound') {
1683
+ return [{
1684
+ variable: this.expressionVariable(this.expressionArg(expression.args[0])),
1685
+ operator: '$bound',
1686
+ value: false,
1687
+ }];
1688
+ }
1689
+ if (operator === '||') {
1690
+ const filter = this.compileOrFilter(expression);
1691
+ return [{
1692
+ ...filter,
1693
+ operator: '$notIn',
1694
+ }];
1695
+ }
1696
+ const binary = this.negatedBinaryFilter(operator);
1697
+ if (binary) {
1698
+ return [this.compileBinaryFilter(binary, expression.args[0], expression.args[1])];
1699
+ }
1700
+ if (operator === 'in' || operator === 'notin') {
1701
+ const values = expression.args[1];
1702
+ if (!Array.isArray(values)) {
1703
+ throw new UnsupportedSparqlQueryError('FILTER negated IN tuple fallback to compatibility engine');
1704
+ }
1705
+ const operand = this.stringOperandVariable(this.expressionArg(expression.args[0]));
1706
+ return [{
1707
+ variable: operand.variable,
1708
+ operator: operator === 'in' ? '$notIn' : '$in',
1709
+ operand: operand.operand,
1710
+ values: values.map((value) => this.filterValue(value)),
1711
+ }];
1712
+ }
1713
+ throw new UnsupportedSparqlQueryError(`FILTER !${operator} fallback to compatibility engine`);
1714
+ }
1715
+ expressionArg(value) {
1716
+ if (!value || value.type === 'bgp') {
1717
+ throw new UnsupportedSparqlQueryError('Unsupported FILTER argument');
1718
+ }
1719
+ return this.normalizeFunctionCallExpression(value);
1720
+ }
1721
+ expressionVariable(expression) {
1722
+ if (isVariableTerm(expression)) {
1723
+ return expression.value;
1724
+ }
1725
+ throw new UnsupportedSparqlQueryError('Only variable expressions are supported in this query position');
1726
+ }
1727
+ expressionVariableOrUndefined(expression) {
1728
+ return isVariableTerm(expression) ? expression.value : undefined;
1729
+ }
1730
+ filterValue(expression) {
1731
+ if (isRdfTermExpression(expression)) {
1732
+ return expression;
1733
+ }
1734
+ throw new UnsupportedSparqlQueryError('Only RDF term filter values are supported locally');
1735
+ }
1736
+ literalString(expression) {
1737
+ if (isLiteralTerm(expression)) {
1738
+ return expression.value;
1739
+ }
1740
+ throw new UnsupportedSparqlQueryError('String FILTER arguments must be literals');
1741
+ }
1742
+ binaryFilter(operator) {
1743
+ switch (operator) {
1744
+ case '=':
1745
+ return '$eq';
1746
+ case '!=':
1747
+ return '$ne';
1748
+ case '>':
1749
+ return '$gt';
1750
+ case '>=':
1751
+ return '$gte';
1752
+ case '<':
1753
+ return '$lt';
1754
+ case '<=':
1755
+ return '$lte';
1756
+ default:
1757
+ return null;
1758
+ }
1759
+ }
1760
+ reverseBinaryFilter(operator) {
1761
+ switch (operator) {
1762
+ case '$eq':
1763
+ case '$ne':
1764
+ return operator;
1765
+ case '$gt':
1766
+ return '$lt';
1767
+ case '$gte':
1768
+ return '$lte';
1769
+ case '$lt':
1770
+ return '$gt';
1771
+ case '$lte':
1772
+ return '$gte';
1773
+ default:
1774
+ throw new UnsupportedSparqlQueryError(`FILTER ${operator} cannot be reversed locally`);
1775
+ }
1776
+ }
1777
+ negatedBinaryFilter(operator) {
1778
+ switch (operator) {
1779
+ case '=':
1780
+ return '$ne';
1781
+ case '!=':
1782
+ return '$eq';
1783
+ case '>':
1784
+ return '$lte';
1785
+ case '>=':
1786
+ return '$lt';
1787
+ case '<':
1788
+ return '$gte';
1789
+ case '<=':
1790
+ return '$gt';
1791
+ default:
1792
+ return null;
1793
+ }
1794
+ }
1795
+ stringFilter(operator) {
1796
+ switch (operator) {
1797
+ case 'strstarts':
1798
+ return '$startsWith';
1799
+ case 'contains':
1800
+ return '$contains';
1801
+ case 'strends':
1802
+ return '$endsWith';
1803
+ case 'regex':
1804
+ return '$regex';
1805
+ default:
1806
+ return null;
1807
+ }
1808
+ }
1809
+ normalizeFunctionCallExpression(expression) {
1810
+ if (!isFunctionCallExpression(expression)) {
1811
+ return expression;
1812
+ }
1813
+ if (expression.distinct) {
1814
+ throw new UnsupportedSparqlQueryError('DISTINCT function calls fallback to compatibility engine');
1815
+ }
1816
+ const functionIri = typeof expression.function === 'string'
1817
+ ? expression.function
1818
+ : expression.function.value;
1819
+ const operator = this.xpathFunctionOperator(functionIri);
1820
+ if (!operator) {
1821
+ throw new UnsupportedSparqlQueryError(`Unsupported SPARQL function ${functionIri} fallback to compatibility engine`);
1822
+ }
1823
+ return {
1824
+ type: 'operation',
1825
+ operator,
1826
+ args: expression.args.map((arg) => (Array.isArray(arg)
1827
+ ? arg.map((item) => this.normalizeFunctionCallExpression(this.expressionArg(item)))
1828
+ : this.normalizeFunctionCallExpression(this.expressionArg(arg)))),
1829
+ };
1830
+ }
1831
+ xpathFunctionOperator(iri) {
1832
+ if (!iri.startsWith(XPATH_FUNCTION_NS)) {
1833
+ return null;
1834
+ }
1835
+ switch (iri.slice(XPATH_FUNCTION_NS.length).toLowerCase()) {
1836
+ case 'concat':
1837
+ return 'concat';
1838
+ case 'contains':
1839
+ return 'contains';
1840
+ case 'starts-with':
1841
+ return 'strstarts';
1842
+ case 'ends-with':
1843
+ return 'strends';
1844
+ case 'matches':
1845
+ return 'regex';
1846
+ case 'string-length':
1847
+ return 'strlen';
1848
+ case 'lower-case':
1849
+ return 'lcase';
1850
+ case 'upper-case':
1851
+ return 'ucase';
1852
+ case 'substring':
1853
+ return 'substring';
1854
+ case 'langmatches':
1855
+ return 'langmatches';
1856
+ default:
1857
+ return null;
1858
+ }
1859
+ }
1860
+ }
1861
+ exports.RdfSparqlAdapter = RdfSparqlAdapter;
1862
+ class CompileState {
1863
+ constructor(basePath, skipMinusSharedVariableCheck = false) {
1864
+ this.basePath = basePath;
1865
+ this.skipMinusSharedVariableCheck = skipMinusSharedVariableCheck;
1866
+ this.query = {
1867
+ patterns: [],
1868
+ unions: [],
1869
+ optional: [],
1870
+ filters: [],
1871
+ };
1872
+ this.optionalStack = [];
1873
+ this.pathJoinVariableIndex = 0;
1874
+ this.groupVariableIndex = 0;
1875
+ this.orderVariableIndex = 0;
1876
+ this.havingAggregateVariableIndex = 0;
1877
+ }
1878
+ addPattern(pattern, optional) {
1879
+ if (optional) {
1880
+ this.currentOptionalFrame().patterns.push(this.scopePattern(pattern));
1881
+ return;
1882
+ }
1883
+ this.query.patterns.push(this.scopePattern(pattern));
1884
+ }
1885
+ addImpossibleGraphPattern(optional) {
1886
+ const impossible = n3_1.DataFactory.namedNode(`${this.basePath}__outside_graph_scope__`);
1887
+ this.addPattern({ graph: impossible }, optional);
1888
+ }
1889
+ startOptional() {
1890
+ this.optionalStack.push({
1891
+ patterns: [],
1892
+ filters: [],
1893
+ binds: [],
1894
+ unions: [],
1895
+ values: [],
1896
+ optional: [],
1897
+ minus: [],
1898
+ exists: [],
1899
+ });
1900
+ }
1901
+ finishOptional() {
1902
+ const frame = this.optionalStack.pop();
1903
+ if (!frame) {
1904
+ throw new UnsupportedSparqlQueryError('OPTIONAL scope fallback to compatibility engine');
1905
+ }
1906
+ if (frame.patterns.length > 0
1907
+ || frame.filters.length > 0
1908
+ || frame.binds.length > 0
1909
+ || frame.unions.length > 0
1910
+ || frame.values.length > 0
1911
+ || frame.optional.length > 0
1912
+ || frame.minus.length > 0
1913
+ || frame.exists.length > 0) {
1914
+ const optionalGroup = {
1915
+ patterns: frame.patterns,
1916
+ ...(frame.values.length ? { values: frame.values } : {}),
1917
+ ...(frame.unions.length ? { unions: frame.unions } : {}),
1918
+ ...(frame.optional.length ? { optional: frame.optional } : {}),
1919
+ ...(frame.minus.length ? { minus: frame.minus } : {}),
1920
+ ...(frame.exists.length ? { exists: frame.exists } : {}),
1921
+ ...(frame.binds.length ? { binds: frame.binds } : {}),
1922
+ ...(frame.filters.length > 0 ? { filters: frame.filters } : {}),
1923
+ };
1924
+ const parent = this.peekOptionalFrame();
1925
+ if (parent) {
1926
+ parent.optional.push(optionalGroup);
1927
+ }
1928
+ else {
1929
+ this.query.optional?.push(optionalGroup);
1930
+ }
1931
+ }
1932
+ }
1933
+ addOptionalFilters(filters) {
1934
+ this.currentOptionalFrame().filters.push(...filters);
1935
+ }
1936
+ addBind(bind, optional) {
1937
+ if (optional) {
1938
+ this.currentOptionalFrame().binds.push(bind);
1939
+ return;
1940
+ }
1941
+ this.query.binds ??= [];
1942
+ this.query.binds.push(bind);
1943
+ }
1944
+ addOptionalUnion(branches) {
1945
+ this.currentOptionalFrame().unions.push({ branches });
1946
+ }
1947
+ addUnion(branches) {
1948
+ this.query.unions?.push({ branches });
1949
+ }
1950
+ addOptionalMinus(group) {
1951
+ this.currentOptionalFrame().minus.push(group);
1952
+ }
1953
+ addMinus(group) {
1954
+ this.query.minus ??= [];
1955
+ this.query.minus.push(group);
1956
+ }
1957
+ addOptionalExists(group) {
1958
+ this.currentOptionalFrame().exists.push(group);
1959
+ }
1960
+ addExists(group) {
1961
+ this.query.exists ??= [];
1962
+ this.query.exists.push(group);
1963
+ }
1964
+ addValuesSource(source, optional) {
1965
+ if (optional) {
1966
+ this.currentOptionalFrame().values.push(source);
1967
+ return;
1968
+ }
1969
+ this.query.values ??= [];
1970
+ this.query.values.push(source);
1971
+ }
1972
+ nextPathJoinVariable() {
1973
+ this.pathJoinVariableIndex += 1;
1974
+ return (0, RdfLocalQueryEngine_1.variable)(`${PATH_JOIN_VARIABLE_PREFIX}_${this.pathJoinVariableIndex}`);
1975
+ }
1976
+ nextGroupVariable(index) {
1977
+ this.groupVariableIndex += 1;
1978
+ return `__rdf_group_${index}_${this.groupVariableIndex}`;
1979
+ }
1980
+ nextOrderVariable(index) {
1981
+ this.orderVariableIndex += 1;
1982
+ return `__rdf_order_${index}_${this.orderVariableIndex}`;
1983
+ }
1984
+ nextHavingAggregateVariable() {
1985
+ this.havingAggregateVariableIndex += 1;
1986
+ return `__rdf_having_aggregate_${this.havingAggregateVariableIndex}`;
1987
+ }
1988
+ assertValuesVariablesBoundByRequiredPatterns() {
1989
+ for (const source of this.query.values ?? []) {
1990
+ for (const variable of source.variables) {
1991
+ if (!this.isVariableBoundByRequiredShape(variable)) {
1992
+ throw new UnsupportedSparqlQueryError('VALUES must constrain a variable from every required embedded query branch');
1993
+ }
1994
+ }
1995
+ }
1996
+ for (const filter of this.query.filters ?? []) {
1997
+ if (filter.operator !== '$in' || filter.source !== 'values') {
1998
+ continue;
1999
+ }
2000
+ if (!this.isVariableBoundByRequiredShape(filter.variable)) {
2001
+ throw new UnsupportedSparqlQueryError('VALUES must constrain a variable from every required embedded query branch');
2002
+ }
2003
+ }
2004
+ }
2005
+ assertBindVariablesSafe() {
2006
+ const bound = new Set();
2007
+ for (const variableName of variablesInPatterns(this.query.patterns)) {
2008
+ bound.add(variableName);
2009
+ }
2010
+ for (const unionGroup of this.query.unions ?? []) {
2011
+ for (const branch of unionGroup.branches) {
2012
+ for (const variableName of variablesInPatterns(branch.patterns)) {
2013
+ bound.add(variableName);
2014
+ }
2015
+ for (const bind of branch.binds ?? []) {
2016
+ for (const dependency of variablesInBindExpression(bind.expression)) {
2017
+ if (!bound.has(dependency)) {
2018
+ throw new UnsupportedSparqlQueryError('BIND dependency must be bound before use locally');
2019
+ }
2020
+ }
2021
+ bound.add(bind.variable);
2022
+ }
2023
+ }
2024
+ }
2025
+ for (const bind of this.query.binds ?? []) {
2026
+ for (const dependency of variablesInBindExpression(bind.expression)) {
2027
+ if (!bound.has(dependency)) {
2028
+ throw new UnsupportedSparqlQueryError('BIND dependency must be bound before use locally');
2029
+ }
2030
+ }
2031
+ bound.add(bind.variable);
2032
+ }
2033
+ for (const rawOptionalGroup of this.query.optional ?? []) {
2034
+ assertOptionalBindVariablesSafe(rawOptionalGroup, bound);
2035
+ }
2036
+ }
2037
+ assertDependentGroupsShareRequiredVariables() {
2038
+ if (this.skipMinusSharedVariableCheck) {
2039
+ return;
2040
+ }
2041
+ for (const minusGroup of this.query.minus ?? []) {
2042
+ const shared = variablesInDependentGroup(minusGroup)
2043
+ .some((variableName) => queryBindsVariableInRequiredShape(this.query, variableName));
2044
+ if (!shared) {
2045
+ throw new UnsupportedSparqlQueryError('MINUS must share a required query variable locally');
2046
+ }
2047
+ }
2048
+ for (const existsGroup of this.query.exists ?? []) {
2049
+ const shared = variablesInDependentGroup(existsGroup)
2050
+ .some((variableName) => queryBindsVariableInRequiredShape(this.query, variableName));
2051
+ if (!shared) {
2052
+ throw new UnsupportedSparqlQueryError('FILTER EXISTS must share a required query variable locally');
2053
+ }
2054
+ }
2055
+ const requiredBound = variablesBoundByRequiredShape(this.query);
2056
+ for (const optionalGroup of this.query.optional ?? []) {
2057
+ assertOptionalDependentGroupsShareVariables(normalizeOptionalGroupForAdapter(optionalGroup), requiredBound);
2058
+ }
2059
+ }
2060
+ isVariableBoundByRequiredShape(variableName) {
2061
+ return queryBindsVariableInRequiredShape(this.query, variableName);
2062
+ }
2063
+ scopePattern(pattern) {
2064
+ return pattern.graph ? pattern : { ...pattern, graph: { $startsWith: this.basePath } };
2065
+ }
2066
+ currentOptionalFrame() {
2067
+ const frame = this.peekOptionalFrame();
2068
+ if (!frame) {
2069
+ throw new UnsupportedSparqlQueryError('OPTIONAL scope fallback to compatibility engine');
2070
+ }
2071
+ return frame;
2072
+ }
2073
+ peekOptionalFrame() {
2074
+ return this.optionalStack[this.optionalStack.length - 1];
2075
+ }
2076
+ }
2077
+ function isVariableTerm(value) {
2078
+ return Boolean(value && 'termType' in value && value.termType === 'Variable');
2079
+ }
2080
+ function isSelectVariableTerm(value) {
2081
+ return Boolean(value && 'termType' in value && value.termType === 'Variable');
2082
+ }
2083
+ function isVariableExpression(value) {
2084
+ return Boolean(value && 'expression' in value && 'variable' in value);
2085
+ }
2086
+ function isVariableExpressionTerm(value) {
2087
+ return Boolean(value && 'termType' in value && value.termType === 'Variable');
2088
+ }
2089
+ function isOperationExpression(value) {
2090
+ return Boolean(value && 'type' in value && value.type === 'operation');
2091
+ }
2092
+ function isStrOperation(value) {
2093
+ return isOperationExpression(value) && value.operator.toLowerCase() === 'str';
2094
+ }
2095
+ function isFunctionCallExpression(value) {
2096
+ return Boolean(value && 'type' in value && value.type === 'functionCall');
2097
+ }
2098
+ function isAggregateExpression(value) {
2099
+ return Boolean(value && 'type' in value && value.type === 'aggregate');
2100
+ }
2101
+ function isLiteralTerm(value) {
2102
+ return Boolean(value && 'termType' in value && value.termType === 'Literal');
2103
+ }
2104
+ function isWildcardTerm(value) {
2105
+ return value instanceof sparqljs_1.Wildcard;
2106
+ }
2107
+ function isRdfTermExpression(value) {
2108
+ return Boolean(value && 'termType' in value && value.termType !== 'Quad');
2109
+ }
2110
+ function isNamedNodeTerm(value) {
2111
+ return Boolean(value && typeof value === 'object' && 'termType' in value && value.termType === 'NamedNode');
2112
+ }
2113
+ function isRdfJsTerm(value) {
2114
+ return Boolean(value && typeof value === 'object' && 'termType' in value);
2115
+ }
2116
+ function isSimpleTerm(value) {
2117
+ return Boolean(value && 'termType' in value);
2118
+ }
2119
+ function visibleSelectVariables(query) {
2120
+ const variables = new Set();
2121
+ for (const pattern of query.where ?? []) {
2122
+ collectPatternVariables(pattern, variables);
2123
+ }
2124
+ for (const row of query.values ?? []) {
2125
+ for (const key of Object.keys(row)) {
2126
+ variables.add(key.replace(/^\?/, ''));
2127
+ }
2128
+ }
2129
+ return [...variables];
2130
+ }
2131
+ function collectPatternVariables(pattern, variables) {
2132
+ switch (pattern.type) {
2133
+ case 'bgp':
2134
+ for (const triple of pattern.triples) {
2135
+ collectTripleVariables(triple, variables);
2136
+ }
2137
+ break;
2138
+ case 'graph':
2139
+ if (pattern.name.termType === 'Variable') {
2140
+ variables.add(pattern.name.value);
2141
+ }
2142
+ for (const child of pattern.patterns) {
2143
+ collectPatternVariables(child, variables);
2144
+ }
2145
+ break;
2146
+ case 'optional':
2147
+ case 'group':
2148
+ case 'union':
2149
+ case 'minus':
2150
+ case 'service':
2151
+ for (const child of pattern.patterns) {
2152
+ collectPatternVariables(child, variables);
2153
+ }
2154
+ break;
2155
+ case 'filter':
2156
+ collectExpressionVariables(pattern.expression, variables);
2157
+ break;
2158
+ case 'bind':
2159
+ collectExpressionVariables(pattern.expression, variables);
2160
+ variables.add(pattern.variable.value);
2161
+ break;
2162
+ case 'values':
2163
+ for (const row of pattern.values) {
2164
+ for (const key of Object.keys(row)) {
2165
+ variables.add(key.replace(/^\?/, ''));
2166
+ }
2167
+ }
2168
+ break;
2169
+ default:
2170
+ if ('queryType' in pattern) {
2171
+ for (const child of pattern.where ?? []) {
2172
+ collectPatternVariables(child, variables);
2173
+ }
2174
+ }
2175
+ break;
2176
+ }
2177
+ }
2178
+ function collectTripleVariables(triple, variables) {
2179
+ collectTermVariables(triple.subject, variables);
2180
+ if (isSimpleTerm(triple.predicate)) {
2181
+ collectTermVariables(triple.predicate, variables);
2182
+ }
2183
+ else {
2184
+ collectPathVariables(triple.predicate, variables);
2185
+ }
2186
+ collectTermVariables(triple.object, variables);
2187
+ }
2188
+ function collectPathVariables(path, variables) {
2189
+ for (const item of path.items) {
2190
+ if (isSimpleTerm(item)) {
2191
+ collectTermVariables(item, variables);
2192
+ }
2193
+ else {
2194
+ collectPathVariables(item, variables);
2195
+ }
2196
+ }
2197
+ }
2198
+ function collectExpressionVariables(expression, variables) {
2199
+ if (isVariableTerm(expression)) {
2200
+ variables.add(expression.value);
2201
+ return;
2202
+ }
2203
+ if (!expression || typeof expression !== 'object' || !('type' in expression)) {
2204
+ return;
2205
+ }
2206
+ if (isOperationExpression(expression) || isFunctionCallExpression(expression)) {
2207
+ for (const arg of expression.args) {
2208
+ if (Array.isArray(arg)) {
2209
+ for (const item of arg) {
2210
+ collectExpressionVariables(item, variables);
2211
+ }
2212
+ }
2213
+ else if (arg && !isPattern(arg)) {
2214
+ collectExpressionVariables(arg, variables);
2215
+ }
2216
+ }
2217
+ return;
2218
+ }
2219
+ if (isAggregateExpression(expression) && !isWildcardTerm(expression.expression)) {
2220
+ collectExpressionVariables(expression.expression, variables);
2221
+ }
2222
+ }
2223
+ function collectTermVariables(term, variables) {
2224
+ if (term.termType === 'Variable') {
2225
+ variables.add(term.value);
2226
+ }
2227
+ }
2228
+ function isPattern(value) {
2229
+ return Boolean(value
2230
+ && typeof value === 'object'
2231
+ && 'type' in value
2232
+ && [
2233
+ 'bgp',
2234
+ 'optional',
2235
+ 'union',
2236
+ 'group',
2237
+ 'graph',
2238
+ 'minus',
2239
+ 'service',
2240
+ 'filter',
2241
+ 'bind',
2242
+ 'values',
2243
+ 'query',
2244
+ ].includes(value.type));
2245
+ }
2246
+ function isCompiledVariable(value) {
2247
+ return Boolean(value && typeof value === 'object' && 'variable' in value);
2248
+ }
2249
+ function unique(values) {
2250
+ return [...new Set(values)];
2251
+ }
2252
+ function uniqueTerms(values) {
2253
+ const seen = new Set();
2254
+ return values.filter((value) => {
2255
+ const key = (0, n3_1.termToId)(value);
2256
+ if (seen.has(key)) {
2257
+ return false;
2258
+ }
2259
+ seen.add(key);
2260
+ return true;
2261
+ });
2262
+ }
2263
+ function variablesInPattern(pattern) {
2264
+ const values = [pattern.graph, pattern.subject, pattern.predicate, pattern.object];
2265
+ return values
2266
+ .filter((value) => Boolean(value && typeof value === 'object' && 'variable' in value))
2267
+ .map((value) => value.variable);
2268
+ }
2269
+ function patternsBindVariable(patterns, variableName) {
2270
+ return patterns.some((pattern) => variablesInPattern(pattern).includes(variableName));
2271
+ }
2272
+ function variablesInPatterns(patterns) {
2273
+ return unique(patterns.flatMap((pattern) => variablesInPattern(pattern)));
2274
+ }
2275
+ function variablesBoundByOptionalGroup(optionalGroup) {
2276
+ return unique([
2277
+ ...variablesInPatterns(optionalGroup.patterns),
2278
+ ...variablesInValuesSources(optionalGroup.values ?? []),
2279
+ ...variablesInUnionGroups(optionalGroup.unions ?? []),
2280
+ ...((optionalGroup.binds ?? []).map((bind) => bind.variable)),
2281
+ ]);
2282
+ }
2283
+ function variablesInUnionGroups(unions) {
2284
+ return unique(unions.flatMap((unionGroup) => (unionGroup.branches.flatMap((branch) => [
2285
+ ...variablesInPatterns(branch.patterns),
2286
+ ...variablesInValuesSources(branch.values ?? []),
2287
+ ...((branch.binds ?? []).map((bind) => bind.variable)),
2288
+ ]))));
2289
+ }
2290
+ function variablesBoundByRequiredShape(query) {
2291
+ return new Set([
2292
+ ...variablesInPatterns(query.patterns),
2293
+ ...variablesInValuesSources(query.values ?? []),
2294
+ ...variablesInUnionGroups(query.unions ?? []),
2295
+ ...((query.binds ?? []).map((bind) => bind.variable)),
2296
+ ]);
2297
+ }
2298
+ function hasNumericGuard(filters, variableName) {
2299
+ return filters.some((filter) => (filter.variable === variableName
2300
+ && filter.operator === '$termType'
2301
+ && filter.value === 'numeric'));
2302
+ }
2303
+ function variablesInDependentGroup(group) {
2304
+ return unique([
2305
+ ...variablesInPatterns(group.patterns),
2306
+ ...variablesInValuesSources(group.values ?? []),
2307
+ ...variablesInUnionGroups(group.unions ?? []),
2308
+ ...((group.binds ?? []).map((bind) => bind.variable)),
2309
+ ...variablesBoundByNestedOptionalGroups(group.optional ?? []),
2310
+ ]);
2311
+ }
2312
+ function variablesBoundByNestedOptionalGroups(groups) {
2313
+ return unique(groups.flatMap((group) => variablesBoundByOptionalGroup(normalizeOptionalGroupForAdapter(group))));
2314
+ }
2315
+ function variablesInValuesSources(sources) {
2316
+ return unique(sources.flatMap((source) => source.variables));
2317
+ }
2318
+ function variablesInBindExpression(expression) {
2319
+ switch (expression.type) {
2320
+ case 'term':
2321
+ return [];
2322
+ case 'variable':
2323
+ case 'stringValue':
2324
+ case 'stringLength':
2325
+ return [expression.variable];
2326
+ case 'lowerCase':
2327
+ case 'upperCase':
2328
+ return variablesInBindExpression(expression.expression);
2329
+ case 'substring':
2330
+ return unique([
2331
+ ...variablesInBindExpression(expression.expression),
2332
+ ...variablesInBindExpression(expression.start),
2333
+ ...(expression.length ? variablesInBindExpression(expression.length) : []),
2334
+ ]);
2335
+ case 'concat':
2336
+ return unique(expression.expressions.flatMap((item) => variablesInBindExpression(item)));
2337
+ case 'iri':
2338
+ return variablesInBindExpression(expression.expression);
2339
+ default: {
2340
+ const exhaustive = expression;
2341
+ return exhaustive;
2342
+ }
2343
+ }
2344
+ }
2345
+ function assertOptionalBindVariablesSafe(rawOptionalGroup, outerBound) {
2346
+ const optionalGroup = normalizeOptionalGroupForAdapter(rawOptionalGroup);
2347
+ const optionalBound = new Set(outerBound);
2348
+ for (const variableName of variablesInPatterns(optionalGroup.patterns)) {
2349
+ optionalBound.add(variableName);
2350
+ }
2351
+ for (const variableName of variablesInValuesSources(optionalGroup.values ?? [])) {
2352
+ optionalBound.add(variableName);
2353
+ }
2354
+ for (const unionGroup of optionalGroup.unions ?? []) {
2355
+ for (const branch of unionGroup.branches) {
2356
+ const branchBound = new Set(optionalBound);
2357
+ for (const variableName of variablesInPatterns(branch.patterns)) {
2358
+ branchBound.add(variableName);
2359
+ }
2360
+ for (const variableName of variablesInValuesSources(branch.values ?? [])) {
2361
+ branchBound.add(variableName);
2362
+ }
2363
+ for (const bind of branch.binds ?? []) {
2364
+ assertBindDependenciesBound(bind, branchBound);
2365
+ branchBound.add(bind.variable);
2366
+ }
2367
+ for (const variableName of branchBound) {
2368
+ optionalBound.add(variableName);
2369
+ }
2370
+ }
2371
+ }
2372
+ for (const bind of optionalGroup.binds ?? []) {
2373
+ assertBindDependenciesBound(bind, optionalBound);
2374
+ optionalBound.add(bind.variable);
2375
+ }
2376
+ for (const nestedOptionalGroup of optionalGroup.optional ?? []) {
2377
+ assertOptionalBindVariablesSafe(nestedOptionalGroup, optionalBound);
2378
+ }
2379
+ }
2380
+ function assertOptionalDependentGroupsShareVariables(optionalGroup, outerBound = new Set()) {
2381
+ const bound = new Set(outerBound);
2382
+ for (const variableName of variablesBoundByOptionalGroup(optionalGroup)) {
2383
+ bound.add(variableName);
2384
+ }
2385
+ for (const minusGroup of optionalGroup.minus ?? []) {
2386
+ const shared = variablesInDependentGroup(minusGroup).some((variableName) => bound.has(variableName));
2387
+ if (!shared) {
2388
+ throw new UnsupportedSparqlQueryError('OPTIONAL MINUS must share a locally bound optional variable');
2389
+ }
2390
+ }
2391
+ for (const existsGroup of optionalGroup.exists ?? []) {
2392
+ const shared = variablesInDependentGroup(existsGroup).some((variableName) => bound.has(variableName));
2393
+ if (!shared) {
2394
+ throw new UnsupportedSparqlQueryError('OPTIONAL FILTER EXISTS must share a locally bound optional variable');
2395
+ }
2396
+ }
2397
+ for (const nestedOptionalGroup of optionalGroup.optional ?? []) {
2398
+ assertOptionalDependentGroupsShareVariables(normalizeOptionalGroupForAdapter(nestedOptionalGroup), bound);
2399
+ }
2400
+ }
2401
+ function assertBindDependenciesBound(bind, bound) {
2402
+ for (const dependency of variablesInBindExpression(bind.expression)) {
2403
+ if (!bound.has(dependency)) {
2404
+ throw new UnsupportedSparqlQueryError('OPTIONAL BIND dependency must be bound before use locally');
2405
+ }
2406
+ }
2407
+ }
2408
+ function queryBindsVariableInRequiredShape(query, variableName) {
2409
+ if (patternsBindVariable(query.patterns, variableName)) {
2410
+ return true;
2411
+ }
2412
+ if ((query.unions?.length ?? 0) === 0) {
2413
+ return false;
2414
+ }
2415
+ return (query.unions ?? []).every((group) => (group.branches.every((branch) => patternsBindVariable(branch.patterns, variableName))));
2416
+ }
2417
+ function normalizeOptionalGroupForAdapter(group) {
2418
+ return Array.isArray(group) ? { patterns: group } : group;
2419
+ }
2420
+ //# sourceMappingURL=RdfSparqlAdapter.js.map