@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.
- package/config/bun.json +57 -11
- package/config/cloud.json +14 -12
- package/config/local.json +16 -14
- package/config/xpod.json +47 -9
- package/dist/api/matrix/PodMatrixStore.d.ts +4 -7
- package/dist/api/matrix/PodMatrixStore.js +116 -148
- package/dist/api/matrix/PodMatrixStore.js.map +1 -1
- package/dist/api/matrix/types.d.ts +2 -0
- package/dist/api/matrix/types.js.map +1 -1
- package/dist/components/components.jsonld +3 -0
- package/dist/components/context.jsonld +71 -32
- package/dist/http/SubgraphSparqlHttpHandler.d.ts +1 -0
- package/dist/http/SubgraphSparqlHttpHandler.js +27 -4
- package/dist/http/SubgraphSparqlHttpHandler.js.map +1 -1
- package/dist/http/SubgraphSparqlHttpHandler.jsonld +4 -0
- package/dist/http/vector/VectorHttpHandler.d.ts +5 -1
- package/dist/http/vector/VectorHttpHandler.js +5 -5
- package/dist/http/vector/VectorHttpHandler.js.map +1 -1
- package/dist/http/vector/VectorHttpHandler.jsonld +40 -28
- package/dist/index.d.ts +5 -2
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/runtime/Proxy.d.ts +3 -0
- package/dist/runtime/Proxy.js +31 -7
- package/dist/runtime/Proxy.js.map +1 -1
- package/dist/storage/SparqlUpdateResourceStore.js +94 -33
- package/dist/storage/SparqlUpdateResourceStore.js.map +1 -1
- package/dist/storage/accessors/MixDataAccessor.d.ts +22 -5
- package/dist/storage/accessors/MixDataAccessor.js +376 -61
- package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
- package/dist/storage/accessors/MixDataAccessor.jsonld +73 -5
- package/dist/storage/accessors/QuadstoreSparqlDataAccessor.js +32 -10
- package/dist/storage/accessors/QuadstoreSparqlDataAccessor.js.map +1 -1
- package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js +28 -6
- package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js.map +1 -1
- package/dist/storage/accessors/SolidRdfDataAccessor.d.ts +45 -0
- package/dist/storage/accessors/SolidRdfDataAccessor.js +277 -0
- package/dist/storage/accessors/SolidRdfDataAccessor.js.map +1 -0
- package/dist/storage/accessors/SolidRdfDataAccessor.jsonld +161 -0
- package/dist/storage/rdf/Rdf3xIndex.d.ts +122 -0
- package/dist/storage/rdf/Rdf3xIndex.js +2695 -0
- package/dist/storage/rdf/Rdf3xIndex.js.map +1 -0
- package/dist/storage/rdf/Rdf3xIndex.jsonld +528 -0
- package/dist/storage/rdf/Rdf3xSchema.d.ts +20 -0
- package/dist/storage/rdf/Rdf3xSchema.js +65 -0
- package/dist/storage/rdf/Rdf3xSchema.js.map +1 -0
- package/dist/storage/rdf/RdfLocalQueryEngine.d.ts +10 -4
- package/dist/storage/rdf/RdfLocalQueryEngine.js +607 -127
- package/dist/storage/rdf/RdfLocalQueryEngine.js.map +1 -1
- package/dist/storage/rdf/RdfQuadIndex.d.ts +12 -1
- package/dist/storage/rdf/RdfQuadIndex.js +152 -22
- package/dist/storage/rdf/RdfQuadIndex.js.map +1 -1
- package/dist/storage/rdf/RdfQuadIndex.jsonld +36 -4
- package/dist/storage/rdf/RdfSparqlAdapter.d.ts +20 -2
- package/dist/storage/rdf/RdfSparqlAdapter.js +364 -40
- package/dist/storage/rdf/RdfSparqlAdapter.js.map +1 -1
- package/dist/storage/rdf/RdfSparqlAdapter.jsonld +60 -0
- package/dist/storage/rdf/RdfTermDictionary.d.ts +8 -0
- package/dist/storage/rdf/RdfTermDictionary.js +141 -70
- package/dist/storage/rdf/RdfTermDictionary.js.map +1 -1
- package/dist/storage/rdf/RdfTermDictionary.jsonld +24 -0
- package/dist/storage/rdf/RdfTextIndex.js +10 -3
- package/dist/storage/rdf/RdfTextIndex.js.map +1 -1
- package/dist/storage/rdf/SolidRdfEngine.d.ts +15 -6
- package/dist/storage/rdf/SolidRdfEngine.js +218 -25
- package/dist/storage/rdf/SolidRdfEngine.js.map +1 -1
- package/dist/storage/rdf/SolidRdfEngine.jsonld +70 -7
- package/dist/storage/rdf/SolidRdfSparqlEngine.d.ts +11 -7
- package/dist/storage/rdf/SolidRdfSparqlEngine.js +60 -47
- package/dist/storage/rdf/SolidRdfSparqlEngine.js.map +1 -1
- package/dist/storage/rdf/SolidRdfSparqlEngine.jsonld +9 -5
- package/dist/storage/rdf/index.d.ts +2 -2
- package/dist/storage/rdf/index.js +3 -3
- package/dist/storage/rdf/index.js.map +1 -1
- package/dist/storage/rdf/models-benchmark.d.ts +12 -1
- package/dist/storage/rdf/models-benchmark.js +549 -32
- package/dist/storage/rdf/models-benchmark.js.map +1 -1
- package/dist/storage/rdf/types.d.ts +81 -7
- package/dist/storage/rdf/types.js.map +1 -1
- package/dist/storage/sparql/CompatibilitySparqlEngine.d.ts +36 -0
- package/dist/storage/sparql/CompatibilitySparqlEngine.js +96 -0
- package/dist/storage/sparql/CompatibilitySparqlEngine.js.map +1 -0
- package/dist/storage/sparql/CompatibilitySparqlEngine.jsonld +123 -0
- package/dist/storage/sparql/CompatibilitySparqlEngineImpl.d.ts +35 -0
- package/dist/storage/sparql/CompatibilitySparqlEngineImpl.js +112 -0
- package/dist/storage/sparql/CompatibilitySparqlEngineImpl.js.map +1 -0
- package/dist/storage/sparql/SubgraphQueryEngine.d.ts +1 -36
- package/dist/storage/sparql/SubgraphQueryEngine.js +2 -115
- package/dist/storage/sparql/SubgraphQueryEngine.js.map +1 -1
- package/dist/storage/sparql/SubgraphQueryEngine.jsonld +1 -124
- package/dist/terminal/AclPermissionService.d.ts +2 -1
- package/dist/terminal/AclPermissionService.js +26 -3
- package/dist/terminal/AclPermissionService.js.map +1 -1
- package/dist/terminal/TerminalSessionManager.js +25 -3
- package/dist/terminal/TerminalSessionManager.js.map +1 -1
- package/package.json +1 -1
- package/dist/storage/rdf/Rdf3xTripleIndex.d.ts +0 -55
- package/dist/storage/rdf/Rdf3xTripleIndex.js +0 -1235
- 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
|
|
18
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
188
|
-
?
|
|
189
|
-
|
|
190
|
-
|
|
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.
|
|
286
|
-
if (columns.
|
|
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":"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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 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
|
-
|
|
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) {
|