@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.
Files changed (35) hide show
  1. package/dist/browser.js +298 -1
  2. package/dist/browser.js.map +13 -11
  3. package/dist/bun.js +388 -1
  4. package/dist/bun.js.map +16 -14
  5. package/dist/common.d.ts +3 -0
  6. package/dist/common.d.ts.map +1 -1
  7. package/dist/node.js +388 -1
  8. package/dist/node.js.map +16 -14
  9. package/dist/tabular/BaseTabularStorage.d.ts +15 -1
  10. package/dist/tabular/BaseTabularStorage.d.ts.map +1 -1
  11. package/dist/tabular/CachedTabularStorage.d.ts +2 -1
  12. package/dist/tabular/CachedTabularStorage.d.ts.map +1 -1
  13. package/dist/tabular/CoveringIndexMissingError.d.ts +14 -0
  14. package/dist/tabular/CoveringIndexMissingError.d.ts.map +1 -0
  15. package/dist/tabular/FsFolderTabularStorage.d.ts +6 -1
  16. package/dist/tabular/FsFolderTabularStorage.d.ts.map +1 -1
  17. package/dist/tabular/ITabularStorage.d.ts +19 -1
  18. package/dist/tabular/ITabularStorage.d.ts.map +1 -1
  19. package/dist/tabular/InMemoryTabularStorage.d.ts +7 -1
  20. package/dist/tabular/InMemoryTabularStorage.d.ts.map +1 -1
  21. package/dist/tabular/IndexedDbTabularStorage.d.ts +10 -1
  22. package/dist/tabular/IndexedDbTabularStorage.d.ts.map +1 -1
  23. package/dist/tabular/PostgresTabularStorage.d.ts +11 -1
  24. package/dist/tabular/PostgresTabularStorage.d.ts.map +1 -1
  25. package/dist/tabular/SqliteTabularStorage.d.ts +11 -1
  26. package/dist/tabular/SqliteTabularStorage.d.ts.map +1 -1
  27. package/dist/tabular/SupabaseTabularStorage.d.ts +2 -1
  28. package/dist/tabular/SupabaseTabularStorage.d.ts.map +1 -1
  29. package/dist/tabular/TelemetryTabularStorage.d.ts +2 -1
  30. package/dist/tabular/TelemetryTabularStorage.d.ts.map +1 -1
  31. package/dist/tabular/coveringIndexPicker.d.ts +37 -0
  32. package/dist/tabular/coveringIndexPicker.d.ts.map +1 -0
  33. package/dist/vector/IVectorStorage.d.ts +3 -1
  34. package/dist/vector/IVectorStorage.d.ts.map +1 -1
  35. 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";
@@ -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=1E55C44CEF8B06B964756E2164756E21
9053
+ //# debugId=FEAE1DAF1DC5CDCE64756E2164756E21