s3db.js 10.0.12 → 10.0.13
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/s3db.cjs.js +241 -35
- package/dist/s3db.cjs.js.map +1 -1
- package/dist/s3db.es.js +241 -35
- package/dist/s3db.es.js.map +1 -1
- package/package.json +5 -5
- package/src/plugins/eventual-consistency.plugin.js +308 -45
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "s3db.js",
|
|
3
|
-
"version": "10.0.
|
|
3
|
+
"version": "10.0.13",
|
|
4
4
|
"description": "Use AWS S3, the world's most reliable document storage, as a database with this ORM.",
|
|
5
5
|
"main": "dist/s3db.cjs.js",
|
|
6
6
|
"module": "dist/s3db.es.js",
|
|
@@ -131,11 +131,11 @@
|
|
|
131
131
|
"build:binaries": "./scripts/scripts/build-binaries.sh",
|
|
132
132
|
"dev": "rollup -c -w",
|
|
133
133
|
"test": "pnpm run test:js && pnpm run test:ts",
|
|
134
|
-
"test:js": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js
|
|
134
|
+
"test:js": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
135
135
|
"test:ts": "tsc --noEmit --project tests/typescript/tsconfig.json",
|
|
136
|
-
"test:coverage": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js --
|
|
137
|
-
"test:
|
|
138
|
-
"test:plugins": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js tests/plugins/ --
|
|
136
|
+
"test:coverage": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js --coverage --maxWorkers=1",
|
|
137
|
+
"test:serial": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js --runInBand",
|
|
138
|
+
"test:plugins": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js tests/plugins/ --testTimeout=60000",
|
|
139
139
|
"test:full": "pnpm run test:js && pnpm run test:ts",
|
|
140
140
|
"benchmark": "node benchmark-compression.js",
|
|
141
141
|
"version": "echo 'Use pnpm run release v<version> instead of npm version'",
|
|
@@ -317,10 +317,20 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
async onStart() {
|
|
320
|
-
//
|
|
320
|
+
// Start timers and emit events for all field handlers
|
|
321
321
|
for (const [resourceName, fieldHandlers] of this.fieldHandlers) {
|
|
322
322
|
for (const [fieldName, handler] of fieldHandlers) {
|
|
323
323
|
if (!handler.deferredSetup) {
|
|
324
|
+
// Start auto-consolidation timer if enabled
|
|
325
|
+
if (this.config.autoConsolidate && this.config.mode === 'async') {
|
|
326
|
+
this.startConsolidationTimerForHandler(handler, resourceName, fieldName);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Start garbage collection timer
|
|
330
|
+
if (this.config.transactionRetention && this.config.transactionRetention > 0) {
|
|
331
|
+
this.startGarbageCollectionTimerForHandler(handler, resourceName, fieldName);
|
|
332
|
+
}
|
|
333
|
+
|
|
324
334
|
this.emit('eventual-consistency.started', {
|
|
325
335
|
resource: resourceName,
|
|
326
336
|
field: fieldName,
|
|
@@ -467,20 +477,57 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
467
477
|
// Add method to set value (replaces current value)
|
|
468
478
|
// Signature: set(id, field, value)
|
|
469
479
|
resource.set = async (id, field, value) => {
|
|
470
|
-
const { plugin:
|
|
480
|
+
const { plugin: handler } =
|
|
471
481
|
plugin._resolveFieldAndPlugin(resource, field, value);
|
|
472
482
|
|
|
473
|
-
// Create
|
|
474
|
-
|
|
483
|
+
// Create transaction inline
|
|
484
|
+
const now = new Date();
|
|
485
|
+
const cohortInfo = plugin.getCohortInfo(now);
|
|
486
|
+
|
|
487
|
+
const transaction = {
|
|
488
|
+
id: idGenerator(),
|
|
475
489
|
originalId: id,
|
|
476
|
-
|
|
490
|
+
field: handler.field,
|
|
477
491
|
value: value,
|
|
478
|
-
|
|
479
|
-
|
|
492
|
+
operation: 'set',
|
|
493
|
+
timestamp: now.toISOString(),
|
|
494
|
+
cohortDate: cohortInfo.date,
|
|
495
|
+
cohortHour: cohortInfo.hour,
|
|
496
|
+
cohortMonth: cohortInfo.month,
|
|
497
|
+
source: 'set',
|
|
498
|
+
applied: false
|
|
499
|
+
};
|
|
480
500
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
501
|
+
await handler.transactionResource.insert(transaction);
|
|
502
|
+
|
|
503
|
+
// In sync mode, immediately consolidate
|
|
504
|
+
if (plugin.config.mode === 'sync') {
|
|
505
|
+
// Temporarily set config for legacy methods
|
|
506
|
+
const oldResource = plugin.config.resource;
|
|
507
|
+
const oldField = plugin.config.field;
|
|
508
|
+
const oldTransactionResource = plugin.transactionResource;
|
|
509
|
+
const oldTargetResource = plugin.targetResource;
|
|
510
|
+
const oldLockResource = plugin.lockResource;
|
|
511
|
+
const oldAnalyticsResource = plugin.analyticsResource;
|
|
512
|
+
|
|
513
|
+
plugin.config.resource = handler.resource;
|
|
514
|
+
plugin.config.field = handler.field;
|
|
515
|
+
plugin.transactionResource = handler.transactionResource;
|
|
516
|
+
plugin.targetResource = handler.targetResource;
|
|
517
|
+
plugin.lockResource = handler.lockResource;
|
|
518
|
+
plugin.analyticsResource = handler.analyticsResource;
|
|
519
|
+
|
|
520
|
+
const result = await plugin._syncModeConsolidate(id, field);
|
|
521
|
+
|
|
522
|
+
// Restore
|
|
523
|
+
plugin.config.resource = oldResource;
|
|
524
|
+
plugin.config.field = oldField;
|
|
525
|
+
plugin.transactionResource = oldTransactionResource;
|
|
526
|
+
plugin.targetResource = oldTargetResource;
|
|
527
|
+
plugin.lockResource = oldLockResource;
|
|
528
|
+
plugin.analyticsResource = oldAnalyticsResource;
|
|
529
|
+
|
|
530
|
+
return result;
|
|
484
531
|
}
|
|
485
532
|
|
|
486
533
|
return value;
|
|
@@ -489,48 +536,120 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
489
536
|
// Add method to increment value
|
|
490
537
|
// Signature: add(id, field, amount)
|
|
491
538
|
resource.add = async (id, field, amount) => {
|
|
492
|
-
const { plugin:
|
|
539
|
+
const { plugin: handler } =
|
|
493
540
|
plugin._resolveFieldAndPlugin(resource, field, amount);
|
|
494
541
|
|
|
495
|
-
// Create
|
|
496
|
-
|
|
542
|
+
// Create transaction inline
|
|
543
|
+
const now = new Date();
|
|
544
|
+
const cohortInfo = plugin.getCohortInfo(now);
|
|
545
|
+
|
|
546
|
+
const transaction = {
|
|
547
|
+
id: idGenerator(),
|
|
497
548
|
originalId: id,
|
|
498
|
-
|
|
549
|
+
field: handler.field,
|
|
499
550
|
value: amount,
|
|
500
|
-
|
|
501
|
-
|
|
551
|
+
operation: 'add',
|
|
552
|
+
timestamp: now.toISOString(),
|
|
553
|
+
cohortDate: cohortInfo.date,
|
|
554
|
+
cohortHour: cohortInfo.hour,
|
|
555
|
+
cohortMonth: cohortInfo.month,
|
|
556
|
+
source: 'add',
|
|
557
|
+
applied: false
|
|
558
|
+
};
|
|
502
559
|
|
|
503
|
-
|
|
504
|
-
if (fieldPlugin.config.mode === 'sync') {
|
|
505
|
-
return await fieldPlugin._syncModeConsolidate(fieldPlugin, id, field);
|
|
506
|
-
}
|
|
560
|
+
await handler.transactionResource.insert(transaction);
|
|
507
561
|
|
|
508
|
-
// In
|
|
509
|
-
|
|
562
|
+
// In sync mode, immediately consolidate
|
|
563
|
+
if (plugin.config.mode === 'sync') {
|
|
564
|
+
const oldResource = plugin.config.resource;
|
|
565
|
+
const oldField = plugin.config.field;
|
|
566
|
+
const oldTransactionResource = plugin.transactionResource;
|
|
567
|
+
const oldTargetResource = plugin.targetResource;
|
|
568
|
+
const oldLockResource = plugin.lockResource;
|
|
569
|
+
const oldAnalyticsResource = plugin.analyticsResource;
|
|
570
|
+
|
|
571
|
+
plugin.config.resource = handler.resource;
|
|
572
|
+
plugin.config.field = handler.field;
|
|
573
|
+
plugin.transactionResource = handler.transactionResource;
|
|
574
|
+
plugin.targetResource = handler.targetResource;
|
|
575
|
+
plugin.lockResource = handler.lockResource;
|
|
576
|
+
plugin.analyticsResource = handler.analyticsResource;
|
|
577
|
+
|
|
578
|
+
const result = await plugin._syncModeConsolidate(id, field);
|
|
579
|
+
|
|
580
|
+
plugin.config.resource = oldResource;
|
|
581
|
+
plugin.config.field = oldField;
|
|
582
|
+
plugin.transactionResource = oldTransactionResource;
|
|
583
|
+
plugin.targetResource = oldTargetResource;
|
|
584
|
+
plugin.lockResource = oldLockResource;
|
|
585
|
+
plugin.analyticsResource = oldAnalyticsResource;
|
|
586
|
+
|
|
587
|
+
return result;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Async mode - return current value (optimistic)
|
|
591
|
+
const [ok, err, record] = await tryFn(() => handler.targetResource.get(id));
|
|
592
|
+
const currentValue = (ok && record) ? (record[field] || 0) : 0;
|
|
510
593
|
return currentValue + amount;
|
|
511
594
|
};
|
|
512
595
|
|
|
513
596
|
// Add method to decrement value
|
|
514
597
|
// Signature: sub(id, field, amount)
|
|
515
598
|
resource.sub = async (id, field, amount) => {
|
|
516
|
-
const { plugin:
|
|
599
|
+
const { plugin: handler } =
|
|
517
600
|
plugin._resolveFieldAndPlugin(resource, field, amount);
|
|
518
601
|
|
|
519
|
-
// Create
|
|
520
|
-
|
|
602
|
+
// Create transaction inline
|
|
603
|
+
const now = new Date();
|
|
604
|
+
const cohortInfo = plugin.getCohortInfo(now);
|
|
605
|
+
|
|
606
|
+
const transaction = {
|
|
607
|
+
id: idGenerator(),
|
|
521
608
|
originalId: id,
|
|
522
|
-
|
|
609
|
+
field: handler.field,
|
|
523
610
|
value: amount,
|
|
524
|
-
|
|
525
|
-
|
|
611
|
+
operation: 'sub',
|
|
612
|
+
timestamp: now.toISOString(),
|
|
613
|
+
cohortDate: cohortInfo.date,
|
|
614
|
+
cohortHour: cohortInfo.hour,
|
|
615
|
+
cohortMonth: cohortInfo.month,
|
|
616
|
+
source: 'sub',
|
|
617
|
+
applied: false
|
|
618
|
+
};
|
|
526
619
|
|
|
527
|
-
|
|
528
|
-
if (fieldPlugin.config.mode === 'sync') {
|
|
529
|
-
return await fieldPlugin._syncModeConsolidate(fieldPlugin, id, field);
|
|
530
|
-
}
|
|
620
|
+
await handler.transactionResource.insert(transaction);
|
|
531
621
|
|
|
532
|
-
// In
|
|
533
|
-
|
|
622
|
+
// In sync mode, immediately consolidate
|
|
623
|
+
if (plugin.config.mode === 'sync') {
|
|
624
|
+
const oldResource = plugin.config.resource;
|
|
625
|
+
const oldField = plugin.config.field;
|
|
626
|
+
const oldTransactionResource = plugin.transactionResource;
|
|
627
|
+
const oldTargetResource = plugin.targetResource;
|
|
628
|
+
const oldLockResource = plugin.lockResource;
|
|
629
|
+
const oldAnalyticsResource = plugin.analyticsResource;
|
|
630
|
+
|
|
631
|
+
plugin.config.resource = handler.resource;
|
|
632
|
+
plugin.config.field = handler.field;
|
|
633
|
+
plugin.transactionResource = handler.transactionResource;
|
|
634
|
+
plugin.targetResource = handler.targetResource;
|
|
635
|
+
plugin.lockResource = handler.lockResource;
|
|
636
|
+
plugin.analyticsResource = handler.analyticsResource;
|
|
637
|
+
|
|
638
|
+
const result = await plugin._syncModeConsolidate(id, field);
|
|
639
|
+
|
|
640
|
+
plugin.config.resource = oldResource;
|
|
641
|
+
plugin.config.field = oldField;
|
|
642
|
+
plugin.transactionResource = oldTransactionResource;
|
|
643
|
+
plugin.targetResource = oldTargetResource;
|
|
644
|
+
plugin.lockResource = oldLockResource;
|
|
645
|
+
plugin.analyticsResource = oldAnalyticsResource;
|
|
646
|
+
|
|
647
|
+
return result;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// Async mode - return current value (optimistic)
|
|
651
|
+
const [ok, err, record] = await tryFn(() => handler.targetResource.get(id));
|
|
652
|
+
const currentValue = (ok && record) ? (record[field] || 0) : 0;
|
|
534
653
|
return currentValue - amount;
|
|
535
654
|
};
|
|
536
655
|
|
|
@@ -541,9 +660,9 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
541
660
|
throw new Error(`Field parameter is required: consolidate(id, field)`);
|
|
542
661
|
}
|
|
543
662
|
|
|
544
|
-
const
|
|
663
|
+
const handler = resource._eventualConsistencyPlugins[field];
|
|
545
664
|
|
|
546
|
-
if (!
|
|
665
|
+
if (!handler) {
|
|
547
666
|
const availableFields = Object.keys(resource._eventualConsistencyPlugins).join(', ');
|
|
548
667
|
throw new Error(
|
|
549
668
|
`No eventual consistency plugin found for field "${field}". ` +
|
|
@@ -551,15 +670,39 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
551
670
|
);
|
|
552
671
|
}
|
|
553
672
|
|
|
554
|
-
|
|
673
|
+
// Temporarily set config for legacy methods
|
|
674
|
+
const oldResource = plugin.config.resource;
|
|
675
|
+
const oldField = plugin.config.field;
|
|
676
|
+
const oldTransactionResource = plugin.transactionResource;
|
|
677
|
+
const oldTargetResource = plugin.targetResource;
|
|
678
|
+
const oldLockResource = plugin.lockResource;
|
|
679
|
+
const oldAnalyticsResource = plugin.analyticsResource;
|
|
680
|
+
|
|
681
|
+
plugin.config.resource = handler.resource;
|
|
682
|
+
plugin.config.field = handler.field;
|
|
683
|
+
plugin.transactionResource = handler.transactionResource;
|
|
684
|
+
plugin.targetResource = handler.targetResource;
|
|
685
|
+
plugin.lockResource = handler.lockResource;
|
|
686
|
+
plugin.analyticsResource = handler.analyticsResource;
|
|
687
|
+
|
|
688
|
+
const result = await plugin.consolidateRecord(id);
|
|
689
|
+
|
|
690
|
+
plugin.config.resource = oldResource;
|
|
691
|
+
plugin.config.field = oldField;
|
|
692
|
+
plugin.transactionResource = oldTransactionResource;
|
|
693
|
+
plugin.targetResource = oldTargetResource;
|
|
694
|
+
plugin.lockResource = oldLockResource;
|
|
695
|
+
plugin.analyticsResource = oldAnalyticsResource;
|
|
696
|
+
|
|
697
|
+
return result;
|
|
555
698
|
};
|
|
556
699
|
|
|
557
700
|
// Add method to get consolidated value without applying
|
|
558
701
|
// Signature: getConsolidatedValue(id, field, options)
|
|
559
702
|
resource.getConsolidatedValue = async (id, field, options = {}) => {
|
|
560
|
-
const
|
|
703
|
+
const handler = resource._eventualConsistencyPlugins[field];
|
|
561
704
|
|
|
562
|
-
if (!
|
|
705
|
+
if (!handler) {
|
|
563
706
|
const availableFields = Object.keys(resource._eventualConsistencyPlugins).join(', ');
|
|
564
707
|
throw new Error(
|
|
565
708
|
`No eventual consistency plugin found for field "${field}". ` +
|
|
@@ -567,7 +710,25 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
567
710
|
);
|
|
568
711
|
}
|
|
569
712
|
|
|
570
|
-
|
|
713
|
+
// Temporarily set config for legacy methods
|
|
714
|
+
const oldResource = plugin.config.resource;
|
|
715
|
+
const oldField = plugin.config.field;
|
|
716
|
+
const oldTransactionResource = plugin.transactionResource;
|
|
717
|
+
const oldTargetResource = plugin.targetResource;
|
|
718
|
+
|
|
719
|
+
plugin.config.resource = handler.resource;
|
|
720
|
+
plugin.config.field = handler.field;
|
|
721
|
+
plugin.transactionResource = handler.transactionResource;
|
|
722
|
+
plugin.targetResource = handler.targetResource;
|
|
723
|
+
|
|
724
|
+
const result = await plugin.getConsolidatedValue(id, options);
|
|
725
|
+
|
|
726
|
+
plugin.config.resource = oldResource;
|
|
727
|
+
plugin.config.field = oldField;
|
|
728
|
+
plugin.transactionResource = oldTransactionResource;
|
|
729
|
+
plugin.targetResource = oldTargetResource;
|
|
730
|
+
|
|
731
|
+
return result;
|
|
571
732
|
};
|
|
572
733
|
}
|
|
573
734
|
|
|
@@ -746,6 +907,52 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
746
907
|
}, intervalMs);
|
|
747
908
|
}
|
|
748
909
|
|
|
910
|
+
startConsolidationTimerForHandler(handler, resourceName, fieldName) {
|
|
911
|
+
const intervalMs = this.config.consolidationInterval * 1000; // Convert seconds to ms
|
|
912
|
+
|
|
913
|
+
if (this.config.verbose) {
|
|
914
|
+
const nextRun = new Date(Date.now() + intervalMs);
|
|
915
|
+
console.log(
|
|
916
|
+
`[EventualConsistency] ${resourceName}.${fieldName} - ` +
|
|
917
|
+
`Consolidation timer started. Next run at ${nextRun.toISOString()} ` +
|
|
918
|
+
`(every ${this.config.consolidationInterval}s)`
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
handler.consolidationTimer = setInterval(async () => {
|
|
923
|
+
await this.runConsolidationForHandler(handler, resourceName, fieldName);
|
|
924
|
+
}, intervalMs);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
async runConsolidationForHandler(handler, resourceName, fieldName) {
|
|
928
|
+
// Temporarily swap config to use this handler
|
|
929
|
+
const oldResource = this.config.resource;
|
|
930
|
+
const oldField = this.config.field;
|
|
931
|
+
const oldTransactionResource = this.transactionResource;
|
|
932
|
+
const oldTargetResource = this.targetResource;
|
|
933
|
+
const oldLockResource = this.lockResource;
|
|
934
|
+
const oldAnalyticsResource = this.analyticsResource;
|
|
935
|
+
|
|
936
|
+
this.config.resource = resourceName;
|
|
937
|
+
this.config.field = fieldName;
|
|
938
|
+
this.transactionResource = handler.transactionResource;
|
|
939
|
+
this.targetResource = handler.targetResource;
|
|
940
|
+
this.lockResource = handler.lockResource;
|
|
941
|
+
this.analyticsResource = handler.analyticsResource;
|
|
942
|
+
|
|
943
|
+
try {
|
|
944
|
+
await this.runConsolidation();
|
|
945
|
+
} finally {
|
|
946
|
+
// Restore
|
|
947
|
+
this.config.resource = oldResource;
|
|
948
|
+
this.config.field = oldField;
|
|
949
|
+
this.transactionResource = oldTransactionResource;
|
|
950
|
+
this.targetResource = oldTargetResource;
|
|
951
|
+
this.lockResource = oldLockResource;
|
|
952
|
+
this.analyticsResource = oldAnalyticsResource;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
749
956
|
async runConsolidation() {
|
|
750
957
|
const startTime = Date.now();
|
|
751
958
|
|
|
@@ -1035,7 +1242,7 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
1035
1242
|
}
|
|
1036
1243
|
|
|
1037
1244
|
// Invalidate cache for this record after consolidation
|
|
1038
|
-
if (this.targetResource.cache && typeof this.targetResource.cache.delete === 'function') {
|
|
1245
|
+
if (this.targetResource && this.targetResource.cache && typeof this.targetResource.cache.delete === 'function') {
|
|
1039
1246
|
try {
|
|
1040
1247
|
const cacheKey = await this.targetResource.cacheKeyFor({ id: originalId });
|
|
1041
1248
|
await this.targetResource.cache.delete(cacheKey);
|
|
@@ -1244,6 +1451,40 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
1244
1451
|
}, gcIntervalMs);
|
|
1245
1452
|
}
|
|
1246
1453
|
|
|
1454
|
+
startGarbageCollectionTimerForHandler(handler, resourceName, fieldName) {
|
|
1455
|
+
const gcIntervalMs = this.config.gcInterval * 1000; // Convert seconds to ms
|
|
1456
|
+
|
|
1457
|
+
handler.gcTimer = setInterval(async () => {
|
|
1458
|
+
await this.runGarbageCollectionForHandler(handler, resourceName, fieldName);
|
|
1459
|
+
}, gcIntervalMs);
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
async runGarbageCollectionForHandler(handler, resourceName, fieldName) {
|
|
1463
|
+
// Temporarily swap config to use this handler
|
|
1464
|
+
const oldResource = this.config.resource;
|
|
1465
|
+
const oldField = this.config.field;
|
|
1466
|
+
const oldTransactionResource = this.transactionResource;
|
|
1467
|
+
const oldTargetResource = this.targetResource;
|
|
1468
|
+
const oldLockResource = this.lockResource;
|
|
1469
|
+
|
|
1470
|
+
this.config.resource = resourceName;
|
|
1471
|
+
this.config.field = fieldName;
|
|
1472
|
+
this.transactionResource = handler.transactionResource;
|
|
1473
|
+
this.targetResource = handler.targetResource;
|
|
1474
|
+
this.lockResource = handler.lockResource;
|
|
1475
|
+
|
|
1476
|
+
try {
|
|
1477
|
+
await this.runGarbageCollection();
|
|
1478
|
+
} finally {
|
|
1479
|
+
// Restore
|
|
1480
|
+
this.config.resource = oldResource;
|
|
1481
|
+
this.config.field = oldField;
|
|
1482
|
+
this.transactionResource = oldTransactionResource;
|
|
1483
|
+
this.targetResource = oldTargetResource;
|
|
1484
|
+
this.lockResource = oldLockResource;
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1247
1488
|
/**
|
|
1248
1489
|
* Delete old applied transactions based on retention policy
|
|
1249
1490
|
* Uses distributed locking to prevent multiple containers from running GC simultaneously
|
|
@@ -1634,14 +1875,25 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
1634
1875
|
* @returns {Promise<Array>} Analytics data
|
|
1635
1876
|
*/
|
|
1636
1877
|
async getAnalytics(resourceName, field, options = {}) {
|
|
1637
|
-
|
|
1878
|
+
// Get handler for this resource/field combination
|
|
1879
|
+
const fieldHandlers = this.fieldHandlers.get(resourceName);
|
|
1880
|
+
if (!fieldHandlers) {
|
|
1881
|
+
throw new Error(`No eventual consistency configured for resource: ${resourceName}`);
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
const handler = fieldHandlers.get(field);
|
|
1885
|
+
if (!handler) {
|
|
1886
|
+
throw new Error(`No eventual consistency configured for field: ${resourceName}.${field}`);
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
if (!handler.analyticsResource) {
|
|
1638
1890
|
throw new Error('Analytics not enabled for this plugin');
|
|
1639
1891
|
}
|
|
1640
1892
|
|
|
1641
1893
|
const { period = 'day', date, startDate, endDate, month, year, breakdown = false } = options;
|
|
1642
1894
|
|
|
1643
1895
|
const [ok, err, allAnalytics] = await tryFn(() =>
|
|
1644
|
-
|
|
1896
|
+
handler.analyticsResource.list()
|
|
1645
1897
|
);
|
|
1646
1898
|
|
|
1647
1899
|
if (!ok || !allAnalytics) {
|
|
@@ -1921,7 +2173,18 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
1921
2173
|
* @returns {Promise<Array>} Top records
|
|
1922
2174
|
*/
|
|
1923
2175
|
async getTopRecords(resourceName, field, options = {}) {
|
|
1924
|
-
|
|
2176
|
+
// Get handler for this resource/field combination
|
|
2177
|
+
const fieldHandlers = this.fieldHandlers.get(resourceName);
|
|
2178
|
+
if (!fieldHandlers) {
|
|
2179
|
+
throw new Error(`No eventual consistency configured for resource: ${resourceName}`);
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
const handler = fieldHandlers.get(field);
|
|
2183
|
+
if (!handler) {
|
|
2184
|
+
throw new Error(`No eventual consistency configured for field: ${resourceName}.${field}`);
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
if (!handler.transactionResource) {
|
|
1925
2188
|
throw new Error('Transaction resource not initialized');
|
|
1926
2189
|
}
|
|
1927
2190
|
|
|
@@ -1929,7 +2192,7 @@ export class EventualConsistencyPlugin extends Plugin {
|
|
|
1929
2192
|
|
|
1930
2193
|
// Get all transactions for the period
|
|
1931
2194
|
const [ok, err, transactions] = await tryFn(() =>
|
|
1932
|
-
|
|
2195
|
+
handler.transactionResource.list()
|
|
1933
2196
|
);
|
|
1934
2197
|
|
|
1935
2198
|
if (!ok || !transactions) {
|