@workglow/storage 0.0.103 → 0.0.105
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 +570 -219
- package/dist/browser.js.map +13 -11
- package/dist/bun.js +671 -288
- package/dist/bun.js.map +15 -13
- package/dist/common.d.ts +2 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/credentials/EncryptedKvCredentialStore.d.ts +52 -0
- package/dist/credentials/EncryptedKvCredentialStore.d.ts.map +1 -0
- package/dist/node.js +671 -288
- package/dist/node.js.map +15 -13
- package/dist/tabular/BaseTabularStorage.d.ts +21 -7
- package/dist/tabular/BaseTabularStorage.d.ts.map +1 -1
- package/dist/tabular/CachedTabularStorage.d.ts +14 -10
- package/dist/tabular/CachedTabularStorage.d.ts.map +1 -1
- package/dist/tabular/FsFolderTabularStorage.d.ts +6 -6
- package/dist/tabular/FsFolderTabularStorage.d.ts.map +1 -1
- package/dist/tabular/HuggingFaceTabularStorage.d.ts +11 -6
- package/dist/tabular/HuggingFaceTabularStorage.d.ts.map +1 -1
- package/dist/tabular/ITabularStorage.d.ts +22 -3
- package/dist/tabular/ITabularStorage.d.ts.map +1 -1
- package/dist/tabular/InMemoryTabularStorage.d.ts +12 -10
- package/dist/tabular/InMemoryTabularStorage.d.ts.map +1 -1
- package/dist/tabular/IndexedDbTabularStorage.d.ts +12 -10
- package/dist/tabular/IndexedDbTabularStorage.d.ts.map +1 -1
- package/dist/tabular/PostgresTabularStorage.d.ts +12 -11
- package/dist/tabular/PostgresTabularStorage.d.ts.map +1 -1
- package/dist/tabular/SharedInMemoryTabularStorage.d.ts +12 -10
- package/dist/tabular/SharedInMemoryTabularStorage.d.ts.map +1 -1
- package/dist/tabular/SqliteTabularStorage.d.ts +12 -11
- package/dist/tabular/SqliteTabularStorage.d.ts.map +1 -1
- package/dist/tabular/StorageError.d.ts +31 -0
- package/dist/tabular/StorageError.d.ts.map +1 -0
- package/dist/tabular/SupabaseTabularStorage.d.ts +12 -10
- package/dist/tabular/SupabaseTabularStorage.d.ts.map +1 -1
- package/package.json +7 -7
package/dist/bun.js
CHANGED
|
@@ -5,6 +5,58 @@ import {
|
|
|
5
5
|
EventEmitter,
|
|
6
6
|
makeFingerprint
|
|
7
7
|
} from "@workglow/util";
|
|
8
|
+
|
|
9
|
+
// src/tabular/ITabularStorage.ts
|
|
10
|
+
function isSearchCondition(value) {
|
|
11
|
+
return typeof value === "object" && value !== null && "value" in value && "operator" in value && typeof value.operator === "string";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/tabular/StorageError.ts
|
|
15
|
+
import { BaseError } from "@workglow/util";
|
|
16
|
+
|
|
17
|
+
class StorageError extends BaseError {
|
|
18
|
+
static type = "StorageError";
|
|
19
|
+
constructor(message) {
|
|
20
|
+
super(message);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class StorageValidationError extends StorageError {
|
|
25
|
+
static type = "StorageValidationError";
|
|
26
|
+
constructor(message) {
|
|
27
|
+
super(message);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class StorageEmptyCriteriaError extends StorageValidationError {
|
|
32
|
+
static type = "StorageEmptyCriteriaError";
|
|
33
|
+
constructor() {
|
|
34
|
+
super("Query criteria must not be empty. Use getAll() to retrieve all records.");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class StorageInvalidLimitError extends StorageValidationError {
|
|
39
|
+
static type = "StorageInvalidLimitError";
|
|
40
|
+
constructor(limit) {
|
|
41
|
+
super(`Query limit must be greater than 0, got ${limit}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
class StorageInvalidColumnError extends StorageValidationError {
|
|
46
|
+
static type = "StorageInvalidColumnError";
|
|
47
|
+
constructor(column) {
|
|
48
|
+
super(`Column "${column}" does not exist in the schema`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
class StorageUnsupportedError extends StorageError {
|
|
53
|
+
static type = "StorageUnsupportedError";
|
|
54
|
+
constructor(operation, backend) {
|
|
55
|
+
super(`${operation} is not supported for ${backend}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/tabular/BaseTabularStorage.ts
|
|
8
60
|
var TABULAR_REPOSITORY = createServiceToken("storage.tabularRepository");
|
|
9
61
|
|
|
10
62
|
class BaseTabularStorage {
|
|
@@ -163,6 +215,62 @@ class BaseTabularStorage {
|
|
|
163
215
|
subscribeToChanges(_callback, _options) {
|
|
164
216
|
throw new Error(`subscribeToChanges is not implemented for ${this.constructor.name}. ` + `All concrete repository implementations should override this method.`);
|
|
165
217
|
}
|
|
218
|
+
validateQueryParams(criteria, options) {
|
|
219
|
+
const criteriaKeys = Object.keys(criteria);
|
|
220
|
+
if (criteriaKeys.length === 0) {
|
|
221
|
+
throw new StorageEmptyCriteriaError;
|
|
222
|
+
}
|
|
223
|
+
if (options?.limit !== undefined && options.limit <= 0) {
|
|
224
|
+
throw new StorageInvalidLimitError(options.limit);
|
|
225
|
+
}
|
|
226
|
+
if (options?.offset !== undefined && options.offset < 0) {
|
|
227
|
+
throw new StorageValidationError(`Query offset must be non-negative, got ${options.offset}`);
|
|
228
|
+
}
|
|
229
|
+
for (const column of criteriaKeys) {
|
|
230
|
+
if (!(column in this.schema.properties)) {
|
|
231
|
+
throw new StorageInvalidColumnError(String(column));
|
|
232
|
+
}
|
|
233
|
+
const criterion = criteria[column];
|
|
234
|
+
if (isSearchCondition(criterion)) {
|
|
235
|
+
const validOperators = ["=", "<", "<=", ">", ">="];
|
|
236
|
+
if (!validOperators.includes(criterion.operator)) {
|
|
237
|
+
throw new StorageValidationError(`Invalid operator "${criterion.operator}". Must be one of: ${validOperators.join(", ")}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (options?.orderBy) {
|
|
242
|
+
const validDirections = ["ASC", "DESC"];
|
|
243
|
+
for (const { column, direction } of options.orderBy) {
|
|
244
|
+
if (!(column in this.schema.properties)) {
|
|
245
|
+
throw new StorageInvalidColumnError(String(column));
|
|
246
|
+
}
|
|
247
|
+
if (!validDirections.includes(direction)) {
|
|
248
|
+
throw new StorageValidationError(`Invalid sort direction "${direction}". Must be "ASC" or "DESC"`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
validateGetAllOptions(options) {
|
|
254
|
+
if (!options)
|
|
255
|
+
return;
|
|
256
|
+
if (options.limit !== undefined && options.limit <= 0) {
|
|
257
|
+
throw new StorageInvalidLimitError(options.limit);
|
|
258
|
+
}
|
|
259
|
+
if (options.offset !== undefined && options.offset < 0) {
|
|
260
|
+
throw new StorageValidationError(`Query offset must be non-negative, got ${options.offset}`);
|
|
261
|
+
}
|
|
262
|
+
if (options.orderBy) {
|
|
263
|
+
const validDirections = ["ASC", "DESC"];
|
|
264
|
+
for (const { column, direction } of options.orderBy) {
|
|
265
|
+
if (!(column in this.schema.properties)) {
|
|
266
|
+
throw new StorageInvalidColumnError(String(column));
|
|
267
|
+
}
|
|
268
|
+
if (!validDirections.includes(direction)) {
|
|
269
|
+
throw new StorageValidationError(`Invalid sort direction "${direction}". Must be "ASC" or "DESC"`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
166
274
|
primaryKeyColumns() {
|
|
167
275
|
const columns = [];
|
|
168
276
|
for (const key of Object.keys(this.primaryKeySchema.properties)) {
|
|
@@ -280,7 +388,8 @@ class BaseTabularStorage {
|
|
|
280
388
|
}
|
|
281
389
|
// src/tabular/CachedTabularStorage.ts
|
|
282
390
|
import {
|
|
283
|
-
createServiceToken as createServiceToken3
|
|
391
|
+
createServiceToken as createServiceToken3,
|
|
392
|
+
getLogger
|
|
284
393
|
} from "@workglow/util";
|
|
285
394
|
|
|
286
395
|
// src/tabular/InMemoryTabularStorage.ts
|
|
@@ -289,13 +398,6 @@ import {
|
|
|
289
398
|
makeFingerprint as makeFingerprint2,
|
|
290
399
|
uuid4
|
|
291
400
|
} from "@workglow/util";
|
|
292
|
-
|
|
293
|
-
// src/tabular/ITabularStorage.ts
|
|
294
|
-
function isSearchCondition(value) {
|
|
295
|
-
return typeof value === "object" && value !== null && "value" in value && "operator" in value && typeof value.operator === "string";
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// src/tabular/InMemoryTabularStorage.ts
|
|
299
401
|
var MEMORY_TABULAR_REPOSITORY = createServiceToken2("storage.tabularRepository.inMemory");
|
|
300
402
|
|
|
301
403
|
class InMemoryTabularStorage extends BaseTabularStorage {
|
|
@@ -349,24 +451,6 @@ class InMemoryTabularStorage extends BaseTabularStorage {
|
|
|
349
451
|
this.events.emit("get", key, out);
|
|
350
452
|
return out;
|
|
351
453
|
}
|
|
352
|
-
async search(key) {
|
|
353
|
-
const searchKeys = Object.keys(key);
|
|
354
|
-
if (searchKeys.length === 0) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
const bestIndex = this.findBestMatchingIndex(searchKeys);
|
|
358
|
-
if (!bestIndex) {
|
|
359
|
-
throw new Error(`No suitable index found for the search criteria, searching for ['${searchKeys.join("', '")}'] with pk ['${this.primaryKeyNames.join("', '")}'] and indexes ['${this.indexes.join("', '")}']`);
|
|
360
|
-
}
|
|
361
|
-
const results = Array.from(this.values.values()).filter((item) => Object.entries(key).every(([k, v]) => item[k] === v));
|
|
362
|
-
if (results.length > 0) {
|
|
363
|
-
this.events.emit("search", key, results);
|
|
364
|
-
return results;
|
|
365
|
-
} else {
|
|
366
|
-
this.events.emit("search", key, undefined);
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
454
|
async delete(value) {
|
|
371
455
|
const { key } = this.separateKeyValueFromCombined(value);
|
|
372
456
|
const id = await makeFingerprint2(key);
|
|
@@ -377,8 +461,34 @@ class InMemoryTabularStorage extends BaseTabularStorage {
|
|
|
377
461
|
this.values.clear();
|
|
378
462
|
this.events.emit("clearall");
|
|
379
463
|
}
|
|
380
|
-
async getAll() {
|
|
381
|
-
|
|
464
|
+
async getAll(options) {
|
|
465
|
+
this.validateGetAllOptions(options);
|
|
466
|
+
let all = Array.from(this.values.values());
|
|
467
|
+
if (options?.orderBy && options.orderBy.length > 0) {
|
|
468
|
+
all.sort((a, b) => {
|
|
469
|
+
for (const { column, direction } of options.orderBy) {
|
|
470
|
+
const aVal = a[column];
|
|
471
|
+
const bVal = b[column];
|
|
472
|
+
if (aVal == null && bVal == null)
|
|
473
|
+
continue;
|
|
474
|
+
if (aVal == null)
|
|
475
|
+
return direction === "ASC" ? -1 : 1;
|
|
476
|
+
if (bVal == null)
|
|
477
|
+
return direction === "ASC" ? 1 : -1;
|
|
478
|
+
if (aVal < bVal)
|
|
479
|
+
return direction === "ASC" ? -1 : 1;
|
|
480
|
+
if (aVal > bVal)
|
|
481
|
+
return direction === "ASC" ? 1 : -1;
|
|
482
|
+
}
|
|
483
|
+
return 0;
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
if (options?.offset !== undefined) {
|
|
487
|
+
all = all.slice(options.offset);
|
|
488
|
+
}
|
|
489
|
+
if (options?.limit !== undefined) {
|
|
490
|
+
all = all.slice(0, options.limit);
|
|
491
|
+
}
|
|
382
492
|
return all.length > 0 ? all : undefined;
|
|
383
493
|
}
|
|
384
494
|
async size() {
|
|
@@ -451,6 +561,77 @@ class InMemoryTabularStorage extends BaseTabularStorage {
|
|
|
451
561
|
this.events.emit("delete", key);
|
|
452
562
|
}
|
|
453
563
|
}
|
|
564
|
+
async query(criteria, options) {
|
|
565
|
+
this.validateQueryParams(criteria, options);
|
|
566
|
+
const criteriaKeys = Object.keys(criteria);
|
|
567
|
+
let results = Array.from(this.values.values()).filter((entity) => {
|
|
568
|
+
for (const column of criteriaKeys) {
|
|
569
|
+
const criterion = criteria[column];
|
|
570
|
+
const columnValue = entity[column];
|
|
571
|
+
if (isSearchCondition(criterion)) {
|
|
572
|
+
const { value, operator } = criterion;
|
|
573
|
+
const v = value;
|
|
574
|
+
const cv = columnValue;
|
|
575
|
+
switch (operator) {
|
|
576
|
+
case "=":
|
|
577
|
+
if (cv !== v)
|
|
578
|
+
return false;
|
|
579
|
+
break;
|
|
580
|
+
case "<":
|
|
581
|
+
if (cv === null || cv === undefined || !(cv < v))
|
|
582
|
+
return false;
|
|
583
|
+
break;
|
|
584
|
+
case "<=":
|
|
585
|
+
if (cv === null || cv === undefined || !(cv <= v))
|
|
586
|
+
return false;
|
|
587
|
+
break;
|
|
588
|
+
case ">":
|
|
589
|
+
if (cv === null || cv === undefined || !(cv > v))
|
|
590
|
+
return false;
|
|
591
|
+
break;
|
|
592
|
+
case ">=":
|
|
593
|
+
if (cv === null || cv === undefined || !(cv >= v))
|
|
594
|
+
return false;
|
|
595
|
+
break;
|
|
596
|
+
default:
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
} else {
|
|
600
|
+
if (columnValue !== criterion)
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return true;
|
|
605
|
+
});
|
|
606
|
+
if (options?.orderBy && options.orderBy.length > 0) {
|
|
607
|
+
results.sort((a, b) => {
|
|
608
|
+
for (const { column, direction } of options.orderBy) {
|
|
609
|
+
const aVal = a[column];
|
|
610
|
+
const bVal = b[column];
|
|
611
|
+
if (aVal == null && bVal == null)
|
|
612
|
+
continue;
|
|
613
|
+
if (aVal == null)
|
|
614
|
+
return direction === "ASC" ? -1 : 1;
|
|
615
|
+
if (bVal == null)
|
|
616
|
+
return direction === "ASC" ? 1 : -1;
|
|
617
|
+
if (aVal < bVal)
|
|
618
|
+
return direction === "ASC" ? -1 : 1;
|
|
619
|
+
if (aVal > bVal)
|
|
620
|
+
return direction === "ASC" ? 1 : -1;
|
|
621
|
+
}
|
|
622
|
+
return 0;
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
if (options?.offset !== undefined) {
|
|
626
|
+
results = results.slice(options.offset);
|
|
627
|
+
}
|
|
628
|
+
if (options?.limit !== undefined) {
|
|
629
|
+
results = results.slice(0, options.limit);
|
|
630
|
+
}
|
|
631
|
+
const result = results.length > 0 ? results : undefined;
|
|
632
|
+
this.events.emit("query", criteria, result);
|
|
633
|
+
return result;
|
|
634
|
+
}
|
|
454
635
|
subscribeToChanges(callback, options) {
|
|
455
636
|
const handlePut = (entity) => {
|
|
456
637
|
callback({ type: "UPDATE", new: entity });
|
|
@@ -502,8 +683,8 @@ class CachedTabularStorage extends BaseTabularStorage {
|
|
|
502
683
|
this.cache.on("get", (key, entity) => {
|
|
503
684
|
this.events.emit("get", key, entity);
|
|
504
685
|
});
|
|
505
|
-
this.cache.on("
|
|
506
|
-
this.events.emit("
|
|
686
|
+
this.cache.on("query", (key, entities) => {
|
|
687
|
+
this.events.emit("query", key, entities);
|
|
507
688
|
});
|
|
508
689
|
this.cache.on("delete", (key) => {
|
|
509
690
|
this.events.emit("delete", key);
|
|
@@ -522,7 +703,7 @@ class CachedTabularStorage extends BaseTabularStorage {
|
|
|
522
703
|
}
|
|
523
704
|
this.cacheInitialized = true;
|
|
524
705
|
} catch (error) {
|
|
525
|
-
|
|
706
|
+
getLogger().warn("Failed to initialize cache from durable repository:", { error });
|
|
526
707
|
this.cacheInitialized = true;
|
|
527
708
|
}
|
|
528
709
|
}
|
|
@@ -549,17 +730,6 @@ class CachedTabularStorage extends BaseTabularStorage {
|
|
|
549
730
|
}
|
|
550
731
|
return result;
|
|
551
732
|
}
|
|
552
|
-
async search(key) {
|
|
553
|
-
await this.initializeCache();
|
|
554
|
-
let results = await this.cache.search(key);
|
|
555
|
-
if (results === undefined) {
|
|
556
|
-
results = await this.durable.search(key);
|
|
557
|
-
if (results && results.length > 0) {
|
|
558
|
-
await this.cache.putBulk(results);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
return results;
|
|
562
|
-
}
|
|
563
733
|
async delete(value) {
|
|
564
734
|
await this.initializeCache();
|
|
565
735
|
await this.durable.delete(value);
|
|
@@ -570,7 +740,7 @@ class CachedTabularStorage extends BaseTabularStorage {
|
|
|
570
740
|
await this.durable.deleteAll();
|
|
571
741
|
await this.cache.deleteAll();
|
|
572
742
|
}
|
|
573
|
-
async getAll() {
|
|
743
|
+
async getAll(options) {
|
|
574
744
|
await this.initializeCache();
|
|
575
745
|
let results = await this.cache.getAll();
|
|
576
746
|
if (!results || results.length === 0) {
|
|
@@ -579,6 +749,9 @@ class CachedTabularStorage extends BaseTabularStorage {
|
|
|
579
749
|
await this.cache.putBulk(results);
|
|
580
750
|
}
|
|
581
751
|
}
|
|
752
|
+
if (options && results && results.length > 0) {
|
|
753
|
+
return await this.cache.getAll(options);
|
|
754
|
+
}
|
|
582
755
|
return results;
|
|
583
756
|
}
|
|
584
757
|
async size() {
|
|
@@ -589,6 +762,10 @@ class CachedTabularStorage extends BaseTabularStorage {
|
|
|
589
762
|
await this.initializeCache();
|
|
590
763
|
return await this.durable.getBulk(offset, limit);
|
|
591
764
|
}
|
|
765
|
+
async query(criteria, options) {
|
|
766
|
+
await this.initializeCache();
|
|
767
|
+
return await this.cache.query(criteria, options);
|
|
768
|
+
}
|
|
592
769
|
async deleteSearch(criteria) {
|
|
593
770
|
await this.initializeCache();
|
|
594
771
|
await this.durable.deleteSearch(criteria);
|
|
@@ -709,7 +886,8 @@ class HuggingFaceTabularStorage extends BaseTabularStorage {
|
|
|
709
886
|
this.events.emit("get", key, undefined);
|
|
710
887
|
return;
|
|
711
888
|
}
|
|
712
|
-
async getAll() {
|
|
889
|
+
async getAll(options) {
|
|
890
|
+
this.validateGetAllOptions(options);
|
|
713
891
|
const allEntities = [];
|
|
714
892
|
let offset = 0;
|
|
715
893
|
const pageSize = 100;
|
|
@@ -724,7 +902,36 @@ class HuggingFaceTabularStorage extends BaseTabularStorage {
|
|
|
724
902
|
break;
|
|
725
903
|
}
|
|
726
904
|
}
|
|
727
|
-
|
|
905
|
+
if (allEntities.length === 0)
|
|
906
|
+
return;
|
|
907
|
+
let results = allEntities;
|
|
908
|
+
if (options?.orderBy && options.orderBy.length > 0) {
|
|
909
|
+
results = [...results];
|
|
910
|
+
results.sort((a, b) => {
|
|
911
|
+
for (const { column, direction } of options.orderBy) {
|
|
912
|
+
const aVal = a[column];
|
|
913
|
+
const bVal = b[column];
|
|
914
|
+
if (aVal == null && bVal == null)
|
|
915
|
+
continue;
|
|
916
|
+
if (aVal == null)
|
|
917
|
+
return direction === "ASC" ? -1 : 1;
|
|
918
|
+
if (bVal == null)
|
|
919
|
+
return direction === "ASC" ? 1 : -1;
|
|
920
|
+
if (aVal < bVal)
|
|
921
|
+
return direction === "ASC" ? -1 : 1;
|
|
922
|
+
if (aVal > bVal)
|
|
923
|
+
return direction === "ASC" ? 1 : -1;
|
|
924
|
+
}
|
|
925
|
+
return 0;
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
if (options?.offset !== undefined) {
|
|
929
|
+
results = results.slice(options.offset);
|
|
930
|
+
}
|
|
931
|
+
if (options?.limit !== undefined) {
|
|
932
|
+
results = results.slice(0, options.limit);
|
|
933
|
+
}
|
|
934
|
+
return results.length > 0 ? results : undefined;
|
|
728
935
|
}
|
|
729
936
|
async getBulk(offset, limit) {
|
|
730
937
|
const data = await this.fetchApi("/rows", {
|
|
@@ -740,18 +947,40 @@ class HuggingFaceTabularStorage extends BaseTabularStorage {
|
|
|
740
947
|
}
|
|
741
948
|
return entities;
|
|
742
949
|
}
|
|
743
|
-
async
|
|
744
|
-
const
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
950
|
+
async size() {
|
|
951
|
+
const data = await this.fetchApi("/size", {});
|
|
952
|
+
return data.size.num_rows;
|
|
953
|
+
}
|
|
954
|
+
async put(_value) {
|
|
955
|
+
throw new Error("HuggingFaceTabularStorage is readonly");
|
|
956
|
+
}
|
|
957
|
+
async putBulk(_values) {
|
|
958
|
+
throw new Error("HuggingFaceTabularStorage is readonly");
|
|
959
|
+
}
|
|
960
|
+
async delete(_value) {
|
|
961
|
+
throw new Error("HuggingFaceTabularStorage is readonly");
|
|
962
|
+
}
|
|
963
|
+
async deleteAll() {
|
|
964
|
+
throw new Error("HuggingFaceTabularStorage is readonly");
|
|
965
|
+
}
|
|
966
|
+
async query(criteria, options) {
|
|
967
|
+
this.validateQueryParams(criteria, options);
|
|
752
968
|
const whereConditions = [];
|
|
753
|
-
for (const [k, v] of Object.entries(
|
|
754
|
-
if (v
|
|
969
|
+
for (const [k, v] of Object.entries(criteria)) {
|
|
970
|
+
if (v === undefined || v === null)
|
|
971
|
+
continue;
|
|
972
|
+
if (isSearchCondition(v)) {
|
|
973
|
+
if (v.operator !== "=") {
|
|
974
|
+
throw new StorageUnsupportedError(`Operator "${v.operator}" in query`, "HuggingFaceTabularStorage");
|
|
975
|
+
}
|
|
976
|
+
const val = v.value;
|
|
977
|
+
if (typeof val === "string") {
|
|
978
|
+
const escaped = val.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
979
|
+
whereConditions.push(`${k}='${escaped}'`);
|
|
980
|
+
} else {
|
|
981
|
+
whereConditions.push(`${k}=${val}`);
|
|
982
|
+
}
|
|
983
|
+
} else {
|
|
755
984
|
if (typeof v === "string") {
|
|
756
985
|
const escaped = v.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
757
986
|
whereConditions.push(`${k}='${escaped}'`);
|
|
@@ -761,50 +990,60 @@ class HuggingFaceTabularStorage extends BaseTabularStorage {
|
|
|
761
990
|
}
|
|
762
991
|
}
|
|
763
992
|
if (whereConditions.length === 0) {
|
|
764
|
-
|
|
993
|
+
return;
|
|
765
994
|
}
|
|
766
995
|
const where = whereConditions.join(" AND ");
|
|
767
996
|
const allEntities = [];
|
|
768
|
-
let
|
|
769
|
-
const
|
|
997
|
+
let fetchOffset = 0;
|
|
998
|
+
const fetchLimit = 100;
|
|
770
999
|
while (true) {
|
|
771
1000
|
const data = await this.fetchApi("/filter", {
|
|
772
1001
|
where,
|
|
773
|
-
offset:
|
|
774
|
-
limit:
|
|
1002
|
+
offset: fetchOffset.toString(),
|
|
1003
|
+
limit: fetchLimit.toString()
|
|
775
1004
|
});
|
|
776
1005
|
for (const row of data.rows) {
|
|
777
1006
|
allEntities.push(this.rowToEntity(row));
|
|
778
1007
|
}
|
|
779
|
-
|
|
780
|
-
if (
|
|
1008
|
+
fetchOffset += data.rows.length;
|
|
1009
|
+
if (fetchOffset >= data.num_rows_total || data.rows.length < fetchLimit) {
|
|
781
1010
|
break;
|
|
782
1011
|
}
|
|
783
1012
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
1013
|
+
let results = allEntities;
|
|
1014
|
+
if (options?.orderBy && options.orderBy.length > 0) {
|
|
1015
|
+
results.sort((a, b) => {
|
|
1016
|
+
for (const { column, direction } of options.orderBy) {
|
|
1017
|
+
const aVal = a[column];
|
|
1018
|
+
const bVal = b[column];
|
|
1019
|
+
if (aVal == null && bVal == null)
|
|
1020
|
+
continue;
|
|
1021
|
+
if (aVal == null)
|
|
1022
|
+
return direction === "ASC" ? -1 : 1;
|
|
1023
|
+
if (bVal == null)
|
|
1024
|
+
return direction === "ASC" ? 1 : -1;
|
|
1025
|
+
if (aVal < bVal)
|
|
1026
|
+
return direction === "ASC" ? -1 : 1;
|
|
1027
|
+
if (aVal > bVal)
|
|
1028
|
+
return direction === "ASC" ? 1 : -1;
|
|
1029
|
+
}
|
|
1030
|
+
return 0;
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
if (options?.offset !== undefined) {
|
|
1034
|
+
results = results.slice(options.offset);
|
|
1035
|
+
}
|
|
1036
|
+
if (options?.limit !== undefined) {
|
|
1037
|
+
results = results.slice(0, options.limit);
|
|
1038
|
+
}
|
|
1039
|
+
if (results.length > 0) {
|
|
1040
|
+
this.events.emit("query", criteria, results);
|
|
1041
|
+
return results;
|
|
787
1042
|
} else {
|
|
788
|
-
this.events.emit("
|
|
1043
|
+
this.events.emit("query", criteria, undefined);
|
|
789
1044
|
return;
|
|
790
1045
|
}
|
|
791
1046
|
}
|
|
792
|
-
async size() {
|
|
793
|
-
const data = await this.fetchApi("/size", {});
|
|
794
|
-
return data.size.num_rows;
|
|
795
|
-
}
|
|
796
|
-
async put(_value) {
|
|
797
|
-
throw new Error("HuggingFaceTabularStorage is readonly");
|
|
798
|
-
}
|
|
799
|
-
async putBulk(_values) {
|
|
800
|
-
throw new Error("HuggingFaceTabularStorage is readonly");
|
|
801
|
-
}
|
|
802
|
-
async delete(_value) {
|
|
803
|
-
throw new Error("HuggingFaceTabularStorage is readonly");
|
|
804
|
-
}
|
|
805
|
-
async deleteAll() {
|
|
806
|
-
throw new Error("HuggingFaceTabularStorage is readonly");
|
|
807
|
-
}
|
|
808
1047
|
async deleteSearch(_criteria) {
|
|
809
1048
|
throw new Error("HuggingFaceTabularStorage is readonly");
|
|
810
1049
|
}
|
|
@@ -1035,7 +1274,7 @@ class InMemoryKvStorage extends KvViaTabularStorage {
|
|
|
1035
1274
|
import {
|
|
1036
1275
|
createServiceToken as createServiceToken9,
|
|
1037
1276
|
EventEmitter as EventEmitter3,
|
|
1038
|
-
getLogger,
|
|
1277
|
+
getLogger as getLogger2,
|
|
1039
1278
|
makeFingerprint as makeFingerprint4,
|
|
1040
1279
|
sleep,
|
|
1041
1280
|
uuid4 as uuid42
|
|
@@ -1134,7 +1373,7 @@ class InMemoryQueueStorage {
|
|
|
1134
1373
|
const job = this.jobQueue.find((j) => j.id === id && this.matchesPrefixes(j));
|
|
1135
1374
|
if (!job) {
|
|
1136
1375
|
const jobWithAnyPrefix = this.jobQueue.find((j) => j.id === id);
|
|
1137
|
-
|
|
1376
|
+
getLogger2().warn("Job not found for progress update", {
|
|
1138
1377
|
id,
|
|
1139
1378
|
reason: jobWithAnyPrefix ? "prefix_mismatch" : "missing",
|
|
1140
1379
|
existingStatus: jobWithAnyPrefix?.status,
|
|
@@ -1144,7 +1383,7 @@ class InMemoryQueueStorage {
|
|
|
1144
1383
|
return;
|
|
1145
1384
|
}
|
|
1146
1385
|
if (job.status === JobStatus.COMPLETED || job.status === JobStatus.FAILED) {
|
|
1147
|
-
|
|
1386
|
+
getLogger2().warn("Job already completed or failed for progress update", {
|
|
1148
1387
|
id,
|
|
1149
1388
|
status: job.status,
|
|
1150
1389
|
completedAt: job.completed_at,
|
|
@@ -1695,6 +1934,81 @@ class InMemoryVectorStorage extends InMemoryTabularStorage {
|
|
|
1695
1934
|
return topResults;
|
|
1696
1935
|
}
|
|
1697
1936
|
}
|
|
1937
|
+
// src/credentials/EncryptedKvCredentialStore.ts
|
|
1938
|
+
import { decrypt, encrypt } from "@workglow/util";
|
|
1939
|
+
|
|
1940
|
+
class EncryptedKvCredentialStore {
|
|
1941
|
+
kv;
|
|
1942
|
+
passphrase;
|
|
1943
|
+
keyCache = new Map;
|
|
1944
|
+
constructor(kv, passphrase) {
|
|
1945
|
+
this.kv = kv;
|
|
1946
|
+
this.passphrase = passphrase;
|
|
1947
|
+
if (!passphrase) {
|
|
1948
|
+
throw new Error("EncryptedKvCredentialStore requires a non-empty passphrase.");
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
async get(key) {
|
|
1952
|
+
const raw = await this.kv.get(key);
|
|
1953
|
+
if (!raw)
|
|
1954
|
+
return;
|
|
1955
|
+
if (raw.expiresAt && new Date(raw.expiresAt) <= new Date) {
|
|
1956
|
+
await this.kv.delete(key);
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
return decrypt(raw.encrypted, raw.iv, this.passphrase, this.keyCache);
|
|
1960
|
+
}
|
|
1961
|
+
async put(key, value, options) {
|
|
1962
|
+
const now = new Date;
|
|
1963
|
+
const existing = await this.kv.get(key);
|
|
1964
|
+
const { encrypted, iv } = await encrypt(value, this.passphrase, this.keyCache);
|
|
1965
|
+
const stored = {
|
|
1966
|
+
encrypted,
|
|
1967
|
+
iv,
|
|
1968
|
+
label: options?.label ?? existing?.label,
|
|
1969
|
+
provider: options?.provider ?? existing?.provider,
|
|
1970
|
+
createdAt: existing?.createdAt ?? now.toISOString(),
|
|
1971
|
+
updatedAt: now.toISOString(),
|
|
1972
|
+
expiresAt: options?.expiresAt ? options.expiresAt.toISOString() : existing?.expiresAt
|
|
1973
|
+
};
|
|
1974
|
+
await this.kv.put(key, stored);
|
|
1975
|
+
}
|
|
1976
|
+
async delete(key) {
|
|
1977
|
+
const exists = await this.kv.get(key) !== undefined;
|
|
1978
|
+
if (exists) {
|
|
1979
|
+
await this.kv.delete(key);
|
|
1980
|
+
}
|
|
1981
|
+
return exists;
|
|
1982
|
+
}
|
|
1983
|
+
async has(key) {
|
|
1984
|
+
const raw = await this.kv.get(key);
|
|
1985
|
+
if (!raw)
|
|
1986
|
+
return false;
|
|
1987
|
+
if (raw.expiresAt && new Date(raw.expiresAt) <= new Date) {
|
|
1988
|
+
await this.kv.delete(key);
|
|
1989
|
+
return false;
|
|
1990
|
+
}
|
|
1991
|
+
return true;
|
|
1992
|
+
}
|
|
1993
|
+
async keys() {
|
|
1994
|
+
const all = await this.kv.getAll();
|
|
1995
|
+
if (!all)
|
|
1996
|
+
return [];
|
|
1997
|
+
const now = new Date;
|
|
1998
|
+
const result = [];
|
|
1999
|
+
for (const entry of all) {
|
|
2000
|
+
if (entry.value.expiresAt && new Date(entry.value.expiresAt) <= now) {
|
|
2001
|
+
await this.kv.delete(entry.key);
|
|
2002
|
+
continue;
|
|
2003
|
+
}
|
|
2004
|
+
result.push(entry.key);
|
|
2005
|
+
}
|
|
2006
|
+
return result;
|
|
2007
|
+
}
|
|
2008
|
+
async deleteAll() {
|
|
2009
|
+
await this.kv.deleteAll();
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
1698
2012
|
// src/tabular/FsFolderTabularStorage.ts
|
|
1699
2013
|
import {
|
|
1700
2014
|
createServiceToken as createServiceToken12,
|
|
@@ -1855,15 +2169,15 @@ class FsFolderTabularStorage extends BaseTabularStorage {
|
|
|
1855
2169
|
const page = allEntities.slice(offset, offset + limit);
|
|
1856
2170
|
return page.length > 0 ? page : undefined;
|
|
1857
2171
|
}
|
|
1858
|
-
async search(key) {
|
|
1859
|
-
throw new Error("Search not supported for FsFolderTabularStorage");
|
|
1860
|
-
}
|
|
1861
2172
|
async getFilePath(value) {
|
|
1862
2173
|
const { key } = this.separateKeyValueFromCombined(value);
|
|
1863
2174
|
const filename = await this.getKeyAsIdString(key);
|
|
1864
2175
|
const fullPath = path.join(this.folderPath, `${filename}.json`);
|
|
1865
2176
|
return fullPath;
|
|
1866
2177
|
}
|
|
2178
|
+
async query(_criteria, _options) {
|
|
2179
|
+
throw new StorageUnsupportedError("query", "FsFolderTabularStorage");
|
|
2180
|
+
}
|
|
1867
2181
|
async deleteSearch(_criteria) {
|
|
1868
2182
|
throw new Error("deleteSearch is not supported for FsFolderTabularStorage");
|
|
1869
2183
|
}
|
|
@@ -2451,39 +2765,6 @@ class PostgresTabularStorage extends BaseSqlTabularStorage {
|
|
|
2451
2765
|
this.events.emit("get", key, val);
|
|
2452
2766
|
return val;
|
|
2453
2767
|
}
|
|
2454
|
-
async search(key) {
|
|
2455
|
-
const db = this.db;
|
|
2456
|
-
const searchKeys = Object.keys(key);
|
|
2457
|
-
if (searchKeys.length === 0) {
|
|
2458
|
-
return;
|
|
2459
|
-
}
|
|
2460
|
-
const bestIndex = this.findBestMatchingIndex(searchKeys);
|
|
2461
|
-
if (!bestIndex) {
|
|
2462
|
-
throw new Error(`No suitable index found for the search criteria, searching for ['${searchKeys.join("', '")}'] with pk ['${this.primaryKeyNames.join("', '")}'] and indexes ['${this.indexes.join("', '")}']`);
|
|
2463
|
-
}
|
|
2464
|
-
const validColumns = [...this.primaryKeyColumns(), ...this.valueColumns()];
|
|
2465
|
-
const invalidColumns = searchKeys.filter((key2) => !validColumns.includes(key2));
|
|
2466
|
-
if (invalidColumns.length > 0) {
|
|
2467
|
-
throw new Error(`Invalid columns in search criteria: ${invalidColumns.join(", ")}`);
|
|
2468
|
-
}
|
|
2469
|
-
const whereClauses = Object.keys(key).map((key2, i) => `"${key2}" = $${i + 1}`).join(" AND ");
|
|
2470
|
-
const whereClauseValues = Object.entries(key).map(([k, v]) => this.jsToSqlValue(k, v));
|
|
2471
|
-
const sql = `SELECT * FROM "${this.table}" WHERE ${whereClauses}`;
|
|
2472
|
-
const result = await db.query(sql, whereClauseValues);
|
|
2473
|
-
if (result.rows.length > 0) {
|
|
2474
|
-
for (const row of result.rows) {
|
|
2475
|
-
const record = row;
|
|
2476
|
-
for (const k in this.schema.properties) {
|
|
2477
|
-
record[k] = this.sqlToJsValue(k, record[k]);
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
this.events.emit("search", key, result.rows);
|
|
2481
|
-
return result.rows;
|
|
2482
|
-
} else {
|
|
2483
|
-
this.events.emit("search", key, undefined);
|
|
2484
|
-
return;
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
2768
|
async delete(value) {
|
|
2488
2769
|
const db = this.db;
|
|
2489
2770
|
const { key } = this.separateKeyValueFromCombined(value);
|
|
@@ -2492,10 +2773,24 @@ class PostgresTabularStorage extends BaseSqlTabularStorage {
|
|
|
2492
2773
|
await db.query(`DELETE FROM "${this.table}" WHERE ${whereClauses}`, params);
|
|
2493
2774
|
this.events.emit("delete", key);
|
|
2494
2775
|
}
|
|
2495
|
-
async getAll() {
|
|
2776
|
+
async getAll(options) {
|
|
2777
|
+
this.validateGetAllOptions(options);
|
|
2496
2778
|
const db = this.db;
|
|
2497
|
-
|
|
2498
|
-
const
|
|
2779
|
+
let sql = `SELECT * FROM "${this.table}"`;
|
|
2780
|
+
const params = [];
|
|
2781
|
+
if (options?.orderBy && options.orderBy.length > 0) {
|
|
2782
|
+
const orderClauses = options.orderBy.map((o) => `"${String(o.column)}" ${o.direction}`);
|
|
2783
|
+
sql += ` ORDER BY ${orderClauses.join(", ")}`;
|
|
2784
|
+
}
|
|
2785
|
+
if (options?.limit !== undefined) {
|
|
2786
|
+
sql += ` LIMIT $${params.length + 1}`;
|
|
2787
|
+
params.push(options.limit);
|
|
2788
|
+
}
|
|
2789
|
+
if (options?.offset !== undefined) {
|
|
2790
|
+
sql += ` OFFSET $${params.length + 1}`;
|
|
2791
|
+
params.push(options.offset);
|
|
2792
|
+
}
|
|
2793
|
+
const result = params.length > 0 ? await db.query(sql, params) : await db.query(sql);
|
|
2499
2794
|
if (result.rows.length > 0) {
|
|
2500
2795
|
for (const row of result.rows) {
|
|
2501
2796
|
const record = row;
|
|
@@ -2568,6 +2863,38 @@ class PostgresTabularStorage extends BaseSqlTabularStorage {
|
|
|
2568
2863
|
await db.query(`DELETE FROM "${this.table}" WHERE ${whereClause}`, params);
|
|
2569
2864
|
this.events.emit("delete", criteriaKeys[0]);
|
|
2570
2865
|
}
|
|
2866
|
+
async query(criteria, options) {
|
|
2867
|
+
this.validateQueryParams(criteria, options);
|
|
2868
|
+
const db = this.db;
|
|
2869
|
+
let sql = `SELECT * FROM "${this.table}"`;
|
|
2870
|
+
const { whereClause, params } = this.buildDeleteSearchWhere(criteria);
|
|
2871
|
+
sql += ` WHERE ${whereClause}`;
|
|
2872
|
+
if (options?.orderBy && options.orderBy.length > 0) {
|
|
2873
|
+
const orderClauses = options.orderBy.map((o) => `"${String(o.column)}" ${o.direction}`);
|
|
2874
|
+
sql += ` ORDER BY ${orderClauses.join(", ")}`;
|
|
2875
|
+
}
|
|
2876
|
+
if (options?.limit !== undefined) {
|
|
2877
|
+
sql += ` LIMIT $${params.length + 1}`;
|
|
2878
|
+
params.push(options.limit);
|
|
2879
|
+
}
|
|
2880
|
+
if (options?.offset !== undefined) {
|
|
2881
|
+
sql += ` OFFSET $${params.length + 1}`;
|
|
2882
|
+
params.push(options.offset);
|
|
2883
|
+
}
|
|
2884
|
+
const result = await db.query(sql, params);
|
|
2885
|
+
if (result.rows.length > 0) {
|
|
2886
|
+
for (const row of result.rows) {
|
|
2887
|
+
const record = row;
|
|
2888
|
+
for (const k in this.schema.properties) {
|
|
2889
|
+
record[k] = this.sqlToJsValue(k, record[k]);
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
this.events.emit("query", criteria, result.rows);
|
|
2893
|
+
return result.rows;
|
|
2894
|
+
}
|
|
2895
|
+
this.events.emit("query", criteria, undefined);
|
|
2896
|
+
return;
|
|
2897
|
+
}
|
|
2571
2898
|
subscribeToChanges(callback, options) {
|
|
2572
2899
|
throw new Error("subscribeToChanges is not supported for PostgresTabularStorage");
|
|
2573
2900
|
}
|
|
@@ -2900,40 +3227,6 @@ class SqliteTabularStorage extends BaseSqlTabularStorage {
|
|
|
2900
3227
|
return;
|
|
2901
3228
|
}
|
|
2902
3229
|
}
|
|
2903
|
-
async search(key) {
|
|
2904
|
-
const db = this.db;
|
|
2905
|
-
const searchKeys = Object.keys(key);
|
|
2906
|
-
if (searchKeys.length === 0) {
|
|
2907
|
-
return;
|
|
2908
|
-
}
|
|
2909
|
-
const bestIndex = super.findBestMatchingIndex(searchKeys);
|
|
2910
|
-
if (!bestIndex) {
|
|
2911
|
-
throw new Error(`No suitable index found for the search criteria, searching for ['${searchKeys.join("', '")}'] with pk ['${this.primaryKeyNames.join("', '")}'] and indexes ['${this.indexes.join("', '")}']`);
|
|
2912
|
-
}
|
|
2913
|
-
const validColumns = [...this.primaryKeyColumns(), ...this.valueColumns()];
|
|
2914
|
-
const invalidColumns = searchKeys.filter((key2) => !validColumns.includes(key2));
|
|
2915
|
-
if (invalidColumns.length > 0) {
|
|
2916
|
-
throw new Error(`Invalid columns in search criteria: ${invalidColumns.join(", ")}`);
|
|
2917
|
-
}
|
|
2918
|
-
const whereClauses = Object.keys(key).map((key2, i) => `"${key2}" = ?`).join(" AND ");
|
|
2919
|
-
const whereClauseValues = Object.entries(key).map(([k, v]) => this.jsToSqlValue(k, v));
|
|
2920
|
-
const sql = `SELECT * FROM \`${this.table}\` WHERE ${whereClauses}`;
|
|
2921
|
-
const stmt = db.prepare(sql);
|
|
2922
|
-
const result = stmt.all(...whereClauseValues);
|
|
2923
|
-
if (result.length > 0) {
|
|
2924
|
-
for (const row of result) {
|
|
2925
|
-
const record = row;
|
|
2926
|
-
for (const k in this.schema.properties) {
|
|
2927
|
-
record[k] = this.sqlToJsValue(k, record[k]);
|
|
2928
|
-
}
|
|
2929
|
-
}
|
|
2930
|
-
this.events.emit("search", key, result);
|
|
2931
|
-
return result;
|
|
2932
|
-
} else {
|
|
2933
|
-
this.events.emit("search", key, undefined);
|
|
2934
|
-
return;
|
|
2935
|
-
}
|
|
2936
|
-
}
|
|
2937
3230
|
async delete(key) {
|
|
2938
3231
|
const db = this.db;
|
|
2939
3232
|
const whereClauses = this.primaryKeyColumns().map((key2) => `${key2} = ?`).join(" AND ");
|
|
@@ -2942,11 +3235,28 @@ class SqliteTabularStorage extends BaseSqlTabularStorage {
|
|
|
2942
3235
|
stmt.run(...params);
|
|
2943
3236
|
this.events.emit("delete", key);
|
|
2944
3237
|
}
|
|
2945
|
-
async getAll() {
|
|
3238
|
+
async getAll(options) {
|
|
3239
|
+
this.validateGetAllOptions(options);
|
|
2946
3240
|
const db = this.db;
|
|
2947
|
-
|
|
3241
|
+
let sql = `SELECT * FROM \`${this.table}\``;
|
|
3242
|
+
const params = [];
|
|
3243
|
+
if (options?.orderBy && options.orderBy.length > 0) {
|
|
3244
|
+
const orderClauses = options.orderBy.map((o) => `\`${String(o.column)}\` ${o.direction}`);
|
|
3245
|
+
sql += ` ORDER BY ${orderClauses.join(", ")}`;
|
|
3246
|
+
}
|
|
3247
|
+
if (options?.limit !== undefined) {
|
|
3248
|
+
sql += ` LIMIT ?`;
|
|
3249
|
+
params.push(options.limit);
|
|
3250
|
+
}
|
|
3251
|
+
if (options?.offset !== undefined) {
|
|
3252
|
+
if (options.limit === undefined) {
|
|
3253
|
+
sql += ` LIMIT -1`;
|
|
3254
|
+
}
|
|
3255
|
+
sql += ` OFFSET ?`;
|
|
3256
|
+
params.push(options.offset);
|
|
3257
|
+
}
|
|
2948
3258
|
const stmt = db.prepare(sql);
|
|
2949
|
-
const value = stmt.all();
|
|
3259
|
+
const value = params.length > 0 ? stmt.all(...params) : stmt.all();
|
|
2950
3260
|
if (!value.length)
|
|
2951
3261
|
return;
|
|
2952
3262
|
for (const row of value) {
|
|
@@ -3022,6 +3332,42 @@ class SqliteTabularStorage extends BaseSqlTabularStorage {
|
|
|
3022
3332
|
stmt.run(...params);
|
|
3023
3333
|
this.events.emit("delete", criteriaKeys[0]);
|
|
3024
3334
|
}
|
|
3335
|
+
async query(criteria, options) {
|
|
3336
|
+
this.validateQueryParams(criteria, options);
|
|
3337
|
+
const db = this.db;
|
|
3338
|
+
let sql = `SELECT * FROM \`${this.table}\``;
|
|
3339
|
+
const { whereClause, params } = this.buildDeleteSearchWhere(criteria);
|
|
3340
|
+
sql += ` WHERE ${whereClause}`;
|
|
3341
|
+
if (options?.orderBy && options.orderBy.length > 0) {
|
|
3342
|
+
const orderClauses = options.orderBy.map((o) => `\`${String(o.column)}\` ${o.direction}`);
|
|
3343
|
+
sql += ` ORDER BY ${orderClauses.join(", ")}`;
|
|
3344
|
+
}
|
|
3345
|
+
if (options?.limit !== undefined) {
|
|
3346
|
+
sql += ` LIMIT ?`;
|
|
3347
|
+
params.push(options.limit);
|
|
3348
|
+
}
|
|
3349
|
+
if (options?.offset !== undefined) {
|
|
3350
|
+
if (options.limit === undefined) {
|
|
3351
|
+
sql += ` LIMIT -1`;
|
|
3352
|
+
}
|
|
3353
|
+
sql += ` OFFSET ?`;
|
|
3354
|
+
params.push(options.offset);
|
|
3355
|
+
}
|
|
3356
|
+
const stmt = db.prepare(sql);
|
|
3357
|
+
const result = stmt.all(...params);
|
|
3358
|
+
if (result.length > 0) {
|
|
3359
|
+
for (const row of result) {
|
|
3360
|
+
const record = row;
|
|
3361
|
+
for (const k in this.schema.properties) {
|
|
3362
|
+
record[k] = this.sqlToJsValue(k, record[k]);
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
this.events.emit("query", criteria, result);
|
|
3366
|
+
return result;
|
|
3367
|
+
}
|
|
3368
|
+
this.events.emit("query", criteria, undefined);
|
|
3369
|
+
return;
|
|
3370
|
+
}
|
|
3025
3371
|
subscribeToChanges(callback, options) {
|
|
3026
3372
|
throw new Error("subscribeToChanges is not supported for SqliteTabularStorage");
|
|
3027
3373
|
}
|
|
@@ -3305,41 +3651,6 @@ class SupabaseTabularStorage extends BaseSqlTabularStorage {
|
|
|
3305
3651
|
this.events.emit("get", key, val);
|
|
3306
3652
|
return val;
|
|
3307
3653
|
}
|
|
3308
|
-
async search(searchCriteria) {
|
|
3309
|
-
const searchKeys = Object.keys(searchCriteria);
|
|
3310
|
-
if (searchKeys.length === 0) {
|
|
3311
|
-
return;
|
|
3312
|
-
}
|
|
3313
|
-
const bestIndex = this.findBestMatchingIndex(searchKeys);
|
|
3314
|
-
if (!bestIndex) {
|
|
3315
|
-
throw new Error(`No suitable index found for the search criteria, searching for ['${searchKeys.join("', '")}'] with pk ['${this.primaryKeyNames.join("', '")}'] and indexes ['${this.indexes.join("', '")}']`);
|
|
3316
|
-
}
|
|
3317
|
-
const validColumns = [...this.primaryKeyColumns(), ...this.valueColumns()];
|
|
3318
|
-
const invalidColumns = searchKeys.filter((key) => !validColumns.includes(key));
|
|
3319
|
-
if (invalidColumns.length > 0) {
|
|
3320
|
-
throw new Error(`Invalid columns in search criteria: ${invalidColumns.join(", ")}`);
|
|
3321
|
-
}
|
|
3322
|
-
let query = this.client.from(this.table).select("*");
|
|
3323
|
-
for (const [key, value] of Object.entries(searchCriteria)) {
|
|
3324
|
-
query = query.eq(key, value);
|
|
3325
|
-
}
|
|
3326
|
-
const { data, error } = await query;
|
|
3327
|
-
if (error)
|
|
3328
|
-
throw error;
|
|
3329
|
-
if (data && data.length > 0) {
|
|
3330
|
-
for (const row of data) {
|
|
3331
|
-
const record = row;
|
|
3332
|
-
for (const key in this.schema.properties) {
|
|
3333
|
-
record[key] = this.sqlToJsValue(key, record[key]);
|
|
3334
|
-
}
|
|
3335
|
-
}
|
|
3336
|
-
this.events.emit("search", searchCriteria, data);
|
|
3337
|
-
return data;
|
|
3338
|
-
} else {
|
|
3339
|
-
this.events.emit("search", searchCriteria, undefined);
|
|
3340
|
-
return;
|
|
3341
|
-
}
|
|
3342
|
-
}
|
|
3343
3654
|
async delete(value) {
|
|
3344
3655
|
const { key } = this.separateKeyValueFromCombined(value);
|
|
3345
3656
|
let query = this.client.from(this.table).delete();
|
|
@@ -3352,8 +3663,23 @@ class SupabaseTabularStorage extends BaseSqlTabularStorage {
|
|
|
3352
3663
|
throw error;
|
|
3353
3664
|
this.events.emit("delete", key);
|
|
3354
3665
|
}
|
|
3355
|
-
async getAll() {
|
|
3356
|
-
|
|
3666
|
+
async getAll(options) {
|
|
3667
|
+
this.validateGetAllOptions(options);
|
|
3668
|
+
let query = this.client.from(this.table).select("*");
|
|
3669
|
+
if (options?.orderBy) {
|
|
3670
|
+
for (const { column, direction } of options.orderBy) {
|
|
3671
|
+
query = query.order(String(column), { ascending: direction === "ASC" });
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
if (options?.offset !== undefined || options?.limit !== undefined) {
|
|
3675
|
+
const start = options?.offset ?? 0;
|
|
3676
|
+
if (options?.limit !== undefined) {
|
|
3677
|
+
query = query.range(start, start + options.limit - 1);
|
|
3678
|
+
} else if (options?.offset !== undefined) {
|
|
3679
|
+
query = query.range(start, start + 999999);
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
const { data, error } = await query;
|
|
3357
3683
|
if (error)
|
|
3358
3684
|
throw error;
|
|
3359
3685
|
if (data && data.length) {
|
|
@@ -3441,6 +3767,69 @@ class SupabaseTabularStorage extends BaseSqlTabularStorage {
|
|
|
3441
3767
|
throw error;
|
|
3442
3768
|
this.events.emit("delete", criteriaKeys[0]);
|
|
3443
3769
|
}
|
|
3770
|
+
async query(criteria, options) {
|
|
3771
|
+
this.validateQueryParams(criteria, options);
|
|
3772
|
+
const criteriaKeys = Object.keys(criteria);
|
|
3773
|
+
let query = this.client.from(this.table).select("*");
|
|
3774
|
+
for (const column of criteriaKeys) {
|
|
3775
|
+
const criterion = criteria[column];
|
|
3776
|
+
let operator = "=";
|
|
3777
|
+
let value;
|
|
3778
|
+
if (isSearchCondition(criterion)) {
|
|
3779
|
+
operator = criterion.operator;
|
|
3780
|
+
value = criterion.value;
|
|
3781
|
+
} else {
|
|
3782
|
+
value = criterion;
|
|
3783
|
+
}
|
|
3784
|
+
switch (operator) {
|
|
3785
|
+
case "=":
|
|
3786
|
+
query = query.eq(String(column), value);
|
|
3787
|
+
break;
|
|
3788
|
+
case "<":
|
|
3789
|
+
query = query.lt(String(column), value);
|
|
3790
|
+
break;
|
|
3791
|
+
case "<=":
|
|
3792
|
+
query = query.lte(String(column), value);
|
|
3793
|
+
break;
|
|
3794
|
+
case ">":
|
|
3795
|
+
query = query.gt(String(column), value);
|
|
3796
|
+
break;
|
|
3797
|
+
case ">=":
|
|
3798
|
+
query = query.gte(String(column), value);
|
|
3799
|
+
break;
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
if (options?.orderBy) {
|
|
3803
|
+
for (const { column, direction } of options.orderBy) {
|
|
3804
|
+
query = query.order(String(column), { ascending: direction === "ASC" });
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
if (options?.offset !== undefined || options?.limit !== undefined) {
|
|
3808
|
+
const start = options?.offset ?? 0;
|
|
3809
|
+
if (options?.limit !== undefined) {
|
|
3810
|
+
query = query.range(start, start + options.limit - 1);
|
|
3811
|
+
} else if (options?.offset !== undefined) {
|
|
3812
|
+
query = query.range(start, start + 999999);
|
|
3813
|
+
}
|
|
3814
|
+
} else if (options?.limit !== undefined) {
|
|
3815
|
+
query = query.limit(options.limit);
|
|
3816
|
+
}
|
|
3817
|
+
const { data, error } = await query;
|
|
3818
|
+
if (error)
|
|
3819
|
+
throw error;
|
|
3820
|
+
if (data && data.length > 0) {
|
|
3821
|
+
for (const row of data) {
|
|
3822
|
+
const record = row;
|
|
3823
|
+
for (const key in this.schema.properties) {
|
|
3824
|
+
record[key] = this.sqlToJsValue(key, record[key]);
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
this.events.emit("query", criteria, data);
|
|
3828
|
+
return data;
|
|
3829
|
+
}
|
|
3830
|
+
this.events.emit("query", criteria, undefined);
|
|
3831
|
+
return;
|
|
3832
|
+
}
|
|
3444
3833
|
convertRealtimeRow(row) {
|
|
3445
3834
|
const entity = { ...row };
|
|
3446
3835
|
const record = entity;
|
|
@@ -6005,7 +6394,8 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
|
|
|
6005
6394
|
};
|
|
6006
6395
|
});
|
|
6007
6396
|
}
|
|
6008
|
-
async getAll() {
|
|
6397
|
+
async getAll(options) {
|
|
6398
|
+
this.validateGetAllOptions(options);
|
|
6009
6399
|
const db = await this.getDb();
|
|
6010
6400
|
const transaction = db.transaction(this.table, "readonly");
|
|
6011
6401
|
const store = transaction.objectStore(this.table);
|
|
@@ -6013,96 +6403,38 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
|
|
|
6013
6403
|
return new Promise((resolve, reject) => {
|
|
6014
6404
|
request.onerror = () => reject(request.error);
|
|
6015
6405
|
request.onsuccess = () => {
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
}
|
|
6021
|
-
async search(key) {
|
|
6022
|
-
const db = await this.getDb();
|
|
6023
|
-
const searchKeys = Object.keys(key);
|
|
6024
|
-
if (searchKeys.length === 0) {
|
|
6025
|
-
return;
|
|
6026
|
-
}
|
|
6027
|
-
const bestIndex = this.findBestMatchingIndex(searchKeys);
|
|
6028
|
-
if (!bestIndex) {
|
|
6029
|
-
throw new Error("No suitable index found for the search criteria");
|
|
6030
|
-
}
|
|
6031
|
-
return new Promise((resolve, reject) => {
|
|
6032
|
-
const transaction = db.transaction(this.table, "readonly");
|
|
6033
|
-
const store = transaction.objectStore(this.table);
|
|
6034
|
-
const indexName = bestIndex.join("_");
|
|
6035
|
-
const primaryKeyName = this.primaryKeyColumns().join("_");
|
|
6036
|
-
const isPrimaryKey = indexName === primaryKeyName;
|
|
6037
|
-
const indexValues = [];
|
|
6038
|
-
for (const col of bestIndex) {
|
|
6039
|
-
const val = key[col];
|
|
6040
|
-
if (val === undefined)
|
|
6041
|
-
break;
|
|
6042
|
-
if (typeof val !== "string" && typeof val !== "number") {
|
|
6043
|
-
throw new Error(`Invalid value type for indexed column ${String(col)}`);
|
|
6406
|
+
let values = request.result;
|
|
6407
|
+
if (values.length === 0) {
|
|
6408
|
+
resolve(undefined);
|
|
6409
|
+
return;
|
|
6044
6410
|
}
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6411
|
+
if (options?.orderBy && options.orderBy.length > 0) {
|
|
6412
|
+
values.sort((a, b) => {
|
|
6413
|
+
for (const { column, direction } of options.orderBy) {
|
|
6414
|
+
const aVal = a[column];
|
|
6415
|
+
const bVal = b[column];
|
|
6416
|
+
if (aVal == null && bVal == null)
|
|
6417
|
+
continue;
|
|
6418
|
+
if (aVal == null)
|
|
6419
|
+
return direction === "ASC" ? -1 : 1;
|
|
6420
|
+
if (bVal == null)
|
|
6421
|
+
return direction === "ASC" ? 1 : -1;
|
|
6422
|
+
if (aVal < bVal)
|
|
6423
|
+
return direction === "ASC" ? -1 : 1;
|
|
6424
|
+
if (aVal > bVal)
|
|
6425
|
+
return direction === "ASC" ? 1 : -1;
|
|
6426
|
+
}
|
|
6427
|
+
return 0;
|
|
6054
6428
|
});
|
|
6055
|
-
if (allColumnsRequired) {
|
|
6056
|
-
const results = [];
|
|
6057
|
-
const keyRange = IDBKeyRange.lowerBound(indexValues);
|
|
6058
|
-
const cursorRequest = index.openCursor(keyRange);
|
|
6059
|
-
cursorRequest.onsuccess = () => {
|
|
6060
|
-
const cursor = cursorRequest.result;
|
|
6061
|
-
if (cursor) {
|
|
6062
|
-
const item = cursor.value;
|
|
6063
|
-
const cursorKey = Array.isArray(cursor.key) ? cursor.key : [cursor.key];
|
|
6064
|
-
const prefixMatches = indexValues.every((val, idx) => cursorKey[idx] === val);
|
|
6065
|
-
if (!prefixMatches) {
|
|
6066
|
-
resolve(results.length > 0 ? results : undefined);
|
|
6067
|
-
return;
|
|
6068
|
-
}
|
|
6069
|
-
const matches = Object.entries(key).every(([k, v]) => item[k] === v);
|
|
6070
|
-
if (matches) {
|
|
6071
|
-
results.push(item);
|
|
6072
|
-
}
|
|
6073
|
-
cursor.continue();
|
|
6074
|
-
} else {
|
|
6075
|
-
resolve(results.length > 0 ? results : undefined);
|
|
6076
|
-
}
|
|
6077
|
-
};
|
|
6078
|
-
cursorRequest.onerror = () => {
|
|
6079
|
-
reject(cursorRequest.error);
|
|
6080
|
-
};
|
|
6081
|
-
} else {
|
|
6082
|
-
const getAllRequest = store.getAll();
|
|
6083
|
-
getAllRequest.onsuccess = () => {
|
|
6084
|
-
const allRecords = getAllRequest.result;
|
|
6085
|
-
const results = allRecords.filter((item) => Object.entries(key).every(([k, v]) => item[k] === v));
|
|
6086
|
-
resolve(results.length > 0 ? results : undefined);
|
|
6087
|
-
};
|
|
6088
|
-
getAllRequest.onerror = () => {
|
|
6089
|
-
reject(getAllRequest.error);
|
|
6090
|
-
};
|
|
6091
|
-
}
|
|
6092
|
-
} else {
|
|
6093
|
-
const request = index.getAll(indexValues.length === 1 ? indexValues[0] : indexValues);
|
|
6094
|
-
request.onsuccess = () => {
|
|
6095
|
-
const results = request.result.filter((item) => Object.entries(key).every(([k, v]) => item[k] === v));
|
|
6096
|
-
resolve(results.length > 0 ? results : undefined);
|
|
6097
|
-
};
|
|
6098
|
-
request.onerror = () => {
|
|
6099
|
-
console.error("Search error:", request.error);
|
|
6100
|
-
reject(request.error);
|
|
6101
|
-
};
|
|
6102
6429
|
}
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6430
|
+
if (options?.offset !== undefined) {
|
|
6431
|
+
values = values.slice(options.offset);
|
|
6432
|
+
}
|
|
6433
|
+
if (options?.limit !== undefined) {
|
|
6434
|
+
values = values.slice(0, options.limit);
|
|
6435
|
+
}
|
|
6436
|
+
resolve(values.length > 0 ? values : undefined);
|
|
6437
|
+
};
|
|
6106
6438
|
});
|
|
6107
6439
|
}
|
|
6108
6440
|
async delete(key) {
|
|
@@ -6268,6 +6600,50 @@ class IndexedDbTabularStorage extends BaseTabularStorage {
|
|
|
6268
6600
|
}
|
|
6269
6601
|
});
|
|
6270
6602
|
}
|
|
6603
|
+
async query(criteria, options) {
|
|
6604
|
+
this.validateQueryParams(criteria, options);
|
|
6605
|
+
const db = await this.getDb();
|
|
6606
|
+
return new Promise((resolve, reject) => {
|
|
6607
|
+
const transaction = db.transaction(this.table, "readonly");
|
|
6608
|
+
const store = transaction.objectStore(this.table);
|
|
6609
|
+
const getAllRequest = store.getAll();
|
|
6610
|
+
getAllRequest.onsuccess = () => {
|
|
6611
|
+
const allRecords = getAllRequest.result;
|
|
6612
|
+
let results = allRecords.filter((record) => this.matchesCriteria(record, criteria));
|
|
6613
|
+
if (options?.orderBy && options.orderBy.length > 0) {
|
|
6614
|
+
results.sort((a, b) => {
|
|
6615
|
+
for (const { column, direction } of options.orderBy) {
|
|
6616
|
+
const aVal = a[column];
|
|
6617
|
+
const bVal = b[column];
|
|
6618
|
+
if (aVal == null && bVal == null)
|
|
6619
|
+
continue;
|
|
6620
|
+
if (aVal == null)
|
|
6621
|
+
return direction === "ASC" ? -1 : 1;
|
|
6622
|
+
if (bVal == null)
|
|
6623
|
+
return direction === "ASC" ? 1 : -1;
|
|
6624
|
+
if (aVal < bVal)
|
|
6625
|
+
return direction === "ASC" ? -1 : 1;
|
|
6626
|
+
if (aVal > bVal)
|
|
6627
|
+
return direction === "ASC" ? 1 : -1;
|
|
6628
|
+
}
|
|
6629
|
+
return 0;
|
|
6630
|
+
});
|
|
6631
|
+
}
|
|
6632
|
+
if (options?.offset !== undefined) {
|
|
6633
|
+
results = results.slice(options.offset);
|
|
6634
|
+
}
|
|
6635
|
+
if (options?.limit !== undefined) {
|
|
6636
|
+
results = results.slice(0, options.limit);
|
|
6637
|
+
}
|
|
6638
|
+
const result = results.length > 0 ? results : undefined;
|
|
6639
|
+
this.events.emit("query", criteria, result);
|
|
6640
|
+
resolve(result);
|
|
6641
|
+
};
|
|
6642
|
+
getAllRequest.onerror = () => {
|
|
6643
|
+
reject(getAllRequest.error);
|
|
6644
|
+
};
|
|
6645
|
+
});
|
|
6646
|
+
}
|
|
6271
6647
|
getHybridManager() {
|
|
6272
6648
|
if (!this.hybridManager) {
|
|
6273
6649
|
const channelName = `indexeddb-tabular-${this.table}`;
|
|
@@ -7222,6 +7598,12 @@ export {
|
|
|
7222
7598
|
SupabaseRateLimiterStorage,
|
|
7223
7599
|
SupabaseQueueStorage,
|
|
7224
7600
|
SupabaseKvStorage,
|
|
7601
|
+
StorageValidationError,
|
|
7602
|
+
StorageUnsupportedError,
|
|
7603
|
+
StorageInvalidLimitError,
|
|
7604
|
+
StorageInvalidColumnError,
|
|
7605
|
+
StorageError,
|
|
7606
|
+
StorageEmptyCriteriaError,
|
|
7225
7607
|
SqliteVectorStorage,
|
|
7226
7608
|
SqliteTabularStorage,
|
|
7227
7609
|
SqliteRateLimiterStorage,
|
|
@@ -7279,6 +7661,7 @@ export {
|
|
|
7279
7661
|
FS_FOLDER_TABULAR_REPOSITORY,
|
|
7280
7662
|
FS_FOLDER_KV_REPOSITORY,
|
|
7281
7663
|
FS_FOLDER_JSON_KV_REPOSITORY,
|
|
7664
|
+
EncryptedKvCredentialStore,
|
|
7282
7665
|
DefaultKeyValueSchema,
|
|
7283
7666
|
DefaultKeyValueKey,
|
|
7284
7667
|
CachedTabularStorage,
|
|
@@ -7286,4 +7669,4 @@ export {
|
|
|
7286
7669
|
BaseTabularStorage
|
|
7287
7670
|
};
|
|
7288
7671
|
|
|
7289
|
-
//# debugId=
|
|
7672
|
+
//# debugId=AEE8AEFAEA2AD47464756E2164756E21
|