@undefineds.co/xpod 0.3.18 → 0.3.22

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 (99) hide show
  1. package/config/bun.json +57 -11
  2. package/config/cloud.json +14 -12
  3. package/config/local.json +16 -14
  4. package/config/xpod.json +47 -9
  5. package/dist/api/matrix/PodMatrixStore.d.ts +4 -7
  6. package/dist/api/matrix/PodMatrixStore.js +116 -148
  7. package/dist/api/matrix/PodMatrixStore.js.map +1 -1
  8. package/dist/api/matrix/types.d.ts +2 -0
  9. package/dist/api/matrix/types.js.map +1 -1
  10. package/dist/components/components.jsonld +3 -0
  11. package/dist/components/context.jsonld +71 -32
  12. package/dist/http/SubgraphSparqlHttpHandler.d.ts +1 -0
  13. package/dist/http/SubgraphSparqlHttpHandler.js +27 -4
  14. package/dist/http/SubgraphSparqlHttpHandler.js.map +1 -1
  15. package/dist/http/SubgraphSparqlHttpHandler.jsonld +4 -0
  16. package/dist/http/vector/VectorHttpHandler.d.ts +5 -1
  17. package/dist/http/vector/VectorHttpHandler.js +5 -5
  18. package/dist/http/vector/VectorHttpHandler.js.map +1 -1
  19. package/dist/http/vector/VectorHttpHandler.jsonld +40 -28
  20. package/dist/index.d.ts +5 -2
  21. package/dist/index.js +9 -4
  22. package/dist/index.js.map +1 -1
  23. package/dist/runtime/Proxy.d.ts +3 -0
  24. package/dist/runtime/Proxy.js +31 -7
  25. package/dist/runtime/Proxy.js.map +1 -1
  26. package/dist/storage/SparqlUpdateResourceStore.js +94 -33
  27. package/dist/storage/SparqlUpdateResourceStore.js.map +1 -1
  28. package/dist/storage/accessors/MixDataAccessor.d.ts +22 -5
  29. package/dist/storage/accessors/MixDataAccessor.js +376 -61
  30. package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
  31. package/dist/storage/accessors/MixDataAccessor.jsonld +73 -5
  32. package/dist/storage/accessors/QuadstoreSparqlDataAccessor.js +32 -10
  33. package/dist/storage/accessors/QuadstoreSparqlDataAccessor.js.map +1 -1
  34. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js +28 -6
  35. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js.map +1 -1
  36. package/dist/storage/accessors/SolidRdfDataAccessor.d.ts +45 -0
  37. package/dist/storage/accessors/SolidRdfDataAccessor.js +277 -0
  38. package/dist/storage/accessors/SolidRdfDataAccessor.js.map +1 -0
  39. package/dist/storage/accessors/SolidRdfDataAccessor.jsonld +161 -0
  40. package/dist/storage/rdf/Rdf3xIndex.d.ts +122 -0
  41. package/dist/storage/rdf/Rdf3xIndex.js +2695 -0
  42. package/dist/storage/rdf/Rdf3xIndex.js.map +1 -0
  43. package/dist/storage/rdf/Rdf3xIndex.jsonld +528 -0
  44. package/dist/storage/rdf/Rdf3xSchema.d.ts +20 -0
  45. package/dist/storage/rdf/Rdf3xSchema.js +65 -0
  46. package/dist/storage/rdf/Rdf3xSchema.js.map +1 -0
  47. package/dist/storage/rdf/RdfLocalQueryEngine.d.ts +10 -4
  48. package/dist/storage/rdf/RdfLocalQueryEngine.js +607 -127
  49. package/dist/storage/rdf/RdfLocalQueryEngine.js.map +1 -1
  50. package/dist/storage/rdf/RdfQuadIndex.d.ts +12 -1
  51. package/dist/storage/rdf/RdfQuadIndex.js +152 -22
  52. package/dist/storage/rdf/RdfQuadIndex.js.map +1 -1
  53. package/dist/storage/rdf/RdfQuadIndex.jsonld +36 -4
  54. package/dist/storage/rdf/RdfSparqlAdapter.d.ts +20 -2
  55. package/dist/storage/rdf/RdfSparqlAdapter.js +364 -40
  56. package/dist/storage/rdf/RdfSparqlAdapter.js.map +1 -1
  57. package/dist/storage/rdf/RdfSparqlAdapter.jsonld +60 -0
  58. package/dist/storage/rdf/RdfTermDictionary.d.ts +8 -0
  59. package/dist/storage/rdf/RdfTermDictionary.js +141 -70
  60. package/dist/storage/rdf/RdfTermDictionary.js.map +1 -1
  61. package/dist/storage/rdf/RdfTermDictionary.jsonld +24 -0
  62. package/dist/storage/rdf/RdfTextIndex.js +10 -3
  63. package/dist/storage/rdf/RdfTextIndex.js.map +1 -1
  64. package/dist/storage/rdf/SolidRdfEngine.d.ts +15 -6
  65. package/dist/storage/rdf/SolidRdfEngine.js +218 -25
  66. package/dist/storage/rdf/SolidRdfEngine.js.map +1 -1
  67. package/dist/storage/rdf/SolidRdfEngine.jsonld +70 -7
  68. package/dist/storage/rdf/SolidRdfSparqlEngine.d.ts +11 -7
  69. package/dist/storage/rdf/SolidRdfSparqlEngine.js +60 -47
  70. package/dist/storage/rdf/SolidRdfSparqlEngine.js.map +1 -1
  71. package/dist/storage/rdf/SolidRdfSparqlEngine.jsonld +9 -5
  72. package/dist/storage/rdf/index.d.ts +2 -2
  73. package/dist/storage/rdf/index.js +3 -3
  74. package/dist/storage/rdf/index.js.map +1 -1
  75. package/dist/storage/rdf/models-benchmark.d.ts +12 -1
  76. package/dist/storage/rdf/models-benchmark.js +549 -32
  77. package/dist/storage/rdf/models-benchmark.js.map +1 -1
  78. package/dist/storage/rdf/types.d.ts +81 -7
  79. package/dist/storage/rdf/types.js.map +1 -1
  80. package/dist/storage/sparql/CompatibilitySparqlEngine.d.ts +36 -0
  81. package/dist/storage/sparql/CompatibilitySparqlEngine.js +96 -0
  82. package/dist/storage/sparql/CompatibilitySparqlEngine.js.map +1 -0
  83. package/dist/storage/sparql/CompatibilitySparqlEngine.jsonld +123 -0
  84. package/dist/storage/sparql/CompatibilitySparqlEngineImpl.d.ts +35 -0
  85. package/dist/storage/sparql/CompatibilitySparqlEngineImpl.js +112 -0
  86. package/dist/storage/sparql/CompatibilitySparqlEngineImpl.js.map +1 -0
  87. package/dist/storage/sparql/SubgraphQueryEngine.d.ts +1 -36
  88. package/dist/storage/sparql/SubgraphQueryEngine.js +2 -115
  89. package/dist/storage/sparql/SubgraphQueryEngine.js.map +1 -1
  90. package/dist/storage/sparql/SubgraphQueryEngine.jsonld +1 -124
  91. package/dist/terminal/AclPermissionService.d.ts +2 -1
  92. package/dist/terminal/AclPermissionService.js +26 -3
  93. package/dist/terminal/AclPermissionService.js.map +1 -1
  94. package/dist/terminal/TerminalSessionManager.js +25 -3
  95. package/dist/terminal/TerminalSessionManager.js.map +1 -1
  96. package/package.json +1 -1
  97. package/dist/storage/rdf/Rdf3xTripleIndex.d.ts +0 -55
  98. package/dist/storage/rdf/Rdf3xTripleIndex.js +0 -1235
  99. package/dist/storage/rdf/Rdf3xTripleIndex.js.map +0 -1
@@ -67,6 +67,10 @@
67
67
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_compileQueryDatasetScope",
68
68
  "memberFieldName": "compileQueryDatasetScope"
69
69
  },
70
+ {
71
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_compileImplicitQueryDefaultGraph",
72
+ "memberFieldName": "compileImplicitQueryDefaultGraph"
73
+ },
70
74
  {
71
75
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_compileQueryDatasetGraphs",
72
76
  "memberFieldName": "compileQueryDatasetGraphs"
@@ -95,6 +99,26 @@
95
99
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_compileGraphQuadsTemplate",
96
100
  "memberFieldName": "compileGraphQuadsTemplate"
97
101
  },
102
+ {
103
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_safeUpdateTemplateGraphVariables",
104
+ "memberFieldName": "safeUpdateTemplateGraphVariables"
105
+ },
106
+ {
107
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_collectQueryGraphVariables",
108
+ "memberFieldName": "collectQueryGraphVariables"
109
+ },
110
+ {
111
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_collectFiniteGraphFilterVariables",
112
+ "memberFieldName": "collectFiniteGraphFilterVariables"
113
+ },
114
+ {
115
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_isNamedNodeFilterValue",
116
+ "memberFieldName": "isNamedNodeFilterValue"
117
+ },
118
+ {
119
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_updateTemplateTriples",
120
+ "memberFieldName": "updateTemplateTriples"
121
+ },
98
122
  {
99
123
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_assertSafeUpdateTemplatePattern",
100
124
  "memberFieldName": "assertSafeUpdateTemplatePattern"
@@ -103,10 +127,34 @@
103
127
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_assertScopedUpdateWherePatterns",
104
128
  "memberFieldName": "assertScopedUpdateWherePatterns"
105
129
  },
130
+ {
131
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_assertFiniteUpdateGraphVariables",
132
+ "memberFieldName": "assertFiniteUpdateGraphVariables"
133
+ },
134
+ {
135
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_collectUnboundedUpdateGraphVariables",
136
+ "memberFieldName": "collectUnboundedUpdateGraphVariables"
137
+ },
138
+ {
139
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_collectFiniteGraphFilterVariablesFromFilters",
140
+ "memberFieldName": "collectFiniteGraphFilterVariablesFromFilters"
141
+ },
142
+ {
143
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_isBasePathNamedNodeFilterValue",
144
+ "memberFieldName": "isBasePathNamedNodeFilterValue"
145
+ },
146
+ {
147
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_collectFiniteGraphValueVariables",
148
+ "memberFieldName": "collectFiniteGraphValueVariables"
149
+ },
106
150
  {
107
151
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_compileUpdateGraphQuads",
108
152
  "memberFieldName": "compileUpdateGraphQuads"
109
153
  },
154
+ {
155
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_compileUpdateDefaultGraph",
156
+ "memberFieldName": "compileUpdateDefaultGraph"
157
+ },
110
158
  {
111
159
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_compileUpdateTriple",
112
160
  "memberFieldName": "compileUpdateTriple"
@@ -331,6 +379,10 @@
331
379
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_compileFunctionComparisonFilter",
332
380
  "memberFieldName": "compileFunctionComparisonFilter"
333
381
  },
382
+ {
383
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_compileFunctionInFilter",
384
+ "memberFieldName": "compileFunctionInFilter"
385
+ },
334
386
  {
335
387
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_stringLengthVariableOrUndefined",
336
388
  "memberFieldName": "stringLengthVariableOrUndefined"
@@ -399,6 +451,14 @@
399
451
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_stringFilter",
400
452
  "memberFieldName": "stringFilter"
401
453
  },
454
+ {
455
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_negatedStringFilter",
456
+ "memberFieldName": "negatedStringFilter"
457
+ },
458
+ {
459
+ "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_negateTermTestFilter",
460
+ "memberFieldName": "negateTermTestFilter"
461
+ },
402
462
  {
403
463
  "@id": "undefineds:dist/storage/rdf/RdfSparqlAdapter.jsonld#RdfSparqlAdapter__member_normalizeFunctionCallExpression",
404
464
  "memberFieldName": "normalizeFunctionCallExpression"
@@ -1,6 +1,7 @@
1
1
  import type { Term } from '@rdfjs/types';
2
2
  import type { SqliteDatabase } from '../SqliteRuntime';
3
3
  import type { RdfTermKind } from './types';
4
+ export declare const RDF_TERM_VALUE_HEAD_LENGTH = 256;
4
5
  export declare class RdfTermDictionary {
5
6
  private readonly db;
6
7
  private readonly termCache;
@@ -20,8 +21,15 @@ export declare class RdfTermDictionary {
20
21
  private toIdentity;
21
22
  private identity;
22
23
  private numericValueForLiteral;
24
+ private ensureSafeTermTableSchema;
25
+ private createSafeTermTable;
26
+ private dropUnsafeRawTextIndexes;
27
+ private ensureValueHeadColumn;
23
28
  private ensureNumericValueColumn;
24
29
  private backfillNumericValues;
25
30
  private identityCacheKey;
31
+ private rowMatchesIdentity;
32
+ private termTableColumns;
26
33
  private rowToTerm;
27
34
  }
35
+ export declare function rdfTermValueHead(value: string): string;
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RdfTermDictionary = void 0;
3
+ exports.RdfTermDictionary = exports.RDF_TERM_VALUE_HEAD_LENGTH = void 0;
4
+ exports.rdfTermValueHead = rdfTermValueHead;
4
5
  const node_crypto_1 = require("node:crypto");
5
6
  const n3_1 = require("n3");
6
7
  const RdfTermSemantics_1 = require("./RdfTermSemantics");
8
+ exports.RDF_TERM_VALUE_HEAD_LENGTH = 256;
7
9
  const XSD_STRING = 'http://www.w3.org/2001/XMLSchema#string';
8
10
  const RDF_LANG_STRING = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString';
9
11
  class RdfTermDictionary {
@@ -13,27 +15,17 @@ class RdfTermDictionary {
13
15
  this.idCache = new Map();
14
16
  }
15
17
  initialize() {
18
+ this.ensureSafeTermTableSchema();
19
+ this.dropUnsafeRawTextIndexes();
20
+ this.ensureValueHeadColumn();
21
+ this.ensureNumericValueColumn();
16
22
  this.db.exec(`
17
- CREATE TABLE IF NOT EXISTS rdf_terms (
18
- id INTEGER PRIMARY KEY AUTOINCREMENT,
19
- kind TEXT NOT NULL,
20
- value TEXT NOT NULL,
21
- datatype_id INTEGER,
22
- lang TEXT,
23
- hash TEXT NOT NULL,
24
- normalized_text TEXT,
25
- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
26
- UNIQUE (kind, value, datatype_id, lang)
27
- );
28
-
29
- CREATE INDEX IF NOT EXISTS rdf_terms_hash ON rdf_terms (hash);
30
- CREATE INDEX IF NOT EXISTS rdf_terms_kind_value ON rdf_terms (kind, value);
23
+ CREATE UNIQUE INDEX IF NOT EXISTS rdf_terms_identity_hash ON rdf_terms (hash);
24
+ CREATE INDEX IF NOT EXISTS rdf_terms_kind_value_head ON rdf_terms (kind, value_head);
31
25
  CREATE INDEX IF NOT EXISTS rdf_terms_kind_datatype ON rdf_terms (kind, datatype_id);
32
26
  CREATE INDEX IF NOT EXISTS rdf_terms_kind_lang ON rdf_terms (kind, lang);
33
- CREATE INDEX IF NOT EXISTS rdf_terms_normalized_text ON rdf_terms (normalized_text);
27
+ CREATE INDEX IF NOT EXISTS rdf_terms_kind_numeric_value ON rdf_terms (kind, numeric_value);
34
28
  `);
35
- this.ensureNumericValueColumn();
36
- this.db.exec('CREATE INDEX IF NOT EXISTS rdf_terms_kind_numeric_value ON rdf_terms (kind, numeric_value);');
37
29
  this.backfillNumericValues();
38
30
  }
39
31
  getOrCreate(term) {
@@ -49,10 +41,21 @@ class RdfTermDictionary {
49
41
  return existing;
50
42
  }
51
43
  const stmt = this.db.prepare(`
52
- INSERT INTO rdf_terms (kind, value, datatype_id, lang, hash, normalized_text, numeric_value)
53
- VALUES (?, ?, ?, ?, ?, ?, ?)
44
+ INSERT INTO rdf_terms (kind, value, value_head, datatype_id, lang, hash, normalized_text, numeric_value)
45
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
54
46
  `);
55
- const result = stmt.run(identity.kind, identity.value, identity.datatypeId, identity.lang, identity.hash, identity.normalizedText, identity.numericValue);
47
+ let result;
48
+ try {
49
+ result = stmt.run(identity.kind, identity.value, identity.valueHead, identity.datatypeId, identity.lang, identity.hash, identity.normalizedText, identity.numericValue);
50
+ }
51
+ catch (error) {
52
+ const raced = this.findId(identity);
53
+ if (raced !== undefined) {
54
+ this.termCache.set(cacheKey, raced);
55
+ return raced;
56
+ }
57
+ throw error;
58
+ }
56
59
  const id = Number(result.lastInsertRowid);
57
60
  this.termCache.set(cacheKey, id);
58
61
  this.idCache.set(id, term);
@@ -120,13 +123,17 @@ class RdfTermDictionary {
120
123
  }
121
124
  const rows = this.db
122
125
  .prepare(`
123
- SELECT id FROM rdf_terms
126
+ SELECT id, value FROM rdf_terms
124
127
  WHERE kind IN (${kinds.map(() => '?').join(', ')})
128
+ AND value_head >= ?
129
+ AND value_head < ?
125
130
  AND value >= ?
126
131
  AND value < ?
127
132
  `)
128
- .all(...kinds, prefix, `${prefix}\uffff`);
129
- return rows.map((row) => row.id);
133
+ .all(...kinds, rdfTermValueHead(prefix), `${rdfTermValueHead(prefix)}\uffff`, prefix, `${prefix}\uffff`);
134
+ return rows
135
+ .filter((row) => row.value.startsWith(prefix))
136
+ .map((row) => row.id);
130
137
  }
131
138
  idsByNormalizedTextContains(kind, text) {
132
139
  const kinds = Array.isArray(kind) ? kind : [kind];
@@ -184,50 +191,10 @@ class RdfTermDictionary {
184
191
  return row?.count ?? 0;
185
192
  }
186
193
  findId(identity) {
187
- const row = identity.datatypeId === null && identity.lang === null
188
- ? this.db
189
- .prepare(`
190
- SELECT id FROM rdf_terms
191
- WHERE kind = ?
192
- AND value = ?
193
- AND datatype_id IS NULL
194
- AND lang IS NULL
195
- LIMIT 1
196
- `)
197
- .get(identity.kind, identity.value)
198
- : identity.datatypeId === null
199
- ? this.db
200
- .prepare(`
201
- SELECT id FROM rdf_terms
202
- WHERE kind = ?
203
- AND value = ?
204
- AND datatype_id IS NULL
205
- AND lang = ?
206
- LIMIT 1
207
- `)
208
- .get(identity.kind, identity.value, identity.lang)
209
- : identity.lang === null
210
- ? this.db
211
- .prepare(`
212
- SELECT id FROM rdf_terms
213
- WHERE kind = ?
214
- AND value = ?
215
- AND datatype_id = ?
216
- AND lang IS NULL
217
- LIMIT 1
218
- `)
219
- .get(identity.kind, identity.value, identity.datatypeId)
220
- : this.db
221
- .prepare(`
222
- SELECT id FROM rdf_terms
223
- WHERE kind = ?
224
- AND value = ?
225
- AND datatype_id = ?
226
- AND lang = ?
227
- LIMIT 1
228
- `)
229
- .get(identity.kind, identity.value, identity.datatypeId, identity.lang);
230
- return row?.id;
194
+ const rows = this.db
195
+ .prepare('SELECT * FROM rdf_terms WHERE hash = ?')
196
+ .all(identity.hash);
197
+ return rows.find((row) => this.rowMatchesIdentity(row, identity))?.id;
231
198
  }
232
199
  toIdentity(term) {
233
200
  switch (term.termType) {
@@ -267,6 +234,7 @@ class RdfTermDictionary {
267
234
  return {
268
235
  kind,
269
236
  value,
237
+ valueHead: rdfTermValueHead(value),
270
238
  datatypeId,
271
239
  lang,
272
240
  normalizedText: normalizedText ? normalizedText.toLowerCase() : null,
@@ -281,9 +249,100 @@ class RdfTermDictionary {
281
249
  const numeric = (0, RdfTermSemantics_1.rdfNumericValue)(value);
282
250
  return Number.isFinite(numeric) ? numeric : null;
283
251
  }
252
+ ensureSafeTermTableSchema() {
253
+ const table = this.db
254
+ .prepare("SELECT sql FROM sqlite_schema WHERE type = 'table' AND name = 'rdf_terms'")
255
+ .get();
256
+ if (!table) {
257
+ this.createSafeTermTable('rdf_terms');
258
+ return;
259
+ }
260
+ const columns = this.termTableColumns();
261
+ const hasRawUniqueConstraint = table.sql?.includes('UNIQUE (kind, value, datatype_id, lang)') ?? false;
262
+ if (!hasRawUniqueConstraint && columns.has('value_head') && columns.has('numeric_value')) {
263
+ return;
264
+ }
265
+ const foreignKeys = this.db.prepare('PRAGMA foreign_keys').get()?.foreign_keys ?? 0;
266
+ this.db.exec('PRAGMA foreign_keys = OFF;');
267
+ try {
268
+ this.db.transaction(() => {
269
+ this.db.exec('DROP TABLE IF EXISTS rdf_terms_next;');
270
+ this.createSafeTermTable('rdf_terms_next');
271
+ this.db.exec(`
272
+ INSERT INTO rdf_terms_next (
273
+ id,
274
+ kind,
275
+ value,
276
+ value_head,
277
+ datatype_id,
278
+ lang,
279
+ hash,
280
+ normalized_text,
281
+ numeric_value,
282
+ created_at
283
+ )
284
+ SELECT
285
+ id,
286
+ kind,
287
+ value,
288
+ substr(value, 1, ${exports.RDF_TERM_VALUE_HEAD_LENGTH}),
289
+ datatype_id,
290
+ lang,
291
+ hash,
292
+ normalized_text,
293
+ ${columns.has('numeric_value') ? 'numeric_value' : 'NULL'},
294
+ created_at
295
+ FROM rdf_terms;
296
+ `);
297
+ this.db.exec(`
298
+ DROP TABLE rdf_terms;
299
+ ALTER TABLE rdf_terms_next RENAME TO rdf_terms;
300
+ `);
301
+ })();
302
+ }
303
+ finally {
304
+ if (foreignKeys) {
305
+ this.db.exec('PRAGMA foreign_keys = ON;');
306
+ }
307
+ }
308
+ }
309
+ createSafeTermTable(name) {
310
+ this.db.exec(`
311
+ CREATE TABLE IF NOT EXISTS ${name} (
312
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
313
+ kind TEXT NOT NULL,
314
+ value TEXT NOT NULL,
315
+ value_head TEXT NOT NULL,
316
+ datatype_id INTEGER,
317
+ lang TEXT,
318
+ hash TEXT NOT NULL,
319
+ normalized_text TEXT,
320
+ numeric_value REAL,
321
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
322
+ );
323
+ `);
324
+ }
325
+ dropUnsafeRawTextIndexes() {
326
+ this.db.exec(`
327
+ DROP INDEX IF EXISTS rdf_terms_hash;
328
+ DROP INDEX IF EXISTS rdf_terms_kind_value;
329
+ DROP INDEX IF EXISTS rdf_terms_normalized_text;
330
+ `);
331
+ }
332
+ ensureValueHeadColumn() {
333
+ const columns = this.termTableColumns();
334
+ if (!columns.has('value_head')) {
335
+ this.db.exec('ALTER TABLE rdf_terms ADD COLUMN value_head TEXT;');
336
+ }
337
+ this.db.exec(`
338
+ UPDATE rdf_terms
339
+ SET value_head = substr(value, 1, ${exports.RDF_TERM_VALUE_HEAD_LENGTH})
340
+ WHERE value_head IS NULL;
341
+ `);
342
+ }
284
343
  ensureNumericValueColumn() {
285
- const columns = this.db.prepare('PRAGMA table_info(rdf_terms)').all();
286
- if (columns.some((column) => column.name === 'numeric_value')) {
344
+ const columns = this.termTableColumns();
345
+ if (columns.has('numeric_value')) {
287
346
  return;
288
347
  }
289
348
  this.db.exec('ALTER TABLE rdf_terms ADD COLUMN numeric_value REAL;');
@@ -317,6 +376,15 @@ class RdfTermDictionary {
317
376
  identity.lang ?? '',
318
377
  ].join('\u001f');
319
378
  }
379
+ rowMatchesIdentity(row, identity) {
380
+ return row.kind === identity.kind
381
+ && row.value === identity.value
382
+ && row.datatype_id === identity.datatypeId
383
+ && row.lang === identity.lang;
384
+ }
385
+ termTableColumns() {
386
+ return new Set(this.db.prepare('PRAGMA table_info(rdf_terms)').all().map((column) => column.name));
387
+ }
320
388
  rowToTerm(row) {
321
389
  switch (row.kind) {
322
390
  case 'iri':
@@ -343,6 +411,9 @@ class RdfTermDictionary {
343
411
  }
344
412
  }
345
413
  exports.RdfTermDictionary = RdfTermDictionary;
414
+ function rdfTermValueHead(value) {
415
+ return value.slice(0, exports.RDF_TERM_VALUE_HEAD_LENGTH);
416
+ }
346
417
  function normalizeSearchText(value) {
347
418
  return value.toLowerCase();
348
419
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RdfTermDictionary.js","sourceRoot":"","sources":["../../../src/storage/rdf/RdfTermDictionary.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto';\nimport { DataFactory } from 'n3';\nimport type { Term } from '@rdfjs/types';\nimport type { SqliteDatabase } from '../SqliteRuntime';\nimport type { RdfTermKind, RdfTermRow } from './types';\nimport { isRdfNumericDatatype, rdfNumericValue } from './RdfTermSemantics';\n\ninterface RdfTermIdentity {\n kind: RdfTermKind;\n value: string;\n datatypeId: number | null;\n lang: string | null;\n normalizedText: string | null;\n numericValue: number | null;\n hash: string;\n}\n\nconst XSD_STRING = 'http://www.w3.org/2001/XMLSchema#string';\nconst RDF_LANG_STRING = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString';\n\nexport class RdfTermDictionary {\n private readonly termCache = new Map<string, number>();\n private readonly idCache = new Map<number, Term>();\n\n public constructor(private readonly db: SqliteDatabase) {}\n\n public initialize(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS rdf_terms (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n kind TEXT NOT NULL,\n value TEXT NOT NULL,\n datatype_id INTEGER,\n lang TEXT,\n hash TEXT NOT NULL,\n normalized_text TEXT,\n created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),\n UNIQUE (kind, value, datatype_id, lang)\n );\n\n CREATE INDEX IF NOT EXISTS rdf_terms_hash ON rdf_terms (hash);\n CREATE INDEX IF NOT EXISTS rdf_terms_kind_value ON rdf_terms (kind, value);\n CREATE INDEX IF NOT EXISTS rdf_terms_kind_datatype ON rdf_terms (kind, datatype_id);\n CREATE INDEX IF NOT EXISTS rdf_terms_kind_lang ON rdf_terms (kind, lang);\n CREATE INDEX IF NOT EXISTS rdf_terms_normalized_text ON rdf_terms (normalized_text);\n `);\n this.ensureNumericValueColumn();\n this.db.exec('CREATE INDEX IF NOT EXISTS rdf_terms_kind_numeric_value ON rdf_terms (kind, numeric_value);');\n this.backfillNumericValues();\n }\n\n public getOrCreate(term: Term): number {\n const identity = this.toIdentity(term);\n const cacheKey = this.identityCacheKey(identity);\n const cached = this.termCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const existing = this.findId(identity);\n if (existing !== undefined) {\n this.termCache.set(cacheKey, existing);\n return existing;\n }\n\n const stmt = this.db.prepare(`\n INSERT INTO rdf_terms (kind, value, datatype_id, lang, hash, normalized_text, numeric_value)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n const result = stmt.run(\n identity.kind,\n identity.value,\n identity.datatypeId,\n identity.lang,\n identity.hash,\n identity.normalizedText,\n identity.numericValue,\n );\n const id = Number(result.lastInsertRowid);\n this.termCache.set(cacheKey, id);\n this.idCache.set(id, term);\n return id;\n }\n\n public find(term: Term): number | undefined {\n const identity = this.toIdentity(term);\n const cacheKey = this.identityCacheKey(identity);\n const cached = this.termCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const id = this.findId(identity);\n if (id !== undefined) {\n this.termCache.set(cacheKey, id);\n }\n return id;\n }\n\n public termForId(id: number): Term {\n const cached = this.idCache.get(id);\n if (cached) {\n return cached;\n }\n\n const row = this.db\n .prepare<RdfTermRow>('SELECT * FROM rdf_terms WHERE id = ?')\n .get(id);\n if (!row) {\n throw new Error(`RDF term not found: ${id}`);\n }\n\n const term = this.rowToTerm(row);\n this.idCache.set(id, term);\n return term;\n }\n\n public rowsForIds(ids: number[]): Map<number, Term> {\n const uniqueIds = Array.from(new Set(ids));\n const result = new Map<number, Term>();\n const missing: number[] = [];\n\n for (const id of uniqueIds) {\n const cached = this.idCache.get(id);\n if (cached) {\n result.set(id, cached);\n } else {\n missing.push(id);\n }\n }\n\n if (missing.length === 0) {\n return result;\n }\n\n const placeholders = missing.map(() => '?').join(', ');\n const rows = this.db\n .prepare<RdfTermRow>(`SELECT * FROM rdf_terms WHERE id IN (${placeholders})`)\n .all(...missing);\n\n for (const row of rows) {\n const term = this.rowToTerm(row);\n this.idCache.set(row.id, term);\n result.set(row.id, term);\n }\n\n return result;\n }\n\n public idsByValuePrefix(kind: RdfTermKind | RdfTermKind[], prefix: string): number[] {\n const kinds = Array.isArray(kind) ? kind : [kind];\n if (kinds.length === 0) {\n return [];\n }\n const rows = this.db\n .prepare<{ id: number }>(`\n SELECT id FROM rdf_terms\n WHERE kind IN (${kinds.map(() => '?').join(', ')})\n AND value >= ?\n AND value < ?\n `)\n .all(...kinds, prefix, `${prefix}\\uffff`);\n return rows.map((row) => row.id);\n }\n\n public idsByNormalizedTextContains(kind: RdfTermKind | RdfTermKind[], text: string): number[] {\n const kinds = Array.isArray(kind) ? kind : [kind];\n if (kinds.length === 0) {\n return [];\n }\n const needle = normalizeSearchText(text);\n const rows = this.db\n .prepare<{ id: number; value: string }>(`\n SELECT id, value FROM rdf_terms\n WHERE kind IN (${kinds.map(() => '?').join(', ')})\n AND normalized_text LIKE ? ESCAPE '\\\\'\n `)\n .all(...kinds, `%${escapeLikePattern(needle)}%`);\n return rows\n .filter((row) => row.value.includes(text))\n .map((row) => row.id);\n }\n\n public idsByNormalizedTextSuffix(kind: RdfTermKind | RdfTermKind[], suffix: string): number[] {\n const kinds = Array.isArray(kind) ? kind : [kind];\n if (kinds.length === 0) {\n return [];\n }\n const needle = normalizeSearchText(suffix);\n const rows = this.db\n .prepare<{ id: number; value: string }>(`\n SELECT id, value FROM rdf_terms\n WHERE kind IN (${kinds.map(() => '?').join(', ')})\n AND normalized_text LIKE ? ESCAPE '\\\\'\n `)\n .all(...kinds, `%${escapeLikePattern(needle)}`);\n return rows\n .filter((row) => row.value.endsWith(suffix))\n .map((row) => row.id);\n }\n\n public idsByNormalizedTextRegex(kind: RdfTermKind | RdfTermKind[], pattern: string, flags?: string): number[] {\n const kinds = Array.isArray(kind) ? kind : [kind];\n if (kinds.length === 0) {\n return [];\n }\n const rows = this.db\n .prepare<RdfTermRow>(`\n SELECT * FROM rdf_terms\n WHERE kind IN (${kinds.map(() => '?').join(', ')})\n AND normalized_text IS NOT NULL\n `)\n .all(...kinds);\n const regex = new RegExp(pattern, flags);\n return rows\n .filter((row) => regex.test(row.value))\n .map((row) => row.id);\n }\n\n public count(): number {\n const row = this.db.prepare<{ count: number }>('SELECT COUNT(*) AS count FROM rdf_terms').get();\n return row?.count ?? 0;\n }\n\n private findId(identity: RdfTermIdentity): number | undefined {\n const row = identity.datatypeId === null && identity.lang === null\n ? this.db\n .prepare<{ id: number }>(`\n SELECT id FROM rdf_terms\n WHERE kind = ?\n AND value = ?\n AND datatype_id IS NULL\n AND lang IS NULL\n LIMIT 1\n `)\n .get(identity.kind, identity.value)\n : identity.datatypeId === null\n ? this.db\n .prepare<{ id: number }>(`\n SELECT id FROM rdf_terms\n WHERE kind = ?\n AND value = ?\n AND datatype_id IS NULL\n AND lang = ?\n LIMIT 1\n `)\n .get(identity.kind, identity.value, identity.lang)\n : identity.lang === null\n ? this.db\n .prepare<{ id: number }>(`\n SELECT id FROM rdf_terms\n WHERE kind = ?\n AND value = ?\n AND datatype_id = ?\n AND lang IS NULL\n LIMIT 1\n `)\n .get(identity.kind, identity.value, identity.datatypeId)\n : this.db\n .prepare<{ id: number }>(`\n SELECT id FROM rdf_terms\n WHERE kind = ?\n AND value = ?\n AND datatype_id = ?\n AND lang = ?\n LIMIT 1\n `)\n .get(identity.kind, identity.value, identity.datatypeId, identity.lang);\n return row?.id;\n }\n\n private toIdentity(term: Term): RdfTermIdentity {\n switch (term.termType) {\n case 'NamedNode':\n return this.identity('iri', term.value, null, null, term.value, null);\n case 'BlankNode':\n return this.identity('blank', term.value, null, null, term.value, null);\n case 'DefaultGraph':\n return this.identity('default_graph', '', null, null, null, null);\n case 'Literal': {\n const datatypeValue = term.datatype?.value || XSD_STRING;\n const datatypeId = datatypeValue === XSD_STRING && !term.language\n ? null\n : this.getOrCreate(DataFactory.namedNode(datatypeValue));\n return this.identity(\n 'literal',\n term.value,\n datatypeId,\n term.language || null,\n term.value,\n this.numericValueForLiteral(term.value, datatypeValue),\n );\n }\n case 'Variable':\n throw new Error(`Variables cannot be indexed as RDF terms: ${term.value}`);\n case 'Quad':\n throw new Error('Nested RDF-star quads are not supported by the first SolidRdfEngine index');\n default: {\n const exhaustive: never = term;\n throw new Error(`Unsupported RDF term: ${String(exhaustive)}`);\n }\n }\n }\n\n private identity(\n kind: RdfTermKind,\n value: string,\n datatypeId: number | null,\n lang: string | null,\n normalizedText: string | null,\n numericValue: number | null,\n ): RdfTermIdentity {\n const hash = createHash('sha256')\n .update(kind)\n .update('\\0')\n .update(value)\n .update('\\0')\n .update(String(datatypeId ?? ''))\n .update('\\0')\n .update(lang ?? '')\n .digest('hex');\n return {\n kind,\n value,\n datatypeId,\n lang,\n normalizedText: normalizedText ? normalizedText.toLowerCase() : null,\n numericValue,\n hash,\n };\n }\n\n private numericValueForLiteral(value: string, datatypeValue: string): number | null {\n if (!isRdfNumericDatatype(datatypeValue)) {\n return null;\n }\n const numeric = rdfNumericValue(value);\n return Number.isFinite(numeric) ? numeric : null;\n }\n\n private ensureNumericValueColumn(): void {\n const columns = this.db.prepare<{ name: string }>('PRAGMA table_info(rdf_terms)').all();\n if (columns.some((column) => column.name === 'numeric_value')) {\n return;\n }\n this.db.exec('ALTER TABLE rdf_terms ADD COLUMN numeric_value REAL;');\n }\n\n private backfillNumericValues(): void {\n const rows = this.db.prepare<RdfTermRow>(`\n SELECT literal.*\n FROM rdf_terms literal\n JOIN rdf_terms datatype ON datatype.id = literal.datatype_id\n WHERE literal.kind = 'literal'\n AND literal.numeric_value IS NULL\n AND datatype.kind = 'iri'\n `).all();\n const update = this.db.prepare('UPDATE rdf_terms SET numeric_value = ? WHERE id = ?');\n for (const row of rows) {\n const datatype = this.termForId(row.datatype_id as number);\n if (datatype.termType !== 'NamedNode') {\n continue;\n }\n const numericValue = this.numericValueForLiteral(row.value, datatype.value);\n if (numericValue !== null) {\n update.run(numericValue, row.id);\n }\n }\n }\n\n private identityCacheKey(identity: RdfTermIdentity): string {\n return [\n identity.kind,\n identity.value,\n identity.datatypeId ?? '',\n identity.lang ?? '',\n ].join('\\u001f');\n }\n\n private rowToTerm(row: RdfTermRow): Term {\n switch (row.kind) {\n case 'iri':\n return DataFactory.namedNode(row.value);\n case 'blank':\n return DataFactory.blankNode(row.value);\n case 'default_graph':\n return DataFactory.defaultGraph();\n case 'literal': {\n if (row.lang) {\n return DataFactory.literal(row.value, row.lang);\n }\n if (row.datatype_id) {\n const datatype = this.termForId(row.datatype_id);\n if (datatype.termType === 'NamedNode' && datatype.value !== XSD_STRING && datatype.value !== RDF_LANG_STRING) {\n return DataFactory.literal(row.value, datatype);\n }\n }\n return DataFactory.literal(row.value);\n }\n default:\n throw new Error(`Unsupported RDF term kind in dictionary row: ${(row as RdfTermRow).kind}`);\n }\n }\n}\n\nfunction normalizeSearchText(value: string): string {\n return value.toLowerCase();\n}\n\nfunction escapeLikePattern(value: string): string {\n return value.replace(/[\\\\%_]/g, (match) => `\\\\${match}`);\n}\n"]}
1
+ {"version":3,"file":"RdfTermDictionary.js","sourceRoot":"","sources":["../../../src/storage/rdf/RdfTermDictionary.ts"],"names":[],"mappings":";;;AAieA,4CAEC;AAneD,6CAAyC;AACzC,2BAAiC;AAIjC,yDAA2E;AAa9D,QAAA,0BAA0B,GAAG,GAAG,CAAC;AAE9C,MAAM,UAAU,GAAG,yCAAyC,CAAC;AAC7D,MAAM,eAAe,GAAG,uDAAuD,CAAC;AAEhF,MAAa,iBAAiB;IAI5B,YAAoC,EAAkB;QAAlB,OAAE,GAAF,EAAE,CAAgB;QAHrC,cAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;QACtC,YAAO,GAAG,IAAI,GAAG,EAAgB,CAAC;IAEM,CAAC;IAEnD,UAAU;QACf,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACjC,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAChC,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAChC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;KAMZ,CAAC,CAAC;QACH,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC/B,CAAC;IAEM,WAAW,CAAC,IAAU;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACvC,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;KAG5B,CAAC,CAAC;QACH,IAAI,MAAM,CAAC;QACX,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,GAAG,CACf,QAAQ,CAAC,IAAI,EACb,QAAQ,CAAC,KAAK,EACd,QAAQ,CAAC,SAAS,EAClB,QAAQ,CAAC,UAAU,EACnB,QAAQ,CAAC,IAAI,EACb,QAAQ,CAAC,IAAI,EACb,QAAQ,CAAC,cAAc,EACvB,QAAQ,CAAC,YAAY,CACtB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBACpC,OAAO,KAAK,CAAC;YACf,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QAC1C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC3B,OAAO,EAAE,CAAC;IACZ,CAAC;IAEM,IAAI,CAAC,IAAU;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAEM,SAAS,CAAC,EAAU;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,OAAO,CAAa,sCAAsC,CAAC;aAC3D,GAAG,CAAC,EAAE,CAAC,CAAC;QACX,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,UAAU,CAAC,GAAa;QAC7B,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAgB,CAAC;QACvC,MAAM,OAAO,GAAa,EAAE,CAAC;QAE7B,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YACzB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAa,wCAAwC,YAAY,GAAG,CAAC;aAC5E,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC;QAEnB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YAC/B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC3B,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEM,gBAAgB,CAAC,IAAiC,EAAE,MAAc;QACvE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAgC;;yBAErB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;OAKjD,CAAC;aACD,GAAG,CAAC,GAAG,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,CAAC;QAC3G,OAAO,IAAI;aACR,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;aAC7C,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;IAEM,2BAA2B,CAAC,IAAiC,EAAE,IAAY;QAChF,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAgC;;yBAErB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;OAEjD,CAAC;aACD,GAAG,CAAC,GAAG,KAAK,EAAE,IAAI,iBAAiB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnD,OAAO,IAAI;aACR,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;aACzC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;IAEM,yBAAyB,CAAC,IAAiC,EAAE,MAAc;QAChF,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAgC;;yBAErB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;OAEjD,CAAC;aACD,GAAG,CAAC,GAAG,KAAK,EAAE,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAClD,OAAO,IAAI;aACR,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;aAC3C,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;IAEM,wBAAwB,CAAC,IAAiC,EAAE,OAAe,EAAE,KAAc;QAChG,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAa;;yBAEF,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;OAEjD,CAAC;aACD,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;QACjB,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACzC,OAAO,IAAI;aACR,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;aACtC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;IAEM,KAAK;QACV,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAoB,yCAAyC,CAAC,CAAC,GAAG,EAAE,CAAC;QAChG,OAAO,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC;IACzB,CAAC;IAEO,MAAM,CAAC,QAAyB;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAa,wCAAwC,CAAC;aAC7D,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC;IACxE,CAAC;IAEO,UAAU,CAAC,IAAU;QAC3B,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;YACtB,KAAK,WAAW;gBACd,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACxE,KAAK,WAAW;gBACd,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC1E,KAAK,cAAc;gBACjB,OAAO,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YACpE,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,UAAU,CAAC;gBACzD,MAAM,UAAU,GAAG,aAAa,KAAK,UAAU,IAAI,CAAC,IAAI,CAAC,QAAQ;oBAC/D,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,gBAAW,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC;gBAC3D,OAAO,IAAI,CAAC,QAAQ,CAClB,SAAS,EACT,IAAI,CAAC,KAAK,EACV,UAAU,EACV,IAAI,CAAC,QAAQ,IAAI,IAAI,EACrB,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,CACvD,CAAC;YACJ,CAAC;YACD,KAAK,UAAU;gBACb,MAAM,IAAI,KAAK,CAAC,6CAA6C,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAC7E,KAAK,MAAM;gBACT,MAAM,IAAI,KAAK,CAAC,2EAA2E,CAAC,CAAC;YAC/F,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,UAAU,GAAU,IAAI,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;IACH,CAAC;IAEO,QAAQ,CACd,IAAiB,EACjB,KAAa,EACb,UAAyB,EACzB,IAAmB,EACnB,cAA6B,EAC7B,YAA2B;QAE3B,MAAM,IAAI,GAAG,IAAA,wBAAU,EAAC,QAAQ,CAAC;aAC9B,MAAM,CAAC,IAAI,CAAC;aACZ,MAAM,CAAC,IAAI,CAAC;aACZ,MAAM,CAAC,KAAK,CAAC;aACb,MAAM,CAAC,IAAI,CAAC;aACZ,MAAM,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;aAChC,MAAM,CAAC,IAAI,CAAC;aACZ,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;aAClB,MAAM,CAAC,KAAK,CAAC,CAAC;QACjB,OAAO;YACL,IAAI;YACJ,KAAK;YACL,SAAS,EAAE,gBAAgB,CAAC,KAAK,CAAC;YAClC,UAAU;YACV,IAAI;YACJ,cAAc,EAAE,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI;YACpE,YAAY;YACZ,IAAI;SACL,CAAC;IACJ,CAAC;IAEO,sBAAsB,CAAC,KAAa,EAAE,aAAqB;QACjE,IAAI,CAAC,IAAA,uCAAoB,EAAC,aAAa,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,IAAA,kCAAe,EAAC,KAAK,CAAC,CAAC;QACvC,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IACnD,CAAC;IAEO,yBAAyB;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE;aAClB,OAAO,CAAyB,2EAA2E,CAAC;aAC5G,GAAG,EAAE,CAAC;QACT,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;YACtC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACxC,MAAM,sBAAsB,GAAG,KAAK,CAAC,GAAG,EAAE,QAAQ,CAAC,yCAAyC,CAAC,IAAI,KAAK,CAAC;QACvG,IAAI,CAAC,sBAAsB,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YACzF,OAAO;QACT,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAA2B,qBAAqB,CAAC,CAAC,GAAG,EAAE,EAAE,YAAY,IAAI,CAAC,CAAC;QAC9G,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;gBACvB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;gBACrD,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;gBAC3C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;+BAiBU,kCAA0B;;;;;cAK3C,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM;;;SAG5D,CAAC,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;SAGZ,CAAC,CAAC;YACL,CAAC,CAAC,EAAE,CAAC;QACP,CAAC;gBAAS,CAAC;YACT,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAEO,mBAAmB,CAAC,IAAY;QACtC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;mCACkB,IAAI;;;;;;;;;;;;KAYlC,CAAC,CAAC;IACL,CAAC;IAEO,wBAAwB;QAC9B,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;KAIZ,CAAC,CAAC;IACL,CAAC;IAEO,qBAAqB;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;0CAEyB,kCAA0B;;KAE/D,CAAC,CAAC;IACL,CAAC;IAEO,wBAAwB;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACxC,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YACjC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;IACvE,CAAC;IAEO,qBAAqB;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAa;;;;;;;KAOxC,CAAC,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,qDAAqD,CAAC,CAAC;QACtF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAqB,CAAC,CAAC;YAC3D,IAAI,QAAQ,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;gBACtC,SAAS;YACX,CAAC;YACD,MAAM,YAAY,GAAG,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC5E,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;gBAC1B,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;IAEO,gBAAgB,CAAC,QAAyB;QAChD,OAAO;YACL,QAAQ,CAAC,IAAI;YACb,QAAQ,CAAC,KAAK;YACd,QAAQ,CAAC,UAAU,IAAI,EAAE;YACzB,QAAQ,CAAC,IAAI,IAAI,EAAE;SACpB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnB,CAAC;IAEO,kBAAkB,CAAC,GAAe,EAAE,QAAyB;QACnE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI;eAC5B,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK;eAC5B,GAAG,CAAC,WAAW,KAAK,QAAQ,CAAC,UAAU;eACvC,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC;IAClC,CAAC;IAEO,gBAAgB;QACtB,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAmB,8BAA8B,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACvH,CAAC;IAEO,SAAS,CAAC,GAAe;QAC/B,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,KAAK;gBACR,OAAO,gBAAW,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC1C,KAAK,OAAO;gBACV,OAAO,gBAAW,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC1C,KAAK,eAAe;gBAClB,OAAO,gBAAW,CAAC,YAAY,EAAE,CAAC;YACpC,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;oBACb,OAAO,gBAAW,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;gBAClD,CAAC;gBACD,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;oBACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;oBACjD,IAAI,QAAQ,CAAC,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,KAAK,KAAK,UAAU,IAAI,QAAQ,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;wBAC7G,OAAO,gBAAW,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;oBAClD,CAAC;gBACH,CAAC;gBACD,OAAO,gBAAW,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxC,CAAC;YACD;gBACE,MAAM,IAAI,KAAK,CAAC,gDAAiD,GAAkB,CAAC,IAAI,EAAE,CAAC,CAAC;QAChG,CAAC;IACH,CAAC;CACF;AAxcD,8CAwcC;AAED,SAAgB,gBAAgB,CAAC,KAAa;IAC5C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,kCAA0B,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;AAC3D,CAAC","sourcesContent":["import { createHash } from 'node:crypto';\nimport { DataFactory } from 'n3';\nimport type { Term } from '@rdfjs/types';\nimport type { SqliteDatabase } from '../SqliteRuntime';\nimport type { RdfTermKind, RdfTermRow } from './types';\nimport { isRdfNumericDatatype, rdfNumericValue } from './RdfTermSemantics';\n\ninterface RdfTermIdentity {\n kind: RdfTermKind;\n value: string;\n valueHead: string;\n datatypeId: number | null;\n lang: string | null;\n normalizedText: string | null;\n numericValue: number | null;\n hash: string;\n}\n\nexport const RDF_TERM_VALUE_HEAD_LENGTH = 256;\n\nconst XSD_STRING = 'http://www.w3.org/2001/XMLSchema#string';\nconst RDF_LANG_STRING = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString';\n\nexport class RdfTermDictionary {\n private readonly termCache = new Map<string, number>();\n private readonly idCache = new Map<number, Term>();\n\n public constructor(private readonly db: SqliteDatabase) {}\n\n public initialize(): void {\n this.ensureSafeTermTableSchema();\n this.dropUnsafeRawTextIndexes();\n this.ensureValueHeadColumn();\n this.ensureNumericValueColumn();\n this.db.exec(`\n CREATE UNIQUE INDEX IF NOT EXISTS rdf_terms_identity_hash ON rdf_terms (hash);\n CREATE INDEX IF NOT EXISTS rdf_terms_kind_value_head ON rdf_terms (kind, value_head);\n CREATE INDEX IF NOT EXISTS rdf_terms_kind_datatype ON rdf_terms (kind, datatype_id);\n CREATE INDEX IF NOT EXISTS rdf_terms_kind_lang ON rdf_terms (kind, lang);\n CREATE INDEX IF NOT EXISTS rdf_terms_kind_numeric_value ON rdf_terms (kind, numeric_value);\n `);\n this.backfillNumericValues();\n }\n\n public getOrCreate(term: Term): number {\n const identity = this.toIdentity(term);\n const cacheKey = this.identityCacheKey(identity);\n const cached = this.termCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const existing = this.findId(identity);\n if (existing !== undefined) {\n this.termCache.set(cacheKey, existing);\n return existing;\n }\n\n const stmt = this.db.prepare(`\n INSERT INTO rdf_terms (kind, value, value_head, datatype_id, lang, hash, normalized_text, numeric_value)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n let result;\n try {\n result = stmt.run(\n identity.kind,\n identity.value,\n identity.valueHead,\n identity.datatypeId,\n identity.lang,\n identity.hash,\n identity.normalizedText,\n identity.numericValue,\n );\n } catch (error) {\n const raced = this.findId(identity);\n if (raced !== undefined) {\n this.termCache.set(cacheKey, raced);\n return raced;\n }\n throw error;\n }\n const id = Number(result.lastInsertRowid);\n this.termCache.set(cacheKey, id);\n this.idCache.set(id, term);\n return id;\n }\n\n public find(term: Term): number | undefined {\n const identity = this.toIdentity(term);\n const cacheKey = this.identityCacheKey(identity);\n const cached = this.termCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const id = this.findId(identity);\n if (id !== undefined) {\n this.termCache.set(cacheKey, id);\n }\n return id;\n }\n\n public termForId(id: number): Term {\n const cached = this.idCache.get(id);\n if (cached) {\n return cached;\n }\n\n const row = this.db\n .prepare<RdfTermRow>('SELECT * FROM rdf_terms WHERE id = ?')\n .get(id);\n if (!row) {\n throw new Error(`RDF term not found: ${id}`);\n }\n\n const term = this.rowToTerm(row);\n this.idCache.set(id, term);\n return term;\n }\n\n public rowsForIds(ids: number[]): Map<number, Term> {\n const uniqueIds = Array.from(new Set(ids));\n const result = new Map<number, Term>();\n const missing: number[] = [];\n\n for (const id of uniqueIds) {\n const cached = this.idCache.get(id);\n if (cached) {\n result.set(id, cached);\n } else {\n missing.push(id);\n }\n }\n\n if (missing.length === 0) {\n return result;\n }\n\n const placeholders = missing.map(() => '?').join(', ');\n const rows = this.db\n .prepare<RdfTermRow>(`SELECT * FROM rdf_terms WHERE id IN (${placeholders})`)\n .all(...missing);\n\n for (const row of rows) {\n const term = this.rowToTerm(row);\n this.idCache.set(row.id, term);\n result.set(row.id, term);\n }\n\n return result;\n }\n\n public idsByValuePrefix(kind: RdfTermKind | RdfTermKind[], prefix: string): number[] {\n const kinds = Array.isArray(kind) ? kind : [kind];\n if (kinds.length === 0) {\n return [];\n }\n const rows = this.db\n .prepare<{ id: number; value: string }>(`\n SELECT id, value FROM rdf_terms\n WHERE kind IN (${kinds.map(() => '?').join(', ')})\n AND value_head >= ?\n AND value_head < ?\n AND value >= ?\n AND value < ?\n `)\n .all(...kinds, rdfTermValueHead(prefix), `${rdfTermValueHead(prefix)}\\uffff`, prefix, `${prefix}\\uffff`);\n return rows\n .filter((row) => row.value.startsWith(prefix))\n .map((row) => row.id);\n }\n\n public idsByNormalizedTextContains(kind: RdfTermKind | RdfTermKind[], text: string): number[] {\n const kinds = Array.isArray(kind) ? kind : [kind];\n if (kinds.length === 0) {\n return [];\n }\n const needle = normalizeSearchText(text);\n const rows = this.db\n .prepare<{ id: number; value: string }>(`\n SELECT id, value FROM rdf_terms\n WHERE kind IN (${kinds.map(() => '?').join(', ')})\n AND normalized_text LIKE ? ESCAPE '\\\\'\n `)\n .all(...kinds, `%${escapeLikePattern(needle)}%`);\n return rows\n .filter((row) => row.value.includes(text))\n .map((row) => row.id);\n }\n\n public idsByNormalizedTextSuffix(kind: RdfTermKind | RdfTermKind[], suffix: string): number[] {\n const kinds = Array.isArray(kind) ? kind : [kind];\n if (kinds.length === 0) {\n return [];\n }\n const needle = normalizeSearchText(suffix);\n const rows = this.db\n .prepare<{ id: number; value: string }>(`\n SELECT id, value FROM rdf_terms\n WHERE kind IN (${kinds.map(() => '?').join(', ')})\n AND normalized_text LIKE ? ESCAPE '\\\\'\n `)\n .all(...kinds, `%${escapeLikePattern(needle)}`);\n return rows\n .filter((row) => row.value.endsWith(suffix))\n .map((row) => row.id);\n }\n\n public idsByNormalizedTextRegex(kind: RdfTermKind | RdfTermKind[], pattern: string, flags?: string): number[] {\n const kinds = Array.isArray(kind) ? kind : [kind];\n if (kinds.length === 0) {\n return [];\n }\n const rows = this.db\n .prepare<RdfTermRow>(`\n SELECT * FROM rdf_terms\n WHERE kind IN (${kinds.map(() => '?').join(', ')})\n AND normalized_text IS NOT NULL\n `)\n .all(...kinds);\n const regex = new RegExp(pattern, flags);\n return rows\n .filter((row) => regex.test(row.value))\n .map((row) => row.id);\n }\n\n public count(): number {\n const row = this.db.prepare<{ count: number }>('SELECT COUNT(*) AS count FROM rdf_terms').get();\n return row?.count ?? 0;\n }\n\n private findId(identity: RdfTermIdentity): number | undefined {\n const rows = this.db\n .prepare<RdfTermRow>('SELECT * FROM rdf_terms WHERE hash = ?')\n .all(identity.hash);\n return rows.find((row) => this.rowMatchesIdentity(row, identity))?.id;\n }\n\n private toIdentity(term: Term): RdfTermIdentity {\n switch (term.termType) {\n case 'NamedNode':\n return this.identity('iri', term.value, null, null, term.value, null);\n case 'BlankNode':\n return this.identity('blank', term.value, null, null, term.value, null);\n case 'DefaultGraph':\n return this.identity('default_graph', '', null, null, null, null);\n case 'Literal': {\n const datatypeValue = term.datatype?.value || XSD_STRING;\n const datatypeId = datatypeValue === XSD_STRING && !term.language\n ? null\n : this.getOrCreate(DataFactory.namedNode(datatypeValue));\n return this.identity(\n 'literal',\n term.value,\n datatypeId,\n term.language || null,\n term.value,\n this.numericValueForLiteral(term.value, datatypeValue),\n );\n }\n case 'Variable':\n throw new Error(`Variables cannot be indexed as RDF terms: ${term.value}`);\n case 'Quad':\n throw new Error('Nested RDF-star quads are not supported by the first SolidRdfEngine index');\n default: {\n const exhaustive: never = term;\n throw new Error(`Unsupported RDF term: ${String(exhaustive)}`);\n }\n }\n }\n\n private identity(\n kind: RdfTermKind,\n value: string,\n datatypeId: number | null,\n lang: string | null,\n normalizedText: string | null,\n numericValue: number | null,\n ): RdfTermIdentity {\n const hash = createHash('sha256')\n .update(kind)\n .update('\\0')\n .update(value)\n .update('\\0')\n .update(String(datatypeId ?? ''))\n .update('\\0')\n .update(lang ?? '')\n .digest('hex');\n return {\n kind,\n value,\n valueHead: rdfTermValueHead(value),\n datatypeId,\n lang,\n normalizedText: normalizedText ? normalizedText.toLowerCase() : null,\n numericValue,\n hash,\n };\n }\n\n private numericValueForLiteral(value: string, datatypeValue: string): number | null {\n if (!isRdfNumericDatatype(datatypeValue)) {\n return null;\n }\n const numeric = rdfNumericValue(value);\n return Number.isFinite(numeric) ? numeric : null;\n }\n\n private ensureSafeTermTableSchema(): void {\n const table = this.db\n .prepare<{ sql: string | null }>(\"SELECT sql FROM sqlite_schema WHERE type = 'table' AND name = 'rdf_terms'\")\n .get();\n if (!table) {\n this.createSafeTermTable('rdf_terms');\n return;\n }\n\n const columns = this.termTableColumns();\n const hasRawUniqueConstraint = table.sql?.includes('UNIQUE (kind, value, datatype_id, lang)') ?? false;\n if (!hasRawUniqueConstraint && columns.has('value_head') && columns.has('numeric_value')) {\n return;\n }\n\n const foreignKeys = this.db.prepare<{ foreign_keys: number }>('PRAGMA foreign_keys').get()?.foreign_keys ?? 0;\n this.db.exec('PRAGMA foreign_keys = OFF;');\n try {\n this.db.transaction(() => {\n this.db.exec('DROP TABLE IF EXISTS rdf_terms_next;');\n this.createSafeTermTable('rdf_terms_next');\n this.db.exec(`\n INSERT INTO rdf_terms_next (\n id,\n kind,\n value,\n value_head,\n datatype_id,\n lang,\n hash,\n normalized_text,\n numeric_value,\n created_at\n )\n SELECT\n id,\n kind,\n value,\n substr(value, 1, ${RDF_TERM_VALUE_HEAD_LENGTH}),\n datatype_id,\n lang,\n hash,\n normalized_text,\n ${columns.has('numeric_value') ? 'numeric_value' : 'NULL'},\n created_at\n FROM rdf_terms;\n `);\n this.db.exec(`\n DROP TABLE rdf_terms;\n ALTER TABLE rdf_terms_next RENAME TO rdf_terms;\n `);\n })();\n } finally {\n if (foreignKeys) {\n this.db.exec('PRAGMA foreign_keys = ON;');\n }\n }\n }\n\n private createSafeTermTable(name: string): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS ${name} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n kind TEXT NOT NULL,\n value TEXT NOT NULL,\n value_head TEXT NOT NULL,\n datatype_id INTEGER,\n lang TEXT,\n hash TEXT NOT NULL,\n normalized_text TEXT,\n numeric_value REAL,\n created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))\n );\n `);\n }\n\n private dropUnsafeRawTextIndexes(): void {\n this.db.exec(`\n DROP INDEX IF EXISTS rdf_terms_hash;\n DROP INDEX IF EXISTS rdf_terms_kind_value;\n DROP INDEX IF EXISTS rdf_terms_normalized_text;\n `);\n }\n\n private ensureValueHeadColumn(): void {\n const columns = this.termTableColumns();\n if (!columns.has('value_head')) {\n this.db.exec('ALTER TABLE rdf_terms ADD COLUMN value_head TEXT;');\n }\n this.db.exec(`\n UPDATE rdf_terms\n SET value_head = substr(value, 1, ${RDF_TERM_VALUE_HEAD_LENGTH})\n WHERE value_head IS NULL;\n `);\n }\n\n private ensureNumericValueColumn(): void {\n const columns = this.termTableColumns();\n if (columns.has('numeric_value')) {\n return;\n }\n this.db.exec('ALTER TABLE rdf_terms ADD COLUMN numeric_value REAL;');\n }\n\n private backfillNumericValues(): void {\n const rows = this.db.prepare<RdfTermRow>(`\n SELECT literal.*\n FROM rdf_terms literal\n JOIN rdf_terms datatype ON datatype.id = literal.datatype_id\n WHERE literal.kind = 'literal'\n AND literal.numeric_value IS NULL\n AND datatype.kind = 'iri'\n `).all();\n const update = this.db.prepare('UPDATE rdf_terms SET numeric_value = ? WHERE id = ?');\n for (const row of rows) {\n const datatype = this.termForId(row.datatype_id as number);\n if (datatype.termType !== 'NamedNode') {\n continue;\n }\n const numericValue = this.numericValueForLiteral(row.value, datatype.value);\n if (numericValue !== null) {\n update.run(numericValue, row.id);\n }\n }\n }\n\n private identityCacheKey(identity: RdfTermIdentity): string {\n return [\n identity.kind,\n identity.value,\n identity.datatypeId ?? '',\n identity.lang ?? '',\n ].join('\\u001f');\n }\n\n private rowMatchesIdentity(row: RdfTermRow, identity: RdfTermIdentity): boolean {\n return row.kind === identity.kind\n && row.value === identity.value\n && row.datatype_id === identity.datatypeId\n && row.lang === identity.lang;\n }\n\n private termTableColumns(): Set<string> {\n return new Set(this.db.prepare<{ name: string }>('PRAGMA table_info(rdf_terms)').all().map((column) => column.name));\n }\n\n private rowToTerm(row: RdfTermRow): Term {\n switch (row.kind) {\n case 'iri':\n return DataFactory.namedNode(row.value);\n case 'blank':\n return DataFactory.blankNode(row.value);\n case 'default_graph':\n return DataFactory.defaultGraph();\n case 'literal': {\n if (row.lang) {\n return DataFactory.literal(row.value, row.lang);\n }\n if (row.datatype_id) {\n const datatype = this.termForId(row.datatype_id);\n if (datatype.termType === 'NamedNode' && datatype.value !== XSD_STRING && datatype.value !== RDF_LANG_STRING) {\n return DataFactory.literal(row.value, datatype);\n }\n }\n return DataFactory.literal(row.value);\n }\n default:\n throw new Error(`Unsupported RDF term kind in dictionary row: ${(row as RdfTermRow).kind}`);\n }\n }\n}\n\nexport function rdfTermValueHead(value: string): string {\n return value.slice(0, RDF_TERM_VALUE_HEAD_LENGTH);\n}\n\nfunction normalizeSearchText(value: string): string {\n return value.toLowerCase();\n}\n\nfunction escapeLikePattern(value: string): string {\n return value.replace(/[\\\\%_]/g, (match) => `\\\\${match}`);\n}\n"]}
@@ -87,6 +87,22 @@
87
87
  "@id": "undefineds:dist/storage/rdf/RdfTermDictionary.jsonld#RdfTermDictionary__member_numericValueForLiteral",
88
88
  "memberFieldName": "numericValueForLiteral"
89
89
  },
90
+ {
91
+ "@id": "undefineds:dist/storage/rdf/RdfTermDictionary.jsonld#RdfTermDictionary__member_ensureSafeTermTableSchema",
92
+ "memberFieldName": "ensureSafeTermTableSchema"
93
+ },
94
+ {
95
+ "@id": "undefineds:dist/storage/rdf/RdfTermDictionary.jsonld#RdfTermDictionary__member_createSafeTermTable",
96
+ "memberFieldName": "createSafeTermTable"
97
+ },
98
+ {
99
+ "@id": "undefineds:dist/storage/rdf/RdfTermDictionary.jsonld#RdfTermDictionary__member_dropUnsafeRawTextIndexes",
100
+ "memberFieldName": "dropUnsafeRawTextIndexes"
101
+ },
102
+ {
103
+ "@id": "undefineds:dist/storage/rdf/RdfTermDictionary.jsonld#RdfTermDictionary__member_ensureValueHeadColumn",
104
+ "memberFieldName": "ensureValueHeadColumn"
105
+ },
90
106
  {
91
107
  "@id": "undefineds:dist/storage/rdf/RdfTermDictionary.jsonld#RdfTermDictionary__member_ensureNumericValueColumn",
92
108
  "memberFieldName": "ensureNumericValueColumn"
@@ -99,6 +115,14 @@
99
115
  "@id": "undefineds:dist/storage/rdf/RdfTermDictionary.jsonld#RdfTermDictionary__member_identityCacheKey",
100
116
  "memberFieldName": "identityCacheKey"
101
117
  },
118
+ {
119
+ "@id": "undefineds:dist/storage/rdf/RdfTermDictionary.jsonld#RdfTermDictionary__member_rowMatchesIdentity",
120
+ "memberFieldName": "rowMatchesIdentity"
121
+ },
122
+ {
123
+ "@id": "undefineds:dist/storage/rdf/RdfTermDictionary.jsonld#RdfTermDictionary__member_termTableColumns",
124
+ "memberFieldName": "termTableColumns"
125
+ },
102
126
  {
103
127
  "@id": "undefineds:dist/storage/rdf/RdfTermDictionary.jsonld#RdfTermDictionary__member_rowToTerm",
104
128
  "memberFieldName": "rowToTerm"
@@ -6,6 +6,7 @@ const node_fs_1 = require("node:fs");
6
6
  const node_path_1 = require("node:path");
7
7
  const HeadingChunker_1 = require("../../document/HeadingChunker");
8
8
  const SqliteRuntime_1 = require("../SqliteRuntime");
9
+ const RDF_TEXT_TERM_MAX_INDEX_LENGTH = 256;
9
10
  class RdfTextIndex {
10
11
  constructor(options) {
11
12
  this.options = options;
@@ -241,7 +242,7 @@ class RdfTextIndex {
241
242
 
242
243
  CREATE TABLE IF NOT EXISTS rdf_text_terms (
243
244
  id INTEGER PRIMARY KEY AUTOINCREMENT,
244
- term TEXT NOT NULL,
245
+ term TEXT NOT NULL CHECK (length(term) <= ${RDF_TEXT_TERM_MAX_INDEX_LENGTH}),
245
246
  source_id INTEGER NOT NULL,
246
247
  chunk_id INTEGER NOT NULL,
247
248
  occurrences INTEGER NOT NULL,
@@ -254,10 +255,12 @@ class RdfTextIndex {
254
255
  CREATE INDEX IF NOT EXISTS rdf_text_sources_workspace ON rdf_text_sources(workspace);
255
256
  CREATE INDEX IF NOT EXISTS rdf_text_sources_source ON rdf_text_sources(source);
256
257
  CREATE INDEX IF NOT EXISTS rdf_text_chunks_source ON rdf_text_chunks(source_id, ordinal);
257
- CREATE INDEX IF NOT EXISTS rdf_text_chunks_normalized ON rdf_text_chunks(normalized_text);
258
+ DELETE FROM rdf_text_terms WHERE length(term) > ${RDF_TEXT_TERM_MAX_INDEX_LENGTH};
258
259
  CREATE INDEX IF NOT EXISTS rdf_text_terms_term ON rdf_text_terms(term);
259
260
  CREATE INDEX IF NOT EXISTS rdf_text_terms_source_term ON rdf_text_terms(source_id, term);
260
261
  CREATE INDEX IF NOT EXISTS rdf_text_terms_chunk ON rdf_text_terms(chunk_id);
262
+
263
+ DROP INDEX IF EXISTS rdf_text_chunks_normalized;
261
264
  `);
262
265
  this.backfillTermPostings();
263
266
  }
@@ -451,6 +454,9 @@ function tokenizeNormalizedText(value) {
451
454
  }
452
455
  function insertTermOccurrences(insertTerm, sourceId, chunkId, normalizedText) {
453
456
  for (const [term, occurrences] of termOccurrences(normalizedText)) {
457
+ if (term.length > RDF_TEXT_TERM_MAX_INDEX_LENGTH) {
458
+ continue;
459
+ }
454
460
  insertTerm.run(term, sourceId, chunkId, occurrences);
455
461
  }
456
462
  }
@@ -462,7 +468,8 @@ function termOccurrences(normalizedText) {
462
468
  return terms;
463
469
  }
464
470
  function buildTextSearchPredicate(query) {
465
- const terms = [...new Set(tokenizeNormalizedText(query))];
471
+ const terms = [...new Set(tokenizeNormalizedText(query))]
472
+ .filter((term) => term.length <= RDF_TEXT_TERM_MAX_INDEX_LENGTH);
466
473
  const phraseCondition = "chunk.normalized_text LIKE ? ESCAPE '\\'";
467
474
  const phrasePattern = `%${escapeLikePattern(query)}%`;
468
475
  if (terms.length === 0) {