@oimdb/core 1.3.1 → 1.4.1
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/README.md +482 -15
- package/dist/index.cjs +1997 -335
- package/dist/index.d.cts +685 -151
- package/dist/index.d.ts +685 -151
- package/dist/index.js +1968 -330
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,6 +15,11 @@ var OIMEventEmitter = class {
|
|
|
15
15
|
constructor() {
|
|
16
16
|
this.buckets = {};
|
|
17
17
|
}
|
|
18
|
+
hasHandlers(event) {
|
|
19
|
+
const bucket = this.buckets[event];
|
|
20
|
+
if (!bucket) return false;
|
|
21
|
+
return bucket.indexByHandler.size > 0;
|
|
22
|
+
}
|
|
18
23
|
getOrCreateBucket(event) {
|
|
19
24
|
let bucket = this.buckets[event];
|
|
20
25
|
if (!bucket) {
|
|
@@ -28,39 +33,40 @@ var OIMEventEmitter = class {
|
|
|
28
33
|
}
|
|
29
34
|
return bucket;
|
|
30
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Compacts the handlers array by removing null entries (tombstones) left by handler removal.
|
|
38
|
+
* Rebuilds the indexByHandler map with updated indices and resets the tombstone count.
|
|
39
|
+
* This reduces array fragmentation and improves iteration performance.
|
|
40
|
+
*/
|
|
31
41
|
compactBucket(bucket) {
|
|
32
42
|
const handlers = bucket.handlers;
|
|
33
43
|
const length = handlers.length;
|
|
34
44
|
const newHandlers = [];
|
|
35
45
|
bucket.indexByHandler.clear();
|
|
36
|
-
if (bucket.tombstoneCount < length >> 2) {
|
|
37
|
-
newHandlers.length = length - bucket.tombstoneCount;
|
|
38
|
-
}
|
|
39
|
-
let writeIndex = 0;
|
|
40
46
|
for (let i = 0; i < length; i++) {
|
|
41
47
|
const handler = handlers[i];
|
|
42
48
|
if (handler) {
|
|
43
|
-
|
|
49
|
+
const writeIndex = newHandlers.length;
|
|
50
|
+
newHandlers.push(handler);
|
|
44
51
|
bucket.indexByHandler.set(handler, writeIndex);
|
|
45
|
-
writeIndex++;
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
|
-
if (newHandlers.length !== writeIndex) {
|
|
49
|
-
newHandlers.length = writeIndex;
|
|
50
|
-
}
|
|
51
54
|
bucket.handlers = newHandlers;
|
|
52
55
|
bucket.tombstoneCount = 0;
|
|
53
56
|
}
|
|
54
57
|
on(event, handler) {
|
|
55
58
|
const bucket = this.getOrCreateBucket(event);
|
|
56
|
-
if (bucket.indexByHandler.has(handler))
|
|
57
|
-
return
|
|
59
|
+
if (bucket.indexByHandler.has(handler)) {
|
|
60
|
+
return () => {
|
|
61
|
+
this.off(event, handler);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
58
64
|
const index = bucket.handlers.length;
|
|
59
65
|
bucket.handlers.push(handler);
|
|
60
|
-
bucket.indexByHandler.set(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
bucket.indexByHandler.set(handler, index);
|
|
67
|
+
return () => {
|
|
68
|
+
this.off(event, handler);
|
|
69
|
+
};
|
|
64
70
|
}
|
|
65
71
|
emit(event, payload) {
|
|
66
72
|
const bucket = this.buckets[event];
|
|
@@ -75,10 +81,11 @@ var OIMEventEmitter = class {
|
|
|
75
81
|
}
|
|
76
82
|
bucket.isEmitting--;
|
|
77
83
|
if (bucket.isEmitting === 0 && bucket.tombstoneCount > 0) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
} else if (length === bucket.tombstoneCount) {
|
|
84
|
+
const currentLength = bucket.handlers.length;
|
|
85
|
+
if (bucket.tombstoneCount === currentLength) {
|
|
81
86
|
delete this.buckets[event];
|
|
87
|
+
} else if (bucket.tombstoneCount >= currentLength >> 1) {
|
|
88
|
+
this.compactBucket(bucket);
|
|
82
89
|
}
|
|
83
90
|
}
|
|
84
91
|
}
|
|
@@ -92,10 +99,10 @@ var OIMEventEmitter = class {
|
|
|
92
99
|
bucket.indexByHandler.delete(handler);
|
|
93
100
|
if (bucket.isEmitting === 0) {
|
|
94
101
|
const length = bucket.handlers.length;
|
|
95
|
-
if (bucket.tombstoneCount
|
|
96
|
-
this.compactBucket(bucket);
|
|
97
|
-
} else if (length === bucket.tombstoneCount) {
|
|
102
|
+
if (bucket.tombstoneCount === length) {
|
|
98
103
|
delete this.buckets[event];
|
|
104
|
+
} else if (bucket.tombstoneCount >= length >> 1) {
|
|
105
|
+
this.compactBucket(bucket);
|
|
99
106
|
}
|
|
100
107
|
}
|
|
101
108
|
}
|
|
@@ -295,6 +302,12 @@ var OIMIndexSetBased = class {
|
|
|
295
302
|
emitUpdate(keys) {
|
|
296
303
|
this.emitter.emit(0 /* UPDATE */, { keys });
|
|
297
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Emit update event for a single key (fast-path override point).
|
|
307
|
+
*/
|
|
308
|
+
emitUpdateOne(key) {
|
|
309
|
+
this.emitUpdate([key]);
|
|
310
|
+
}
|
|
298
311
|
};
|
|
299
312
|
|
|
300
313
|
// src/core/OIMIndexStoreMapDrivenArrayBased.ts
|
|
@@ -444,70 +457,195 @@ var OIMIndexArrayBased = class {
|
|
|
444
457
|
emitUpdate(keys) {
|
|
445
458
|
this.emitter.emit(0 /* UPDATE */, { keys });
|
|
446
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* Emit update event for a single key (fast-path override point).
|
|
462
|
+
*/
|
|
463
|
+
emitUpdateOne(key) {
|
|
464
|
+
this.emitUpdate([key]);
|
|
465
|
+
}
|
|
447
466
|
};
|
|
448
467
|
|
|
449
|
-
// src/enum/
|
|
450
|
-
var
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
})(EOIMUpdateEventCoalescerEventType || {});
|
|
468
|
+
// src/enum/EOIMEventQueueEventType.ts
|
|
469
|
+
var EOIMEventQueueEventType = /* @__PURE__ */ ((EOIMEventQueueEventType2) => {
|
|
470
|
+
EOIMEventQueueEventType2[EOIMEventQueueEventType2["AFTER_FLUSH"] = 0] = "AFTER_FLUSH";
|
|
471
|
+
EOIMEventQueueEventType2[EOIMEventQueueEventType2["BEFORE_FLUSH"] = 1] = "BEFORE_FLUSH";
|
|
472
|
+
return EOIMEventQueueEventType2;
|
|
473
|
+
})(EOIMEventQueueEventType || {});
|
|
456
474
|
|
|
457
475
|
// src/core/OIMUpdateEventEmitter.ts
|
|
458
476
|
var OIMUpdateEventEmitter = class {
|
|
459
|
-
constructor(
|
|
477
|
+
constructor(queue, deliveryMode = "queue") {
|
|
460
478
|
this.keyHandlers = /* @__PURE__ */ new Map();
|
|
461
|
-
this.
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
479
|
+
this.isFlushEnqueued = false;
|
|
480
|
+
this.updatedKeys = /* @__PURE__ */ new Set();
|
|
481
|
+
this.isAfterFlushDeliveryScheduled = false;
|
|
482
|
+
// Stable handler reference to avoid allocating a new closure on every HAS_CHANGES.
|
|
483
|
+
this.onFlush = () => {
|
|
484
|
+
this.isFlushEnqueued = false;
|
|
485
|
+
this.dequeueFlush = void 0;
|
|
486
|
+
if (this.keyHandlers.size === 0) {
|
|
487
|
+
this.updatedKeys.clear();
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const makeHandlerSnapshot = (handlers) => {
|
|
491
|
+
const snapshot = [];
|
|
492
|
+
handlers.forEach((h) => snapshot.push(h));
|
|
493
|
+
return snapshot;
|
|
494
|
+
};
|
|
495
|
+
this.runSinglePass(makeHandlerSnapshot);
|
|
496
|
+
};
|
|
497
|
+
this.onAfterFlush = () => {
|
|
498
|
+
if (!this.isAfterFlushDeliveryScheduled) return;
|
|
499
|
+
this.isAfterFlushDeliveryScheduled = false;
|
|
500
|
+
this.deliverImmediate();
|
|
501
|
+
};
|
|
502
|
+
this.queue = queue;
|
|
503
|
+
this.deliveryMode = deliveryMode;
|
|
504
|
+
if (this.deliveryMode === "after_flush") {
|
|
505
|
+
this.unsubscribeAfterFlushDelivery = this.queue.emitter.on(
|
|
506
|
+
0 /* AFTER_FLUSH */,
|
|
507
|
+
this.onAfterFlush
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Mark keys as updated and schedule delivery.
|
|
513
|
+
*
|
|
514
|
+
* If there are no subscriptions, this is a no-op and does not allocate or retain keys.
|
|
515
|
+
*/
|
|
516
|
+
markUpdatedKeys(keys) {
|
|
517
|
+
if (keys.length === 0) return;
|
|
518
|
+
if (this.deliveryMode === "queue" && this.queue.isInFlush) {
|
|
519
|
+
throw new Error(
|
|
520
|
+
"OIMUpdateEventEmitter: updates during queue.flush() are not allowed. Finish all writes before calling queue.flush()."
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
if (this.keyHandlers.size === 0) return;
|
|
524
|
+
let didAddAny = false;
|
|
525
|
+
for (let i = 0; i < keys.length; i++) {
|
|
526
|
+
const key = keys[i];
|
|
527
|
+
const handlers = this.keyHandlers.get(key);
|
|
528
|
+
if (!handlers || handlers.size === 0) continue;
|
|
529
|
+
this.updatedKeys.add(key);
|
|
530
|
+
didAddAny = true;
|
|
531
|
+
}
|
|
532
|
+
if (!didAddAny) return;
|
|
533
|
+
if (this.deliveryMode === "immediate") {
|
|
534
|
+
this.deliverImmediate();
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
if (this.deliveryMode === "after_flush") {
|
|
538
|
+
this.isAfterFlushDeliveryScheduled = true;
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
if (this.isFlushEnqueued) return;
|
|
542
|
+
this.isFlushEnqueued = true;
|
|
543
|
+
this.dequeueFlush = this.queue.enqueue(this.onFlush);
|
|
544
|
+
}
|
|
545
|
+
markUpdatedKey(key) {
|
|
546
|
+
if (this.deliveryMode === "queue" && this.queue.isInFlush) {
|
|
547
|
+
throw new Error(
|
|
548
|
+
"OIMUpdateEventEmitter: updates during queue.flush() are not allowed. Finish all writes before calling queue.flush()."
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
if (this.keyHandlers.size === 0) return;
|
|
552
|
+
const handlers = this.keyHandlers.get(key);
|
|
553
|
+
if (!handlers || handlers.size === 0) return;
|
|
554
|
+
this.updatedKeys.add(key);
|
|
555
|
+
if (this.deliveryMode === "immediate") {
|
|
556
|
+
this.deliverImmediate();
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (this.deliveryMode === "after_flush") {
|
|
560
|
+
this.isAfterFlushDeliveryScheduled = true;
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (this.isFlushEnqueued) return;
|
|
564
|
+
this.isFlushEnqueued = true;
|
|
565
|
+
this.dequeueFlush = this.queue.enqueue(this.onFlush);
|
|
566
|
+
}
|
|
567
|
+
markAllUpdated() {
|
|
568
|
+
if (this.deliveryMode === "queue" && this.queue.isInFlush) {
|
|
569
|
+
throw new Error(
|
|
570
|
+
"OIMUpdateEventEmitter: updates during queue.flush() are not allowed. Finish all writes before calling queue.flush()."
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
if (this.keyHandlers.size === 0) return;
|
|
574
|
+
this.keyHandlers.forEach((_handlers, key) => {
|
|
575
|
+
this.updatedKeys.add(key);
|
|
576
|
+
});
|
|
577
|
+
if (this.deliveryMode === "immediate") {
|
|
578
|
+
this.deliverImmediate();
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
if (this.deliveryMode === "after_flush") {
|
|
582
|
+
this.isAfterFlushDeliveryScheduled = true;
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (this.isFlushEnqueued) return;
|
|
586
|
+
this.isFlushEnqueued = true;
|
|
587
|
+
this.dequeueFlush = this.queue.enqueue(this.onFlush);
|
|
588
|
+
}
|
|
589
|
+
deliverImmediate() {
|
|
590
|
+
const makeHandlerSnapshot = (handlers) => {
|
|
591
|
+
const snapshot = [];
|
|
592
|
+
handlers.forEach((h) => snapshot.push(h));
|
|
593
|
+
return snapshot;
|
|
594
|
+
};
|
|
595
|
+
this.runSinglePass(makeHandlerSnapshot);
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Deliver updated keys and notify handlers once.
|
|
599
|
+
* Re-entrant updates during delivery are forbidden and will throw in markUpdatedKeys().
|
|
600
|
+
*/
|
|
601
|
+
runSinglePass(makeHandlerSnapshot) {
|
|
602
|
+
if (this.updatedKeys.size === 0) return;
|
|
603
|
+
const flushingKeys = this.updatedKeys;
|
|
604
|
+
this.updatedKeys = /* @__PURE__ */ new Set();
|
|
605
|
+
if (this.keyHandlers.size === 0 || flushingKeys.size === 0) return;
|
|
606
|
+
if (flushingKeys.size * 2 < this.keyHandlers.size) {
|
|
607
|
+
flushingKeys.forEach((key) => {
|
|
608
|
+
const handlers = this.keyHandlers.get(key);
|
|
609
|
+
if (!handlers || handlers.size === 0) return;
|
|
610
|
+
const handlerSnapshot = makeHandlerSnapshot(handlers);
|
|
611
|
+
for (let i = 0; i < handlerSnapshot.length; i++) {
|
|
612
|
+
const handler = handlerSnapshot[i];
|
|
613
|
+
if (handlers.has(handler)) handler();
|
|
467
614
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
} else {
|
|
478
|
-
for (const [key, handlers] of this.keyHandlers) {
|
|
479
|
-
if (updatedKeys.has(key)) {
|
|
480
|
-
for (const handler of handlers) {
|
|
481
|
-
handler();
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
615
|
+
});
|
|
616
|
+
} else {
|
|
617
|
+
this.keyHandlers.forEach((handlers, key) => {
|
|
618
|
+
if (!flushingKeys.has(key)) return;
|
|
619
|
+
if (!handlers || handlers.size === 0) return;
|
|
620
|
+
const handlerSnapshot = makeHandlerSnapshot(handlers);
|
|
621
|
+
for (let i = 0; i < handlerSnapshot.length; i++) {
|
|
622
|
+
const handler = handlerSnapshot[i];
|
|
623
|
+
if (handlers.has(handler)) handler();
|
|
485
624
|
}
|
|
486
|
-
this.coalescer.clearUpdatedKeys();
|
|
487
625
|
});
|
|
488
|
-
}
|
|
489
|
-
this.coalescer = opts.coalescer;
|
|
490
|
-
this.coalescer.emitter.on(
|
|
491
|
-
0 /* HAS_CHANGES */,
|
|
492
|
-
this.handleHasChanges
|
|
493
|
-
);
|
|
494
|
-
this.queue = opts.queue;
|
|
626
|
+
}
|
|
495
627
|
}
|
|
496
628
|
destroy() {
|
|
497
|
-
this.
|
|
498
|
-
|
|
499
|
-
this.
|
|
500
|
-
|
|
629
|
+
if (this.dequeueFlush) {
|
|
630
|
+
this.dequeueFlush();
|
|
631
|
+
this.dequeueFlush = void 0;
|
|
632
|
+
}
|
|
633
|
+
if (this.unsubscribeAfterFlushDelivery) {
|
|
634
|
+
this.unsubscribeAfterFlushDelivery();
|
|
635
|
+
this.unsubscribeAfterFlushDelivery = void 0;
|
|
636
|
+
}
|
|
637
|
+
this.keyHandlers.forEach((handlers) => handlers.clear());
|
|
501
638
|
this.keyHandlers.clear();
|
|
639
|
+
this.updatedKeys.clear();
|
|
502
640
|
}
|
|
503
641
|
/**
|
|
504
642
|
* Get performance metrics for monitoring and debugging
|
|
505
643
|
*/
|
|
506
644
|
getMetrics() {
|
|
507
645
|
let totalHandlers = 0;
|
|
508
|
-
|
|
646
|
+
this.keyHandlers.forEach((handlers) => {
|
|
509
647
|
totalHandlers += handlers.size;
|
|
510
|
-
}
|
|
648
|
+
});
|
|
511
649
|
return {
|
|
512
650
|
totalKeys: this.keyHandlers.size,
|
|
513
651
|
totalHandlers,
|
|
@@ -544,6 +682,15 @@ var OIMUpdateEventEmitter = class {
|
|
|
544
682
|
handlers.delete(handler);
|
|
545
683
|
if (handlers.size === 0) {
|
|
546
684
|
this.keyHandlers.delete(key);
|
|
685
|
+
this.updatedKeys.delete(key);
|
|
686
|
+
}
|
|
687
|
+
if (this.keyHandlers.size === 0) {
|
|
688
|
+
this.updatedKeys.clear();
|
|
689
|
+
if (this.dequeueFlush) {
|
|
690
|
+
this.dequeueFlush();
|
|
691
|
+
this.dequeueFlush = void 0;
|
|
692
|
+
}
|
|
693
|
+
this.isFlushEnqueued = false;
|
|
547
694
|
}
|
|
548
695
|
}
|
|
549
696
|
subscribeOnKeys(keys, handler) {
|
|
@@ -572,181 +719,11 @@ var OIMUpdateEventEmitter = class {
|
|
|
572
719
|
}
|
|
573
720
|
};
|
|
574
721
|
|
|
575
|
-
// src/core/OIMIndexManualSetBased.ts
|
|
576
|
-
var OIMIndexManualSetBased = class extends OIMIndexSetBased {
|
|
577
|
-
constructor(options = {}) {
|
|
578
|
-
super(options);
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* Set primary keys for a specific index key, replacing any existing values.
|
|
582
|
-
* Uses optional comparator to skip updates if PKs haven't actually changed.
|
|
583
|
-
*/
|
|
584
|
-
setPks(key, pks) {
|
|
585
|
-
const hasChanges = this.setPksWithComparison(key, new Set(pks));
|
|
586
|
-
if (hasChanges) {
|
|
587
|
-
this.emitUpdate([key]);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
/**
|
|
591
|
-
* Add primary keys to a specific index key
|
|
592
|
-
*/
|
|
593
|
-
addPks(key, pks) {
|
|
594
|
-
if (pks.length === 0) return;
|
|
595
|
-
let pksSet = this.store.getOneByKey(key);
|
|
596
|
-
if (!pksSet) {
|
|
597
|
-
pksSet = /* @__PURE__ */ new Set();
|
|
598
|
-
this.store.setOneByKey(key, pksSet);
|
|
599
|
-
}
|
|
600
|
-
let hasChanges = false;
|
|
601
|
-
for (const pk of pks) {
|
|
602
|
-
if (!pksSet.has(pk)) {
|
|
603
|
-
pksSet.add(pk);
|
|
604
|
-
hasChanges = true;
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
if (hasChanges) {
|
|
608
|
-
this.store.setOneByKey(key, pksSet);
|
|
609
|
-
this.emitUpdate([key]);
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
/**
|
|
613
|
-
* Remove primary keys from a specific index key
|
|
614
|
-
*/
|
|
615
|
-
removePks(key, pks) {
|
|
616
|
-
if (pks.length === 0) return;
|
|
617
|
-
const pksSet = this.store.getOneByKey(key);
|
|
618
|
-
if (!pksSet) return;
|
|
619
|
-
let hasChanges = false;
|
|
620
|
-
for (const pk of pks) {
|
|
621
|
-
if (pksSet.delete(pk)) {
|
|
622
|
-
hasChanges = true;
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
if (pksSet.size === 0) {
|
|
626
|
-
this.store.removeOneByKey(key);
|
|
627
|
-
hasChanges = true;
|
|
628
|
-
} else if (hasChanges) {
|
|
629
|
-
this.store.setOneByKey(key, pksSet);
|
|
630
|
-
}
|
|
631
|
-
if (hasChanges) {
|
|
632
|
-
this.emitUpdate([key]);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
/**
|
|
636
|
-
* Clear all primary keys for a specific index key, or all keys if no key specified
|
|
637
|
-
*/
|
|
638
|
-
clear(key) {
|
|
639
|
-
if (key === void 0) {
|
|
640
|
-
const allKeys = this.store.getAllKeys();
|
|
641
|
-
if (allKeys.length > 0) {
|
|
642
|
-
this.store.clear();
|
|
643
|
-
this.emitUpdate(allKeys);
|
|
644
|
-
}
|
|
645
|
-
} else {
|
|
646
|
-
if (this.store.getOneByKey(key) !== void 0) {
|
|
647
|
-
this.store.removeOneByKey(key);
|
|
648
|
-
this.emitUpdate([key]);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
};
|
|
653
|
-
|
|
654
|
-
// src/const/OIMDBSettings.ts
|
|
655
|
-
var OIMDBSettings = class {
|
|
656
|
-
};
|
|
657
|
-
/**
|
|
658
|
-
* Fixed key used in the manual index to store updated keys set in coalescers.
|
|
659
|
-
* This constant is exported so users can create their own indexes and pass them to coalescers.
|
|
660
|
-
*/
|
|
661
|
-
OIMDBSettings.UPDATED_KEYS_INDEX_KEY = "__updatedKeys__";
|
|
662
|
-
|
|
663
|
-
// src/core/OIMUpdateEventCoalescer.ts
|
|
664
|
-
var OIMUpdateEventCoalescer = class {
|
|
665
|
-
constructor(index) {
|
|
666
|
-
this.emitter = new OIMEventEmitter();
|
|
667
|
-
this.hasEmittedChanges = false;
|
|
668
|
-
this.updatedKeysIndex = index ?? new OIMIndexManualSetBased({
|
|
669
|
-
store: new OIMIndexStoreMapDrivenSetBased()
|
|
670
|
-
});
|
|
671
|
-
if (!this.updatedKeysIndex.hasKey(OIMDBSettings.UPDATED_KEYS_INDEX_KEY)) {
|
|
672
|
-
this.updatedKeysIndex.setPks(
|
|
673
|
-
OIMDBSettings.UPDATED_KEYS_INDEX_KEY,
|
|
674
|
-
[]
|
|
675
|
-
);
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
/**
|
|
679
|
-
* Get the set of keys that have been updated since last clear
|
|
680
|
-
*/
|
|
681
|
-
getUpdatedKeys() {
|
|
682
|
-
return this.updatedKeysIndex.getPksByKey(
|
|
683
|
-
OIMDBSettings.UPDATED_KEYS_INDEX_KEY
|
|
684
|
-
);
|
|
685
|
-
}
|
|
686
|
-
/**
|
|
687
|
-
* Clear all updated keys and reset the changed state
|
|
688
|
-
*/
|
|
689
|
-
clearUpdatedKeys() {
|
|
690
|
-
this.emitter.emit(
|
|
691
|
-
1 /* BEFORE_FLUSH */,
|
|
692
|
-
void 0
|
|
693
|
-
);
|
|
694
|
-
this.updatedKeysIndex.setPks(OIMDBSettings.UPDATED_KEYS_INDEX_KEY, []);
|
|
695
|
-
this.hasEmittedChanges = false;
|
|
696
|
-
this.emitter.emit(
|
|
697
|
-
2 /* AFTER_FLUSH */,
|
|
698
|
-
void 0
|
|
699
|
-
);
|
|
700
|
-
}
|
|
701
|
-
/**
|
|
702
|
-
* Add keys to the updated set and emit HAS_CHANGES event if needed
|
|
703
|
-
*/
|
|
704
|
-
addUpdatedKeys(keys) {
|
|
705
|
-
this.updatedKeysIndex.addPks(
|
|
706
|
-
OIMDBSettings.UPDATED_KEYS_INDEX_KEY,
|
|
707
|
-
keys
|
|
708
|
-
);
|
|
709
|
-
if (!this.hasEmittedChanges) {
|
|
710
|
-
this.hasEmittedChanges = true;
|
|
711
|
-
this.emitter.emit(
|
|
712
|
-
0 /* HAS_CHANGES */,
|
|
713
|
-
void 0
|
|
714
|
-
);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
// src/core/OIMUpdateEventCoalescerIndex.ts
|
|
720
|
-
var OIMUpdateEventCoalescerIndex = class extends OIMUpdateEventCoalescer {
|
|
721
|
-
constructor(indexEmitter) {
|
|
722
|
-
super();
|
|
723
|
-
this.indexEmitter = indexEmitter;
|
|
724
|
-
/**
|
|
725
|
-
* When the index is updated, we keep track of the updated keys.
|
|
726
|
-
*/
|
|
727
|
-
this.handleUpdate = (payload) => {
|
|
728
|
-
this.addUpdatedKeys(payload.keys);
|
|
729
|
-
};
|
|
730
|
-
this.indexEmitter.on(0 /* UPDATE */, this.handleUpdate);
|
|
731
|
-
}
|
|
732
|
-
destroy() {
|
|
733
|
-
this.indexEmitter.off(0 /* UPDATE */, this.handleUpdate);
|
|
734
|
-
this.emitter.offAll();
|
|
735
|
-
this.clearUpdatedKeys();
|
|
736
|
-
}
|
|
737
|
-
};
|
|
738
|
-
|
|
739
722
|
// src/abstract/OIMReactiveIndexSetBased.ts
|
|
740
723
|
var OIMReactiveIndexSetBased = class {
|
|
741
|
-
constructor(queue,
|
|
742
|
-
this.
|
|
743
|
-
this.
|
|
744
|
-
this.index.emitter
|
|
745
|
-
);
|
|
746
|
-
this.updateEventEmitter = new OIMUpdateEventEmitter({
|
|
747
|
-
coalescer: this.coalescer,
|
|
748
|
-
queue
|
|
749
|
-
});
|
|
724
|
+
constructor(queue, createIndex) {
|
|
725
|
+
this.updateEmitter = new OIMUpdateEventEmitter(queue);
|
|
726
|
+
this.index = createIndex(this.updateEmitter);
|
|
750
727
|
}
|
|
751
728
|
getPksByKey(key) {
|
|
752
729
|
return this.index.getPksByKey(key);
|
|
@@ -772,22 +749,38 @@ var OIMReactiveIndexSetBased = class {
|
|
|
772
749
|
getMetrics() {
|
|
773
750
|
return this.index.getMetrics();
|
|
774
751
|
}
|
|
752
|
+
subscribeOnKey(key, handler) {
|
|
753
|
+
return this.updateEmitter.subscribeOnKey(key, handler);
|
|
754
|
+
}
|
|
755
|
+
subscribeOnKeys(keys, handler) {
|
|
756
|
+
return this.updateEmitter.subscribeOnKeys(keys, handler);
|
|
757
|
+
}
|
|
758
|
+
unsubscribeFromKey(key, handler) {
|
|
759
|
+
this.updateEmitter.unsubscribeFromKey(key, handler);
|
|
760
|
+
}
|
|
761
|
+
unsubscribeFromKeys(keys, handler) {
|
|
762
|
+
this.updateEmitter.unsubscribeFromKeys(keys, handler);
|
|
763
|
+
}
|
|
764
|
+
hasSubscriptions() {
|
|
765
|
+
return this.updateEmitter.hasSubscriptions();
|
|
766
|
+
}
|
|
767
|
+
getHandlerCount(key) {
|
|
768
|
+
return this.updateEmitter.getHandlerCount(key);
|
|
769
|
+
}
|
|
770
|
+
getSubscriptionMetrics() {
|
|
771
|
+
return this.updateEmitter.getMetrics();
|
|
772
|
+
}
|
|
775
773
|
destroy() {
|
|
774
|
+
this.updateEmitter.destroy();
|
|
776
775
|
this.index.destroy();
|
|
777
776
|
}
|
|
778
777
|
};
|
|
779
778
|
|
|
780
779
|
// src/abstract/OIMReactiveIndexArrayBased.ts
|
|
781
780
|
var OIMReactiveIndexArrayBased = class {
|
|
782
|
-
constructor(queue,
|
|
783
|
-
this.
|
|
784
|
-
this.
|
|
785
|
-
this.index.emitter
|
|
786
|
-
);
|
|
787
|
-
this.updateEventEmitter = new OIMUpdateEventEmitter({
|
|
788
|
-
coalescer: this.coalescer,
|
|
789
|
-
queue
|
|
790
|
-
});
|
|
781
|
+
constructor(queue, createIndex) {
|
|
782
|
+
this.updateEmitter = new OIMUpdateEventEmitter(queue);
|
|
783
|
+
this.index = createIndex(this.updateEmitter);
|
|
791
784
|
}
|
|
792
785
|
getPksByKey(key) {
|
|
793
786
|
return this.index.getPksByKey(key);
|
|
@@ -813,11 +806,37 @@ var OIMReactiveIndexArrayBased = class {
|
|
|
813
806
|
getMetrics() {
|
|
814
807
|
return this.index.getMetrics();
|
|
815
808
|
}
|
|
809
|
+
subscribeOnKey(key, handler) {
|
|
810
|
+
return this.updateEmitter.subscribeOnKey(key, handler);
|
|
811
|
+
}
|
|
812
|
+
subscribeOnKeys(keys, handler) {
|
|
813
|
+
return this.updateEmitter.subscribeOnKeys(keys, handler);
|
|
814
|
+
}
|
|
815
|
+
unsubscribeFromKey(key, handler) {
|
|
816
|
+
this.updateEmitter.unsubscribeFromKey(key, handler);
|
|
817
|
+
}
|
|
818
|
+
unsubscribeFromKeys(keys, handler) {
|
|
819
|
+
this.updateEmitter.unsubscribeFromKeys(keys, handler);
|
|
820
|
+
}
|
|
821
|
+
hasSubscriptions() {
|
|
822
|
+
return this.updateEmitter.hasSubscriptions();
|
|
823
|
+
}
|
|
824
|
+
getHandlerCount(key) {
|
|
825
|
+
return this.updateEmitter.getHandlerCount(key);
|
|
826
|
+
}
|
|
827
|
+
getSubscriptionMetrics() {
|
|
828
|
+
return this.updateEmitter.getMetrics();
|
|
829
|
+
}
|
|
816
830
|
destroy() {
|
|
831
|
+
this.updateEmitter.destroy();
|
|
817
832
|
this.index.destroy();
|
|
818
833
|
}
|
|
819
834
|
};
|
|
820
835
|
|
|
836
|
+
// src/abstract/OIMObjectStore.ts
|
|
837
|
+
var OIMObjectStore = class {
|
|
838
|
+
};
|
|
839
|
+
|
|
821
840
|
// src/core/OIMPkSelectorFactory.ts
|
|
822
841
|
var OIMPkSelectorFactory = class {
|
|
823
842
|
createIdSelector() {
|
|
@@ -875,6 +894,9 @@ var OIMCollectionStoreMapDriven = class extends OIMCollectionStore {
|
|
|
875
894
|
getAllPks() {
|
|
876
895
|
return Array.from(this.entities.keys());
|
|
877
896
|
}
|
|
897
|
+
destroy() {
|
|
898
|
+
this.clear();
|
|
899
|
+
}
|
|
878
900
|
};
|
|
879
901
|
|
|
880
902
|
// src/core/OIMEntityUpdaterFactory.ts
|
|
@@ -972,31 +994,9 @@ var OIMCollection = class {
|
|
|
972
994
|
this.store.setOneByPk(pk, entity);
|
|
973
995
|
}
|
|
974
996
|
}
|
|
975
|
-
};
|
|
976
|
-
|
|
977
|
-
// src/core/OIMUpdateEventCoalescerCollection.ts
|
|
978
|
-
var OIMUpdateEventCoalescerCollection = class extends OIMUpdateEventCoalescer {
|
|
979
|
-
constructor(collectionEmitter) {
|
|
980
|
-
super();
|
|
981
|
-
this.collectionEmitter = collectionEmitter;
|
|
982
|
-
/**
|
|
983
|
-
* When the collection is updated, we keep track of the updated pks.
|
|
984
|
-
*/
|
|
985
|
-
this.handleUpdate = (payload) => {
|
|
986
|
-
this.addUpdatedKeys(payload.pks);
|
|
987
|
-
};
|
|
988
|
-
this.collectionEmitter.on(
|
|
989
|
-
0 /* UPDATE */,
|
|
990
|
-
this.handleUpdate
|
|
991
|
-
);
|
|
992
|
-
}
|
|
993
997
|
destroy() {
|
|
994
|
-
this.
|
|
995
|
-
0 /* UPDATE */,
|
|
996
|
-
this.handleUpdate
|
|
997
|
-
);
|
|
998
|
+
this.store.destroy();
|
|
998
999
|
this.emitter.offAll();
|
|
999
|
-
this.clearUpdatedKeys();
|
|
1000
1000
|
}
|
|
1001
1001
|
};
|
|
1002
1002
|
|
|
@@ -1004,28 +1004,367 @@ var OIMUpdateEventCoalescerCollection = class extends OIMUpdateEventCoalescer {
|
|
|
1004
1004
|
var OIMReactiveCollection = class extends OIMCollection {
|
|
1005
1005
|
constructor(queue, opts) {
|
|
1006
1006
|
super(opts);
|
|
1007
|
-
this.
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
this.
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1007
|
+
this.anyUpdateHandlers = /* @__PURE__ */ new Set();
|
|
1008
|
+
this.pendingAnyUpdatePks = /* @__PURE__ */ new Set();
|
|
1009
|
+
this.isAnyUpdateClearPending = false;
|
|
1010
|
+
this.isAnyUpdateScheduled = false;
|
|
1011
|
+
this.runAnyUpdate = () => {
|
|
1012
|
+
if (!this.isAnyUpdateScheduled) return;
|
|
1013
|
+
this.isAnyUpdateScheduled = false;
|
|
1014
|
+
this.dequeueAnyUpdate = void 0;
|
|
1015
|
+
const pks = this.isAnyUpdateClearPending ? [] : Array.from(this.pendingAnyUpdatePks);
|
|
1016
|
+
this.pendingAnyUpdatePks.clear();
|
|
1017
|
+
this.isAnyUpdateClearPending = false;
|
|
1018
|
+
const snapshot = Array.from(this.anyUpdateHandlers);
|
|
1019
|
+
for (let i = 0; i < snapshot.length; i++) snapshot[i](pks);
|
|
1020
|
+
};
|
|
1021
|
+
this.queue = queue;
|
|
1022
|
+
this.updateEmitter = new OIMUpdateEventEmitter(queue, "queue");
|
|
1014
1023
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
// src/core/OIMReactiveIndexManualSetBased.ts
|
|
1018
|
-
var OIMReactiveIndexManualSetBased = class extends OIMReactiveIndexSetBased {
|
|
1019
|
-
constructor(queue, opts) {
|
|
1020
|
-
super(queue, opts);
|
|
1024
|
+
subscribeOnKey(pk, handler) {
|
|
1025
|
+
return this.updateEmitter.subscribeOnKey(pk, handler);
|
|
1021
1026
|
}
|
|
1022
|
-
|
|
1023
|
-
return
|
|
1027
|
+
subscribeOnKeys(pks, handler) {
|
|
1028
|
+
return this.updateEmitter.subscribeOnKeys(pks, handler);
|
|
1024
1029
|
}
|
|
1025
|
-
|
|
1026
|
-
this.
|
|
1030
|
+
unsubscribeFromKey(pk, handler) {
|
|
1031
|
+
this.updateEmitter.unsubscribeFromKey(pk, handler);
|
|
1027
1032
|
}
|
|
1028
|
-
|
|
1033
|
+
unsubscribeFromKeys(pks, handler) {
|
|
1034
|
+
this.updateEmitter.unsubscribeFromKeys(pks, handler);
|
|
1035
|
+
}
|
|
1036
|
+
destroySubscriptions() {
|
|
1037
|
+
this.updateEmitter.destroy();
|
|
1038
|
+
}
|
|
1039
|
+
hasSubscriptions() {
|
|
1040
|
+
return this.updateEmitter.hasSubscriptions();
|
|
1041
|
+
}
|
|
1042
|
+
getHandlerCount(pk) {
|
|
1043
|
+
return this.updateEmitter.getHandlerCount(pk);
|
|
1044
|
+
}
|
|
1045
|
+
getMetrics() {
|
|
1046
|
+
return this.updateEmitter.getMetrics();
|
|
1047
|
+
}
|
|
1048
|
+
subscribeOnAnyUpdate(handler) {
|
|
1049
|
+
this.anyUpdateHandlers.add(handler);
|
|
1050
|
+
return () => {
|
|
1051
|
+
this.anyUpdateHandlers.delete(handler);
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
upsertOneByPk(pk, entity) {
|
|
1055
|
+
this.upsertOneWithoutNotificationsByPk(pk, entity);
|
|
1056
|
+
this.updateEmitter.markUpdatedKey(pk);
|
|
1057
|
+
this.trackAnyUpdatePk(pk);
|
|
1058
|
+
}
|
|
1059
|
+
upsertOne(entity) {
|
|
1060
|
+
const pk = this.upsertOneWithoutNotifications(entity);
|
|
1061
|
+
this.updateEmitter.markUpdatedKey(pk);
|
|
1062
|
+
this.trackAnyUpdatePk(pk);
|
|
1063
|
+
}
|
|
1064
|
+
upsertMany(entities) {
|
|
1065
|
+
const pks = entities.map(
|
|
1066
|
+
(entity) => this.upsertOneWithoutNotifications(entity)
|
|
1067
|
+
);
|
|
1068
|
+
this.updateEmitter.markUpdatedKeys(pks);
|
|
1069
|
+
this.trackAnyUpdatePks(pks);
|
|
1070
|
+
}
|
|
1071
|
+
removeOne(entity) {
|
|
1072
|
+
const pk = this.selectPk(entity);
|
|
1073
|
+
this.store.removeOneByPk(pk);
|
|
1074
|
+
this.updateEmitter.markUpdatedKey(pk);
|
|
1075
|
+
this.trackAnyUpdatePk(pk);
|
|
1076
|
+
}
|
|
1077
|
+
removeMany(entities) {
|
|
1078
|
+
const pks = entities.map(this.selectPk);
|
|
1079
|
+
this.store.removeManyByPks(pks);
|
|
1080
|
+
this.updateEmitter.markUpdatedKeys(pks);
|
|
1081
|
+
this.trackAnyUpdatePks(pks);
|
|
1082
|
+
}
|
|
1083
|
+
removeOneByPk(pk) {
|
|
1084
|
+
this.store.removeOneByPk(pk);
|
|
1085
|
+
this.updateEmitter.markUpdatedKey(pk);
|
|
1086
|
+
this.trackAnyUpdatePk(pk);
|
|
1087
|
+
}
|
|
1088
|
+
removeManyByPks(pks) {
|
|
1089
|
+
this.store.removeManyByPks(pks);
|
|
1090
|
+
this.updateEmitter.markUpdatedKeys(pks);
|
|
1091
|
+
this.trackAnyUpdatePks(pks);
|
|
1092
|
+
}
|
|
1093
|
+
clear() {
|
|
1094
|
+
this.store.clear();
|
|
1095
|
+
this.updateEmitter.markAllUpdated();
|
|
1096
|
+
this.trackAnyUpdateClear();
|
|
1097
|
+
}
|
|
1098
|
+
trackAnyUpdatePk(pk) {
|
|
1099
|
+
if (this.anyUpdateHandlers.size === 0) return;
|
|
1100
|
+
this.pendingAnyUpdatePks.add(pk);
|
|
1101
|
+
this.ensureAnyUpdateEnqueued();
|
|
1102
|
+
}
|
|
1103
|
+
trackAnyUpdatePks(pks) {
|
|
1104
|
+
if (this.anyUpdateHandlers.size === 0) return;
|
|
1105
|
+
for (let i = 0; i < pks.length; i++)
|
|
1106
|
+
this.pendingAnyUpdatePks.add(pks[i]);
|
|
1107
|
+
this.ensureAnyUpdateEnqueued();
|
|
1108
|
+
}
|
|
1109
|
+
trackAnyUpdateClear() {
|
|
1110
|
+
if (this.anyUpdateHandlers.size === 0) return;
|
|
1111
|
+
this.isAnyUpdateClearPending = true;
|
|
1112
|
+
this.pendingAnyUpdatePks.clear();
|
|
1113
|
+
this.ensureAnyUpdateEnqueued();
|
|
1114
|
+
}
|
|
1115
|
+
ensureAnyUpdateEnqueued() {
|
|
1116
|
+
if (this.isAnyUpdateScheduled) return;
|
|
1117
|
+
this.isAnyUpdateScheduled = true;
|
|
1118
|
+
this.dequeueAnyUpdate = this.queue.enqueue(this.runAnyUpdate);
|
|
1119
|
+
}
|
|
1120
|
+
destroy() {
|
|
1121
|
+
this.updateEmitter.destroy();
|
|
1122
|
+
if (this.dequeueAnyUpdate) {
|
|
1123
|
+
this.dequeueAnyUpdate();
|
|
1124
|
+
this.dequeueAnyUpdate = void 0;
|
|
1125
|
+
}
|
|
1126
|
+
this.anyUpdateHandlers.clear();
|
|
1127
|
+
this.pendingAnyUpdatePks.clear();
|
|
1128
|
+
super.destroy();
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
// src/core/OIMObjectStoreRecordDriven.ts
|
|
1133
|
+
var OIMObjectStoreRecordDriven = class extends OIMObjectStore {
|
|
1134
|
+
constructor(initial) {
|
|
1135
|
+
super();
|
|
1136
|
+
this.properties = Object.assign(/* @__PURE__ */ Object.create(null), initial ?? {});
|
|
1137
|
+
}
|
|
1138
|
+
setProperty(key, value) {
|
|
1139
|
+
this.properties[key] = value;
|
|
1140
|
+
}
|
|
1141
|
+
merge(draft) {
|
|
1142
|
+
Object.assign(this.properties, draft);
|
|
1143
|
+
}
|
|
1144
|
+
delete(key) {
|
|
1145
|
+
delete this.properties[key];
|
|
1146
|
+
}
|
|
1147
|
+
get(key) {
|
|
1148
|
+
return this.properties[key];
|
|
1149
|
+
}
|
|
1150
|
+
getAll() {
|
|
1151
|
+
return { ...this.properties };
|
|
1152
|
+
}
|
|
1153
|
+
clear() {
|
|
1154
|
+
this.properties = /* @__PURE__ */ Object.create(null);
|
|
1155
|
+
}
|
|
1156
|
+
count() {
|
|
1157
|
+
return Object.keys(this.properties).length;
|
|
1158
|
+
}
|
|
1159
|
+
keys() {
|
|
1160
|
+
return Object.keys(this.properties);
|
|
1161
|
+
}
|
|
1162
|
+
values() {
|
|
1163
|
+
return Object.values(this.properties);
|
|
1164
|
+
}
|
|
1165
|
+
entries() {
|
|
1166
|
+
return Object.entries(this.properties);
|
|
1167
|
+
}
|
|
1168
|
+
destroy() {
|
|
1169
|
+
this.clear();
|
|
1170
|
+
}
|
|
1171
|
+
};
|
|
1172
|
+
|
|
1173
|
+
// src/enum/EOIMObjectEventType.ts
|
|
1174
|
+
var EOIMObjectEventType = /* @__PURE__ */ ((EOIMObjectEventType2) => {
|
|
1175
|
+
EOIMObjectEventType2[EOIMObjectEventType2["UPDATE"] = 0] = "UPDATE";
|
|
1176
|
+
return EOIMObjectEventType2;
|
|
1177
|
+
})(EOIMObjectEventType || {});
|
|
1178
|
+
|
|
1179
|
+
// src/core/OIMObject.ts
|
|
1180
|
+
var OIMObject = class {
|
|
1181
|
+
constructor(opts) {
|
|
1182
|
+
this.emitter = new OIMEventEmitter();
|
|
1183
|
+
this.store = opts?.store ?? new OIMObjectStoreRecordDriven();
|
|
1184
|
+
}
|
|
1185
|
+
setProperty(key, value) {
|
|
1186
|
+
this.store.setProperty(key, value);
|
|
1187
|
+
this.emitter.emit(0 /* UPDATE */, { keys: [key] });
|
|
1188
|
+
}
|
|
1189
|
+
merge(draft) {
|
|
1190
|
+
this.store.merge(draft);
|
|
1191
|
+
this.emitter.emit(0 /* UPDATE */, {
|
|
1192
|
+
keys: Object.keys(draft)
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
delete(key) {
|
|
1196
|
+
this.store.delete(key);
|
|
1197
|
+
this.emitter.emit(0 /* UPDATE */, { keys: [key] });
|
|
1198
|
+
}
|
|
1199
|
+
get(key) {
|
|
1200
|
+
return this.store.get(key);
|
|
1201
|
+
}
|
|
1202
|
+
getAll() {
|
|
1203
|
+
return this.store.getAll();
|
|
1204
|
+
}
|
|
1205
|
+
clear() {
|
|
1206
|
+
this.store.clear();
|
|
1207
|
+
this.emitter.emit(0 /* UPDATE */, { keys: [] });
|
|
1208
|
+
}
|
|
1209
|
+
count() {
|
|
1210
|
+
return this.store.count();
|
|
1211
|
+
}
|
|
1212
|
+
keys() {
|
|
1213
|
+
return this.store.keys();
|
|
1214
|
+
}
|
|
1215
|
+
values() {
|
|
1216
|
+
return this.store.values();
|
|
1217
|
+
}
|
|
1218
|
+
entries() {
|
|
1219
|
+
return this.store.entries();
|
|
1220
|
+
}
|
|
1221
|
+
destroy() {
|
|
1222
|
+
this.store.destroy();
|
|
1223
|
+
this.emitter.offAll();
|
|
1224
|
+
}
|
|
1225
|
+
};
|
|
1226
|
+
|
|
1227
|
+
// src/core/OIMReactiveObject.ts
|
|
1228
|
+
var OIMReactiveObject = class extends OIMObject {
|
|
1229
|
+
constructor(queue, opts) {
|
|
1230
|
+
super(opts);
|
|
1231
|
+
this.updateEmitter = new OIMUpdateEventEmitter(queue, "queue");
|
|
1232
|
+
this.emitter.on(0 /* UPDATE */, (payload) => {
|
|
1233
|
+
this.updateEmitter.markUpdatedKeys(payload.keys);
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
subscribeOnKey(key, handler) {
|
|
1237
|
+
return this.updateEmitter.subscribeOnKey(key, handler);
|
|
1238
|
+
}
|
|
1239
|
+
subscribeOnKeys(keys, handler) {
|
|
1240
|
+
return this.updateEmitter.subscribeOnKeys(keys, handler);
|
|
1241
|
+
}
|
|
1242
|
+
unsubscribeFromKey(key, handler) {
|
|
1243
|
+
this.updateEmitter.unsubscribeFromKey(key, handler);
|
|
1244
|
+
}
|
|
1245
|
+
unsubscribeFromKeys(keys, handler) {
|
|
1246
|
+
this.updateEmitter.unsubscribeFromKeys(keys, handler);
|
|
1247
|
+
}
|
|
1248
|
+
hasSubscriptions() {
|
|
1249
|
+
return this.updateEmitter.hasSubscriptions();
|
|
1250
|
+
}
|
|
1251
|
+
getHandlerCount(key) {
|
|
1252
|
+
return this.updateEmitter.getHandlerCount(key);
|
|
1253
|
+
}
|
|
1254
|
+
getMetrics() {
|
|
1255
|
+
return this.updateEmitter.getMetrics();
|
|
1256
|
+
}
|
|
1257
|
+
destroy() {
|
|
1258
|
+
this.updateEmitter.destroy();
|
|
1259
|
+
super.destroy();
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
|
|
1263
|
+
// src/core/OIMIndexManualSetBased.ts
|
|
1264
|
+
var OIMIndexManualSetBased = class extends OIMIndexSetBased {
|
|
1265
|
+
constructor(options = {}) {
|
|
1266
|
+
super(options);
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Set primary keys for a specific index key, replacing any existing values.
|
|
1270
|
+
* Uses optional comparator to skip updates if PKs haven't actually changed.
|
|
1271
|
+
*/
|
|
1272
|
+
setPks(key, pks) {
|
|
1273
|
+
const hasChanges = this.setPksWithComparison(key, new Set(pks));
|
|
1274
|
+
if (hasChanges) {
|
|
1275
|
+
this.emitUpdateOne(key);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
/**
|
|
1279
|
+
* Add primary keys to a specific index key
|
|
1280
|
+
*/
|
|
1281
|
+
addPks(key, pks) {
|
|
1282
|
+
if (pks.length === 0) return;
|
|
1283
|
+
let pksSet = this.store.getOneByKey(key);
|
|
1284
|
+
if (!pksSet) {
|
|
1285
|
+
pksSet = /* @__PURE__ */ new Set();
|
|
1286
|
+
this.store.setOneByKey(key, pksSet);
|
|
1287
|
+
}
|
|
1288
|
+
let hasChanges = false;
|
|
1289
|
+
for (const pk of pks) {
|
|
1290
|
+
if (!pksSet.has(pk)) {
|
|
1291
|
+
pksSet.add(pk);
|
|
1292
|
+
hasChanges = true;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
if (hasChanges) {
|
|
1296
|
+
this.store.setOneByKey(key, pksSet);
|
|
1297
|
+
this.emitUpdateOne(key);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Remove primary keys from a specific index key
|
|
1302
|
+
*/
|
|
1303
|
+
removePks(key, pks) {
|
|
1304
|
+
if (pks.length === 0) return;
|
|
1305
|
+
const pksSet = this.store.getOneByKey(key);
|
|
1306
|
+
if (!pksSet) return;
|
|
1307
|
+
let hasChanges = false;
|
|
1308
|
+
for (const pk of pks) {
|
|
1309
|
+
if (pksSet.delete(pk)) {
|
|
1310
|
+
hasChanges = true;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
if (pksSet.size === 0) {
|
|
1314
|
+
this.store.removeOneByKey(key);
|
|
1315
|
+
hasChanges = true;
|
|
1316
|
+
} else if (hasChanges) {
|
|
1317
|
+
this.store.setOneByKey(key, pksSet);
|
|
1318
|
+
}
|
|
1319
|
+
if (hasChanges) {
|
|
1320
|
+
this.emitUpdateOne(key);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Clear all primary keys for a specific index key, or all keys if no key specified
|
|
1325
|
+
*/
|
|
1326
|
+
clear(key) {
|
|
1327
|
+
if (key === void 0) {
|
|
1328
|
+
const allKeys = this.store.getAllKeys();
|
|
1329
|
+
if (allKeys.length > 0) {
|
|
1330
|
+
this.store.clear();
|
|
1331
|
+
this.emitUpdate(allKeys);
|
|
1332
|
+
}
|
|
1333
|
+
} else {
|
|
1334
|
+
if (this.store.getOneByKey(key) !== void 0) {
|
|
1335
|
+
this.store.removeOneByKey(key);
|
|
1336
|
+
this.emitUpdateOne(key);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
};
|
|
1341
|
+
|
|
1342
|
+
// src/core/OIMReactiveIndexManualSetBased.ts
|
|
1343
|
+
var OIMIndexManualSetBasedReactive = class extends OIMIndexManualSetBased {
|
|
1344
|
+
constructor(updateEmitter, opts) {
|
|
1345
|
+
super(opts);
|
|
1346
|
+
this.updateEmitter = updateEmitter;
|
|
1347
|
+
}
|
|
1348
|
+
emitUpdate(keys) {
|
|
1349
|
+
this.updateEmitter.markUpdatedKeys(keys);
|
|
1350
|
+
}
|
|
1351
|
+
emitUpdateOne(key) {
|
|
1352
|
+
this.updateEmitter.markUpdatedKey(key);
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
var OIMReactiveIndexManualSetBased = class extends OIMReactiveIndexSetBased {
|
|
1356
|
+
constructor(queue, opts) {
|
|
1357
|
+
super(queue, (updateEmitter) => {
|
|
1358
|
+
return new OIMIndexManualSetBasedReactive(
|
|
1359
|
+
updateEmitter,
|
|
1360
|
+
opts?.indexOptions
|
|
1361
|
+
);
|
|
1362
|
+
});
|
|
1363
|
+
}
|
|
1364
|
+
setPks(key, pks) {
|
|
1365
|
+
this.index.setPks(key, pks);
|
|
1366
|
+
}
|
|
1367
|
+
addPks(key, pks) {
|
|
1029
1368
|
this.index.addPks(key, pks);
|
|
1030
1369
|
}
|
|
1031
1370
|
removePks(key, pks) {
|
|
@@ -1048,7 +1387,7 @@ var OIMIndexManualArrayBased = class extends OIMIndexArrayBased {
|
|
|
1048
1387
|
setPks(key, pks) {
|
|
1049
1388
|
const hasChanges = this.setPksWithComparison(key, pks);
|
|
1050
1389
|
if (hasChanges) {
|
|
1051
|
-
this.
|
|
1390
|
+
this.emitUpdateOne(key);
|
|
1052
1391
|
}
|
|
1053
1392
|
}
|
|
1054
1393
|
/**
|
|
@@ -1071,7 +1410,7 @@ var OIMIndexManualArrayBased = class extends OIMIndexArrayBased {
|
|
|
1071
1410
|
}
|
|
1072
1411
|
if (hasChanges) {
|
|
1073
1412
|
this.store.setOneByKey(key, Array.from(pksSet));
|
|
1074
|
-
this.
|
|
1413
|
+
this.emitUpdateOne(key);
|
|
1075
1414
|
}
|
|
1076
1415
|
}
|
|
1077
1416
|
/**
|
|
@@ -1090,7 +1429,7 @@ var OIMIndexManualArrayBased = class extends OIMIndexArrayBased {
|
|
|
1090
1429
|
} else {
|
|
1091
1430
|
this.store.setOneByKey(key, filtered);
|
|
1092
1431
|
}
|
|
1093
|
-
this.
|
|
1432
|
+
this.emitUpdateOne(key);
|
|
1094
1433
|
}
|
|
1095
1434
|
}
|
|
1096
1435
|
/**
|
|
@@ -1106,19 +1445,33 @@ var OIMIndexManualArrayBased = class extends OIMIndexArrayBased {
|
|
|
1106
1445
|
} else {
|
|
1107
1446
|
if (this.store.getOneByKey(key) !== void 0) {
|
|
1108
1447
|
this.store.removeOneByKey(key);
|
|
1109
|
-
this.
|
|
1448
|
+
this.emitUpdateOne(key);
|
|
1110
1449
|
}
|
|
1111
1450
|
}
|
|
1112
1451
|
}
|
|
1113
1452
|
};
|
|
1114
1453
|
|
|
1115
1454
|
// src/core/OIMReactiveIndexManualArrayBased.ts
|
|
1455
|
+
var OIMIndexManualArrayBasedReactive = class extends OIMIndexManualArrayBased {
|
|
1456
|
+
constructor(updateEmitter, opts) {
|
|
1457
|
+
super(opts);
|
|
1458
|
+
this.updateEmitter = updateEmitter;
|
|
1459
|
+
}
|
|
1460
|
+
emitUpdate(keys) {
|
|
1461
|
+
this.updateEmitter.markUpdatedKeys(keys);
|
|
1462
|
+
}
|
|
1463
|
+
emitUpdateOne(key) {
|
|
1464
|
+
this.updateEmitter.markUpdatedKey(key);
|
|
1465
|
+
}
|
|
1466
|
+
};
|
|
1116
1467
|
var OIMReactiveIndexManualArrayBased = class extends OIMReactiveIndexArrayBased {
|
|
1117
1468
|
constructor(queue, opts) {
|
|
1118
|
-
super(queue,
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1469
|
+
super(queue, (updateEmitter) => {
|
|
1470
|
+
return new OIMIndexManualArrayBasedReactive(
|
|
1471
|
+
updateEmitter,
|
|
1472
|
+
opts?.indexOptions
|
|
1473
|
+
);
|
|
1474
|
+
});
|
|
1122
1475
|
}
|
|
1123
1476
|
setPks(key, pks) {
|
|
1124
1477
|
this.index.setPks(key, pks);
|
|
@@ -1142,6 +1495,53 @@ var OIMRICollection = class extends OIMReactiveCollection {
|
|
|
1142
1495
|
}
|
|
1143
1496
|
};
|
|
1144
1497
|
|
|
1498
|
+
// src/core/OIMObjectStoreMapDriven.ts
|
|
1499
|
+
var OIMObjectStoreMapDriven = class extends OIMObjectStore {
|
|
1500
|
+
constructor() {
|
|
1501
|
+
super(...arguments);
|
|
1502
|
+
this.properties = /* @__PURE__ */ new Map();
|
|
1503
|
+
}
|
|
1504
|
+
setProperty(key, value) {
|
|
1505
|
+
this.properties.set(key, value);
|
|
1506
|
+
}
|
|
1507
|
+
merge(draft) {
|
|
1508
|
+
for (const key in draft) {
|
|
1509
|
+
if (!Object.prototype.hasOwnProperty.call(draft, key)) continue;
|
|
1510
|
+
this.properties.set(
|
|
1511
|
+
key,
|
|
1512
|
+
draft[key]
|
|
1513
|
+
);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
delete(key) {
|
|
1517
|
+
this.properties.delete(key);
|
|
1518
|
+
}
|
|
1519
|
+
get(key) {
|
|
1520
|
+
return this.properties.get(key);
|
|
1521
|
+
}
|
|
1522
|
+
getAll() {
|
|
1523
|
+
return Object.fromEntries(this.properties.entries());
|
|
1524
|
+
}
|
|
1525
|
+
clear() {
|
|
1526
|
+
this.properties.clear();
|
|
1527
|
+
}
|
|
1528
|
+
count() {
|
|
1529
|
+
return this.properties.size;
|
|
1530
|
+
}
|
|
1531
|
+
keys() {
|
|
1532
|
+
return Array.from(this.properties.keys());
|
|
1533
|
+
}
|
|
1534
|
+
values() {
|
|
1535
|
+
return Array.from(this.properties.values());
|
|
1536
|
+
}
|
|
1537
|
+
entries() {
|
|
1538
|
+
return Array.from(this.properties.entries());
|
|
1539
|
+
}
|
|
1540
|
+
destroy() {
|
|
1541
|
+
this.properties.clear();
|
|
1542
|
+
}
|
|
1543
|
+
};
|
|
1544
|
+
|
|
1145
1545
|
// src/core/OIMComparatorFactory.ts
|
|
1146
1546
|
var OIMComparatorFactory = class {
|
|
1147
1547
|
createShallowComparator() {
|
|
@@ -1160,18 +1560,12 @@ var OIMComparatorFactory = class {
|
|
|
1160
1560
|
}
|
|
1161
1561
|
};
|
|
1162
1562
|
|
|
1163
|
-
// src/enum/EOIMEventQueueEventType.ts
|
|
1164
|
-
var EOIMEventQueueEventType = /* @__PURE__ */ ((EOIMEventQueueEventType2) => {
|
|
1165
|
-
EOIMEventQueueEventType2[EOIMEventQueueEventType2["AFTER_FLUSH"] = 0] = "AFTER_FLUSH";
|
|
1166
|
-
EOIMEventQueueEventType2[EOIMEventQueueEventType2["BEFORE_FLUSH"] = 1] = "BEFORE_FLUSH";
|
|
1167
|
-
return EOIMEventQueueEventType2;
|
|
1168
|
-
})(EOIMEventQueueEventType || {});
|
|
1169
|
-
|
|
1170
1563
|
// src/core/OIMEventQueue.ts
|
|
1171
1564
|
var OIMEventQueue = class {
|
|
1172
1565
|
constructor(options = {}) {
|
|
1173
1566
|
this.emitter = new OIMEventEmitter();
|
|
1174
|
-
this.
|
|
1567
|
+
this.tasks = /* @__PURE__ */ new Set();
|
|
1568
|
+
this.isFlushing = false;
|
|
1175
1569
|
this.scheduler = options.scheduler;
|
|
1176
1570
|
if (this.scheduler) {
|
|
1177
1571
|
this.flushBound = () => this.flush();
|
|
@@ -1182,48 +1576,76 @@ var OIMEventQueue = class {
|
|
|
1182
1576
|
}
|
|
1183
1577
|
}
|
|
1184
1578
|
/**
|
|
1185
|
-
*
|
|
1186
|
-
*
|
|
1579
|
+
* Enqueue a one-shot task to be executed on the next flush.
|
|
1580
|
+
* Returns a dequeue function that can be called to cancel the task before it runs.
|
|
1187
1581
|
*/
|
|
1188
1582
|
enqueue(fn) {
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1583
|
+
let isActive = true;
|
|
1584
|
+
const task = () => {
|
|
1585
|
+
if (!isActive) return;
|
|
1586
|
+
fn();
|
|
1587
|
+
};
|
|
1588
|
+
this.tasks.add(task);
|
|
1589
|
+
this.ensureScheduled();
|
|
1590
|
+
return () => {
|
|
1591
|
+
if (!isActive) return;
|
|
1592
|
+
isActive = false;
|
|
1593
|
+
this.tasks.delete(task);
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
get isInFlush() {
|
|
1597
|
+
return this.isFlushing;
|
|
1598
|
+
}
|
|
1599
|
+
/**
|
|
1600
|
+
* Dequeue (cancel) a previously enqueued task by its dequeue function.
|
|
1601
|
+
*/
|
|
1602
|
+
dequeue(dequeueFn) {
|
|
1603
|
+
dequeueFn();
|
|
1193
1604
|
}
|
|
1194
1605
|
/**
|
|
1195
|
-
* Execute all
|
|
1196
|
-
*
|
|
1606
|
+
* Execute all pending tasks.
|
|
1607
|
+
*
|
|
1608
|
+
* This flush drains until the queue is empty. If tasks enqueue more tasks, they will be
|
|
1609
|
+
* executed within the same flush.
|
|
1197
1610
|
*/
|
|
1198
1611
|
flush() {
|
|
1199
|
-
|
|
1612
|
+
this.scheduler?.cancel();
|
|
1613
|
+
this.isFlushing = true;
|
|
1200
1614
|
this.emitter.emit(1 /* BEFORE_FLUSH */, void 0);
|
|
1201
|
-
const
|
|
1202
|
-
this.
|
|
1203
|
-
for (let i = 0; i <
|
|
1204
|
-
|
|
1615
|
+
const snapshot = Array.from(this.tasks);
|
|
1616
|
+
this.tasks.clear();
|
|
1617
|
+
for (let i = 0; i < snapshot.length; i++) {
|
|
1618
|
+
snapshot[i]();
|
|
1205
1619
|
}
|
|
1620
|
+
this.isFlushing = false;
|
|
1206
1621
|
this.emitter.emit(0 /* AFTER_FLUSH */, void 0);
|
|
1207
1622
|
}
|
|
1208
1623
|
/**
|
|
1209
1624
|
* Get the current number of queued functions.
|
|
1210
1625
|
*/
|
|
1211
1626
|
get length() {
|
|
1212
|
-
return this.
|
|
1627
|
+
return this.tasks.size;
|
|
1213
1628
|
}
|
|
1214
1629
|
/**
|
|
1215
1630
|
* Check if the queue is empty.
|
|
1216
1631
|
*/
|
|
1217
1632
|
get isEmpty() {
|
|
1218
|
-
return this.
|
|
1633
|
+
return this.tasks.size === 0;
|
|
1219
1634
|
}
|
|
1220
1635
|
/**
|
|
1221
1636
|
* Clear the queue without executing functions and cancel any scheduled flush.
|
|
1222
1637
|
*/
|
|
1223
1638
|
clear() {
|
|
1224
|
-
this.
|
|
1639
|
+
this.tasks.clear();
|
|
1225
1640
|
this.scheduler?.cancel();
|
|
1226
1641
|
}
|
|
1642
|
+
ensureScheduled() {
|
|
1643
|
+
if (!this.scheduler) return;
|
|
1644
|
+
if (this.isFlushing) return;
|
|
1645
|
+
if (this.tasks.size === 1) {
|
|
1646
|
+
this.scheduler.schedule();
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1227
1649
|
/**
|
|
1228
1650
|
* Clean up scheduler subscription when queue is no longer needed.
|
|
1229
1651
|
*/
|
|
@@ -1271,7 +1693,7 @@ var OIMIndexComparatorFactory = class {
|
|
|
1271
1693
|
if (existingSet.size !== newSet.size || existingSet.size !== existingPks.length) {
|
|
1272
1694
|
return false;
|
|
1273
1695
|
}
|
|
1274
|
-
for (const pk of existingSet) {
|
|
1696
|
+
for (const pk of Array.from(existingSet)) {
|
|
1275
1697
|
if (!newSet.has(pk)) {
|
|
1276
1698
|
return false;
|
|
1277
1699
|
}
|
|
@@ -1337,9 +1759,390 @@ var OIMMap2Keys = class {
|
|
|
1337
1759
|
}
|
|
1338
1760
|
};
|
|
1339
1761
|
|
|
1340
|
-
// src/
|
|
1341
|
-
var
|
|
1342
|
-
constructor() {
|
|
1762
|
+
// src/modules/wrapper/collection/OIMCollectionChangedFieldsWrapper.ts
|
|
1763
|
+
var OIMCollectionChangedFieldsWrapper = class {
|
|
1764
|
+
constructor(queue, collection, opts) {
|
|
1765
|
+
this.isInWrite = false;
|
|
1766
|
+
this.lastEntitySnapshotByPk = /* @__PURE__ */ new Map();
|
|
1767
|
+
this.changedFieldsByPk = /* @__PURE__ */ new Map();
|
|
1768
|
+
this.changedPksByField = /* @__PURE__ */ new Map();
|
|
1769
|
+
this.onAfterFlush = () => {
|
|
1770
|
+
this.clear();
|
|
1771
|
+
};
|
|
1772
|
+
this.onCollectionUpdate = (payload) => {
|
|
1773
|
+
if (this.isInWrite) return;
|
|
1774
|
+
if (payload.pks.length === 0) return;
|
|
1775
|
+
for (let i = 0; i < payload.pks.length; i++) {
|
|
1776
|
+
const pk = payload.pks[i];
|
|
1777
|
+
this.trackExternalMutationByPk(pk);
|
|
1778
|
+
}
|
|
1779
|
+
};
|
|
1780
|
+
this.collection = collection;
|
|
1781
|
+
this.selectPk = opts?.selectPk ?? (() => {
|
|
1782
|
+
throw new Error(
|
|
1783
|
+
`[OIMCollectionChangedFieldsWrapper]: selectPk was not provided. Use upsertOneByPk(...) or pass opts.selectPk.`
|
|
1784
|
+
);
|
|
1785
|
+
});
|
|
1786
|
+
this.changedPksEventEmitter = new OIMUpdateEventEmitter(
|
|
1787
|
+
queue,
|
|
1788
|
+
"after_flush"
|
|
1789
|
+
);
|
|
1790
|
+
this.changedFieldsEventEmitter = new OIMUpdateEventEmitter(queue, "after_flush");
|
|
1791
|
+
this.unsubscribeAfterFlush = queue.emitter.on(
|
|
1792
|
+
0 /* AFTER_FLUSH */,
|
|
1793
|
+
this.onAfterFlush
|
|
1794
|
+
);
|
|
1795
|
+
const maybeReactive = collection;
|
|
1796
|
+
this.unsubscribeFromCollectionEmitter = maybeReactive.subscribeOnAnyUpdate ? maybeReactive.subscribeOnAnyUpdate((pks) => {
|
|
1797
|
+
this.onCollectionUpdate({
|
|
1798
|
+
pks
|
|
1799
|
+
});
|
|
1800
|
+
}) : collection.emitter.on(
|
|
1801
|
+
0 /* UPDATE */,
|
|
1802
|
+
this.onCollectionUpdate
|
|
1803
|
+
);
|
|
1804
|
+
}
|
|
1805
|
+
upsertOneByPk(pk, patch) {
|
|
1806
|
+
this.withWrite(() => {
|
|
1807
|
+
this.trackPatch(pk, patch);
|
|
1808
|
+
this.collection.upsertOneByPk(pk, patch);
|
|
1809
|
+
});
|
|
1810
|
+
this.updateEntitySnapshot(pk);
|
|
1811
|
+
}
|
|
1812
|
+
upsertOne(entity) {
|
|
1813
|
+
this.withWrite(() => {
|
|
1814
|
+
const pk = this.selectPk(entity);
|
|
1815
|
+
this.trackPatch(pk, entity);
|
|
1816
|
+
this.collection.upsertOne(entity);
|
|
1817
|
+
});
|
|
1818
|
+
this.updateEntitySnapshot(this.selectPk(entity));
|
|
1819
|
+
}
|
|
1820
|
+
upsertMany(entities) {
|
|
1821
|
+
const pks = [];
|
|
1822
|
+
this.withWrite(() => {
|
|
1823
|
+
for (const entity of entities) {
|
|
1824
|
+
const pk = this.selectPk(entity);
|
|
1825
|
+
pks.push(pk);
|
|
1826
|
+
this.trackPatch(pk, entity);
|
|
1827
|
+
}
|
|
1828
|
+
this.collection.upsertMany(entities);
|
|
1829
|
+
});
|
|
1830
|
+
for (let i = 0; i < pks.length; i++) this.updateEntitySnapshot(pks[i]);
|
|
1831
|
+
}
|
|
1832
|
+
getChangedFieldsByPk(pk) {
|
|
1833
|
+
return this.changedFieldsByPk.get(pk) ?? /* @__PURE__ */ new Set();
|
|
1834
|
+
}
|
|
1835
|
+
consumeChangedFieldsByPk(pk) {
|
|
1836
|
+
const existing = this.changedFieldsByPk.get(pk);
|
|
1837
|
+
if (!existing) return /* @__PURE__ */ new Set();
|
|
1838
|
+
return new Set(existing);
|
|
1839
|
+
}
|
|
1840
|
+
getChangedPksByField(field) {
|
|
1841
|
+
return this.changedPksByField.get(field) ?? /* @__PURE__ */ new Set();
|
|
1842
|
+
}
|
|
1843
|
+
consumeChangedPksByField(field) {
|
|
1844
|
+
const existing = this.changedPksByField.get(field);
|
|
1845
|
+
if (!existing) return /* @__PURE__ */ new Set();
|
|
1846
|
+
return new Set(existing);
|
|
1847
|
+
}
|
|
1848
|
+
clear() {
|
|
1849
|
+
this.changedFieldsByPk.clear();
|
|
1850
|
+
this.changedPksByField.clear();
|
|
1851
|
+
}
|
|
1852
|
+
destroy() {
|
|
1853
|
+
this.changedPksEventEmitter.destroy();
|
|
1854
|
+
this.changedFieldsEventEmitter.destroy();
|
|
1855
|
+
this.unsubscribeAfterFlush();
|
|
1856
|
+
this.unsubscribeFromCollectionEmitter();
|
|
1857
|
+
this.clear();
|
|
1858
|
+
}
|
|
1859
|
+
withWrite(fn) {
|
|
1860
|
+
if (this.isInWrite) {
|
|
1861
|
+
fn();
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
this.isInWrite = true;
|
|
1865
|
+
try {
|
|
1866
|
+
fn();
|
|
1867
|
+
} finally {
|
|
1868
|
+
this.isInWrite = false;
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
trackExternalMutationByPk(pk) {
|
|
1872
|
+
const prev = this.lastEntitySnapshotByPk.get(pk);
|
|
1873
|
+
const next = this.collection.getOneByPk(pk);
|
|
1874
|
+
const changedKeys = this.diffChangedKeys(prev, next);
|
|
1875
|
+
this.updateEntitySnapshot(pk);
|
|
1876
|
+
if (changedKeys.length > 0) {
|
|
1877
|
+
this.trackChangedKeys(pk, changedKeys);
|
|
1878
|
+
} else {
|
|
1879
|
+
this.changedPksEventEmitter.markUpdatedKeys([pk]);
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
diffChangedKeys(prev, next) {
|
|
1883
|
+
if (!prev && !next) return [];
|
|
1884
|
+
if (!prev && next) return Object.keys(next);
|
|
1885
|
+
if (prev && !next) return Object.keys(prev);
|
|
1886
|
+
const prevObj = prev;
|
|
1887
|
+
const nextObj = next;
|
|
1888
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1889
|
+
Object.keys(prevObj).forEach((k) => keys.add(k));
|
|
1890
|
+
Object.keys(nextObj).forEach((k) => keys.add(k));
|
|
1891
|
+
const changed = [];
|
|
1892
|
+
keys.forEach((k) => {
|
|
1893
|
+
if (prevObj[k] !== nextObj[k])
|
|
1894
|
+
changed.push(k);
|
|
1895
|
+
});
|
|
1896
|
+
return changed;
|
|
1897
|
+
}
|
|
1898
|
+
updateEntitySnapshot(pk) {
|
|
1899
|
+
const entity = this.collection.getOneByPk(pk);
|
|
1900
|
+
if (!entity) {
|
|
1901
|
+
this.lastEntitySnapshotByPk.delete(pk);
|
|
1902
|
+
return;
|
|
1903
|
+
}
|
|
1904
|
+
this.lastEntitySnapshotByPk.set(pk, {
|
|
1905
|
+
...entity
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
trackChangedKeys(pk, keys) {
|
|
1909
|
+
let pkFields = this.changedFieldsByPk.get(pk);
|
|
1910
|
+
if (!pkFields) {
|
|
1911
|
+
pkFields = /* @__PURE__ */ new Set();
|
|
1912
|
+
this.changedFieldsByPk.set(pk, pkFields);
|
|
1913
|
+
}
|
|
1914
|
+
for (const key of keys) {
|
|
1915
|
+
pkFields.add(key);
|
|
1916
|
+
let fieldPks = this.changedPksByField.get(key);
|
|
1917
|
+
if (!fieldPks) {
|
|
1918
|
+
fieldPks = /* @__PURE__ */ new Set();
|
|
1919
|
+
this.changedPksByField.set(key, fieldPks);
|
|
1920
|
+
}
|
|
1921
|
+
fieldPks.add(pk);
|
|
1922
|
+
}
|
|
1923
|
+
this.changedPksEventEmitter.markUpdatedKeys([pk]);
|
|
1924
|
+
this.changedFieldsEventEmitter.markUpdatedKeys(keys);
|
|
1925
|
+
}
|
|
1926
|
+
trackPatch(pk, patch) {
|
|
1927
|
+
if (pk === void 0 || pk === null || pk === "") {
|
|
1928
|
+
throw new Error(
|
|
1929
|
+
`[OIMCollectionChangedFieldsWrapper]: PK is required to track changes.`
|
|
1930
|
+
);
|
|
1931
|
+
}
|
|
1932
|
+
const keys = Object.keys(patch);
|
|
1933
|
+
if (keys.length === 0) return;
|
|
1934
|
+
this.trackChangedKeys(pk, keys);
|
|
1935
|
+
}
|
|
1936
|
+
};
|
|
1937
|
+
|
|
1938
|
+
// src/modules/wrapper/index/OIMIndexManualOrderedArrayBased.ts
|
|
1939
|
+
var OIMIndexManualOrderedArrayBased = class extends OIMIndexArrayBased {
|
|
1940
|
+
clear(key) {
|
|
1941
|
+
if (key === void 0) {
|
|
1942
|
+
const keys = this.getKeys();
|
|
1943
|
+
if (keys.length > 0) {
|
|
1944
|
+
this.store.clear();
|
|
1945
|
+
this.emitUpdate(Array.from(keys));
|
|
1946
|
+
}
|
|
1947
|
+
return;
|
|
1948
|
+
}
|
|
1949
|
+
if (this.store.getOneByKey(key) !== void 0) {
|
|
1950
|
+
this.store.removeOneByKey(key);
|
|
1951
|
+
this.emitUpdate([key]);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
push(key, itemKey) {
|
|
1955
|
+
const list = this.getOrCreateList(key);
|
|
1956
|
+
const index = list.length;
|
|
1957
|
+
list.push(itemKey);
|
|
1958
|
+
this.emitUpdate([key]);
|
|
1959
|
+
return index;
|
|
1960
|
+
}
|
|
1961
|
+
insertAt(key, index, itemKey) {
|
|
1962
|
+
const list = this.getOrCreateList(key);
|
|
1963
|
+
const safeIndex = Math.max(0, Math.min(index, list.length));
|
|
1964
|
+
list.splice(safeIndex, 0, itemKey);
|
|
1965
|
+
this.emitUpdate([key]);
|
|
1966
|
+
}
|
|
1967
|
+
removeAt(key, index) {
|
|
1968
|
+
const list = this.store.getOneByKey(key);
|
|
1969
|
+
if (!list) return void 0;
|
|
1970
|
+
if (index < 0 || index >= list.length) return void 0;
|
|
1971
|
+
const [removed] = list.splice(index, 1);
|
|
1972
|
+
if (list.length === 0) {
|
|
1973
|
+
this.store.removeOneByKey(key);
|
|
1974
|
+
}
|
|
1975
|
+
this.emitUpdate([key]);
|
|
1976
|
+
return removed;
|
|
1977
|
+
}
|
|
1978
|
+
move(key, fromIndex, toIndex) {
|
|
1979
|
+
const list = this.store.getOneByKey(key);
|
|
1980
|
+
if (!list) return void 0;
|
|
1981
|
+
if (fromIndex < 0 || fromIndex >= list.length) return void 0;
|
|
1982
|
+
if (toIndex < 0 || toIndex >= list.length) return void 0;
|
|
1983
|
+
if (fromIndex === toIndex) return list[fromIndex];
|
|
1984
|
+
const [itemKey] = list.splice(fromIndex, 1);
|
|
1985
|
+
if (itemKey === void 0) return void 0;
|
|
1986
|
+
list.splice(toIndex, 0, itemKey);
|
|
1987
|
+
this.emitUpdate([key]);
|
|
1988
|
+
return itemKey;
|
|
1989
|
+
}
|
|
1990
|
+
reset(key, itemKeys) {
|
|
1991
|
+
if (itemKeys.length === 0) {
|
|
1992
|
+
if (this.store.getOneByKey(key) !== void 0) {
|
|
1993
|
+
this.store.removeOneByKey(key);
|
|
1994
|
+
this.emitUpdate([key]);
|
|
1995
|
+
}
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
this.store.setOneByKey(key, Array.from(itemKeys));
|
|
1999
|
+
this.emitUpdate([key]);
|
|
2000
|
+
}
|
|
2001
|
+
getOrCreateList(key) {
|
|
2002
|
+
let list = this.store.getOneByKey(key);
|
|
2003
|
+
if (!list) {
|
|
2004
|
+
list = [];
|
|
2005
|
+
this.store.setOneByKey(key, list);
|
|
2006
|
+
}
|
|
2007
|
+
return list;
|
|
2008
|
+
}
|
|
2009
|
+
};
|
|
2010
|
+
|
|
2011
|
+
// src/modules/wrapper/index/OIMOrderedListIndexCommandStreamWrapper.ts
|
|
2012
|
+
var OIMOrderedListIndexCommandStreamWrapper = class {
|
|
2013
|
+
constructor(queue, index) {
|
|
2014
|
+
this.isInWrite = false;
|
|
2015
|
+
this.commandsByKey = /* @__PURE__ */ new Map();
|
|
2016
|
+
this.onAfterFlush = () => {
|
|
2017
|
+
this.commandsByKey.clear();
|
|
2018
|
+
};
|
|
2019
|
+
this.onIndexUpdate = (payload) => {
|
|
2020
|
+
if (this.isInWrite) return;
|
|
2021
|
+
if (payload.keys.length === 0) return;
|
|
2022
|
+
for (let i = 0; i < payload.keys.length; i++) {
|
|
2023
|
+
const key = payload.keys[i];
|
|
2024
|
+
const list = this.index.getPksByKey(key);
|
|
2025
|
+
this.appendCommand(key, { type: "set", keys: Array.from(list) });
|
|
2026
|
+
}
|
|
2027
|
+
};
|
|
2028
|
+
this.commandsEventEmitter = new OIMUpdateEventEmitter(
|
|
2029
|
+
queue,
|
|
2030
|
+
"after_flush"
|
|
2031
|
+
);
|
|
2032
|
+
this.index = index ?? new OIMIndexManualOrderedArrayBased();
|
|
2033
|
+
this.unsubscribeAfterFlush = queue.emitter.on(
|
|
2034
|
+
0 /* AFTER_FLUSH */,
|
|
2035
|
+
this.onAfterFlush
|
|
2036
|
+
);
|
|
2037
|
+
this.unsubscribeFromIndexEmitter = this.index.emitter.on(
|
|
2038
|
+
0 /* UPDATE */,
|
|
2039
|
+
this.onIndexUpdate
|
|
2040
|
+
);
|
|
2041
|
+
}
|
|
2042
|
+
getPksByKey(key) {
|
|
2043
|
+
return this.index.getPksByKey(key);
|
|
2044
|
+
}
|
|
2045
|
+
hasKey(key) {
|
|
2046
|
+
return this.index.hasKey(key);
|
|
2047
|
+
}
|
|
2048
|
+
getKeys() {
|
|
2049
|
+
return this.index.getKeys();
|
|
2050
|
+
}
|
|
2051
|
+
push(key, itemKey) {
|
|
2052
|
+
this.withWrite(() => {
|
|
2053
|
+
const index = this.index.push(key, itemKey);
|
|
2054
|
+
this.appendCommand(key, { type: "add", key: itemKey, index });
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
2057
|
+
removeAt(key, index) {
|
|
2058
|
+
this.withWrite(() => {
|
|
2059
|
+
const itemKey = this.index.removeAt(key, index);
|
|
2060
|
+
if (itemKey === void 0) return;
|
|
2061
|
+
this.appendCommand(key, { type: "remove", key: itemKey, index });
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
move(key, fromIndex, toIndex) {
|
|
2065
|
+
this.withWrite(() => {
|
|
2066
|
+
const itemKey = this.index.move(key, fromIndex, toIndex);
|
|
2067
|
+
if (itemKey === void 0) return;
|
|
2068
|
+
this.appendCommand(key, {
|
|
2069
|
+
type: "move",
|
|
2070
|
+
key: itemKey,
|
|
2071
|
+
fromIndex,
|
|
2072
|
+
toIndex
|
|
2073
|
+
});
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2076
|
+
set(key, keys) {
|
|
2077
|
+
this.withWrite(() => {
|
|
2078
|
+
this.index.reset(key, keys);
|
|
2079
|
+
this.appendCommand(key, { type: "set", keys });
|
|
2080
|
+
});
|
|
2081
|
+
}
|
|
2082
|
+
/**
|
|
2083
|
+
* Read-only peek at buffered commands without clearing them.
|
|
2084
|
+
*/
|
|
2085
|
+
getBufferedCommands(key) {
|
|
2086
|
+
return this.commandsByKey.get(key) ?? [];
|
|
2087
|
+
}
|
|
2088
|
+
/**
|
|
2089
|
+
* Drain buffered commands for a key, preserving order.
|
|
2090
|
+
* Intended usage: call inside a `commandsEventEmitter.subscribeOnKey(key, ...)` handler.
|
|
2091
|
+
*/
|
|
2092
|
+
consumeCommands(key) {
|
|
2093
|
+
const cmds = this.commandsByKey.get(key);
|
|
2094
|
+
if (!cmds || cmds.length === 0) return [];
|
|
2095
|
+
return cmds.slice();
|
|
2096
|
+
}
|
|
2097
|
+
clear(key) {
|
|
2098
|
+
if (key === void 0) {
|
|
2099
|
+
this.index.destroy();
|
|
2100
|
+
this.commandsByKey.clear();
|
|
2101
|
+
return;
|
|
2102
|
+
}
|
|
2103
|
+
this.index.clear(key);
|
|
2104
|
+
this.commandsByKey.delete(key);
|
|
2105
|
+
}
|
|
2106
|
+
destroy() {
|
|
2107
|
+
this.commandsEventEmitter.destroy();
|
|
2108
|
+
this.unsubscribeAfterFlush();
|
|
2109
|
+
this.unsubscribeFromIndexEmitter();
|
|
2110
|
+
this.clear();
|
|
2111
|
+
}
|
|
2112
|
+
withWrite(fn) {
|
|
2113
|
+
if (this.isInWrite) {
|
|
2114
|
+
fn();
|
|
2115
|
+
return;
|
|
2116
|
+
}
|
|
2117
|
+
this.isInWrite = true;
|
|
2118
|
+
try {
|
|
2119
|
+
fn();
|
|
2120
|
+
} finally {
|
|
2121
|
+
this.isInWrite = false;
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
appendCommand(key, cmd) {
|
|
2125
|
+
let cmds = this.commandsByKey.get(key);
|
|
2126
|
+
if (!cmds) {
|
|
2127
|
+
cmds = [];
|
|
2128
|
+
this.commandsByKey.set(key, cmds);
|
|
2129
|
+
}
|
|
2130
|
+
if (cmd.type === "set") {
|
|
2131
|
+
cmds.length = 0;
|
|
2132
|
+
cmds.push(cmd);
|
|
2133
|
+
} else if (cmds.length > 0 && cmds[0].type === "set") {
|
|
2134
|
+
const setCmd = cmds[0];
|
|
2135
|
+
setCmd.keys = Array.from(this.index.getPksByKey(key));
|
|
2136
|
+
} else {
|
|
2137
|
+
cmds.push(cmd);
|
|
2138
|
+
}
|
|
2139
|
+
this.commandsEventEmitter.markUpdatedKeys([key]);
|
|
2140
|
+
}
|
|
2141
|
+
};
|
|
2142
|
+
|
|
2143
|
+
// src/core/event-queue-scheduler/OIMEventQueueSchedulerAnimationFrame.ts
|
|
2144
|
+
var OIMEventQueueSchedulerAnimationFrame = class extends OIMEventQueueScheduler {
|
|
2145
|
+
constructor() {
|
|
1343
2146
|
super();
|
|
1344
2147
|
this.useRequestAnimationFrame = typeof requestAnimationFrame !== "undefined";
|
|
1345
2148
|
}
|
|
@@ -1505,17 +2308,842 @@ var OIMEventQueueSchedulerFactory = class {
|
|
|
1505
2308
|
return new OIMEventQueueSchedulerImmediate();
|
|
1506
2309
|
}
|
|
1507
2310
|
};
|
|
2311
|
+
|
|
2312
|
+
// src/const/OIMDBSettings.ts
|
|
2313
|
+
var OIMDBSettings = class {
|
|
2314
|
+
};
|
|
2315
|
+
/**
|
|
2316
|
+
* Fixed key used in the manual index to store updated keys set in coalescers.
|
|
2317
|
+
* This constant is exported so users can create their own indexes and pass them to coalescers.
|
|
2318
|
+
*/
|
|
2319
|
+
OIMDBSettings.UPDATED_KEYS_INDEX_KEY = "__updatedKeys__";
|
|
2320
|
+
OIMDBSettings.FLUSHING_KEYS_INDEX_KEY = "__flushingKeys__";
|
|
2321
|
+
|
|
2322
|
+
// src/modules/effect/core/OIMEffectDependencyComputed.ts
|
|
2323
|
+
var OIMEffectDependencyComputed = class {
|
|
2324
|
+
constructor(computed) {
|
|
2325
|
+
this.computed = computed;
|
|
2326
|
+
}
|
|
2327
|
+
subscribe(onUpdate) {
|
|
2328
|
+
return this.computed.emitter.on("update", onUpdate);
|
|
2329
|
+
}
|
|
2330
|
+
};
|
|
2331
|
+
|
|
2332
|
+
// src/modules/effect/core/OIMEffect.ts
|
|
2333
|
+
var OIMEffect = class {
|
|
2334
|
+
constructor(runtime, opts) {
|
|
2335
|
+
this.sourceDeps = [];
|
|
2336
|
+
this.computedDeps = [];
|
|
2337
|
+
this.sourceUnsubscribers = [];
|
|
2338
|
+
this.computedUnsubscribers = [];
|
|
2339
|
+
this.isResubscribeEnqueued = false;
|
|
2340
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
2341
|
+
this.isScheduled = false;
|
|
2342
|
+
this.runTask = () => {
|
|
2343
|
+
this.isScheduled = false;
|
|
2344
|
+
this.dequeueScheduled = void 0;
|
|
2345
|
+
this.runOnce();
|
|
2346
|
+
};
|
|
2347
|
+
this.onSourceInvalidate = () => {
|
|
2348
|
+
this.onUpdate?.();
|
|
2349
|
+
if (!this.isTemporarilyUnsubscribedForFlush) {
|
|
2350
|
+
this.isTemporarilyUnsubscribedForFlush = true;
|
|
2351
|
+
this.unsubscribeFromSourceDeps();
|
|
2352
|
+
this.ensureResubscribeAfterFlush();
|
|
2353
|
+
}
|
|
2354
|
+
if (this.isScheduled) return;
|
|
2355
|
+
this.isScheduled = true;
|
|
2356
|
+
this.dequeueScheduled = this.runtime.schedule(this.runTask);
|
|
2357
|
+
};
|
|
2358
|
+
this.onComputedInvalidate = () => {
|
|
2359
|
+
this.onUpdate?.();
|
|
2360
|
+
if (this.isScheduled) return;
|
|
2361
|
+
this.isScheduled = true;
|
|
2362
|
+
this.dequeueScheduled = this.runtime.schedule(this.runTask);
|
|
2363
|
+
};
|
|
2364
|
+
this.onAfterFlush = () => {
|
|
2365
|
+
if (!this.isResubscribeEnqueued) return;
|
|
2366
|
+
this.isResubscribeEnqueued = false;
|
|
2367
|
+
this.dequeueResubscribe = void 0;
|
|
2368
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
2369
|
+
if (this.sourceUnsubscribers.length === 0) {
|
|
2370
|
+
for (const dep of this.sourceDeps) {
|
|
2371
|
+
this.sourceUnsubscribers.push(
|
|
2372
|
+
dep.subscribe(this.onSourceInvalidate)
|
|
2373
|
+
);
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
};
|
|
2377
|
+
this.runtime = runtime;
|
|
2378
|
+
this.onUpdate = opts.onUpdate;
|
|
2379
|
+
this.run = opts.run;
|
|
2380
|
+
this.deps = opts.deps ?? [];
|
|
2381
|
+
for (const dep of this.deps) {
|
|
2382
|
+
if (dep instanceof OIMEffectDependencyComputed) {
|
|
2383
|
+
this.computedDeps.push(dep);
|
|
2384
|
+
} else {
|
|
2385
|
+
this.sourceDeps.push(dep);
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
this.subscribeToDeps();
|
|
2389
|
+
}
|
|
2390
|
+
destroy() {
|
|
2391
|
+
if (this.dequeueScheduled) {
|
|
2392
|
+
this.dequeueScheduled();
|
|
2393
|
+
this.dequeueScheduled = void 0;
|
|
2394
|
+
}
|
|
2395
|
+
this.unsubscribeFromAllDeps();
|
|
2396
|
+
if (this.dequeueResubscribe) {
|
|
2397
|
+
this.dequeueResubscribe();
|
|
2398
|
+
this.dequeueResubscribe = void 0;
|
|
2399
|
+
}
|
|
2400
|
+
this.isResubscribeEnqueued = false;
|
|
2401
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
2402
|
+
}
|
|
2403
|
+
runOnce() {
|
|
2404
|
+
this.run();
|
|
2405
|
+
}
|
|
2406
|
+
subscribeToDeps() {
|
|
2407
|
+
if (this.sourceUnsubscribers.length > 0 || this.computedUnsubscribers.length > 0)
|
|
2408
|
+
return;
|
|
2409
|
+
for (const dep of this.sourceDeps) {
|
|
2410
|
+
this.sourceUnsubscribers.push(
|
|
2411
|
+
dep.subscribe(this.onSourceInvalidate)
|
|
2412
|
+
);
|
|
2413
|
+
}
|
|
2414
|
+
for (const dep of this.computedDeps) {
|
|
2415
|
+
this.computedUnsubscribers.push(
|
|
2416
|
+
dep.subscribe(this.onComputedInvalidate)
|
|
2417
|
+
);
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
unsubscribeFromSourceDeps() {
|
|
2421
|
+
if (this.sourceUnsubscribers.length === 0) return;
|
|
2422
|
+
for (const unsubscribe of this.sourceUnsubscribers) unsubscribe();
|
|
2423
|
+
this.sourceUnsubscribers = [];
|
|
2424
|
+
}
|
|
2425
|
+
unsubscribeFromAllDeps() {
|
|
2426
|
+
this.unsubscribeFromSourceDeps();
|
|
2427
|
+
if (this.computedUnsubscribers.length === 0) return;
|
|
2428
|
+
for (const unsubscribe of this.computedUnsubscribers) unsubscribe();
|
|
2429
|
+
this.computedUnsubscribers = [];
|
|
2430
|
+
}
|
|
2431
|
+
ensureResubscribeAfterFlush() {
|
|
2432
|
+
if (this.isResubscribeEnqueued) return;
|
|
2433
|
+
this.isResubscribeEnqueued = true;
|
|
2434
|
+
this.dequeueResubscribe = this.runtime.scheduleAfterFlush(
|
|
2435
|
+
this.onAfterFlush
|
|
2436
|
+
);
|
|
2437
|
+
}
|
|
2438
|
+
};
|
|
2439
|
+
|
|
2440
|
+
// src/modules/computed/enum/EOIMComputedEventType.ts
|
|
2441
|
+
var EOIMComputedEventType = /* @__PURE__ */ ((EOIMComputedEventType2) => {
|
|
2442
|
+
EOIMComputedEventType2["UPDATE"] = "update";
|
|
2443
|
+
return EOIMComputedEventType2;
|
|
2444
|
+
})(EOIMComputedEventType || {});
|
|
2445
|
+
|
|
2446
|
+
// src/modules/computed/core/OIMComputed.ts
|
|
2447
|
+
var OIMComputed = class {
|
|
2448
|
+
constructor(runtime, opts) {
|
|
2449
|
+
this.emitter = new OIMEventEmitter();
|
|
2450
|
+
this.hasValue = false;
|
|
2451
|
+
this.isDirty = true;
|
|
2452
|
+
this.runtime = runtime;
|
|
2453
|
+
this.compute = opts.compute;
|
|
2454
|
+
this.compare = opts.compare ?? Object.is;
|
|
2455
|
+
this.deps = opts.deps ?? [];
|
|
2456
|
+
this.updateEventEmitter = new OIMUpdateEventEmitter(
|
|
2457
|
+
this.runtime.queue,
|
|
2458
|
+
"immediate"
|
|
2459
|
+
);
|
|
2460
|
+
this.effect = new OIMEffect(this.runtime, {
|
|
2461
|
+
deps: this.deps,
|
|
2462
|
+
onUpdate: () => {
|
|
2463
|
+
this.isDirty = true;
|
|
2464
|
+
},
|
|
2465
|
+
run: () => {
|
|
2466
|
+
this.recomputeAndEmitIfChanged();
|
|
2467
|
+
}
|
|
2468
|
+
});
|
|
2469
|
+
}
|
|
2470
|
+
get() {
|
|
2471
|
+
this.recomputeAndEmitIfChanged();
|
|
2472
|
+
return this.value;
|
|
2473
|
+
}
|
|
2474
|
+
getIfReady() {
|
|
2475
|
+
return this.hasValue ? this.value : void 0;
|
|
2476
|
+
}
|
|
2477
|
+
destroy() {
|
|
2478
|
+
this.effect.destroy();
|
|
2479
|
+
this.updateEventEmitter.destroy();
|
|
2480
|
+
this.emitter.offAll();
|
|
2481
|
+
}
|
|
2482
|
+
recomputeAndEmitIfChanged() {
|
|
2483
|
+
if (!this.isDirty) return;
|
|
2484
|
+
const prev = this.value;
|
|
2485
|
+
const hadPrev = this.hasValue;
|
|
2486
|
+
const next = this.compute();
|
|
2487
|
+
this.value = next;
|
|
2488
|
+
this.hasValue = true;
|
|
2489
|
+
this.isDirty = false;
|
|
2490
|
+
const changed = !hadPrev || !this.compare(prev, next);
|
|
2491
|
+
if (!changed) return;
|
|
2492
|
+
this.emitter.emit("update" /* UPDATE */, {
|
|
2493
|
+
keys: ["value"]
|
|
2494
|
+
});
|
|
2495
|
+
this.updateEventEmitter.markUpdatedKey("value");
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
|
|
2499
|
+
// src/modules/effect/core/OIMEffectDependencyKeyed.ts
|
|
2500
|
+
function isReadonlyArray(value) {
|
|
2501
|
+
return Array.isArray(value);
|
|
2502
|
+
}
|
|
2503
|
+
var OIMEffectDependencyKeyed = class {
|
|
2504
|
+
constructor(subscription, keyOrKeys) {
|
|
2505
|
+
this.subscription = subscription;
|
|
2506
|
+
if (isReadonlyArray(keyOrKeys)) {
|
|
2507
|
+
this.keys = keyOrKeys;
|
|
2508
|
+
} else {
|
|
2509
|
+
this.key = keyOrKeys;
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
subscribe(onUpdate) {
|
|
2513
|
+
if (this.keys !== void 0) {
|
|
2514
|
+
return this.subscription.subscribeOnKeys(this.keys, onUpdate);
|
|
2515
|
+
}
|
|
2516
|
+
if (this.key === void 0) return () => {
|
|
2517
|
+
};
|
|
2518
|
+
return this.subscription.subscribeOnKey(this.key, onUpdate);
|
|
2519
|
+
}
|
|
2520
|
+
};
|
|
2521
|
+
|
|
2522
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedObject.ts
|
|
2523
|
+
var OIMEffectDependencyKeyedObject = class {
|
|
2524
|
+
constructor(object, keyOrKeys) {
|
|
2525
|
+
this.dep = new OIMEffectDependencyKeyed(
|
|
2526
|
+
object,
|
|
2527
|
+
keyOrKeys
|
|
2528
|
+
);
|
|
2529
|
+
}
|
|
2530
|
+
subscribe(onUpdate) {
|
|
2531
|
+
return this.dep.subscribe(onUpdate);
|
|
2532
|
+
}
|
|
2533
|
+
};
|
|
2534
|
+
|
|
2535
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedCollection.ts
|
|
2536
|
+
var OIMEffectDependencyKeyedCollection = class {
|
|
2537
|
+
constructor(collection, pkOrPks) {
|
|
2538
|
+
this.dep = new OIMEffectDependencyKeyed(
|
|
2539
|
+
collection,
|
|
2540
|
+
pkOrPks
|
|
2541
|
+
);
|
|
2542
|
+
}
|
|
2543
|
+
subscribe(onUpdate) {
|
|
2544
|
+
return this.dep.subscribe(onUpdate);
|
|
2545
|
+
}
|
|
2546
|
+
};
|
|
2547
|
+
|
|
2548
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedIndex.ts
|
|
2549
|
+
var OIMEffectDependencyKeyedIndex = class {
|
|
2550
|
+
constructor(index, keyOrKeys) {
|
|
2551
|
+
this.dep = new OIMEffectDependencyKeyed(
|
|
2552
|
+
index,
|
|
2553
|
+
keyOrKeys
|
|
2554
|
+
);
|
|
2555
|
+
}
|
|
2556
|
+
subscribe(onUpdate) {
|
|
2557
|
+
return this.dep.subscribe(onUpdate);
|
|
2558
|
+
}
|
|
2559
|
+
};
|
|
2560
|
+
|
|
2561
|
+
// src/modules/selector/core/OIMSelector.ts
|
|
2562
|
+
var OIMSelector = class {
|
|
2563
|
+
constructor(runtime, sourceDeps, computedDeps = []) {
|
|
2564
|
+
this.runtime = runtime;
|
|
2565
|
+
this.sourceDeps = sourceDeps;
|
|
2566
|
+
this.computedDeps = computedDeps;
|
|
2567
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
2568
|
+
this.sourceUnsubscribers = [];
|
|
2569
|
+
this.computedUnsubscribers = [];
|
|
2570
|
+
this.isResubscribeEnqueued = false;
|
|
2571
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
2572
|
+
this.isDeliveryEnqueued = false;
|
|
2573
|
+
this.hasLastValue = false;
|
|
2574
|
+
this.onSourceInvalidate = () => {
|
|
2575
|
+
if (this.listeners.size === 0) return;
|
|
2576
|
+
if (!this.isTemporarilyUnsubscribedForFlush) {
|
|
2577
|
+
this.isTemporarilyUnsubscribedForFlush = true;
|
|
2578
|
+
this.unsubscribeFromSourceDeps();
|
|
2579
|
+
this.ensureResubscribeAfterFlush();
|
|
2580
|
+
}
|
|
2581
|
+
if (this.isDeliveryEnqueued) return;
|
|
2582
|
+
this.isDeliveryEnqueued = true;
|
|
2583
|
+
this.dequeueDelivery = this.runtime.schedule(this.deliver);
|
|
2584
|
+
};
|
|
2585
|
+
this.onComputedInvalidate = () => {
|
|
2586
|
+
if (this.listeners.size === 0) return;
|
|
2587
|
+
if (this.isDeliveryEnqueued) return;
|
|
2588
|
+
this.isDeliveryEnqueued = true;
|
|
2589
|
+
this.dequeueDelivery = this.runtime.schedule(this.deliver);
|
|
2590
|
+
};
|
|
2591
|
+
this.deliver = () => {
|
|
2592
|
+
this.isDeliveryEnqueued = false;
|
|
2593
|
+
this.dequeueDelivery = void 0;
|
|
2594
|
+
if (this.listeners.size === 0) return;
|
|
2595
|
+
const next = this.getValue();
|
|
2596
|
+
if (this.hasLastValue && this.areEqual(this.lastValue, next)) return;
|
|
2597
|
+
this.setLastValue(next);
|
|
2598
|
+
const snapshot = Array.from(this.listeners);
|
|
2599
|
+
for (let i = 0; i < snapshot.length; i++) {
|
|
2600
|
+
const listener = snapshot[i];
|
|
2601
|
+
if (this.listeners.has(listener)) listener(next);
|
|
2602
|
+
}
|
|
2603
|
+
};
|
|
2604
|
+
this.onAfterFlush = () => {
|
|
2605
|
+
if (!this.isResubscribeEnqueued) return;
|
|
2606
|
+
this.isResubscribeEnqueued = false;
|
|
2607
|
+
this.dequeueResubscribe = void 0;
|
|
2608
|
+
if (this.listeners.size === 0) return;
|
|
2609
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
2610
|
+
if (this.sourceUnsubscribers.length === 0) {
|
|
2611
|
+
for (const dep of this.sourceDeps) {
|
|
2612
|
+
this.sourceUnsubscribers.push(
|
|
2613
|
+
dep.subscribe(this.onSourceInvalidate)
|
|
2614
|
+
);
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
};
|
|
2618
|
+
}
|
|
2619
|
+
get queue() {
|
|
2620
|
+
return this.runtime.queue;
|
|
2621
|
+
}
|
|
2622
|
+
/**
|
|
2623
|
+
* Start watching this selector. The callback is called immediately with the current value,
|
|
2624
|
+
* then coalesced and delivered on `queue.flush()` when the selector invalidates.
|
|
2625
|
+
*/
|
|
2626
|
+
watch(onValue) {
|
|
2627
|
+
this.listeners.add(onValue);
|
|
2628
|
+
if (this.listeners.size === 1) {
|
|
2629
|
+
this.subscribeToDeps();
|
|
2630
|
+
}
|
|
2631
|
+
const current = this.getValue();
|
|
2632
|
+
this.setLastValue(current);
|
|
2633
|
+
onValue(current);
|
|
2634
|
+
return () => {
|
|
2635
|
+
this.listeners.delete(onValue);
|
|
2636
|
+
if (this.listeners.size > 0) return;
|
|
2637
|
+
this.unsubscribeFromAllDeps();
|
|
2638
|
+
if (this.dequeueResubscribe) {
|
|
2639
|
+
this.dequeueResubscribe();
|
|
2640
|
+
this.dequeueResubscribe = void 0;
|
|
2641
|
+
}
|
|
2642
|
+
this.isResubscribeEnqueued = false;
|
|
2643
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
2644
|
+
if (this.dequeueDelivery) {
|
|
2645
|
+
this.dequeueDelivery();
|
|
2646
|
+
this.dequeueDelivery = void 0;
|
|
2647
|
+
}
|
|
2648
|
+
this.isDeliveryEnqueued = false;
|
|
2649
|
+
this.hasLastValue = false;
|
|
2650
|
+
};
|
|
2651
|
+
}
|
|
2652
|
+
areEqual(prev, next) {
|
|
2653
|
+
return Object.is(prev, next);
|
|
2654
|
+
}
|
|
2655
|
+
setLastValue(value) {
|
|
2656
|
+
this.lastValue = value;
|
|
2657
|
+
this.hasLastValue = true;
|
|
2658
|
+
}
|
|
2659
|
+
subscribeToDeps() {
|
|
2660
|
+
if (this.sourceUnsubscribers.length > 0 || this.computedUnsubscribers.length > 0)
|
|
2661
|
+
return;
|
|
2662
|
+
for (const dep of this.sourceDeps) {
|
|
2663
|
+
this.sourceUnsubscribers.push(
|
|
2664
|
+
dep.subscribe(this.onSourceInvalidate)
|
|
2665
|
+
);
|
|
2666
|
+
}
|
|
2667
|
+
for (const dep of this.computedDeps) {
|
|
2668
|
+
this.computedUnsubscribers.push(
|
|
2669
|
+
dep.subscribe(this.onComputedInvalidate)
|
|
2670
|
+
);
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
unsubscribeFromSourceDeps() {
|
|
2674
|
+
if (this.sourceUnsubscribers.length === 0) return;
|
|
2675
|
+
for (const unsub of this.sourceUnsubscribers) unsub();
|
|
2676
|
+
this.sourceUnsubscribers = [];
|
|
2677
|
+
}
|
|
2678
|
+
unsubscribeFromAllDeps() {
|
|
2679
|
+
this.unsubscribeFromSourceDeps();
|
|
2680
|
+
if (this.computedUnsubscribers.length === 0) return;
|
|
2681
|
+
for (const unsub of this.computedUnsubscribers) unsub();
|
|
2682
|
+
this.computedUnsubscribers = [];
|
|
2683
|
+
}
|
|
2684
|
+
ensureResubscribeAfterFlush() {
|
|
2685
|
+
if (this.isResubscribeEnqueued) return;
|
|
2686
|
+
this.isResubscribeEnqueued = true;
|
|
2687
|
+
this.dequeueResubscribe = this.runtime.scheduleAfterFlush(
|
|
2688
|
+
this.onAfterFlush
|
|
2689
|
+
);
|
|
2690
|
+
}
|
|
2691
|
+
};
|
|
2692
|
+
|
|
2693
|
+
// src/modules/selector/core/OIMSelectorSourceDependencyUpdateEventEmitterKey.ts
|
|
2694
|
+
var OIMSelectorSourceDependencyUpdateEventEmitterKey = class {
|
|
2695
|
+
constructor(subscription, key) {
|
|
2696
|
+
this.subscription = subscription;
|
|
2697
|
+
this.key = key;
|
|
2698
|
+
}
|
|
2699
|
+
subscribe(onUpdate) {
|
|
2700
|
+
return this.subscription.subscribeOnKey(this.key, onUpdate);
|
|
2701
|
+
}
|
|
2702
|
+
};
|
|
2703
|
+
|
|
2704
|
+
// src/modules/selector/core/OIMCollectionByPkSelector.ts
|
|
2705
|
+
var OIMCollectionByPkSelector = class extends OIMSelector {
|
|
2706
|
+
constructor(runtime, collection, pk) {
|
|
2707
|
+
super(runtime, [
|
|
2708
|
+
new OIMSelectorSourceDependencyUpdateEventEmitterKey(
|
|
2709
|
+
collection,
|
|
2710
|
+
pk
|
|
2711
|
+
)
|
|
2712
|
+
]);
|
|
2713
|
+
this.collection = collection;
|
|
2714
|
+
this.pk = pk;
|
|
2715
|
+
}
|
|
2716
|
+
getValue() {
|
|
2717
|
+
return this.collection.getOneByPk(this.pk);
|
|
2718
|
+
}
|
|
2719
|
+
};
|
|
2720
|
+
|
|
2721
|
+
// src/modules/selector/core/OIMSelectorSourceDependencyUpdateEventEmitterKeys.ts
|
|
2722
|
+
var OIMSelectorSourceDependencyUpdateEventEmitterKeys = class {
|
|
2723
|
+
constructor(subscription, keys) {
|
|
2724
|
+
this.subscription = subscription;
|
|
2725
|
+
this.keys = keys;
|
|
2726
|
+
}
|
|
2727
|
+
subscribe(onUpdate) {
|
|
2728
|
+
return this.subscription.subscribeOnKeys(this.keys, onUpdate);
|
|
2729
|
+
}
|
|
2730
|
+
};
|
|
2731
|
+
|
|
2732
|
+
// src/modules/selector/core/OIMCollectionByPksSelector.ts
|
|
2733
|
+
var OIMCollectionByPksSelector = class extends OIMSelector {
|
|
2734
|
+
constructor(runtime, collection, pks) {
|
|
2735
|
+
super(runtime, [
|
|
2736
|
+
new OIMSelectorSourceDependencyUpdateEventEmitterKeys(
|
|
2737
|
+
collection,
|
|
2738
|
+
pks
|
|
2739
|
+
)
|
|
2740
|
+
]);
|
|
2741
|
+
this.collection = collection;
|
|
2742
|
+
this.pks = pks;
|
|
2743
|
+
}
|
|
2744
|
+
getValue() {
|
|
2745
|
+
return this.pks.map((pk) => this.collection.getOneByPk(pk));
|
|
2746
|
+
}
|
|
2747
|
+
areEqual(prev, next) {
|
|
2748
|
+
if (prev === next) return true;
|
|
2749
|
+
if (prev.length !== next.length) return false;
|
|
2750
|
+
for (let i = 0; i < prev.length; i++) {
|
|
2751
|
+
if (prev[i] !== next[i]) return false;
|
|
2752
|
+
}
|
|
2753
|
+
return true;
|
|
2754
|
+
}
|
|
2755
|
+
};
|
|
2756
|
+
|
|
2757
|
+
// src/modules/selector/core/OIMObjectValueByKeySelector.ts
|
|
2758
|
+
var OIMObjectValueByKeySelector = class extends OIMSelector {
|
|
2759
|
+
constructor(runtime, obj, key) {
|
|
2760
|
+
super(runtime, [
|
|
2761
|
+
new OIMSelectorSourceDependencyUpdateEventEmitterKey(
|
|
2762
|
+
obj,
|
|
2763
|
+
key
|
|
2764
|
+
)
|
|
2765
|
+
]);
|
|
2766
|
+
this.obj = obj;
|
|
2767
|
+
this.key = key;
|
|
2768
|
+
}
|
|
2769
|
+
getValue() {
|
|
2770
|
+
return this.obj.get(this.key);
|
|
2771
|
+
}
|
|
2772
|
+
};
|
|
2773
|
+
|
|
2774
|
+
// src/modules/selector/core/OIMObjectValuesByKeysSelector.ts
|
|
2775
|
+
var OIMObjectValuesByKeysSelector = class extends OIMSelector {
|
|
2776
|
+
constructor(runtime, obj, keys) {
|
|
2777
|
+
super(runtime, [
|
|
2778
|
+
new OIMSelectorSourceDependencyUpdateEventEmitterKeys(
|
|
2779
|
+
obj,
|
|
2780
|
+
keys
|
|
2781
|
+
)
|
|
2782
|
+
]);
|
|
2783
|
+
this.obj = obj;
|
|
2784
|
+
this.keys = keys;
|
|
2785
|
+
}
|
|
2786
|
+
getValue() {
|
|
2787
|
+
return this.keys.map((k) => this.obj.get(k));
|
|
2788
|
+
}
|
|
2789
|
+
areEqual(prev, next) {
|
|
2790
|
+
if (prev === next) return true;
|
|
2791
|
+
if (prev.length !== next.length) return false;
|
|
2792
|
+
for (let i = 0; i < prev.length; i++) {
|
|
2793
|
+
if (prev[i] !== next[i]) return false;
|
|
2794
|
+
}
|
|
2795
|
+
return true;
|
|
2796
|
+
}
|
|
2797
|
+
};
|
|
2798
|
+
|
|
2799
|
+
// src/modules/selector/core/OIMIndexPksByKeySetBasedSelector.ts
|
|
2800
|
+
var OIMIndexPksByKeySetBasedSelector = class extends OIMSelector {
|
|
2801
|
+
constructor(runtime, reactiveIndex, key) {
|
|
2802
|
+
super(runtime, [
|
|
2803
|
+
new OIMSelectorSourceDependencyUpdateEventEmitterKey(
|
|
2804
|
+
reactiveIndex,
|
|
2805
|
+
key
|
|
2806
|
+
)
|
|
2807
|
+
]);
|
|
2808
|
+
this.reactiveIndex = reactiveIndex;
|
|
2809
|
+
this.key = key;
|
|
2810
|
+
}
|
|
2811
|
+
getValue() {
|
|
2812
|
+
return this.reactiveIndex.getPksByKey(this.key);
|
|
2813
|
+
}
|
|
2814
|
+
};
|
|
2815
|
+
|
|
2816
|
+
// src/modules/selector/core/OIMIndexPksByKeyArrayBasedSelector.ts
|
|
2817
|
+
var OIMIndexPksByKeyArrayBasedSelector = class extends OIMSelector {
|
|
2818
|
+
constructor(runtime, reactiveIndex, key) {
|
|
2819
|
+
super(runtime, [
|
|
2820
|
+
new OIMSelectorSourceDependencyUpdateEventEmitterKey(
|
|
2821
|
+
reactiveIndex,
|
|
2822
|
+
key
|
|
2823
|
+
)
|
|
2824
|
+
]);
|
|
2825
|
+
this.reactiveIndex = reactiveIndex;
|
|
2826
|
+
this.key = key;
|
|
2827
|
+
}
|
|
2828
|
+
getValue() {
|
|
2829
|
+
return this.reactiveIndex.getPksByKey(this.key);
|
|
2830
|
+
}
|
|
2831
|
+
areEqual(prev, next) {
|
|
2832
|
+
if (prev === next) return true;
|
|
2833
|
+
if (prev.length !== next.length) return false;
|
|
2834
|
+
for (let i = 0; i < prev.length; i++)
|
|
2835
|
+
if (prev[i] !== next[i]) return false;
|
|
2836
|
+
return true;
|
|
2837
|
+
}
|
|
2838
|
+
};
|
|
2839
|
+
|
|
2840
|
+
// src/modules/selector/core/OIMIndexPksByKeysSetBasedSelector.ts
|
|
2841
|
+
var OIMIndexPksByKeysSetBasedSelector = class extends OIMSelector {
|
|
2842
|
+
constructor(runtime, reactiveIndex, keys) {
|
|
2843
|
+
super(runtime, [
|
|
2844
|
+
new OIMSelectorSourceDependencyUpdateEventEmitterKeys(
|
|
2845
|
+
reactiveIndex,
|
|
2846
|
+
keys
|
|
2847
|
+
)
|
|
2848
|
+
]);
|
|
2849
|
+
this.reactiveIndex = reactiveIndex;
|
|
2850
|
+
this.keys = keys;
|
|
2851
|
+
}
|
|
2852
|
+
getValue() {
|
|
2853
|
+
return this.keys.map((key) => Array.from(this.reactiveIndex.getPksByKey(key))).flat();
|
|
2854
|
+
}
|
|
2855
|
+
areEqual(prev, next) {
|
|
2856
|
+
if (prev === next) return true;
|
|
2857
|
+
if (prev.length !== next.length) return false;
|
|
2858
|
+
for (let i = 0; i < prev.length; i++)
|
|
2859
|
+
if (prev[i] !== next[i]) return false;
|
|
2860
|
+
return true;
|
|
2861
|
+
}
|
|
2862
|
+
};
|
|
2863
|
+
|
|
2864
|
+
// src/modules/selector/core/OIMIndexPksByKeysArrayBasedSelector.ts
|
|
2865
|
+
var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
2866
|
+
constructor(runtime, reactiveIndex, keys) {
|
|
2867
|
+
super(runtime, [
|
|
2868
|
+
new OIMSelectorSourceDependencyUpdateEventEmitterKeys(
|
|
2869
|
+
reactiveIndex,
|
|
2870
|
+
keys
|
|
2871
|
+
)
|
|
2872
|
+
]);
|
|
2873
|
+
this.reactiveIndex = reactiveIndex;
|
|
2874
|
+
this.keys = keys;
|
|
2875
|
+
}
|
|
2876
|
+
getValue() {
|
|
2877
|
+
return this.keys.map((key) => this.reactiveIndex.getPksByKey(key)).flat();
|
|
2878
|
+
}
|
|
2879
|
+
areEqual(prev, next) {
|
|
2880
|
+
if (prev === next) return true;
|
|
2881
|
+
if (prev.length !== next.length) return false;
|
|
2882
|
+
for (let i = 0; i < prev.length; i++)
|
|
2883
|
+
if (prev[i] !== next[i]) return false;
|
|
2884
|
+
return true;
|
|
2885
|
+
}
|
|
2886
|
+
};
|
|
2887
|
+
|
|
2888
|
+
// src/modules/selector/core/OIMSelectorSourceDependencyEntitiesByIndexKeySetBased.ts
|
|
2889
|
+
var OIMSelectorSourceDependencyEntitiesByIndexKeySetBased = class {
|
|
2890
|
+
constructor(collection, reactiveIndex, key) {
|
|
2891
|
+
this.collection = collection;
|
|
2892
|
+
this.reactiveIndex = reactiveIndex;
|
|
2893
|
+
this.key = key;
|
|
2894
|
+
this.currentPks = [];
|
|
2895
|
+
}
|
|
2896
|
+
subscribe(onUpdate) {
|
|
2897
|
+
const resubscribeCollection = () => {
|
|
2898
|
+
const nextPks = Array.from(
|
|
2899
|
+
this.reactiveIndex.getPksByKey(this.key)
|
|
2900
|
+
);
|
|
2901
|
+
if (this.sameArray(this.currentPks, nextPks)) return;
|
|
2902
|
+
this.unsubscribeFromCollectionKeys?.();
|
|
2903
|
+
this.unsubscribeFromCollectionKeys = void 0;
|
|
2904
|
+
this.currentPks = nextPks;
|
|
2905
|
+
if (this.currentPks.length === 0) return;
|
|
2906
|
+
this.unsubscribeFromCollectionKeys = this.collection.subscribeOnKeys(this.currentPks, onUpdate);
|
|
2907
|
+
};
|
|
2908
|
+
const onIndexUpdate = () => {
|
|
2909
|
+
resubscribeCollection();
|
|
2910
|
+
onUpdate();
|
|
2911
|
+
};
|
|
2912
|
+
resubscribeCollection();
|
|
2913
|
+
const unsubscribeFromIndex = this.reactiveIndex.subscribeOnKey(
|
|
2914
|
+
this.key,
|
|
2915
|
+
onIndexUpdate
|
|
2916
|
+
);
|
|
2917
|
+
return () => {
|
|
2918
|
+
unsubscribeFromIndex();
|
|
2919
|
+
this.unsubscribeFromCollectionKeys?.();
|
|
2920
|
+
this.unsubscribeFromCollectionKeys = void 0;
|
|
2921
|
+
this.currentPks = [];
|
|
2922
|
+
};
|
|
2923
|
+
}
|
|
2924
|
+
sameArray(a, b) {
|
|
2925
|
+
if (a === b) return true;
|
|
2926
|
+
if (a.length !== b.length) return false;
|
|
2927
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
2928
|
+
return true;
|
|
2929
|
+
}
|
|
2930
|
+
};
|
|
2931
|
+
|
|
2932
|
+
// src/modules/selector/core/OIMEntitiesByIndexKeySetBasedSelector.ts
|
|
2933
|
+
var OIMEntitiesByIndexKeySetBasedSelector = class extends OIMSelector {
|
|
2934
|
+
constructor(runtime, collection, reactiveIndex, key) {
|
|
2935
|
+
super(runtime, [
|
|
2936
|
+
new OIMSelectorSourceDependencyEntitiesByIndexKeySetBased(collection, reactiveIndex, key)
|
|
2937
|
+
]);
|
|
2938
|
+
this.collection = collection;
|
|
2939
|
+
this.reactiveIndex = reactiveIndex;
|
|
2940
|
+
this.key = key;
|
|
2941
|
+
}
|
|
2942
|
+
getValue() {
|
|
2943
|
+
const pks = Array.from(this.reactiveIndex.getPksByKey(this.key));
|
|
2944
|
+
return pks.map((pk) => this.collection.getOneByPk(pk));
|
|
2945
|
+
}
|
|
2946
|
+
areEqual(prev, next) {
|
|
2947
|
+
if (prev === next) return true;
|
|
2948
|
+
if (prev.length !== next.length) return false;
|
|
2949
|
+
for (let i = 0; i < prev.length; i++)
|
|
2950
|
+
if (prev[i] !== next[i]) return false;
|
|
2951
|
+
return true;
|
|
2952
|
+
}
|
|
2953
|
+
};
|
|
2954
|
+
|
|
2955
|
+
// src/modules/selector/core/OIMSelectorSourceDependencyEntitiesByIndexKeyArrayBased.ts
|
|
2956
|
+
var OIMSelectorSourceDependencyEntitiesByIndexKeyArrayBased = class {
|
|
2957
|
+
constructor(collection, reactiveIndex, key) {
|
|
2958
|
+
this.collection = collection;
|
|
2959
|
+
this.reactiveIndex = reactiveIndex;
|
|
2960
|
+
this.key = key;
|
|
2961
|
+
this.currentPks = [];
|
|
2962
|
+
}
|
|
2963
|
+
subscribe(onUpdate) {
|
|
2964
|
+
const resubscribeCollection = () => {
|
|
2965
|
+
const nextPks = this.reactiveIndex.getPksByKey(this.key);
|
|
2966
|
+
if (this.sameArray(this.currentPks, nextPks)) return;
|
|
2967
|
+
this.unsubscribeFromCollectionKeys?.();
|
|
2968
|
+
this.unsubscribeFromCollectionKeys = void 0;
|
|
2969
|
+
this.currentPks = nextPks;
|
|
2970
|
+
if (this.currentPks.length === 0) return;
|
|
2971
|
+
this.unsubscribeFromCollectionKeys = this.collection.subscribeOnKeys(this.currentPks, onUpdate);
|
|
2972
|
+
};
|
|
2973
|
+
const onIndexUpdate = () => {
|
|
2974
|
+
resubscribeCollection();
|
|
2975
|
+
onUpdate();
|
|
2976
|
+
};
|
|
2977
|
+
resubscribeCollection();
|
|
2978
|
+
const unsubscribeFromIndex = this.reactiveIndex.subscribeOnKey(
|
|
2979
|
+
this.key,
|
|
2980
|
+
onIndexUpdate
|
|
2981
|
+
);
|
|
2982
|
+
return () => {
|
|
2983
|
+
unsubscribeFromIndex();
|
|
2984
|
+
this.unsubscribeFromCollectionKeys?.();
|
|
2985
|
+
this.unsubscribeFromCollectionKeys = void 0;
|
|
2986
|
+
this.currentPks = [];
|
|
2987
|
+
};
|
|
2988
|
+
}
|
|
2989
|
+
sameArray(a, b) {
|
|
2990
|
+
if (a === b) return true;
|
|
2991
|
+
if (a.length !== b.length) return false;
|
|
2992
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
2993
|
+
return true;
|
|
2994
|
+
}
|
|
2995
|
+
};
|
|
2996
|
+
|
|
2997
|
+
// src/modules/selector/core/OIMEntitiesByIndexKeyArrayBasedSelector.ts
|
|
2998
|
+
var OIMEntitiesByIndexKeyArrayBasedSelector = class extends OIMSelector {
|
|
2999
|
+
constructor(runtime, collection, reactiveIndex, key) {
|
|
3000
|
+
super(runtime, [
|
|
3001
|
+
new OIMSelectorSourceDependencyEntitiesByIndexKeyArrayBased(collection, reactiveIndex, key)
|
|
3002
|
+
]);
|
|
3003
|
+
this.collection = collection;
|
|
3004
|
+
this.reactiveIndex = reactiveIndex;
|
|
3005
|
+
this.key = key;
|
|
3006
|
+
}
|
|
3007
|
+
getValue() {
|
|
3008
|
+
const pks = this.reactiveIndex.getPksByKey(this.key);
|
|
3009
|
+
return pks.map((pk) => this.collection.getOneByPk(pk));
|
|
3010
|
+
}
|
|
3011
|
+
areEqual(prev, next) {
|
|
3012
|
+
if (prev === next) return true;
|
|
3013
|
+
if (prev.length !== next.length) return false;
|
|
3014
|
+
for (let i = 0; i < prev.length; i++)
|
|
3015
|
+
if (prev[i] !== next[i]) return false;
|
|
3016
|
+
return true;
|
|
3017
|
+
}
|
|
3018
|
+
};
|
|
3019
|
+
|
|
3020
|
+
// src/modules/computative/core/OIMComputativeRuntime.ts
|
|
3021
|
+
var OIMComputativeRuntime = class {
|
|
3022
|
+
constructor(queue) {
|
|
3023
|
+
this.queue = queue;
|
|
3024
|
+
this.isFlushScheduled = false;
|
|
3025
|
+
this.isFlushing = false;
|
|
3026
|
+
this.minLevel = Infinity;
|
|
3027
|
+
this.maxLevel = -Infinity;
|
|
3028
|
+
this.dirtyByLevel = /* @__PURE__ */ new Map();
|
|
3029
|
+
this.afterFlushTasks = /* @__PURE__ */ new Set();
|
|
3030
|
+
this.queue.emitter.on(0 /* AFTER_FLUSH */, () => {
|
|
3031
|
+
if (!this.isFlushScheduled) return;
|
|
3032
|
+
this.flush();
|
|
3033
|
+
});
|
|
3034
|
+
}
|
|
3035
|
+
/**
|
|
3036
|
+
* Schedule a one-shot task to run on the next `queue.flush()` (AFTER_FLUSH),
|
|
3037
|
+
* ordered by `level` ascending.
|
|
3038
|
+
*/
|
|
3039
|
+
schedule(task, level = 0) {
|
|
3040
|
+
let isActive = true;
|
|
3041
|
+
const wrapped = () => {
|
|
3042
|
+
if (!isActive) return;
|
|
3043
|
+
task();
|
|
3044
|
+
};
|
|
3045
|
+
let bucket = this.dirtyByLevel.get(level);
|
|
3046
|
+
if (!bucket) {
|
|
3047
|
+
bucket = /* @__PURE__ */ new Set();
|
|
3048
|
+
this.dirtyByLevel.set(level, bucket);
|
|
3049
|
+
}
|
|
3050
|
+
bucket.add(wrapped);
|
|
3051
|
+
if (level < this.minLevel) this.minLevel = level;
|
|
3052
|
+
if (level > this.maxLevel) this.maxLevel = level;
|
|
3053
|
+
if (!this.isFlushing) this.isFlushScheduled = true;
|
|
3054
|
+
return () => {
|
|
3055
|
+
if (!isActive) return;
|
|
3056
|
+
isActive = false;
|
|
3057
|
+
bucket.delete(wrapped);
|
|
3058
|
+
};
|
|
3059
|
+
}
|
|
3060
|
+
/**
|
|
3061
|
+
* Run once at the start of the next runtime flush (i.e. after queue.flush()).
|
|
3062
|
+
* Useful for resubscribing dependencies exactly once per source flush.
|
|
3063
|
+
*/
|
|
3064
|
+
scheduleAfterFlush(task) {
|
|
3065
|
+
let isActive = true;
|
|
3066
|
+
const wrapped = () => {
|
|
3067
|
+
if (!isActive) return;
|
|
3068
|
+
task();
|
|
3069
|
+
};
|
|
3070
|
+
this.afterFlushTasks.add(wrapped);
|
|
3071
|
+
if (!this.isFlushing) this.isFlushScheduled = true;
|
|
3072
|
+
return () => {
|
|
3073
|
+
if (!isActive) return;
|
|
3074
|
+
isActive = false;
|
|
3075
|
+
this.afterFlushTasks.delete(wrapped);
|
|
3076
|
+
};
|
|
3077
|
+
}
|
|
3078
|
+
flush() {
|
|
3079
|
+
this.isFlushScheduled = false;
|
|
3080
|
+
if (this.dirtyByLevel.size === 0 && this.afterFlushTasks.size === 0)
|
|
3081
|
+
return;
|
|
3082
|
+
this.isFlushing = true;
|
|
3083
|
+
try {
|
|
3084
|
+
if (this.afterFlushTasks.size > 0) {
|
|
3085
|
+
const snapshot = Array.from(this.afterFlushTasks);
|
|
3086
|
+
this.afterFlushTasks.clear();
|
|
3087
|
+
for (let i = 0; i < snapshot.length; i++) snapshot[i]();
|
|
3088
|
+
}
|
|
3089
|
+
if (this.dirtyByLevel.size === 0) return;
|
|
3090
|
+
let level = this.minLevel;
|
|
3091
|
+
let max = this.maxLevel;
|
|
3092
|
+
while (level <= max) {
|
|
3093
|
+
for (; ; ) {
|
|
3094
|
+
const bucket = this.dirtyByLevel.get(level);
|
|
3095
|
+
if (!bucket || bucket.size === 0) break;
|
|
3096
|
+
this.dirtyByLevel.delete(level);
|
|
3097
|
+
const snapshot = Array.from(bucket);
|
|
3098
|
+
for (let i = 0; i < snapshot.length; i++) snapshot[i]();
|
|
3099
|
+
}
|
|
3100
|
+
if (this.maxLevel > max) max = this.maxLevel;
|
|
3101
|
+
level++;
|
|
3102
|
+
}
|
|
3103
|
+
} finally {
|
|
3104
|
+
this.isFlushing = false;
|
|
3105
|
+
if (this.dirtyByLevel.size === 0) {
|
|
3106
|
+
this.minLevel = Infinity;
|
|
3107
|
+
this.maxLevel = -Infinity;
|
|
3108
|
+
} else {
|
|
3109
|
+
let nextMin = Infinity;
|
|
3110
|
+
let nextMax = -Infinity;
|
|
3111
|
+
this.dirtyByLevel.forEach((_bucket, lvl) => {
|
|
3112
|
+
if (lvl < nextMin) nextMin = lvl;
|
|
3113
|
+
if (lvl > nextMax) nextMax = lvl;
|
|
3114
|
+
});
|
|
3115
|
+
this.minLevel = nextMin;
|
|
3116
|
+
this.maxLevel = nextMax;
|
|
3117
|
+
this.isFlushScheduled = true;
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
};
|
|
1508
3122
|
export {
|
|
1509
3123
|
EOIMCollectionEventType,
|
|
3124
|
+
EOIMComputedEventType,
|
|
1510
3125
|
EOIMEventQueueEventType,
|
|
1511
3126
|
EOIMEventQueueSchedulerEventType,
|
|
1512
3127
|
EOIMIndexEventType,
|
|
1513
|
-
|
|
3128
|
+
EOIMObjectEventType,
|
|
1514
3129
|
OIMCollection,
|
|
3130
|
+
OIMCollectionByPkSelector,
|
|
3131
|
+
OIMCollectionByPksSelector,
|
|
3132
|
+
OIMCollectionChangedFieldsWrapper,
|
|
1515
3133
|
OIMCollectionStore,
|
|
1516
3134
|
OIMCollectionStoreMapDriven,
|
|
1517
3135
|
OIMComparatorFactory,
|
|
3136
|
+
OIMComputativeRuntime,
|
|
3137
|
+
OIMComputed,
|
|
1518
3138
|
OIMDBSettings,
|
|
3139
|
+
OIMEffect,
|
|
3140
|
+
OIMEffectDependencyComputed,
|
|
3141
|
+
OIMEffectDependencyKeyed,
|
|
3142
|
+
OIMEffectDependencyKeyedCollection,
|
|
3143
|
+
OIMEffectDependencyKeyedIndex,
|
|
3144
|
+
OIMEffectDependencyKeyedObject,
|
|
3145
|
+
OIMEntitiesByIndexKeyArrayBasedSelector,
|
|
3146
|
+
OIMEntitiesByIndexKeySetBasedSelector,
|
|
1519
3147
|
OIMEntityUpdaterFactory,
|
|
1520
3148
|
OIMEventEmitter,
|
|
1521
3149
|
OIMEventQueue,
|
|
@@ -1528,13 +3156,25 @@ export {
|
|
|
1528
3156
|
OIMIndexArrayBased,
|
|
1529
3157
|
OIMIndexComparatorFactory,
|
|
1530
3158
|
OIMIndexManualArrayBased,
|
|
3159
|
+
OIMIndexManualOrderedArrayBased,
|
|
1531
3160
|
OIMIndexManualSetBased,
|
|
3161
|
+
OIMIndexPksByKeyArrayBasedSelector,
|
|
3162
|
+
OIMIndexPksByKeySetBasedSelector,
|
|
3163
|
+
OIMIndexPksByKeysArrayBasedSelector,
|
|
3164
|
+
OIMIndexPksByKeysSetBasedSelector,
|
|
1532
3165
|
OIMIndexSetBased,
|
|
1533
3166
|
OIMIndexStoreArrayBased,
|
|
1534
3167
|
OIMIndexStoreMapDrivenArrayBased,
|
|
1535
3168
|
OIMIndexStoreMapDrivenSetBased,
|
|
1536
3169
|
OIMIndexStoreSetBased,
|
|
1537
3170
|
OIMMap2Keys,
|
|
3171
|
+
OIMObject,
|
|
3172
|
+
OIMObjectStore,
|
|
3173
|
+
OIMObjectStoreMapDriven,
|
|
3174
|
+
OIMObjectStoreRecordDriven,
|
|
3175
|
+
OIMObjectValueByKeySelector,
|
|
3176
|
+
OIMObjectValuesByKeysSelector,
|
|
3177
|
+
OIMOrderedListIndexCommandStreamWrapper,
|
|
1538
3178
|
OIMPkSelectorFactory,
|
|
1539
3179
|
OIMRICollection,
|
|
1540
3180
|
OIMReactiveCollection,
|
|
@@ -1542,8 +3182,6 @@ export {
|
|
|
1542
3182
|
OIMReactiveIndexManualArrayBased,
|
|
1543
3183
|
OIMReactiveIndexManualSetBased,
|
|
1544
3184
|
OIMReactiveIndexSetBased,
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
OIMUpdateEventCoalescerIndex,
|
|
1548
|
-
OIMUpdateEventEmitter
|
|
3185
|
+
OIMReactiveObject,
|
|
3186
|
+
OIMSelector
|
|
1549
3187
|
};
|