@workglow/storage 0.2.25 → 0.2.26
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/browser.js +298 -1
- package/dist/browser.js.map +13 -11
- package/dist/bun.js +388 -1
- package/dist/bun.js.map +16 -14
- package/dist/common.d.ts +3 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/node.js +388 -1
- package/dist/node.js.map +16 -14
- package/dist/tabular/BaseTabularStorage.d.ts +15 -1
- package/dist/tabular/BaseTabularStorage.d.ts.map +1 -1
- package/dist/tabular/CachedTabularStorage.d.ts +2 -1
- package/dist/tabular/CachedTabularStorage.d.ts.map +1 -1
- package/dist/tabular/CoveringIndexMissingError.d.ts +14 -0
- package/dist/tabular/CoveringIndexMissingError.d.ts.map +1 -0
- package/dist/tabular/FsFolderTabularStorage.d.ts +6 -1
- package/dist/tabular/FsFolderTabularStorage.d.ts.map +1 -1
- package/dist/tabular/ITabularStorage.d.ts +19 -1
- package/dist/tabular/ITabularStorage.d.ts.map +1 -1
- package/dist/tabular/InMemoryTabularStorage.d.ts +7 -1
- package/dist/tabular/InMemoryTabularStorage.d.ts.map +1 -1
- package/dist/tabular/IndexedDbTabularStorage.d.ts +10 -1
- package/dist/tabular/IndexedDbTabularStorage.d.ts.map +1 -1
- package/dist/tabular/PostgresTabularStorage.d.ts +11 -1
- package/dist/tabular/PostgresTabularStorage.d.ts.map +1 -1
- package/dist/tabular/SqliteTabularStorage.d.ts +11 -1
- package/dist/tabular/SqliteTabularStorage.d.ts.map +1 -1
- package/dist/tabular/SupabaseTabularStorage.d.ts +2 -1
- package/dist/tabular/SupabaseTabularStorage.d.ts.map +1 -1
- package/dist/tabular/TelemetryTabularStorage.d.ts +2 -1
- package/dist/tabular/TelemetryTabularStorage.d.ts.map +1 -1
- package/dist/tabular/coveringIndexPicker.d.ts +37 -0
- package/dist/tabular/coveringIndexPicker.d.ts.map +1 -0
- package/dist/vector/IVectorStorage.d.ts +3 -1
- package/dist/vector/IVectorStorage.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/common.d.ts
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export * from "./tabular/BaseTabularStorage";
|
|
7
7
|
export * from "./tabular/CachedTabularStorage";
|
|
8
|
+
export * from "./tabular/CoveringIndexMissingError";
|
|
9
|
+
export { pickCoveringIndex } from "./tabular/coveringIndexPicker";
|
|
10
|
+
export type { RegisteredIndex, PickCoveringIndexInput, PickedIndex, } from "./tabular/coveringIndexPicker";
|
|
8
11
|
export * from "./tabular/HuggingFaceTabularStorage";
|
|
9
12
|
export * from "./tabular/InMemoryTabularStorage";
|
|
10
13
|
export * from "./tabular/ITabularStorage";
|
package/dist/common.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAElD,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AAExC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAE9C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,qCAAqC,CAAC;AAEpD,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,eAAe,CAAC;AAE9B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,iCAAiC,CAAC;AAEhD,cAAc,0CAA0C,CAAC;AACzD,cAAc,4CAA4C,CAAC"}
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,WAAW,GACZ,MAAM,+BAA+B,CAAC;AACvC,cAAc,qCAAqC,CAAC;AACpD,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAElD,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AAExC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAE9C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,qCAAqC,CAAC;AAEpD,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,eAAe,CAAC;AAE9B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,iCAAiC,CAAC;AAEhD,cAAc,0CAA0C,CAAC;AACzD,cAAc,4CAA4C,CAAC"}
|
package/dist/node.js
CHANGED
|
@@ -48,6 +48,21 @@ class StorageUnsupportedError extends StorageError {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// src/tabular/CoveringIndexMissingError.ts
|
|
52
|
+
class CoveringIndexMissingError extends StorageError {
|
|
53
|
+
static type = "CoveringIndexMissingError";
|
|
54
|
+
table;
|
|
55
|
+
requiredColumns;
|
|
56
|
+
registeredIndexes;
|
|
57
|
+
constructor(table, requiredColumns, registeredIndexes) {
|
|
58
|
+
const indexList = registeredIndexes.map((cols) => `[${cols.join(", ")}]`).join(", ");
|
|
59
|
+
super(`No covering index for table "${table}". ` + `Required columns: [${requiredColumns.join(", ")}]. ` + `Registered indexes: ${indexList || "(none)"}.`);
|
|
60
|
+
this.table = table;
|
|
61
|
+
this.requiredColumns = requiredColumns;
|
|
62
|
+
this.registeredIndexes = registeredIndexes;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
51
66
|
// src/tabular/BaseTabularStorage.ts
|
|
52
67
|
var TABULAR_REPOSITORY = createServiceToken("storage.tabularRepository");
|
|
53
68
|
|
|
@@ -171,6 +186,15 @@ class BaseTabularStorage {
|
|
|
171
186
|
const entities = await this.query(criteria);
|
|
172
187
|
return entities?.length ?? 0;
|
|
173
188
|
}
|
|
189
|
+
queryIndex(criteria, options) {
|
|
190
|
+
this.validateSelect(options);
|
|
191
|
+
const requiredColumns = [
|
|
192
|
+
...Object.keys(criteria),
|
|
193
|
+
...(options.orderBy ?? []).map((o) => String(o.column)),
|
|
194
|
+
...options.select.map(String)
|
|
195
|
+
];
|
|
196
|
+
throw new CoveringIndexMissingError(this.constructor.name, requiredColumns, []);
|
|
197
|
+
}
|
|
174
198
|
async* records(pageSize = 100) {
|
|
175
199
|
if (pageSize <= 0) {
|
|
176
200
|
throw new RangeError(`pageSize must be greater than 0, got ${pageSize}`);
|
|
@@ -266,6 +290,18 @@ class BaseTabularStorage {
|
|
|
266
290
|
}
|
|
267
291
|
}
|
|
268
292
|
}
|
|
293
|
+
validateSelect(options) {
|
|
294
|
+
if (!options.select || options.select.length === 0) {
|
|
295
|
+
throw new StorageValidationError("queryIndex requires a non-empty select array");
|
|
296
|
+
}
|
|
297
|
+
const schemaProps = Object.keys(this.schema.properties);
|
|
298
|
+
for (const col of options.select) {
|
|
299
|
+
const colStr = String(col);
|
|
300
|
+
if (!schemaProps.includes(colStr)) {
|
|
301
|
+
throw new StorageValidationError(`queryIndex select column "${colStr}" is not in schema`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
269
305
|
primaryKeyColumns() {
|
|
270
306
|
const columns = [];
|
|
271
307
|
for (const key of Object.keys(this.primaryKeySchema.properties)) {
|
|
@@ -386,6 +422,61 @@ import { createServiceToken as createServiceToken3, getLogger } from "@workglow/
|
|
|
386
422
|
|
|
387
423
|
// src/tabular/InMemoryTabularStorage.ts
|
|
388
424
|
import { createServiceToken as createServiceToken2, makeFingerprint as makeFingerprint2, uuid4 } from "@workglow/util";
|
|
425
|
+
|
|
426
|
+
// src/tabular/coveringIndexPicker.ts
|
|
427
|
+
function pickCoveringIndex(input) {
|
|
428
|
+
const { table, indexes, criteriaColumns, orderByColumns, selectColumns, primaryKeyColumns } = input;
|
|
429
|
+
const required = uniqueColumns([
|
|
430
|
+
...criteriaColumns,
|
|
431
|
+
...orderByColumns.map((o) => o.column),
|
|
432
|
+
...selectColumns
|
|
433
|
+
]);
|
|
434
|
+
const pkSet = new Set(primaryKeyColumns);
|
|
435
|
+
for (const idx of indexes) {
|
|
436
|
+
const fit = tryFitIndex(idx, criteriaColumns, orderByColumns, selectColumns, pkSet);
|
|
437
|
+
if (fit !== undefined) {
|
|
438
|
+
return { name: idx.name, keyPath: idx.keyPath, reverseDirection: fit.reverseDirection };
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
throw new CoveringIndexMissingError(table, required, indexes.map((i) => i.keyPath));
|
|
442
|
+
}
|
|
443
|
+
function tryFitIndex(index, criteria, orderBy, select, pkSet) {
|
|
444
|
+
const keyPath = index.keyPath;
|
|
445
|
+
const criteriaSet = new Set(criteria);
|
|
446
|
+
if (criteria.length > keyPath.length)
|
|
447
|
+
return;
|
|
448
|
+
for (let i = 0;i < criteria.length; i++) {
|
|
449
|
+
if (!criteriaSet.has(keyPath[i]))
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
let reverseDirection = false;
|
|
453
|
+
if (orderBy.length > 0) {
|
|
454
|
+
const start = criteria.length;
|
|
455
|
+
if (start + orderBy.length > keyPath.length)
|
|
456
|
+
return;
|
|
457
|
+
for (let i = 0;i < orderBy.length; i++) {
|
|
458
|
+
if (keyPath[start + i] !== orderBy[i].column)
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const allDesc = orderBy.every((o) => o.direction === "DESC");
|
|
462
|
+
const allAsc = orderBy.every((o) => o.direction === "ASC");
|
|
463
|
+
if (allDesc)
|
|
464
|
+
reverseDirection = true;
|
|
465
|
+
else if (!allAsc)
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const keyPathSet = new Set(keyPath);
|
|
469
|
+
for (const col of select) {
|
|
470
|
+
if (!keyPathSet.has(col) && !pkSet.has(col))
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
return { reverseDirection };
|
|
474
|
+
}
|
|
475
|
+
function uniqueColumns(cols) {
|
|
476
|
+
return Array.from(new Set(cols));
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// src/tabular/InMemoryTabularStorage.ts
|
|
389
480
|
var MEMORY_TABULAR_REPOSITORY = createServiceToken2("storage.tabularRepository.inMemory");
|
|
390
481
|
|
|
391
482
|
class InMemoryTabularStorage extends BaseTabularStorage {
|
|
@@ -628,6 +719,38 @@ class InMemoryTabularStorage extends BaseTabularStorage {
|
|
|
628
719
|
this.events.emit("query", criteria, result);
|
|
629
720
|
return result;
|
|
630
721
|
}
|
|
722
|
+
async queryIndex(criteria, options) {
|
|
723
|
+
this.validateSelect(options);
|
|
724
|
+
this.validateQueryParams(criteria, options);
|
|
725
|
+
const registered = this.indexes.map((cols, i) => ({
|
|
726
|
+
name: `idx_${i}`,
|
|
727
|
+
keyPath: cols
|
|
728
|
+
}));
|
|
729
|
+
pickCoveringIndex({
|
|
730
|
+
table: "InMemoryTabularStorage",
|
|
731
|
+
indexes: registered,
|
|
732
|
+
criteriaColumns: Object.keys(criteria),
|
|
733
|
+
orderByColumns: (options.orderBy ?? []).map((o) => ({
|
|
734
|
+
column: String(o.column),
|
|
735
|
+
direction: o.direction
|
|
736
|
+
})),
|
|
737
|
+
selectColumns: options.select.map(String),
|
|
738
|
+
primaryKeyColumns: this.primaryKeyNames.map(String)
|
|
739
|
+
});
|
|
740
|
+
const full = await this.query(criteria, {
|
|
741
|
+
orderBy: options.orderBy,
|
|
742
|
+
limit: options.limit,
|
|
743
|
+
offset: options.offset
|
|
744
|
+
});
|
|
745
|
+
if (!full)
|
|
746
|
+
return [];
|
|
747
|
+
return full.map((row) => {
|
|
748
|
+
const out = {};
|
|
749
|
+
for (const k of options.select)
|
|
750
|
+
out[k] = row[k];
|
|
751
|
+
return out;
|
|
752
|
+
});
|
|
753
|
+
}
|
|
631
754
|
subscribeToChanges(callback, options) {
|
|
632
755
|
const handlePut = (entity) => {
|
|
633
756
|
callback({ type: this._lastPutWasInsert ? "INSERT" : "UPDATE", new: entity });
|
|
@@ -770,6 +893,10 @@ class CachedTabularStorage extends BaseTabularStorage {
|
|
|
770
893
|
await this.initializeCache();
|
|
771
894
|
return await this.cache.query(criteria, options);
|
|
772
895
|
}
|
|
896
|
+
async queryIndex(criteria, options) {
|
|
897
|
+
await this.initializeCache();
|
|
898
|
+
return await this.cache.queryIndex(criteria, options);
|
|
899
|
+
}
|
|
773
900
|
async deleteSearch(criteria) {
|
|
774
901
|
await this.initializeCache();
|
|
775
902
|
await this.durable.deleteSearch(criteria);
|
|
@@ -1210,6 +1337,9 @@ class TelemetryTabularStorage {
|
|
|
1210
1337
|
query(criteria, options) {
|
|
1211
1338
|
return traced("workglow.storage.tabular.query", this.storageName, () => this.inner.query(criteria, options));
|
|
1212
1339
|
}
|
|
1340
|
+
queryIndex(criteria, options) {
|
|
1341
|
+
return traced("workglow.storage.tabular.queryIndex", this.storageName, () => this.inner.queryIndex(criteria, options));
|
|
1342
|
+
}
|
|
1213
1343
|
records(pageSize) {
|
|
1214
1344
|
return this.inner.records(pageSize);
|
|
1215
1345
|
}
|
|
@@ -2495,6 +2625,9 @@ class FsFolderTabularStorage extends BaseTabularStorage {
|
|
|
2495
2625
|
async query(_criteria, _options) {
|
|
2496
2626
|
throw new StorageUnsupportedError("query", "FsFolderTabularStorage");
|
|
2497
2627
|
}
|
|
2628
|
+
async queryIndex(_criteria, _options) {
|
|
2629
|
+
throw new StorageUnsupportedError("queryIndex", "FsFolderTabularStorage");
|
|
2630
|
+
}
|
|
2498
2631
|
async deleteSearch(_criteria) {
|
|
2499
2632
|
throw new Error("deleteSearch is not supported for FsFolderTabularStorage");
|
|
2500
2633
|
}
|
|
@@ -3238,6 +3371,49 @@ class PostgresTabularStorage extends BaseSqlTabularStorage {
|
|
|
3238
3371
|
this.events.emit("query", criteria, undefined);
|
|
3239
3372
|
return;
|
|
3240
3373
|
}
|
|
3374
|
+
async queryIndex(criteria, options) {
|
|
3375
|
+
this.validateSelect(options);
|
|
3376
|
+
this.validateQueryParams(criteria, options);
|
|
3377
|
+
const registered = this.indexes.map((cols2, i) => {
|
|
3378
|
+
const cs = Array.isArray(cols2) ? cols2 : [cols2];
|
|
3379
|
+
return { name: `idx_${i}`, keyPath: cs };
|
|
3380
|
+
});
|
|
3381
|
+
pickCoveringIndex({
|
|
3382
|
+
table: this.table,
|
|
3383
|
+
indexes: registered,
|
|
3384
|
+
criteriaColumns: Object.keys(criteria),
|
|
3385
|
+
orderByColumns: (options.orderBy ?? []).map((o) => ({
|
|
3386
|
+
column: String(o.column),
|
|
3387
|
+
direction: o.direction
|
|
3388
|
+
})),
|
|
3389
|
+
selectColumns: options.select.map(String),
|
|
3390
|
+
primaryKeyColumns: this.primaryKeyNames.map(String)
|
|
3391
|
+
});
|
|
3392
|
+
const cols = options.select.map((c) => `"${String(c)}"`).join(", ");
|
|
3393
|
+
let sql = `SELECT ${cols} FROM "${this.table}"`;
|
|
3394
|
+
const { whereClause, params } = this.buildDeleteSearchWhere(criteria);
|
|
3395
|
+
sql += ` WHERE ${whereClause}`;
|
|
3396
|
+
if (options.orderBy && options.orderBy.length > 0) {
|
|
3397
|
+
sql += ` ORDER BY ` + options.orderBy.map((o) => `"${String(o.column)}" ${o.direction}`).join(", ");
|
|
3398
|
+
}
|
|
3399
|
+
if (options.limit !== undefined) {
|
|
3400
|
+
sql += ` LIMIT $${params.length + 1}`;
|
|
3401
|
+
params.push(options.limit);
|
|
3402
|
+
}
|
|
3403
|
+
if (options.offset !== undefined) {
|
|
3404
|
+
sql += ` OFFSET $${params.length + 1}`;
|
|
3405
|
+
params.push(options.offset);
|
|
3406
|
+
}
|
|
3407
|
+
const db = this.db;
|
|
3408
|
+
const result = await db.query(sql, params);
|
|
3409
|
+
for (const row of result.rows) {
|
|
3410
|
+
const record = row;
|
|
3411
|
+
for (const k of Object.keys(record)) {
|
|
3412
|
+
record[k] = this.sqlToJsValue(k, record[k]);
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
return result.rows;
|
|
3416
|
+
}
|
|
3241
3417
|
subscribeToChanges(callback, options) {
|
|
3242
3418
|
throw new Error("subscribeToChanges is not supported for PostgresTabularStorage");
|
|
3243
3419
|
}
|
|
@@ -3722,6 +3898,50 @@ class SqliteTabularStorage extends BaseSqlTabularStorage {
|
|
|
3722
3898
|
this.events.emit("query", criteria, undefined);
|
|
3723
3899
|
return;
|
|
3724
3900
|
}
|
|
3901
|
+
async queryIndex(criteria, options) {
|
|
3902
|
+
this.validateSelect(options);
|
|
3903
|
+
this.validateQueryParams(criteria, options);
|
|
3904
|
+
const registered = this.indexes.map((cols2, i) => {
|
|
3905
|
+
const cs = Array.isArray(cols2) ? cols2 : [cols2];
|
|
3906
|
+
return { name: `idx_${i}`, keyPath: cs };
|
|
3907
|
+
});
|
|
3908
|
+
pickCoveringIndex({
|
|
3909
|
+
table: this.table,
|
|
3910
|
+
indexes: registered,
|
|
3911
|
+
criteriaColumns: Object.keys(criteria),
|
|
3912
|
+
orderByColumns: (options.orderBy ?? []).map((o) => ({
|
|
3913
|
+
column: String(o.column),
|
|
3914
|
+
direction: o.direction
|
|
3915
|
+
})),
|
|
3916
|
+
selectColumns: options.select.map(String),
|
|
3917
|
+
primaryKeyColumns: this.primaryKeyNames.map(String)
|
|
3918
|
+
});
|
|
3919
|
+
const cols = options.select.map((c) => `\`${String(c)}\``).join(", ");
|
|
3920
|
+
let sql = `SELECT ${cols} FROM \`${this.table}\``;
|
|
3921
|
+
const { whereClause, params } = this.buildDeleteSearchWhere(criteria);
|
|
3922
|
+
sql += ` WHERE ${whereClause}`;
|
|
3923
|
+
if (options.orderBy && options.orderBy.length > 0) {
|
|
3924
|
+
sql += ` ORDER BY ` + options.orderBy.map((o) => `\`${String(o.column)}\` ${o.direction}`).join(", ");
|
|
3925
|
+
}
|
|
3926
|
+
if (options.limit !== undefined) {
|
|
3927
|
+
sql += ` LIMIT ?`;
|
|
3928
|
+
params.push(options.limit);
|
|
3929
|
+
}
|
|
3930
|
+
if (options.offset !== undefined) {
|
|
3931
|
+
if (options.limit === undefined)
|
|
3932
|
+
sql += ` LIMIT -1`;
|
|
3933
|
+
sql += ` OFFSET ?`;
|
|
3934
|
+
params.push(options.offset);
|
|
3935
|
+
}
|
|
3936
|
+
const stmt = this.db.prepare(sql);
|
|
3937
|
+
const rows = stmt.all(...params);
|
|
3938
|
+
for (const row of rows) {
|
|
3939
|
+
for (const k of Object.keys(row)) {
|
|
3940
|
+
row[k] = this.sqlToJsValue(k, row[k]);
|
|
3941
|
+
}
|
|
3942
|
+
}
|
|
3943
|
+
return rows;
|
|
3944
|
+
}
|
|
3725
3945
|
subscribeToChanges(callback, options) {
|
|
3726
3946
|
throw new Error("subscribeToChanges is not supported for SqliteTabularStorage");
|
|
3727
3947
|
}
|
|
@@ -4196,6 +4416,56 @@ class SupabaseTabularStorage extends BaseSqlTabularStorage {
|
|
|
4196
4416
|
this.events.emit("query", criteria, undefined);
|
|
4197
4417
|
return;
|
|
4198
4418
|
}
|
|
4419
|
+
async queryIndex(criteria, options) {
|
|
4420
|
+
this.validateSelect(options);
|
|
4421
|
+
this.validateQueryParams(criteria, options);
|
|
4422
|
+
const registered = this.indexes.map((cols, i) => {
|
|
4423
|
+
const cs = Array.isArray(cols) ? cols : [cols];
|
|
4424
|
+
return { name: `idx_${i}`, keyPath: cs };
|
|
4425
|
+
});
|
|
4426
|
+
pickCoveringIndex({
|
|
4427
|
+
table: this.table,
|
|
4428
|
+
indexes: registered,
|
|
4429
|
+
criteriaColumns: Object.keys(criteria),
|
|
4430
|
+
orderByColumns: (options.orderBy ?? []).map((o) => ({
|
|
4431
|
+
column: String(o.column),
|
|
4432
|
+
direction: o.direction
|
|
4433
|
+
})),
|
|
4434
|
+
selectColumns: options.select.map(String),
|
|
4435
|
+
primaryKeyColumns: this.primaryKeyNames.map(String)
|
|
4436
|
+
});
|
|
4437
|
+
const colList = options.select.map(String).join(",");
|
|
4438
|
+
let q = this.applyCriteriaToFilter(this.client.from(this.table).select(colList), criteria);
|
|
4439
|
+
if (options.orderBy) {
|
|
4440
|
+
for (const { column, direction } of options.orderBy) {
|
|
4441
|
+
q = q.order(String(column), { ascending: direction === "ASC" });
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
if (options.offset !== undefined && options.limit === undefined) {
|
|
4445
|
+
throw new StorageValidationError("queryIndex with offset requires limit (no implicit cap)");
|
|
4446
|
+
}
|
|
4447
|
+
if (options.offset !== undefined || options.limit !== undefined) {
|
|
4448
|
+
const start = options.offset ?? 0;
|
|
4449
|
+
if (options.limit !== undefined) {
|
|
4450
|
+
q = q.range(start, start + options.limit - 1);
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
const { data, error } = await q;
|
|
4454
|
+
if (error)
|
|
4455
|
+
throw error;
|
|
4456
|
+
if (!data)
|
|
4457
|
+
return [];
|
|
4458
|
+
const rows = data;
|
|
4459
|
+
const sel = new Set(options.select.map(String));
|
|
4460
|
+
for (const row of rows) {
|
|
4461
|
+
for (const key of Object.keys(row)) {
|
|
4462
|
+
if (sel.has(key)) {
|
|
4463
|
+
row[key] = this.sqlToJsValue(key, row[key]);
|
|
4464
|
+
}
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
return rows;
|
|
4468
|
+
}
|
|
4199
4469
|
convertRealtimeRow(row) {
|
|
4200
4470
|
const entity = { ...row };
|
|
4201
4471
|
const record = entity;
|
|
@@ -7621,6 +7891,105 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
|
|
|
7621
7891
|
request.onerror = () => reject(request.error);
|
|
7622
7892
|
});
|
|
7623
7893
|
}
|
|
7894
|
+
async queryIndex(criteria, options) {
|
|
7895
|
+
this.validateSelect(options);
|
|
7896
|
+
this.validateQueryParams(criteria, options);
|
|
7897
|
+
const registered = this.indexes.map((cols) => {
|
|
7898
|
+
const cs = Array.isArray(cols) ? cols : [cols];
|
|
7899
|
+
return { name: cs.join("_"), keyPath: cs };
|
|
7900
|
+
});
|
|
7901
|
+
const picked = pickCoveringIndex({
|
|
7902
|
+
table: this.table,
|
|
7903
|
+
indexes: registered,
|
|
7904
|
+
criteriaColumns: Object.keys(criteria),
|
|
7905
|
+
orderByColumns: (options.orderBy ?? []).map((o) => ({
|
|
7906
|
+
column: String(o.column),
|
|
7907
|
+
direction: o.direction
|
|
7908
|
+
})),
|
|
7909
|
+
selectColumns: options.select.map(String),
|
|
7910
|
+
primaryKeyColumns: this.primaryKeyColumns().map(String)
|
|
7911
|
+
});
|
|
7912
|
+
const db = await this.getDb();
|
|
7913
|
+
return new Promise((resolve, reject) => {
|
|
7914
|
+
const tx = db.transaction(this.table, "readonly");
|
|
7915
|
+
const store = tx.objectStore(this.table);
|
|
7916
|
+
const idx = store.index(picked.name);
|
|
7917
|
+
const prefix = [];
|
|
7918
|
+
for (const col of picked.keyPath) {
|
|
7919
|
+
const c = criteria[col];
|
|
7920
|
+
if (c === undefined && !(col in criteria))
|
|
7921
|
+
break;
|
|
7922
|
+
if (isSearchCondition(c)) {
|
|
7923
|
+
if (c.operator !== "=")
|
|
7924
|
+
break;
|
|
7925
|
+
prefix.push(c.value);
|
|
7926
|
+
} else {
|
|
7927
|
+
prefix.push(c);
|
|
7928
|
+
}
|
|
7929
|
+
}
|
|
7930
|
+
const range = prefix.length === 0 ? undefined : prefix.length === picked.keyPath.length ? IDBKeyRange.only(prefix.length === 1 ? prefix[0] : prefix) : IDBKeyRange.bound(prefix, [...prefix, []]);
|
|
7931
|
+
const direction = picked.reverseDirection ? "prev" : "next";
|
|
7932
|
+
const request = idx.openKeyCursor(range, direction);
|
|
7933
|
+
const out = [];
|
|
7934
|
+
let toSkip = options.offset ?? 0;
|
|
7935
|
+
const keyPathPositions = new Map;
|
|
7936
|
+
picked.keyPath.forEach((col, i) => keyPathPositions.set(col, i));
|
|
7937
|
+
const pkCols = this.primaryKeyColumns().map(String);
|
|
7938
|
+
const pkPositions = new Map;
|
|
7939
|
+
pkCols.forEach((col, i) => pkPositions.set(col, i));
|
|
7940
|
+
request.onsuccess = () => {
|
|
7941
|
+
const cursor = request.result;
|
|
7942
|
+
if (!cursor) {
|
|
7943
|
+
resolve(out);
|
|
7944
|
+
return;
|
|
7945
|
+
}
|
|
7946
|
+
const key = cursor.key;
|
|
7947
|
+
const row = {};
|
|
7948
|
+
for (const col of options.select) {
|
|
7949
|
+
const colStr = String(col);
|
|
7950
|
+
const pos = keyPathPositions.get(colStr);
|
|
7951
|
+
if (pos !== undefined) {
|
|
7952
|
+
row[colStr] = Array.isArray(key) ? key[pos] : key;
|
|
7953
|
+
} else {
|
|
7954
|
+
if (pkCols.length === 1 && colStr === pkCols[0]) {
|
|
7955
|
+
row[colStr] = cursor.primaryKey;
|
|
7956
|
+
} else {
|
|
7957
|
+
const pkPos = pkPositions.get(colStr);
|
|
7958
|
+
if (pkPos !== undefined) {
|
|
7959
|
+
row[colStr] = Array.isArray(cursor.primaryKey) ? cursor.primaryKey[pkPos] : cursor.primaryKey;
|
|
7960
|
+
}
|
|
7961
|
+
}
|
|
7962
|
+
}
|
|
7963
|
+
}
|
|
7964
|
+
let matches = true;
|
|
7965
|
+
for (const [col, crit] of Object.entries(criteria)) {
|
|
7966
|
+
if (!isSearchCondition(crit))
|
|
7967
|
+
continue;
|
|
7968
|
+
const pos = keyPathPositions.get(col);
|
|
7969
|
+
if (pos === undefined)
|
|
7970
|
+
continue;
|
|
7971
|
+
const valFromKey = Array.isArray(key) ? key[pos] : key;
|
|
7972
|
+
if (!compareWithOperator(valFromKey, crit.operator, crit.value)) {
|
|
7973
|
+
matches = false;
|
|
7974
|
+
break;
|
|
7975
|
+
}
|
|
7976
|
+
}
|
|
7977
|
+
if (matches) {
|
|
7978
|
+
if (toSkip > 0) {
|
|
7979
|
+
toSkip -= 1;
|
|
7980
|
+
} else {
|
|
7981
|
+
out.push(row);
|
|
7982
|
+
if (options.limit !== undefined && out.length >= options.limit) {
|
|
7983
|
+
resolve(out);
|
|
7984
|
+
return;
|
|
7985
|
+
}
|
|
7986
|
+
}
|
|
7987
|
+
}
|
|
7988
|
+
cursor.continue();
|
|
7989
|
+
};
|
|
7990
|
+
request.onerror = () => reject(request.error);
|
|
7991
|
+
});
|
|
7992
|
+
}
|
|
7624
7993
|
getHybridManager() {
|
|
7625
7994
|
if (!this.hybridManager) {
|
|
7626
7995
|
const channelName = `indexeddb-tabular-${this.table}`;
|
|
@@ -7658,6 +8027,22 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
|
|
|
7658
8027
|
this.db?.close();
|
|
7659
8028
|
}
|
|
7660
8029
|
}
|
|
8030
|
+
function compareWithOperator(a, op, b) {
|
|
8031
|
+
const av = a;
|
|
8032
|
+
const bv = b;
|
|
8033
|
+
switch (op) {
|
|
8034
|
+
case "=":
|
|
8035
|
+
return av === bv;
|
|
8036
|
+
case "<":
|
|
8037
|
+
return av !== null && av !== undefined && av < bv;
|
|
8038
|
+
case "<=":
|
|
8039
|
+
return av !== null && av !== undefined && av <= bv;
|
|
8040
|
+
case ">":
|
|
8041
|
+
return av !== null && av !== undefined && av > bv;
|
|
8042
|
+
case ">=":
|
|
8043
|
+
return av !== null && av !== undefined && av >= bv;
|
|
8044
|
+
}
|
|
8045
|
+
}
|
|
7661
8046
|
|
|
7662
8047
|
// src/kv/IndexedDbKvStorage.ts
|
|
7663
8048
|
var IDB_KV_REPOSITORY = createServiceToken28("storage.kvRepository.indexedDb");
|
|
@@ -8573,6 +8958,7 @@ class IndexedDbVectorStorage extends IndexedDbTabularStorage {
|
|
|
8573
8958
|
export {
|
|
8574
8959
|
traced,
|
|
8575
8960
|
registerTabularRepository,
|
|
8961
|
+
pickCoveringIndex,
|
|
8576
8962
|
isSearchCondition,
|
|
8577
8963
|
getVectorProperty,
|
|
8578
8964
|
getTabularRepository,
|
|
@@ -8658,9 +9044,10 @@ export {
|
|
|
8658
9044
|
EncryptedKvCredentialStore,
|
|
8659
9045
|
DefaultKeyValueSchema,
|
|
8660
9046
|
DefaultKeyValueKey,
|
|
9047
|
+
CoveringIndexMissingError,
|
|
8661
9048
|
CachedTabularStorage,
|
|
8662
9049
|
CACHED_TABULAR_REPOSITORY,
|
|
8663
9050
|
BaseTabularStorage
|
|
8664
9051
|
};
|
|
8665
9052
|
|
|
8666
|
-
//# debugId=
|
|
9053
|
+
//# debugId=FEAE1DAF1DC5CDCE64756E2164756E21
|