@undefineds.co/xpod 0.2.43 → 0.2.45
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/dist/components/context.jsonld +45 -0
- package/dist/runtime/configure-drizzle-solid.js +52 -0
- package/dist/runtime/configure-drizzle-solid.js.map +1 -1
- package/dist/storage/quint/BaseQuintStore.jsonld +82 -0
- package/dist/storage/quint/PgQuintStore.d.ts +49 -3
- package/dist/storage/quint/PgQuintStore.js +677 -31
- package/dist/storage/quint/PgQuintStore.js.map +1 -1
- package/dist/storage/quint/PgQuintStore.jsonld +226 -0
- package/dist/storage/quint/SqliteQuintStore.d.ts +1 -0
- package/dist/storage/quint/SqliteQuintStore.js +52 -0
- package/dist/storage/quint/SqliteQuintStore.js.map +1 -1
- package/dist/storage/quint/SqliteQuintStore.jsonld +86 -0
- package/dist/storage/quint/index.d.ts +1 -0
- package/dist/storage/quint/index.js +1 -0
- package/dist/storage/quint/index.js.map +1 -1
- package/dist/storage/quint/types.d.ts +19 -0
- package/dist/storage/quint/types.js.map +1 -1
- package/dist/storage/quint/value-types.d.ts +32 -0
- package/dist/storage/quint/value-types.js +100 -0
- package/dist/storage/quint/value-types.js.map +1 -0
- package/dist/storage/sparql/FilterPushdownExtractor.js +23 -11
- package/dist/storage/sparql/FilterPushdownExtractor.js.map +1 -1
- package/dist/util/identifiers/ClusterIdentifierStrategy.js +29 -1
- package/dist/util/identifiers/ClusterIdentifierStrategy.js.map +1 -1
- package/package.json +1 -1
- package/scripts/patch-jose.js +62 -12
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.PgQuintStore = void 0;
|
|
14
14
|
const pglite_1 = require("@electric-sql/pglite");
|
|
15
|
+
const node_crypto_1 = require("node:crypto");
|
|
15
16
|
const BaseQuintStore_1 = require("./BaseQuintStore");
|
|
17
|
+
const serialization_1 = require("./serialization");
|
|
18
|
+
const value_types_1 = require("./value-types");
|
|
16
19
|
const PostgresPoolManager_1 = require("../database/PostgresPoolManager");
|
|
17
20
|
/**
|
|
18
21
|
* PostgreSQL 兼容的分隔符
|
|
@@ -31,6 +34,9 @@ function toPgSafe(str) {
|
|
|
31
34
|
function fromPgSafe(str) {
|
|
32
35
|
return str.replace(new RegExp(PG_SEP, 'g'), '\u0000');
|
|
33
36
|
}
|
|
37
|
+
function digestObject(value) {
|
|
38
|
+
return (0, node_crypto_1.createHash)('sha256').update(toPgSafe(value)).digest('hex');
|
|
39
|
+
}
|
|
34
40
|
/**
|
|
35
41
|
* PGLite 执行器
|
|
36
42
|
*/
|
|
@@ -157,6 +163,7 @@ class PgQuintStore extends BaseQuintStore_1.BaseQuintStore {
|
|
|
157
163
|
super(options);
|
|
158
164
|
this.pglite = null;
|
|
159
165
|
this.pgPool = null; // pg.Pool
|
|
166
|
+
this.sharedPoolConfig = null;
|
|
160
167
|
this.pgOptions = {
|
|
161
168
|
driver: 'pglite', // 默认使用 PGLite
|
|
162
169
|
...options,
|
|
@@ -167,17 +174,19 @@ class PgQuintStore extends BaseQuintStore_1.BaseQuintStore {
|
|
|
167
174
|
// 使用共享的连接池(如果提供),避免死锁
|
|
168
175
|
if (this.pgOptions.pool) {
|
|
169
176
|
this.pgPool = this.pgOptions.pool;
|
|
177
|
+
this.sharedPoolConfig = null;
|
|
170
178
|
return new PgExecutor(this.pgPool);
|
|
171
179
|
}
|
|
172
180
|
// 使用共享连接池管理器,避免多个组件创建独立连接池
|
|
173
|
-
this.
|
|
181
|
+
this.sharedPoolConfig = {
|
|
174
182
|
connectionString: this.pgOptions.connectionString,
|
|
175
183
|
host: this.pgOptions.host,
|
|
176
184
|
port: this.pgOptions.port,
|
|
177
185
|
database: this.pgOptions.database,
|
|
178
186
|
user: this.pgOptions.user,
|
|
179
187
|
password: this.pgOptions.password,
|
|
180
|
-
}
|
|
188
|
+
};
|
|
189
|
+
this.pgPool = (0, PostgresPoolManager_1.getSharedPool)(this.sharedPoolConfig);
|
|
181
190
|
return new PgExecutor(this.pgPool);
|
|
182
191
|
}
|
|
183
192
|
else {
|
|
@@ -193,8 +202,14 @@ class PgQuintStore extends BaseQuintStore_1.BaseQuintStore {
|
|
|
193
202
|
this.pglite = null;
|
|
194
203
|
}
|
|
195
204
|
if (this.pgPool) {
|
|
196
|
-
|
|
205
|
+
if (this.sharedPoolConfig) {
|
|
206
|
+
(0, PostgresPoolManager_1.releaseSharedPool)(this.sharedPoolConfig);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
await this.pgPool.end();
|
|
210
|
+
}
|
|
197
211
|
this.pgPool = null;
|
|
212
|
+
this.sharedPoolConfig = null;
|
|
198
213
|
}
|
|
199
214
|
}
|
|
200
215
|
/**
|
|
@@ -208,43 +223,45 @@ class PgQuintStore extends BaseQuintStore_1.BaseQuintStore {
|
|
|
208
223
|
// PostgreSQL 建表语法
|
|
209
224
|
await this.executor.exec(`
|
|
210
225
|
CREATE TABLE IF NOT EXISTS quints (
|
|
226
|
+
object_kind TEXT,
|
|
227
|
+
object_key TEXT,
|
|
228
|
+
object_text TEXT,
|
|
229
|
+
object_digest TEXT,
|
|
211
230
|
graph TEXT NOT NULL,
|
|
212
231
|
subject TEXT NOT NULL,
|
|
213
232
|
predicate TEXT NOT NULL,
|
|
214
233
|
object TEXT NOT NULL,
|
|
215
|
-
vector TEXT
|
|
216
|
-
PRIMARY KEY (graph, subject, predicate, object)
|
|
234
|
+
vector TEXT
|
|
217
235
|
)
|
|
218
236
|
`);
|
|
237
|
+
await this.ensureTypedObjectSchema();
|
|
219
238
|
const indexes = [
|
|
220
|
-
'CREATE INDEX IF NOT EXISTS
|
|
221
|
-
'CREATE INDEX IF NOT EXISTS
|
|
222
|
-
'CREATE INDEX IF NOT EXISTS
|
|
223
|
-
'CREATE INDEX IF NOT EXISTS
|
|
224
|
-
'CREATE INDEX IF NOT EXISTS
|
|
225
|
-
'CREATE INDEX IF NOT EXISTS
|
|
239
|
+
'CREATE INDEX IF NOT EXISTS idx_quints_graph ON quints (graph)',
|
|
240
|
+
'CREATE INDEX IF NOT EXISTS idx_quints_subject ON quints (subject)',
|
|
241
|
+
'CREATE INDEX IF NOT EXISTS idx_quints_predicate ON quints (predicate)',
|
|
242
|
+
'CREATE INDEX IF NOT EXISTS idx_quints_object_key ON quints (object_kind, object_key)',
|
|
243
|
+
'CREATE INDEX IF NOT EXISTS idx_quints_predicate_object_key ON quints (predicate, object_kind, object_key)',
|
|
244
|
+
'CREATE INDEX IF NOT EXISTS idx_quints_predicate_object_digest ON quints (predicate, object_kind, object_digest)',
|
|
245
|
+
'CREATE UNIQUE INDEX IF NOT EXISTS idx_quints_gspo_key ON quints (graph, subject, predicate, object_kind, object_key) WHERE object_key IS NOT NULL',
|
|
246
|
+
'CREATE UNIQUE INDEX IF NOT EXISTS idx_quints_gspo_digest ON quints (graph, subject, predicate, object_kind, object_digest) WHERE object_digest IS NOT NULL',
|
|
247
|
+
'CREATE INDEX IF NOT EXISTS idx_quints_gsp ON quints (graph, subject, predicate)',
|
|
248
|
+
'CREATE INDEX IF NOT EXISTS idx_quints_sp ON quints (subject, predicate)',
|
|
249
|
+
'CREATE INDEX IF NOT EXISTS idx_quints_gp ON quints (graph, predicate)',
|
|
226
250
|
];
|
|
227
251
|
for (const indexSql of indexes) {
|
|
228
252
|
await this.executor.exec(indexSql);
|
|
229
253
|
}
|
|
230
254
|
}
|
|
231
255
|
/**
|
|
232
|
-
* 重写 put
|
|
256
|
+
* 重写 put 方法,避免长文本对象进入 PostgreSQL btree 唯一键
|
|
233
257
|
*/
|
|
234
258
|
async put(quint) {
|
|
235
259
|
this.ensureOpen();
|
|
236
|
-
const row = this.
|
|
237
|
-
|
|
238
|
-
const sql = `
|
|
239
|
-
INSERT INTO quints (graph, subject, predicate, object, vector)
|
|
240
|
-
VALUES ($1, $2, $3, $4, $5)
|
|
241
|
-
ON CONFLICT (graph, subject, predicate, object)
|
|
242
|
-
DO UPDATE SET vector = EXCLUDED.vector
|
|
243
|
-
`;
|
|
244
|
-
await this.executor.execute(sql, [row.graph, row.subject, row.predicate, row.object, row.vector]);
|
|
260
|
+
const row = this.quintToPgRow(quint);
|
|
261
|
+
await this.executor.executeInTransaction(this.writeStatementsForRow(row));
|
|
245
262
|
}
|
|
246
263
|
/**
|
|
247
|
-
* 重写 multiPut
|
|
264
|
+
* 重写 multiPut 方法,使用同一事务保持批量写入幂等
|
|
248
265
|
*/
|
|
249
266
|
async multiPut(quintList) {
|
|
250
267
|
console.log(`[PgQuintStore.multiPut] Starting: ${quintList.length} quints`);
|
|
@@ -253,22 +270,651 @@ class PgQuintStore extends BaseQuintStore_1.BaseQuintStore {
|
|
|
253
270
|
console.log(`[PgQuintStore.multiPut] Empty list, skipping`);
|
|
254
271
|
return;
|
|
255
272
|
}
|
|
273
|
+
const statements = quintList.flatMap(quint => {
|
|
274
|
+
const row = this.quintToPgRow(quint);
|
|
275
|
+
return this.writeStatementsForRow(row);
|
|
276
|
+
});
|
|
277
|
+
console.log(`[PgQuintStore.multiPut] Executing ${statements.length} statements in transaction`);
|
|
278
|
+
const start = Date.now();
|
|
279
|
+
await this.executor.executeInTransaction(statements);
|
|
280
|
+
console.log(`[PgQuintStore.multiPut] Completed in ${Date.now() - start}ms`);
|
|
281
|
+
}
|
|
282
|
+
async multiDel(quintList) {
|
|
283
|
+
this.ensureOpen();
|
|
284
|
+
if (quintList.length === 0)
|
|
285
|
+
return;
|
|
256
286
|
const statements = quintList.map(quint => {
|
|
257
|
-
const row = this.
|
|
287
|
+
const row = this.quintToPgRow(quint);
|
|
258
288
|
return {
|
|
259
289
|
sql: `
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
290
|
+
DELETE FROM quints
|
|
291
|
+
WHERE graph = $1
|
|
292
|
+
AND subject = $2
|
|
293
|
+
AND predicate = $3
|
|
294
|
+
AND object = $4
|
|
264
295
|
`,
|
|
265
|
-
params: [row.graph, row.subject, row.predicate, row.object
|
|
296
|
+
params: [row.graph, row.subject, row.predicate, row.object],
|
|
266
297
|
};
|
|
267
298
|
});
|
|
268
|
-
console.log(`[PgQuintStore.multiPut] Executing ${statements.length} statements in transaction`);
|
|
269
|
-
const start = Date.now();
|
|
270
299
|
await this.executor.executeInTransaction(statements);
|
|
271
|
-
|
|
300
|
+
}
|
|
301
|
+
async getAttributes(subjects, predicates, graph) {
|
|
302
|
+
this.ensureOpen();
|
|
303
|
+
if (subjects.length === 0 || predicates.length === 0) {
|
|
304
|
+
return new Map();
|
|
305
|
+
}
|
|
306
|
+
const subjectPlaceholders = subjects.map(() => '?').join(', ');
|
|
307
|
+
const predicatePlaceholders = predicates.map(() => '?').join(', ');
|
|
308
|
+
let sql = `
|
|
309
|
+
SELECT subject, predicate, object
|
|
310
|
+
FROM quints
|
|
311
|
+
WHERE subject IN (${subjectPlaceholders})
|
|
312
|
+
AND predicate IN (${predicatePlaceholders})
|
|
313
|
+
`;
|
|
314
|
+
const params = [...subjects, ...predicates];
|
|
315
|
+
if (graph && graph.termType !== 'DefaultGraph') {
|
|
316
|
+
const graphValue = (0, serialization_1.termToId)(graph);
|
|
317
|
+
sql += ` AND graph = ?`;
|
|
318
|
+
params.push(graphValue);
|
|
319
|
+
}
|
|
320
|
+
const rows = await this.executor.query(sql, params);
|
|
321
|
+
const result = new Map();
|
|
322
|
+
for (const row of rows) {
|
|
323
|
+
if (!result.has(row.subject)) {
|
|
324
|
+
result.set(row.subject, new Map());
|
|
325
|
+
}
|
|
326
|
+
const predicateMap = result.get(row.subject);
|
|
327
|
+
if (!predicateMap.has(row.predicate)) {
|
|
328
|
+
predicateMap.set(row.predicate, []);
|
|
329
|
+
}
|
|
330
|
+
predicateMap.get(row.predicate).push(this.deserializeObject(row.object));
|
|
331
|
+
}
|
|
332
|
+
return result;
|
|
333
|
+
}
|
|
334
|
+
buildWhereClause(pattern) {
|
|
335
|
+
const conditions = [];
|
|
336
|
+
const params = [];
|
|
337
|
+
const predicate = this.extractExactPredicate(pattern.predicate);
|
|
338
|
+
this.addPgCondition(conditions, params, 'graph', pattern.graph);
|
|
339
|
+
this.addPgCondition(conditions, params, 'subject', pattern.subject);
|
|
340
|
+
this.addPgCondition(conditions, params, 'predicate', pattern.predicate);
|
|
341
|
+
if (pattern.object) {
|
|
342
|
+
this.addObjectConditions(conditions, params, undefined, pattern.object, predicate);
|
|
343
|
+
}
|
|
344
|
+
const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';
|
|
345
|
+
return { whereClause, params };
|
|
346
|
+
}
|
|
347
|
+
addPgCondition(conditions, params, column, match) {
|
|
348
|
+
if (!match)
|
|
349
|
+
return;
|
|
350
|
+
if (typeof match === 'object' && 'termType' in match) {
|
|
351
|
+
const value = (0, serialization_1.termToId)(match);
|
|
352
|
+
conditions.push(`${column} = ?`);
|
|
353
|
+
params.push(value);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
const ops = match;
|
|
357
|
+
if (ops.$eq !== undefined) {
|
|
358
|
+
const value = this.serializeOpValue(ops.$eq, false, '$eq');
|
|
359
|
+
conditions.push(`${column} = ?`);
|
|
360
|
+
params.push(String(value));
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
super.addConditions(conditions, params, column, match, false);
|
|
364
|
+
}
|
|
365
|
+
addAliasedConditions(conditions, params, alias, pattern) {
|
|
366
|
+
this.addAliasedPgCondition(conditions, params, alias, 'graph', pattern.graph, false);
|
|
367
|
+
this.addAliasedPgCondition(conditions, params, alias, 'subject', pattern.subject, false);
|
|
368
|
+
this.addAliasedPgCondition(conditions, params, alias, 'predicate', pattern.predicate, false);
|
|
369
|
+
this.addAliasedObjectConditions(conditions, params, alias, pattern);
|
|
370
|
+
}
|
|
371
|
+
buildCompoundQuery(compound, options) {
|
|
372
|
+
const { patterns, joinOn, select } = compound;
|
|
373
|
+
const params = [];
|
|
374
|
+
let selectClause = `q0.${joinOn} as join_value`;
|
|
375
|
+
if (select) {
|
|
376
|
+
for (const s of select) {
|
|
377
|
+
selectClause += `, q${s.pattern}.${s.field} as ${s.alias}`;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
for (let i = 0; i < patterns.length; i++) {
|
|
382
|
+
selectClause += `, q${i}.object as p${i}_object`;
|
|
383
|
+
selectClause += `, q${i}.predicate as p${i}_predicate`;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
let fromClause = 'quints q0';
|
|
387
|
+
for (let i = 1; i < patterns.length; i++) {
|
|
388
|
+
fromClause += ` JOIN quints q${i} ON q0.${joinOn} = q${i}.${joinOn}`;
|
|
389
|
+
fromClause += ` AND q0.graph = q${i}.graph`;
|
|
390
|
+
}
|
|
391
|
+
const whereParts = [];
|
|
392
|
+
for (let i = 0; i < patterns.length; i++) {
|
|
393
|
+
const pattern = patterns[i];
|
|
394
|
+
const alias = `q${i}`;
|
|
395
|
+
this.addAliasedConditions(whereParts, params, alias, pattern);
|
|
396
|
+
}
|
|
397
|
+
let sql = `SELECT ${selectClause} FROM ${fromClause}`;
|
|
398
|
+
if (whereParts.length > 0) {
|
|
399
|
+
sql += ` WHERE ${whereParts.join(' AND ')}`;
|
|
400
|
+
}
|
|
401
|
+
if (options?.limit) {
|
|
402
|
+
sql += ` LIMIT ?`;
|
|
403
|
+
params.push(options.limit);
|
|
404
|
+
}
|
|
405
|
+
if (options?.offset) {
|
|
406
|
+
sql += ` OFFSET ?`;
|
|
407
|
+
params.push(options.offset);
|
|
408
|
+
}
|
|
409
|
+
return { sql, params };
|
|
410
|
+
}
|
|
411
|
+
buildSelectQuery(pattern, options) {
|
|
412
|
+
const { whereClause, params } = this.buildWhereClause(pattern);
|
|
413
|
+
let sql = `SELECT * FROM quints${whereClause}`;
|
|
414
|
+
if (options?.order && options.order.length > 0) {
|
|
415
|
+
const orderCols = options.order.map(field => {
|
|
416
|
+
if (field === 'object') {
|
|
417
|
+
const objectType = this.resolveObjectDataTypeForPattern(pattern);
|
|
418
|
+
if (objectType === 'longText') {
|
|
419
|
+
throw new Error('ORDER BY object is not supported for longText predicates');
|
|
420
|
+
}
|
|
421
|
+
return 'object_key';
|
|
422
|
+
}
|
|
423
|
+
return field;
|
|
424
|
+
}).join(', ');
|
|
425
|
+
sql += ` ORDER BY ${orderCols}`;
|
|
426
|
+
if (options.reverse) {
|
|
427
|
+
sql += ' DESC';
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (options?.limit) {
|
|
431
|
+
sql += ` LIMIT ?`;
|
|
432
|
+
params.push(options.limit);
|
|
433
|
+
}
|
|
434
|
+
if (options?.offset) {
|
|
435
|
+
sql += ` OFFSET ?`;
|
|
436
|
+
params.push(options.offset);
|
|
437
|
+
}
|
|
438
|
+
return { sql, params };
|
|
439
|
+
}
|
|
440
|
+
async count(pattern) {
|
|
441
|
+
const count = await super.count(pattern);
|
|
442
|
+
return Number(count);
|
|
443
|
+
}
|
|
444
|
+
async stats() {
|
|
445
|
+
const stats = await super.stats();
|
|
446
|
+
return {
|
|
447
|
+
totalCount: Number(stats.totalCount),
|
|
448
|
+
vectorCount: Number(stats.vectorCount),
|
|
449
|
+
graphCount: Number(stats.graphCount),
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
async ensureTypedObjectSchema() {
|
|
453
|
+
const statements = [
|
|
454
|
+
'ALTER TABLE quints ADD COLUMN IF NOT EXISTS object_kind TEXT',
|
|
455
|
+
'ALTER TABLE quints ADD COLUMN IF NOT EXISTS object_key TEXT',
|
|
456
|
+
'ALTER TABLE quints ADD COLUMN IF NOT EXISTS object_text TEXT',
|
|
457
|
+
'ALTER TABLE quints ADD COLUMN IF NOT EXISTS object_digest TEXT',
|
|
458
|
+
];
|
|
459
|
+
for (const statement of statements) {
|
|
460
|
+
await this.executor.exec(statement);
|
|
461
|
+
}
|
|
462
|
+
// The old Postgres schema indexed complete RDF terms. Long literals can
|
|
463
|
+
// exceed the btree tuple size and surface as 500s while creating containers.
|
|
464
|
+
const obsoleteIndexes = [
|
|
465
|
+
'idx_spog',
|
|
466
|
+
'idx_ogsp',
|
|
467
|
+
'idx_gspo',
|
|
468
|
+
'idx_sopg',
|
|
469
|
+
'idx_pogs',
|
|
470
|
+
'idx_gpos',
|
|
471
|
+
'idx_pg_spog',
|
|
472
|
+
'idx_pg_ogsp',
|
|
473
|
+
'idx_pg_gspo',
|
|
474
|
+
'idx_pg_sopg',
|
|
475
|
+
'idx_pg_pogs',
|
|
476
|
+
'idx_pg_gpos',
|
|
477
|
+
'idx_pg_graph_prefix',
|
|
478
|
+
'idx_quints_predicate_object_text',
|
|
479
|
+
'idx_quints_quint_hash',
|
|
480
|
+
'idx_quints_graph_hash',
|
|
481
|
+
'idx_quints_subject_hash',
|
|
482
|
+
'idx_quints_predicate_hash',
|
|
483
|
+
'idx_quints_object_hash',
|
|
484
|
+
'idx_quints_gsp_hash',
|
|
485
|
+
'idx_quints_sp_hash',
|
|
486
|
+
'idx_quints_gp_hash',
|
|
487
|
+
];
|
|
488
|
+
for (const indexName of obsoleteIndexes) {
|
|
489
|
+
await this.executor.exec(`DROP INDEX IF EXISTS ${indexName}`);
|
|
490
|
+
}
|
|
491
|
+
await this.executor.exec('ALTER TABLE quints DROP CONSTRAINT IF EXISTS quints_pkey');
|
|
492
|
+
const obsoleteColumns = [
|
|
493
|
+
'quint_hash',
|
|
494
|
+
'graph_hash',
|
|
495
|
+
'subject_hash',
|
|
496
|
+
'predicate_hash',
|
|
497
|
+
'object_hash',
|
|
498
|
+
];
|
|
499
|
+
for (const columnName of obsoleteColumns) {
|
|
500
|
+
await this.executor.exec(`ALTER TABLE quints DROP COLUMN IF EXISTS ${columnName}`);
|
|
501
|
+
}
|
|
502
|
+
await this.backfillMissingObjectIndexFields();
|
|
503
|
+
await this.executor.exec(`
|
|
504
|
+
UPDATE quints
|
|
505
|
+
SET object_kind = 'text'
|
|
506
|
+
WHERE object_kind = 'shortText'
|
|
507
|
+
`);
|
|
508
|
+
}
|
|
509
|
+
async backfillMissingObjectIndexFields() {
|
|
510
|
+
const rows = await this.executor.query(`
|
|
511
|
+
SELECT graph, subject, predicate, object
|
|
512
|
+
FROM quints
|
|
513
|
+
WHERE object_kind IS NULL
|
|
514
|
+
OR (object_key IS NULL AND object_digest IS NULL)
|
|
515
|
+
`);
|
|
516
|
+
for (const row of rows) {
|
|
517
|
+
const objectIndex = this.objectIndexForSerialized(row.predicate, row.object);
|
|
518
|
+
await this.executor.execute(`
|
|
519
|
+
UPDATE quints
|
|
520
|
+
SET object_kind = $1,
|
|
521
|
+
object_key = $2,
|
|
522
|
+
object_text = $3,
|
|
523
|
+
object_digest = $4
|
|
524
|
+
WHERE graph = $5
|
|
525
|
+
AND subject = $6
|
|
526
|
+
AND predicate = $7
|
|
527
|
+
AND object = $8
|
|
528
|
+
`, [
|
|
529
|
+
objectIndex.objectKind,
|
|
530
|
+
objectIndex.objectKey,
|
|
531
|
+
objectIndex.objectText,
|
|
532
|
+
this.objectDigestForIndex(row.object, objectIndex),
|
|
533
|
+
row.graph,
|
|
534
|
+
row.subject,
|
|
535
|
+
row.predicate,
|
|
536
|
+
row.object,
|
|
537
|
+
]);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
quintToPgRow(quint) {
|
|
541
|
+
const row = this.quintToRow(quint);
|
|
542
|
+
const objectIndex = this.objectIndexForTerm(row.predicate, quint.object);
|
|
543
|
+
return {
|
|
544
|
+
...row,
|
|
545
|
+
objectKind: objectIndex.objectKind,
|
|
546
|
+
objectKey: objectIndex.objectKey,
|
|
547
|
+
objectText: objectIndex.objectText,
|
|
548
|
+
objectDigest: this.objectDigestForIndex(row.object, objectIndex),
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
objectIndexForTerm(predicate, object) {
|
|
552
|
+
return (0, value_types_1.objectIndexFieldsFromTerm)(object, {
|
|
553
|
+
predicate,
|
|
554
|
+
predicateObjectDataTypes: this.options.predicateObjectDataTypes,
|
|
555
|
+
textMaxBytes: this.options.textMaxBytes,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
objectIndexForSerialized(predicate, object) {
|
|
559
|
+
return (0, value_types_1.objectIndexFieldsFromSerialized)(object, {
|
|
560
|
+
predicate,
|
|
561
|
+
predicateObjectDataTypes: this.options.predicateObjectDataTypes,
|
|
562
|
+
textMaxBytes: this.options.textMaxBytes,
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
objectDigestForIndex(serialized, fields) {
|
|
566
|
+
return fields.objectKey === null ? digestObject(serialized) : null;
|
|
567
|
+
}
|
|
568
|
+
writeStatementsForRow(row) {
|
|
569
|
+
const params = [
|
|
570
|
+
row.objectKind,
|
|
571
|
+
row.objectKey,
|
|
572
|
+
row.objectText,
|
|
573
|
+
row.objectDigest,
|
|
574
|
+
row.graph,
|
|
575
|
+
row.subject,
|
|
576
|
+
row.predicate,
|
|
577
|
+
row.object,
|
|
578
|
+
row.vector,
|
|
579
|
+
];
|
|
580
|
+
if (row.objectKey !== null) {
|
|
581
|
+
return [{
|
|
582
|
+
sql: `
|
|
583
|
+
INSERT INTO quints (
|
|
584
|
+
object_kind, object_key, object_text, object_digest,
|
|
585
|
+
graph, subject, predicate, object, vector
|
|
586
|
+
)
|
|
587
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
588
|
+
ON CONFLICT (graph, subject, predicate, object_kind, object_key)
|
|
589
|
+
WHERE object_key IS NOT NULL
|
|
590
|
+
DO UPDATE SET
|
|
591
|
+
vector = EXCLUDED.vector,
|
|
592
|
+
object_text = EXCLUDED.object_text,
|
|
593
|
+
object_digest = EXCLUDED.object_digest
|
|
594
|
+
WHERE quints.object = EXCLUDED.object
|
|
595
|
+
`,
|
|
596
|
+
params,
|
|
597
|
+
}];
|
|
598
|
+
}
|
|
599
|
+
return [{
|
|
600
|
+
sql: `
|
|
601
|
+
INSERT INTO quints (
|
|
602
|
+
object_kind, object_key, object_text, object_digest,
|
|
603
|
+
graph, subject, predicate, object, vector
|
|
604
|
+
)
|
|
605
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
606
|
+
ON CONFLICT (graph, subject, predicate, object_kind, object_digest)
|
|
607
|
+
WHERE object_digest IS NOT NULL
|
|
608
|
+
DO UPDATE SET
|
|
609
|
+
object = CASE WHEN quints.object = EXCLUDED.object THEN EXCLUDED.object ELSE NULL END,
|
|
610
|
+
vector = EXCLUDED.vector,
|
|
611
|
+
object_text = EXCLUDED.object_text
|
|
612
|
+
`,
|
|
613
|
+
params,
|
|
614
|
+
}];
|
|
615
|
+
}
|
|
616
|
+
addObjectConditions(conditions, params, alias, match, predicate) {
|
|
617
|
+
const column = (name) => alias ? `${alias}.${name}` : name;
|
|
618
|
+
if (typeof match === 'object' && 'termType' in match) {
|
|
619
|
+
this.addObjectExactCondition(conditions, params, column, match, predicate);
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
const ops = match;
|
|
623
|
+
if (ops.$eq !== undefined) {
|
|
624
|
+
this.addObjectExactValueCondition(conditions, params, column, ops.$eq, '$eq', predicate);
|
|
625
|
+
}
|
|
626
|
+
if (ops.$ne !== undefined) {
|
|
627
|
+
this.addObjectExactValueCondition(conditions, params, column, ops.$ne, '$ne', predicate);
|
|
628
|
+
}
|
|
629
|
+
if (ops.$gt !== undefined) {
|
|
630
|
+
this.addObjectComparableCondition(conditions, params, column, '>', ops.$gt, '$gt', predicate);
|
|
631
|
+
}
|
|
632
|
+
if (ops.$gte !== undefined) {
|
|
633
|
+
this.addObjectComparableCondition(conditions, params, column, '>=', ops.$gte, '$gte', predicate);
|
|
634
|
+
}
|
|
635
|
+
if (ops.$lt !== undefined) {
|
|
636
|
+
this.addObjectComparableCondition(conditions, params, column, '<', ops.$lt, '$lt', predicate);
|
|
637
|
+
}
|
|
638
|
+
if (ops.$lte !== undefined) {
|
|
639
|
+
this.addObjectComparableCondition(conditions, params, column, '<=', ops.$lte, '$lte', predicate);
|
|
640
|
+
}
|
|
641
|
+
if (ops.$in !== undefined && ops.$in.length > 0) {
|
|
642
|
+
const predicates = ops.$in.map((value) => this.objectPredicateForOperatorValue(value, '$in', predicate));
|
|
643
|
+
const placeholders = predicates.map((item) => {
|
|
644
|
+
if (item.fields.objectKey === null) {
|
|
645
|
+
return `(${column('object_kind')} = ? AND ${column('object_digest')} = ? AND ${column('object')} = ?)`;
|
|
646
|
+
}
|
|
647
|
+
return `(${column('object_kind')} = ? AND ${column('object_key')} = ?)`;
|
|
648
|
+
}).join(' OR ');
|
|
649
|
+
conditions.push(`(${placeholders})`);
|
|
650
|
+
for (const item of predicates) {
|
|
651
|
+
if (item.fields.objectKey === null) {
|
|
652
|
+
params.push(item.fields.objectKind, this.objectDigestForIndex(item.serialized, item.fields), item.serialized);
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
params.push(item.fields.objectKind, item.fields.objectKey);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (ops.$notIn !== undefined && ops.$notIn.length > 0) {
|
|
660
|
+
const values = ops.$notIn.map((value) => this.objectPredicateForOperatorValue(value, '$notIn', predicate).serialized);
|
|
661
|
+
for (const value of values) {
|
|
662
|
+
conditions.push(`${column('object')} != ?`);
|
|
663
|
+
params.push(value);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
if (ops.$startsWith !== undefined) {
|
|
667
|
+
const fields = this.objectFieldsForPrefix(ops.$startsWith, predicate);
|
|
668
|
+
this.assertComparableObject(fields, '$startsWith');
|
|
669
|
+
conditions.push(`${column('object_kind')} = ?`);
|
|
670
|
+
params.push(fields.objectKind);
|
|
671
|
+
conditions.push(`${column('object_key')} >= ? AND ${column('object_key')} < ?`);
|
|
672
|
+
params.push(ops.$startsWith, ops.$startsWith + '\uffff');
|
|
673
|
+
}
|
|
674
|
+
if (ops.$endsWith !== undefined) {
|
|
675
|
+
this.addObjectTextCondition(conditions, params, column, 'LIKE', `%${ops.$endsWith}`, predicate);
|
|
676
|
+
}
|
|
677
|
+
if (ops.$contains !== undefined) {
|
|
678
|
+
this.addObjectTextCondition(conditions, params, column, 'LIKE', `%${ops.$contains}%`, predicate);
|
|
679
|
+
}
|
|
680
|
+
if (ops.$regex !== undefined) {
|
|
681
|
+
const pattern = ops.$regex.replace(/\.\*/g, '%').replace(/\./g, '_');
|
|
682
|
+
this.addObjectTextCondition(conditions, params, column, 'LIKE', pattern, predicate);
|
|
683
|
+
}
|
|
684
|
+
if (ops.$strStartsWith !== undefined) {
|
|
685
|
+
this.addObjectLexicalStringCondition(conditions, params, column, 'startsWith', ops.$strStartsWith);
|
|
686
|
+
}
|
|
687
|
+
if (ops.$strEndsWith !== undefined) {
|
|
688
|
+
this.addObjectLexicalStringCondition(conditions, params, column, 'endsWith', ops.$strEndsWith);
|
|
689
|
+
}
|
|
690
|
+
if (ops.$strContains !== undefined) {
|
|
691
|
+
this.addObjectLexicalStringCondition(conditions, params, column, 'contains', ops.$strContains);
|
|
692
|
+
}
|
|
693
|
+
if (ops.$strRegex !== undefined) {
|
|
694
|
+
this.addObjectLexicalStringCondition(conditions, params, column, 'regex', ops.$strRegex);
|
|
695
|
+
}
|
|
696
|
+
if (ops.$language !== undefined) {
|
|
697
|
+
this.addObjectLanguageCondition(conditions, params, column, ops.$language);
|
|
698
|
+
}
|
|
699
|
+
if (ops.$isNull === true) {
|
|
700
|
+
conditions.push(`${column('object')} IS NULL`);
|
|
701
|
+
}
|
|
702
|
+
if (ops.$isNull === false) {
|
|
703
|
+
conditions.push(`${column('object')} IS NOT NULL`);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
addObjectExactCondition(conditions, params, column, object, predicate) {
|
|
707
|
+
const serialized = (0, serialization_1.serializeObject)(object);
|
|
708
|
+
const fields = this.objectFieldsForTerm(object, predicate);
|
|
709
|
+
this.addObjectExactSerializedCondition(conditions, params, column, serialized, fields);
|
|
710
|
+
}
|
|
711
|
+
addObjectExactValueCondition(conditions, params, column, value, op, predicate) {
|
|
712
|
+
const item = this.objectPredicateForOperatorValue(value, op, predicate);
|
|
713
|
+
if (op === '$ne') {
|
|
714
|
+
conditions.push(`${column('object')} != ?`);
|
|
715
|
+
params.push(item.serialized);
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
this.addObjectExactSerializedCondition(conditions, params, column, item.serialized, item.fields);
|
|
719
|
+
}
|
|
720
|
+
addObjectExactSerializedCondition(conditions, params, column, serialized, fields) {
|
|
721
|
+
if (fields.objectKey !== null) {
|
|
722
|
+
conditions.push(`${column('object_kind')} = ?`);
|
|
723
|
+
params.push(fields.objectKind);
|
|
724
|
+
conditions.push(`${column('object_key')} = ?`);
|
|
725
|
+
params.push(fields.objectKey);
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
conditions.push(`${column('object_kind')} = ?`);
|
|
729
|
+
params.push(fields.objectKind);
|
|
730
|
+
conditions.push(`${column('object_digest')} = ?`);
|
|
731
|
+
params.push(this.objectDigestForIndex(serialized, fields));
|
|
732
|
+
conditions.push(`${column('object')} = ?`);
|
|
733
|
+
params.push(serialized);
|
|
734
|
+
}
|
|
735
|
+
addObjectComparableCondition(conditions, params, column, sqlOperator, value, op, predicate) {
|
|
736
|
+
const item = this.objectPredicateForOperatorValue(value, op, predicate);
|
|
737
|
+
this.assertComparableObject(item.fields, op);
|
|
738
|
+
conditions.push(`${column('object_kind')} = ?`);
|
|
739
|
+
params.push(item.fields.objectKind);
|
|
740
|
+
conditions.push(`${column('object_key')} ${sqlOperator} ?`);
|
|
741
|
+
params.push(item.serialized);
|
|
742
|
+
}
|
|
743
|
+
addObjectTextCondition(conditions, params, column, sqlOperator, value, predicate) {
|
|
744
|
+
const declaredType = (0, value_types_1.getPredicateObjectDataType)(predicate, this.options.predicateObjectDataTypes);
|
|
745
|
+
if (declaredType) {
|
|
746
|
+
if (!['text', 'longText', 'literal'].includes(declaredType)) {
|
|
747
|
+
throw new Error(`Object text search is not supported for ${declaredType}`);
|
|
748
|
+
}
|
|
749
|
+
conditions.push(`${column('object_kind')} = ?`);
|
|
750
|
+
params.push(declaredType);
|
|
751
|
+
}
|
|
752
|
+
conditions.push(`${column('object_text')} ${sqlOperator} ?`);
|
|
753
|
+
params.push(value);
|
|
754
|
+
}
|
|
755
|
+
addObjectLexicalStringCondition(conditions, params, column, op, value) {
|
|
756
|
+
const lexical = this.objectLexicalSql(column);
|
|
757
|
+
if (op === 'startsWith') {
|
|
758
|
+
conditions.push(`(${lexical} >= ? AND ${lexical} < ?)`);
|
|
759
|
+
params.push(value, value + '\uffff');
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
if (op === 'endsWith') {
|
|
763
|
+
conditions.push(`RIGHT(${lexical}, LENGTH(?)) = ?`);
|
|
764
|
+
params.push(value, value);
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
if (op === 'contains') {
|
|
768
|
+
conditions.push(`POSITION(? IN ${lexical}) > 0`);
|
|
769
|
+
params.push(value);
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
conditions.push(`${lexical} ~ ?`);
|
|
773
|
+
params.push(value);
|
|
774
|
+
}
|
|
775
|
+
objectLexicalSql(column) {
|
|
776
|
+
return `CASE
|
|
777
|
+
WHEN ${column('object_text')} IS NOT NULL THEN ${column('object_text')}
|
|
778
|
+
WHEN ${column('object_kind')} IN ('iri', 'blankNode') THEN ${column('object_key')}
|
|
779
|
+
WHEN ${column('object_kind')} = 'numeric' THEN split_part(${column('object')}, '${PG_SEP}', 4)
|
|
780
|
+
WHEN ${column('object_kind')} = 'dateTime' THEN split_part(${column('object')}, '${PG_SEP}', 3)
|
|
781
|
+
ELSE NULL
|
|
782
|
+
END`;
|
|
783
|
+
}
|
|
784
|
+
addObjectLanguageCondition(conditions, params, column, lang) {
|
|
785
|
+
const languageLiteralKinds = `${column('object_kind')} IN ('text', 'longText', 'literal')`;
|
|
786
|
+
if (lang === '*') {
|
|
787
|
+
conditions.push(`(${languageLiteralKinds} AND ${column('object')} ~ ?)`);
|
|
788
|
+
params.push('"@[A-Za-z]+(-[A-Za-z0-9]+)*$');
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
const suffix = `"@${lang.toLowerCase()}`;
|
|
792
|
+
conditions.push(`(${languageLiteralKinds} AND (RIGHT(LOWER(${column('object')}), LENGTH(?)) = ? OR LOWER(${column('object')}) LIKE ?))`);
|
|
793
|
+
params.push(suffix, suffix, `%"@${lang.toLowerCase()}-%`);
|
|
794
|
+
}
|
|
795
|
+
objectPredicateForOperatorValue(value, op, predicate) {
|
|
796
|
+
const serialized = this.serializeOpValue(value, true, op);
|
|
797
|
+
return {
|
|
798
|
+
serialized,
|
|
799
|
+
fields: this.objectFieldsForSerialized(serialized, predicate),
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
objectFieldsForTerm(object, predicate) {
|
|
803
|
+
return (0, value_types_1.objectIndexFieldsFromTerm)(object, {
|
|
804
|
+
predicate,
|
|
805
|
+
predicateObjectDataTypes: this.options.predicateObjectDataTypes,
|
|
806
|
+
textMaxBytes: this.options.textMaxBytes,
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
objectFieldsForSerialized(serialized, predicate) {
|
|
810
|
+
return (0, value_types_1.objectIndexFieldsFromSerialized)(serialized, {
|
|
811
|
+
predicate,
|
|
812
|
+
predicateObjectDataTypes: this.options.predicateObjectDataTypes,
|
|
813
|
+
textMaxBytes: this.options.textMaxBytes,
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
objectFieldsForPrefix(prefix, predicate) {
|
|
817
|
+
const declaredType = (0, value_types_1.getPredicateObjectDataType)(predicate, this.options.predicateObjectDataTypes);
|
|
818
|
+
if (declaredType) {
|
|
819
|
+
if (declaredType === 'longText') {
|
|
820
|
+
return { objectKind: 'longText', objectKey: null, objectText: prefix };
|
|
821
|
+
}
|
|
822
|
+
return { objectKind: declaredType, objectKey: prefix, objectText: null };
|
|
823
|
+
}
|
|
824
|
+
if ((0, serialization_1.isSerializedNumericLiteral)(prefix)) {
|
|
825
|
+
return { objectKind: 'numeric', objectKey: prefix, objectText: null };
|
|
826
|
+
}
|
|
827
|
+
if ((0, serialization_1.isSerializedDateTimeLiteral)(prefix)) {
|
|
828
|
+
return { objectKind: 'dateTime', objectKey: prefix, objectText: null };
|
|
829
|
+
}
|
|
830
|
+
if (prefix.startsWith('"')) {
|
|
831
|
+
return { objectKind: 'text', objectKey: prefix, objectText: null };
|
|
832
|
+
}
|
|
833
|
+
if (prefix.startsWith('_:')) {
|
|
834
|
+
return { objectKind: 'blankNode', objectKey: prefix, objectText: null };
|
|
835
|
+
}
|
|
836
|
+
return { objectKind: 'iri', objectKey: prefix, objectText: null };
|
|
837
|
+
}
|
|
838
|
+
assertComparableObject(fields, op) {
|
|
839
|
+
if (fields.objectKey !== null && fields.objectKind !== 'longText') {
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
throw new Error(`Object ${op} is not supported for ${fields.objectKind}; declare/use a comparable data type instead of longText`);
|
|
843
|
+
}
|
|
844
|
+
addAliasedObjectConditions(conditions, params, alias, pattern) {
|
|
845
|
+
if (!pattern.object)
|
|
846
|
+
return;
|
|
847
|
+
this.addObjectConditions(conditions, params, alias, pattern.object, this.extractExactPredicate(pattern.predicate));
|
|
848
|
+
}
|
|
849
|
+
extractExactPredicate(match) {
|
|
850
|
+
if (!match)
|
|
851
|
+
return undefined;
|
|
852
|
+
if (typeof match === 'object' && 'termType' in match) {
|
|
853
|
+
return (0, serialization_1.termToId)(match);
|
|
854
|
+
}
|
|
855
|
+
const ops = match;
|
|
856
|
+
if (ops.$eq !== undefined) {
|
|
857
|
+
return String(this.serializeOpValue(ops.$eq, false, '$eq'));
|
|
858
|
+
}
|
|
859
|
+
return undefined;
|
|
860
|
+
}
|
|
861
|
+
resolveObjectDataTypeForPattern(pattern) {
|
|
862
|
+
const predicate = this.extractExactPredicate(pattern.predicate);
|
|
863
|
+
if (predicate) {
|
|
864
|
+
return (0, value_types_1.getPredicateObjectDataType)(predicate, this.options.predicateObjectDataTypes);
|
|
865
|
+
}
|
|
866
|
+
if (pattern.object && typeof pattern.object === 'object' && 'termType' in pattern.object) {
|
|
867
|
+
return this.objectFieldsForTerm(pattern.object, predicate).objectKind;
|
|
868
|
+
}
|
|
869
|
+
return undefined;
|
|
870
|
+
}
|
|
871
|
+
addAliasedPgCondition(conditions, params, alias, column, match, isObject) {
|
|
872
|
+
if (!match)
|
|
873
|
+
return;
|
|
874
|
+
if (isObject) {
|
|
875
|
+
this.addObjectConditions(conditions, params, alias, match, undefined);
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
if (typeof match === 'object' && 'termType' in match) {
|
|
879
|
+
const value = (0, serialization_1.termToId)(match);
|
|
880
|
+
conditions.push(`${alias}.${column} = ?`);
|
|
881
|
+
params.push(value);
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
if (match.$eq !== undefined) {
|
|
885
|
+
const value = this.serializeOpValue(match.$eq, false, '$eq');
|
|
886
|
+
conditions.push(`${alias}.${column} = ?`);
|
|
887
|
+
params.push(value);
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
this.addFallbackAliasedCondition(conditions, params, alias, column, match, isObject);
|
|
891
|
+
}
|
|
892
|
+
addFallbackAliasedCondition(conditions, params, alias, column, match, isObject) {
|
|
893
|
+
if (isObject) {
|
|
894
|
+
this.addObjectConditions(conditions, params, alias, match, undefined);
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
if (match.$gt !== undefined) {
|
|
898
|
+
conditions.push(`${alias}.${column} > ?`);
|
|
899
|
+
params.push(this.serializeOpValue(match.$gt, false, '$gt'));
|
|
900
|
+
}
|
|
901
|
+
if (match.$gte !== undefined) {
|
|
902
|
+
conditions.push(`${alias}.${column} >= ?`);
|
|
903
|
+
params.push(this.serializeOpValue(match.$gte, false, '$gte'));
|
|
904
|
+
}
|
|
905
|
+
if (match.$lt !== undefined) {
|
|
906
|
+
conditions.push(`${alias}.${column} < ?`);
|
|
907
|
+
params.push(this.serializeOpValue(match.$lt, false, '$lt'));
|
|
908
|
+
}
|
|
909
|
+
if (match.$lte !== undefined) {
|
|
910
|
+
conditions.push(`${alias}.${column} <= ?`);
|
|
911
|
+
params.push(this.serializeOpValue(match.$lte, false, '$lte'));
|
|
912
|
+
}
|
|
913
|
+
if (match.$in !== undefined && match.$in.length > 0) {
|
|
914
|
+
const placeholders = match.$in.map(() => '?').join(', ');
|
|
915
|
+
conditions.push(`${alias}.${column} IN (${placeholders})`);
|
|
916
|
+
params.push(...match.$in.map((value) => this.serializeOpValue(value, false, '$in')));
|
|
917
|
+
}
|
|
272
918
|
}
|
|
273
919
|
}
|
|
274
920
|
exports.PgQuintStore = PgQuintStore;
|