@oimdb/core 3.7.0 → 3.9.0
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 +43 -4
- package/dist/index.cjs +1298 -327
- package/dist/index.d.cts +893 -267
- package/dist/index.d.ts +893 -267
- package/dist/index.js +1284 -327
- package/llms.txt +82 -0
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
EOIMEventQueueSchedulerEventType: () => EOIMEventQueueSchedulerEventType,
|
|
27
27
|
EOIMIndexEventType: () => EOIMIndexEventType,
|
|
28
28
|
EOIMObjectEventType: () => EOIMObjectEventType,
|
|
29
|
+
OIMBucketCarrierProvider: () => OIMBucketCarrierProvider,
|
|
29
30
|
OIMCarrierKeyedEmitter: () => OIMCarrierKeyedEmitter,
|
|
30
31
|
OIMCarrierSingleEmitter: () => OIMCarrierSingleEmitter,
|
|
31
32
|
OIMCollection: () => OIMCollection,
|
|
@@ -38,6 +39,7 @@ __export(index_exports, {
|
|
|
38
39
|
OIMCollectionSelectors: () => OIMCollectionSelectors,
|
|
39
40
|
OIMCollectionStore: () => OIMCollectionStore,
|
|
40
41
|
OIMCollectionStoreMapDriven: () => OIMCollectionStoreMapDriven,
|
|
42
|
+
OIMCollectionStoreTrieDriven: () => OIMCollectionStoreTrieDriven,
|
|
41
43
|
OIMComparatorFactory: () => OIMComparatorFactory,
|
|
42
44
|
OIMComputeRuntime: () => OIMComputeRuntime,
|
|
43
45
|
OIMComputed: () => OIMComputed,
|
|
@@ -46,6 +48,7 @@ __export(index_exports, {
|
|
|
46
48
|
OIMDerivedCollectionGlobalIndexSetBased: () => OIMDerivedCollectionGlobalIndexSetBased,
|
|
47
49
|
OIMDerivedCollectionIndexArrayBased: () => OIMDerivedCollectionIndexArrayBased,
|
|
48
50
|
OIMDerivedCollectionIndexSetBased: () => OIMDerivedCollectionIndexSetBased,
|
|
51
|
+
OIMDisposeScope: () => OIMDisposeScope,
|
|
49
52
|
OIMEffect: () => OIMEffect,
|
|
50
53
|
OIMEffectDependencyComputed: () => OIMEffectDependencyComputed,
|
|
51
54
|
OIMEffectDependencyKeyed: () => OIMEffectDependencyKeyed,
|
|
@@ -88,6 +91,11 @@ __export(index_exports, {
|
|
|
88
91
|
OIMIndexStoreMapDrivenArrayBased: () => OIMIndexStoreMapDrivenArrayBased,
|
|
89
92
|
OIMIndexStoreMapDrivenSetBased: () => OIMIndexStoreMapDrivenSetBased,
|
|
90
93
|
OIMIndexStoreSetBased: () => OIMIndexStoreSetBased,
|
|
94
|
+
OIMIndexStoreTrieDrivenArrayBased: () => OIMIndexStoreTrieDrivenArrayBased,
|
|
95
|
+
OIMIndexStoreTrieDrivenSetBased: () => OIMIndexStoreTrieDrivenSetBased,
|
|
96
|
+
OIMKeyPathCarrierProvider: () => OIMKeyPathCarrierProvider,
|
|
97
|
+
OIMKeyedBucketArrayBased: () => OIMKeyedBucketArrayBased,
|
|
98
|
+
OIMKeyedBucketSetBased: () => OIMKeyedBucketSetBased,
|
|
91
99
|
OIMMap2Keys: () => OIMMap2Keys,
|
|
92
100
|
OIMObject: () => OIMObject,
|
|
93
101
|
OIMObjectStore: () => OIMObjectStore,
|
|
@@ -99,10 +107,13 @@ __export(index_exports, {
|
|
|
99
107
|
OIMOrderedListCommandStream: () => OIMOrderedListCommandStream,
|
|
100
108
|
OIMOrderedListCommandStreamDiffDriven: () => OIMOrderedListCommandStreamDiffDriven,
|
|
101
109
|
OIMOrderedListMappedCommandStream: () => OIMOrderedListMappedCommandStream,
|
|
110
|
+
OIMPkCodecKeyPath: () => OIMPkCodecKeyPath,
|
|
102
111
|
OIMPkSelectorFactory: () => OIMPkSelectorFactory,
|
|
103
112
|
OIMReactiveCollection: () => OIMReactiveCollection,
|
|
104
113
|
OIMReactiveCollectionGlobalIndexManualArrayBased: () => OIMReactiveCollectionGlobalIndexManualArrayBased,
|
|
105
114
|
OIMReactiveCollectionGlobalIndexManualSetBased: () => OIMReactiveCollectionGlobalIndexManualSetBased,
|
|
115
|
+
OIMReactiveCollectionIndexCompositeTrieArrayBased: () => OIMReactiveCollectionIndexCompositeTrieArrayBased,
|
|
116
|
+
OIMReactiveCollectionIndexCompositeTrieSetBased: () => OIMReactiveCollectionIndexCompositeTrieSetBased,
|
|
106
117
|
OIMReactiveCollectionIndexManualArrayBased: () => OIMReactiveCollectionIndexManualArrayBased,
|
|
107
118
|
OIMReactiveCollectionIndexManualSetBased: () => OIMReactiveCollectionIndexManualSetBased,
|
|
108
119
|
OIMReactiveGlobalIndex: () => OIMReactiveGlobalIndex,
|
|
@@ -117,10 +128,13 @@ __export(index_exports, {
|
|
|
117
128
|
OIMReactiveIndexSetBased: () => OIMReactiveIndexSetBased,
|
|
118
129
|
OIMReactiveObject: () => OIMReactiveObject,
|
|
119
130
|
OIMSelector: () => OIMSelector,
|
|
131
|
+
OIMTrieMap: () => OIMTrieMap,
|
|
132
|
+
OIMTrieSet: () => OIMTrieSet,
|
|
120
133
|
createInPlaceEntityUpdater: () => createInPlaceEntityUpdater,
|
|
121
134
|
createMergeEntityUpdater: () => createMergeEntityUpdater,
|
|
122
135
|
createOIMCollectionIndexFactory: () => createOIMCollectionIndexFactory,
|
|
123
136
|
createOIMCollectionKit: () => createOIMCollectionKit,
|
|
137
|
+
createOIMDisposeScope: () => createOIMDisposeScope,
|
|
124
138
|
createOIMGlobalIndexSlotMap: () => createOIMGlobalIndexSlotMap,
|
|
125
139
|
createOIMIndexSlotMap: () => createOIMIndexSlotMap,
|
|
126
140
|
createOIMOrderedListCommandStreamDiffDriven: () => createOIMOrderedListCommandStreamDiffDriven,
|
|
@@ -358,21 +372,82 @@ var OIMEventQueueScheduler = class {
|
|
|
358
372
|
}
|
|
359
373
|
};
|
|
360
374
|
|
|
375
|
+
// src/core/OIMKeyedBucketSetBased.ts
|
|
376
|
+
var OIMKeyedBucketSetBased = class extends Set {
|
|
377
|
+
constructor(key) {
|
|
378
|
+
super();
|
|
379
|
+
this.key = key;
|
|
380
|
+
}
|
|
381
|
+
hasSubscribers() {
|
|
382
|
+
return this.subscribers !== void 0 && this.subscribers.size > 0;
|
|
383
|
+
}
|
|
384
|
+
/** Clearing the slot set also clears the pk membership — they stay in sync. */
|
|
385
|
+
clear() {
|
|
386
|
+
super.clear();
|
|
387
|
+
this.membership?.clear();
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
|
|
361
391
|
// src/core/OIMIndexStoreMapDrivenSetBased.ts
|
|
362
392
|
var OIMIndexStoreMapDrivenSetBased = class extends OIMIndexStoreSetBased {
|
|
363
393
|
constructor() {
|
|
364
394
|
super(...arguments);
|
|
395
|
+
// Live buckets (non-empty, or freshly promoted). Enumeration reads these only.
|
|
365
396
|
this.slots = /* @__PURE__ */ new Map();
|
|
397
|
+
// Empty buckets kept alive solely by their subscribers, so a subscription
|
|
398
|
+
// survives a key going empty → re-filled. Invisible to reads/enumeration.
|
|
399
|
+
this.reservedBuckets = /* @__PURE__ */ new Map();
|
|
400
|
+
}
|
|
401
|
+
getOrReserveBucket(key) {
|
|
402
|
+
const live = this.slots.get(key);
|
|
403
|
+
if (live) return live;
|
|
404
|
+
let reserved = this.reservedBuckets.get(key);
|
|
405
|
+
if (!reserved) {
|
|
406
|
+
reserved = new OIMKeyedBucketSetBased(key);
|
|
407
|
+
this.reservedBuckets.set(key, reserved);
|
|
408
|
+
}
|
|
409
|
+
return reserved;
|
|
410
|
+
}
|
|
411
|
+
findBucket(key) {
|
|
412
|
+
return this.slots.get(key) ?? this.reservedBuckets.get(key);
|
|
413
|
+
}
|
|
414
|
+
retainBucket(bucket) {
|
|
415
|
+
if (bucket.size === 0) return;
|
|
416
|
+
this.reservedBuckets.delete(bucket.key);
|
|
417
|
+
if (!this.slots.has(bucket.key)) this.slots.set(bucket.key, bucket);
|
|
418
|
+
}
|
|
419
|
+
releaseBucket(bucket) {
|
|
420
|
+
if (bucket.size > 0) return;
|
|
421
|
+
this.slots.delete(bucket.key);
|
|
422
|
+
if (bucket.hasSubscribers()) {
|
|
423
|
+
this.reservedBuckets.set(bucket.key, bucket);
|
|
424
|
+
} else {
|
|
425
|
+
this.reservedBuckets.delete(bucket.key);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
dropIfReserved(key) {
|
|
429
|
+
const reserved = this.reservedBuckets.get(key);
|
|
430
|
+
if (reserved && reserved.size === 0 && !reserved.hasSubscribers()) {
|
|
431
|
+
this.reservedBuckets.delete(key);
|
|
432
|
+
}
|
|
366
433
|
}
|
|
367
434
|
setOneByKey(key, slots) {
|
|
368
|
-
this.
|
|
435
|
+
const bucket = this.getOrReserveBucket(key);
|
|
436
|
+
if (bucket !== slots) {
|
|
437
|
+
bucket.clear();
|
|
438
|
+
for (const slot of slots) bucket.add(slot);
|
|
439
|
+
}
|
|
440
|
+
if (bucket.size > 0) this.retainBucket(bucket);
|
|
441
|
+
else this.releaseBucket(bucket);
|
|
369
442
|
}
|
|
370
443
|
removeOneByKey(key) {
|
|
371
444
|
this.slots.delete(key);
|
|
445
|
+
this.reservedBuckets.delete(key);
|
|
372
446
|
}
|
|
373
447
|
removeManyByKeys(keys) {
|
|
374
448
|
for (const key of keys) {
|
|
375
449
|
this.slots.delete(key);
|
|
450
|
+
this.reservedBuckets.delete(key);
|
|
376
451
|
}
|
|
377
452
|
}
|
|
378
453
|
getOneByKey(key) {
|
|
@@ -381,10 +456,8 @@ var OIMIndexStoreMapDrivenSetBased = class extends OIMIndexStoreSetBased {
|
|
|
381
456
|
getManyByKeys(keys) {
|
|
382
457
|
const result = /* @__PURE__ */ new Map();
|
|
383
458
|
for (const key of keys) {
|
|
384
|
-
const slots = this.
|
|
385
|
-
if (slots !== void 0)
|
|
386
|
-
result.set(key, slots);
|
|
387
|
-
}
|
|
459
|
+
const slots = this.slots.get(key);
|
|
460
|
+
if (slots !== void 0) result.set(key, slots);
|
|
388
461
|
}
|
|
389
462
|
return result;
|
|
390
463
|
}
|
|
@@ -398,6 +471,12 @@ var OIMIndexStoreMapDrivenSetBased = class extends OIMIndexStoreSetBased {
|
|
|
398
471
|
return this.slots.size;
|
|
399
472
|
}
|
|
400
473
|
clear() {
|
|
474
|
+
for (const bucket of this.slots.values()) {
|
|
475
|
+
bucket.clear();
|
|
476
|
+
if (bucket.hasSubscribers()) {
|
|
477
|
+
this.reservedBuckets.set(bucket.key, bucket);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
401
480
|
this.slots.clear();
|
|
402
481
|
}
|
|
403
482
|
};
|
|
@@ -405,10 +484,9 @@ var OIMIndexStoreMapDrivenSetBased = class extends OIMIndexStoreSetBased {
|
|
|
405
484
|
// src/abstract/OIMIndexSetBased.ts
|
|
406
485
|
var OIMIndexSetBased = class extends OIMIndex {
|
|
407
486
|
constructor(options = {}) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
);
|
|
487
|
+
const store = options.store ?? new OIMIndexStoreMapDrivenSetBased();
|
|
488
|
+
super(store, options.comparePks);
|
|
489
|
+
this.setStore = store;
|
|
412
490
|
}
|
|
413
491
|
getBucketSize(bucket) {
|
|
414
492
|
return bucket.size;
|
|
@@ -436,22 +514,36 @@ var OIMIndexSetBased = class extends OIMIndex {
|
|
|
436
514
|
for (const slot of slots) pks.add(slot.pk);
|
|
437
515
|
return pks;
|
|
438
516
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
517
|
+
/**
|
|
518
|
+
* True if a comparator is set and considers `bucket`'s current pks equal to
|
|
519
|
+
* `newSlots` — i.e. a `setSlots` would be a no-op and should not emit.
|
|
520
|
+
*/
|
|
521
|
+
bucketMatchesComparator(bucket, newSlots) {
|
|
522
|
+
if (!this.comparePks) return false;
|
|
523
|
+
if (bucket.size !== newSlots.size) return false;
|
|
524
|
+
if (bucket.size === 0) return true;
|
|
525
|
+
return this.comparePks(
|
|
526
|
+
Array.from(this.slotsToPks(bucket)),
|
|
527
|
+
Array.from(this.slotsToPks(newSlots))
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
// src/core/OIMKeyedBucketArrayBased.ts
|
|
533
|
+
var OIMKeyedBucketArrayBased = class extends Array {
|
|
534
|
+
constructor(key) {
|
|
535
|
+
super();
|
|
536
|
+
this.key = key;
|
|
537
|
+
}
|
|
538
|
+
static get [Symbol.species]() {
|
|
539
|
+
return Array;
|
|
540
|
+
}
|
|
541
|
+
hasSubscribers() {
|
|
542
|
+
return this.subscribers !== void 0 && this.subscribers.size > 0;
|
|
543
|
+
}
|
|
544
|
+
/** Empty the bucket in place (Array has no `clear`). */
|
|
545
|
+
clear() {
|
|
546
|
+
this.length = 0;
|
|
455
547
|
}
|
|
456
548
|
};
|
|
457
549
|
|
|
@@ -459,17 +551,61 @@ var OIMIndexSetBased = class extends OIMIndex {
|
|
|
459
551
|
var OIMIndexStoreMapDrivenArrayBased = class extends OIMIndexStoreArrayBased {
|
|
460
552
|
constructor() {
|
|
461
553
|
super(...arguments);
|
|
554
|
+
// Live buckets (non-empty). Enumeration reads these only.
|
|
462
555
|
this.slots = /* @__PURE__ */ new Map();
|
|
556
|
+
// Empty buckets kept alive by their subscribers, invisible to reads.
|
|
557
|
+
this.reservedBuckets = /* @__PURE__ */ new Map();
|
|
558
|
+
}
|
|
559
|
+
getOrReserveBucket(key) {
|
|
560
|
+
const live = this.slots.get(key);
|
|
561
|
+
if (live) return live;
|
|
562
|
+
let reserved = this.reservedBuckets.get(key);
|
|
563
|
+
if (!reserved) {
|
|
564
|
+
reserved = new OIMKeyedBucketArrayBased(key);
|
|
565
|
+
this.reservedBuckets.set(key, reserved);
|
|
566
|
+
}
|
|
567
|
+
return reserved;
|
|
568
|
+
}
|
|
569
|
+
findBucket(key) {
|
|
570
|
+
return this.slots.get(key) ?? this.reservedBuckets.get(key);
|
|
571
|
+
}
|
|
572
|
+
retainBucket(bucket) {
|
|
573
|
+
if (bucket.length === 0) return;
|
|
574
|
+
this.reservedBuckets.delete(bucket.key);
|
|
575
|
+
if (!this.slots.has(bucket.key)) this.slots.set(bucket.key, bucket);
|
|
576
|
+
}
|
|
577
|
+
releaseBucket(bucket) {
|
|
578
|
+
if (bucket.length > 0) return;
|
|
579
|
+
this.slots.delete(bucket.key);
|
|
580
|
+
if (bucket.hasSubscribers()) {
|
|
581
|
+
this.reservedBuckets.set(bucket.key, bucket);
|
|
582
|
+
} else {
|
|
583
|
+
this.reservedBuckets.delete(bucket.key);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
dropIfReserved(key) {
|
|
587
|
+
const reserved = this.reservedBuckets.get(key);
|
|
588
|
+
if (reserved && reserved.length === 0 && !reserved.hasSubscribers()) {
|
|
589
|
+
this.reservedBuckets.delete(key);
|
|
590
|
+
}
|
|
463
591
|
}
|
|
464
592
|
setOneByKey(key, slots) {
|
|
465
|
-
this.
|
|
593
|
+
const bucket = this.getOrReserveBucket(key);
|
|
594
|
+
if (bucket !== slots) {
|
|
595
|
+
bucket.length = 0;
|
|
596
|
+
for (let i = 0; i < slots.length; i++) bucket.push(slots[i]);
|
|
597
|
+
}
|
|
598
|
+
if (bucket.length > 0) this.retainBucket(bucket);
|
|
599
|
+
else this.releaseBucket(bucket);
|
|
466
600
|
}
|
|
467
601
|
removeOneByKey(key) {
|
|
468
602
|
this.slots.delete(key);
|
|
603
|
+
this.reservedBuckets.delete(key);
|
|
469
604
|
}
|
|
470
605
|
removeManyByKeys(keys) {
|
|
471
606
|
for (const key of keys) {
|
|
472
607
|
this.slots.delete(key);
|
|
608
|
+
this.reservedBuckets.delete(key);
|
|
473
609
|
}
|
|
474
610
|
}
|
|
475
611
|
getOneByKey(key) {
|
|
@@ -478,10 +614,8 @@ var OIMIndexStoreMapDrivenArrayBased = class extends OIMIndexStoreArrayBased {
|
|
|
478
614
|
getManyByKeys(keys) {
|
|
479
615
|
const result = /* @__PURE__ */ new Map();
|
|
480
616
|
for (const key of keys) {
|
|
481
|
-
const slots = this.
|
|
482
|
-
if (slots !== void 0)
|
|
483
|
-
result.set(key, slots);
|
|
484
|
-
}
|
|
617
|
+
const slots = this.slots.get(key);
|
|
618
|
+
if (slots !== void 0) result.set(key, slots);
|
|
485
619
|
}
|
|
486
620
|
return result;
|
|
487
621
|
}
|
|
@@ -495,6 +629,12 @@ var OIMIndexStoreMapDrivenArrayBased = class extends OIMIndexStoreArrayBased {
|
|
|
495
629
|
return this.slots.size;
|
|
496
630
|
}
|
|
497
631
|
clear() {
|
|
632
|
+
for (const bucket of this.slots.values()) {
|
|
633
|
+
bucket.length = 0;
|
|
634
|
+
if (bucket.hasSubscribers()) {
|
|
635
|
+
this.reservedBuckets.set(bucket.key, bucket);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
498
638
|
this.slots.clear();
|
|
499
639
|
}
|
|
500
640
|
};
|
|
@@ -502,10 +642,9 @@ var OIMIndexStoreMapDrivenArrayBased = class extends OIMIndexStoreArrayBased {
|
|
|
502
642
|
// src/abstract/OIMIndexArrayBased.ts
|
|
503
643
|
var OIMIndexArrayBased = class extends OIMIndex {
|
|
504
644
|
constructor(options = {}) {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
);
|
|
645
|
+
const store = options.store ?? new OIMIndexStoreMapDrivenArrayBased();
|
|
646
|
+
super(store, options.comparePks);
|
|
647
|
+
this.arrayStore = store;
|
|
509
648
|
}
|
|
510
649
|
getBucketSize(bucket) {
|
|
511
650
|
return bucket.length;
|
|
@@ -523,10 +662,15 @@ var OIMIndexArrayBased = class extends OIMIndex {
|
|
|
523
662
|
return result;
|
|
524
663
|
}
|
|
525
664
|
getSlotsByKey(key) {
|
|
526
|
-
|
|
665
|
+
const bucket = this.store.getOneByKey(key);
|
|
666
|
+
return bucket ? bucket.slice() : [];
|
|
527
667
|
}
|
|
528
668
|
getSlotsByKeys(keys) {
|
|
529
|
-
|
|
669
|
+
const result = /* @__PURE__ */ new Map();
|
|
670
|
+
for (const [key, bucket] of this.store.getManyByKeys(keys)) {
|
|
671
|
+
result.set(key, bucket.slice());
|
|
672
|
+
}
|
|
673
|
+
return result;
|
|
530
674
|
}
|
|
531
675
|
slotsToPks(slots) {
|
|
532
676
|
const pks = [];
|
|
@@ -534,28 +678,24 @@ var OIMIndexArrayBased = class extends OIMIndex {
|
|
|
534
678
|
for (let i = 0; i < slots.length; i++) pks[i] = slots[i].pk;
|
|
535
679
|
return pks;
|
|
536
680
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
this.store.setOneByKey(key, newSlots);
|
|
552
|
-
return true;
|
|
681
|
+
/**
|
|
682
|
+
* True if a comparator is set and considers `bucket`'s pks equal to
|
|
683
|
+
* `newSlots` — i.e. a `setSlots` would be a no-op and should not emit.
|
|
684
|
+
*/
|
|
685
|
+
bucketMatchesComparator(bucket, newSlots) {
|
|
686
|
+
if (!this.comparePks) return false;
|
|
687
|
+
if (bucket.length !== newSlots.length) return false;
|
|
688
|
+
if (bucket.length === 0) return true;
|
|
689
|
+
return this.comparePks(
|
|
690
|
+
this.slotsToPks(bucket),
|
|
691
|
+
this.slotsToPks(newSlots)
|
|
692
|
+
);
|
|
553
693
|
}
|
|
554
694
|
};
|
|
555
695
|
|
|
556
696
|
// src/core/OIMCarrierKeyedEmitter.ts
|
|
557
697
|
var OIMCarrierKeyedEmitter = class {
|
|
558
|
-
constructor(queue,
|
|
698
|
+
constructor(queue, carrierProvider) {
|
|
559
699
|
// Carriers with at least one subscriber — for markAllUpdated / metrics.
|
|
560
700
|
this.subscribedCarriers = /* @__PURE__ */ new Set();
|
|
561
701
|
// Pending flush batch. A plain array + a `carrier.dirty` flag for dedup —
|
|
@@ -580,17 +720,17 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
580
720
|
}
|
|
581
721
|
};
|
|
582
722
|
this.queue = queue;
|
|
583
|
-
this.
|
|
723
|
+
this.carrierProvider = carrierProvider;
|
|
584
724
|
}
|
|
585
725
|
subscribeOnKey(key, handler) {
|
|
586
|
-
const carrier = this.
|
|
726
|
+
const carrier = this.carrierProvider.getOrReserveCarrier(key);
|
|
587
727
|
this.addHandler(carrier, handler);
|
|
588
728
|
return () => this.removeHandler(carrier, handler);
|
|
589
729
|
}
|
|
590
730
|
subscribeOnKeys(keys, handler) {
|
|
591
731
|
const carriers = [];
|
|
592
732
|
for (let i = 0; i < keys.length; i++) {
|
|
593
|
-
const carrier = this.
|
|
733
|
+
const carrier = this.carrierProvider.getOrReserveCarrier(keys[i]);
|
|
594
734
|
this.addHandler(carrier, handler);
|
|
595
735
|
carriers.push(carrier);
|
|
596
736
|
}
|
|
@@ -601,7 +741,7 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
601
741
|
};
|
|
602
742
|
}
|
|
603
743
|
unsubscribeFromKey(key, handler) {
|
|
604
|
-
const carrier = this.
|
|
744
|
+
const carrier = this.carrierProvider.findCarrier(key);
|
|
605
745
|
if (carrier) this.removeHandler(carrier, handler);
|
|
606
746
|
}
|
|
607
747
|
unsubscribeFromKeys(keys, handler) {
|
|
@@ -624,7 +764,7 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
624
764
|
subscribers.delete(handler);
|
|
625
765
|
if (subscribers.size === 0) {
|
|
626
766
|
this.subscribedCarriers.delete(carrier);
|
|
627
|
-
this.
|
|
767
|
+
this.carrierProvider.onCarrierEmptied?.(carrier);
|
|
628
768
|
}
|
|
629
769
|
}
|
|
630
770
|
/** Fast path: the writer already holds the carrier. */
|
|
@@ -638,11 +778,19 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
638
778
|
this.scheduleFlush();
|
|
639
779
|
}
|
|
640
780
|
markUpdatedKey(key) {
|
|
641
|
-
|
|
781
|
+
if (this.subscribedCarriers.size === 0) {
|
|
782
|
+
this.assertNotInFlush();
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
const carrier = this.carrierProvider.findCarrier(key);
|
|
642
786
|
if (carrier) this.markUpdatedCarrier(carrier);
|
|
643
787
|
else this.assertNotInFlush();
|
|
644
788
|
}
|
|
645
789
|
markUpdatedKeys(keys) {
|
|
790
|
+
if (this.subscribedCarriers.size === 0) {
|
|
791
|
+
this.assertNotInFlush();
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
646
794
|
for (let i = 0; i < keys.length; i++) this.markUpdatedKey(keys[i]);
|
|
647
795
|
}
|
|
648
796
|
markAllUpdated() {
|
|
@@ -659,7 +807,7 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
659
807
|
return this.subscribedCarriers.size > 0;
|
|
660
808
|
}
|
|
661
809
|
getHandlerCount(key) {
|
|
662
|
-
return this.
|
|
810
|
+
return this.carrierProvider.findCarrier(key)?.subscribers?.size ?? 0;
|
|
663
811
|
}
|
|
664
812
|
getMetrics() {
|
|
665
813
|
let totalHandlers = 0;
|
|
@@ -719,8 +867,8 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
719
867
|
}
|
|
720
868
|
};
|
|
721
869
|
|
|
722
|
-
// src/core/
|
|
723
|
-
var
|
|
870
|
+
// src/core/OIMKeyedCarrierProvider.ts
|
|
871
|
+
var OIMKeyedCarrierProvider = class {
|
|
724
872
|
constructor() {
|
|
725
873
|
this.carriers = /* @__PURE__ */ new Map();
|
|
726
874
|
}
|
|
@@ -742,8 +890,8 @@ var OIMKeyedCarrierResolver = class {
|
|
|
742
890
|
|
|
743
891
|
// src/abstract/OIMReactiveIndex.ts
|
|
744
892
|
var OIMReactiveIndex = class {
|
|
745
|
-
constructor(queue, createIndex) {
|
|
746
|
-
this.updateEmitter = new OIMCarrierKeyedEmitter(queue,
|
|
893
|
+
constructor(queue, createIndex, createCarrierProvider = () => new OIMKeyedCarrierProvider()) {
|
|
894
|
+
this.updateEmitter = new OIMCarrierKeyedEmitter(queue, createCarrierProvider());
|
|
747
895
|
this.index = createIndex(this.updateEmitter);
|
|
748
896
|
}
|
|
749
897
|
getEntitiesByKey(key) {
|
|
@@ -799,8 +947,8 @@ var OIMReactiveIndex = class {
|
|
|
799
947
|
|
|
800
948
|
// src/abstract/OIMReactiveIndexSetBased.ts
|
|
801
949
|
var OIMReactiveIndexSetBased = class extends OIMReactiveIndex {
|
|
802
|
-
constructor(queue, createIndex) {
|
|
803
|
-
super(queue, createIndex);
|
|
950
|
+
constructor(queue, createIndex, createCarrierProvider) {
|
|
951
|
+
super(queue, createIndex, createCarrierProvider);
|
|
804
952
|
}
|
|
805
953
|
getPksByKey(key) {
|
|
806
954
|
return this.index.getPksByKey(key);
|
|
@@ -818,8 +966,8 @@ var OIMReactiveIndexSetBased = class extends OIMReactiveIndex {
|
|
|
818
966
|
|
|
819
967
|
// src/abstract/OIMReactiveIndexArrayBased.ts
|
|
820
968
|
var OIMReactiveIndexArrayBased = class extends OIMReactiveIndex {
|
|
821
|
-
constructor(queue, createIndex) {
|
|
822
|
-
super(queue, createIndex);
|
|
969
|
+
constructor(queue, createIndex, createCarrierProvider) {
|
|
970
|
+
super(queue, createIndex, createCarrierProvider);
|
|
823
971
|
}
|
|
824
972
|
getPksByKey(key) {
|
|
825
973
|
return this.index.getPksByKey(key);
|
|
@@ -1282,6 +1430,14 @@ var OIMCollection = class {
|
|
|
1282
1430
|
getOrReserveSlotByPk(pk) {
|
|
1283
1431
|
return this.store.getOrReserveSlotByPk(pk);
|
|
1284
1432
|
}
|
|
1433
|
+
/**
|
|
1434
|
+
* The existing slot for `pk` (live or reserved) WITHOUT creating one — used
|
|
1435
|
+
* by indexes to resolve a pk to its canonical slot for removal (delete by
|
|
1436
|
+
* reference), with no side effect for a pk that is not present.
|
|
1437
|
+
*/
|
|
1438
|
+
findSlotByPk(pk) {
|
|
1439
|
+
return this.store.findSlotByPk(pk);
|
|
1440
|
+
}
|
|
1285
1441
|
getSlotsByPks(pks) {
|
|
1286
1442
|
return this.store.getSlotsByPks(pks);
|
|
1287
1443
|
}
|
|
@@ -1350,15 +1506,12 @@ var OIMCollection = class {
|
|
|
1350
1506
|
`[OIMCollection]: PK is required to upsert an entity ${JSON.stringify(entity)}`
|
|
1351
1507
|
);
|
|
1352
1508
|
}
|
|
1353
|
-
const
|
|
1354
|
-
if (
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
this.updateEntity(entity, existingEntity)
|
|
1358
|
-
);
|
|
1359
|
-
} else {
|
|
1360
|
-
return this.store.setOneByPk(pk, entity);
|
|
1509
|
+
const slot = this.store.getSlotByPk(pk);
|
|
1510
|
+
if (slot !== void 0 && slot.item !== void 0) {
|
|
1511
|
+
slot.item = this.updateEntity(entity, slot.item);
|
|
1512
|
+
return slot;
|
|
1361
1513
|
}
|
|
1514
|
+
return this.store.setOneByPk(pk, entity);
|
|
1362
1515
|
}
|
|
1363
1516
|
destroy() {
|
|
1364
1517
|
this.store.destroy();
|
|
@@ -1371,13 +1524,15 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1371
1524
|
constructor(queue, opts) {
|
|
1372
1525
|
super(opts);
|
|
1373
1526
|
this.anyUpdateHandlers = /* @__PURE__ */ new Set();
|
|
1527
|
+
// Only ever holds `slot.pk` (one canonical reference per logical key), so a
|
|
1528
|
+
// native `Set` dedups correctly by reference even for composite pks.
|
|
1374
1529
|
this.pendingAnyUpdatePks = /* @__PURE__ */ new Set();
|
|
1375
1530
|
this.isAnyUpdateClearPending = false;
|
|
1376
1531
|
this.isAnyUpdateScheduled = false;
|
|
1377
1532
|
this.runAnyUpdate = () => {
|
|
1378
1533
|
if (!this.isAnyUpdateScheduled) return;
|
|
1379
1534
|
this.isAnyUpdateScheduled = false;
|
|
1380
|
-
const pks = this.isAnyUpdateClearPending ? [] : Array.from(this.pendingAnyUpdatePks);
|
|
1535
|
+
const pks = this.isAnyUpdateClearPending ? [] : Array.from(this.pendingAnyUpdatePks.values());
|
|
1381
1536
|
this.pendingAnyUpdatePks.clear();
|
|
1382
1537
|
this.isAnyUpdateClearPending = false;
|
|
1383
1538
|
const snapshot = Array.from(this.anyUpdateHandlers);
|
|
@@ -1536,38 +1691,40 @@ var OIMIndexManualOrderedArrayBased = class extends OIMIndexArrayBased {
|
|
|
1536
1691
|
if (key === void 0) {
|
|
1537
1692
|
const keys = this.getKeys();
|
|
1538
1693
|
if (keys.length > 0) {
|
|
1539
|
-
this.
|
|
1694
|
+
this.arrayStore.clear();
|
|
1540
1695
|
this.emitUpdate(Array.from(keys));
|
|
1541
1696
|
}
|
|
1542
1697
|
return;
|
|
1543
1698
|
}
|
|
1544
|
-
|
|
1545
|
-
|
|
1699
|
+
const bucket = this.arrayStore.findBucket(key);
|
|
1700
|
+
if (bucket && bucket.length > 0) {
|
|
1701
|
+
bucket.length = 0;
|
|
1702
|
+
this.arrayStore.releaseBucket(bucket);
|
|
1546
1703
|
this.emitUpdate([key]);
|
|
1547
1704
|
}
|
|
1548
1705
|
}
|
|
1549
1706
|
pushSlot(key, slot) {
|
|
1550
|
-
const
|
|
1551
|
-
const index =
|
|
1552
|
-
|
|
1707
|
+
const bucket = this.arrayStore.getOrReserveBucket(key);
|
|
1708
|
+
const index = bucket.length;
|
|
1709
|
+
bucket.push(slot);
|
|
1710
|
+
this.arrayStore.retainBucket(bucket);
|
|
1553
1711
|
this.emitUpdate([key]);
|
|
1554
1712
|
return index;
|
|
1555
1713
|
}
|
|
1556
1714
|
insertSlotAt(key, index, slot) {
|
|
1557
|
-
const
|
|
1558
|
-
const safeIndex = Math.max(0, Math.min(index,
|
|
1559
|
-
|
|
1715
|
+
const bucket = this.arrayStore.getOrReserveBucket(key);
|
|
1716
|
+
const safeIndex = Math.max(0, Math.min(index, bucket.length));
|
|
1717
|
+
bucket.splice(safeIndex, 0, slot);
|
|
1718
|
+
this.arrayStore.retainBucket(bucket);
|
|
1560
1719
|
this.emitUpdate([key]);
|
|
1561
1720
|
return safeIndex;
|
|
1562
1721
|
}
|
|
1563
1722
|
removeAt(key, index) {
|
|
1564
|
-
const
|
|
1565
|
-
if (!
|
|
1566
|
-
if (index < 0 || index >=
|
|
1567
|
-
const [removed] =
|
|
1568
|
-
if (
|
|
1569
|
-
this.store.removeOneByKey(key);
|
|
1570
|
-
}
|
|
1723
|
+
const bucket = this.arrayStore.findBucket(key);
|
|
1724
|
+
if (!bucket) return void 0;
|
|
1725
|
+
if (index < 0 || index >= bucket.length) return void 0;
|
|
1726
|
+
const [removed] = bucket.splice(index, 1);
|
|
1727
|
+
if (bucket.length === 0) this.arrayStore.releaseBucket(bucket);
|
|
1571
1728
|
this.emitUpdate([key]);
|
|
1572
1729
|
return removed;
|
|
1573
1730
|
}
|
|
@@ -1576,35 +1733,33 @@ var OIMIndexManualOrderedArrayBased = class extends OIMIndexArrayBased {
|
|
|
1576
1733
|
* Returns the number actually removed (clamped to bounds; 0 if nothing).
|
|
1577
1734
|
*/
|
|
1578
1735
|
removeRange(key, index, count) {
|
|
1579
|
-
const
|
|
1580
|
-
if (!
|
|
1581
|
-
if (index < 0 || index >=
|
|
1582
|
-
const actual = Math.min(count,
|
|
1583
|
-
|
|
1584
|
-
if (
|
|
1585
|
-
this.store.removeOneByKey(key);
|
|
1586
|
-
}
|
|
1736
|
+
const bucket = this.arrayStore.findBucket(key);
|
|
1737
|
+
if (!bucket) return 0;
|
|
1738
|
+
if (index < 0 || index >= bucket.length || count <= 0) return 0;
|
|
1739
|
+
const actual = Math.min(count, bucket.length - index);
|
|
1740
|
+
bucket.splice(index, actual);
|
|
1741
|
+
if (bucket.length === 0) this.arrayStore.releaseBucket(bucket);
|
|
1587
1742
|
this.emitUpdate([key]);
|
|
1588
1743
|
return actual;
|
|
1589
1744
|
}
|
|
1590
1745
|
move(key, fromIndex, toIndex) {
|
|
1591
|
-
const
|
|
1592
|
-
if (!
|
|
1593
|
-
if (fromIndex < 0 || fromIndex >=
|
|
1594
|
-
if (toIndex < 0 || toIndex >=
|
|
1595
|
-
if (fromIndex === toIndex) return
|
|
1596
|
-
const [slot] =
|
|
1746
|
+
const bucket = this.arrayStore.findBucket(key);
|
|
1747
|
+
if (!bucket) return void 0;
|
|
1748
|
+
if (fromIndex < 0 || fromIndex >= bucket.length) return void 0;
|
|
1749
|
+
if (toIndex < 0 || toIndex >= bucket.length) return void 0;
|
|
1750
|
+
if (fromIndex === toIndex) return bucket[fromIndex];
|
|
1751
|
+
const [slot] = bucket.splice(fromIndex, 1);
|
|
1597
1752
|
if (slot === void 0) return void 0;
|
|
1598
|
-
|
|
1753
|
+
bucket.splice(toIndex, 0, slot);
|
|
1599
1754
|
this.emitUpdate([key]);
|
|
1600
1755
|
return slot;
|
|
1601
1756
|
}
|
|
1602
1757
|
/** Replace the slot at `index` in place. Returns the safe index, or -1. */
|
|
1603
1758
|
setSlotAt(key, index, slot) {
|
|
1604
|
-
const
|
|
1605
|
-
if (!
|
|
1606
|
-
if (index < 0 || index >=
|
|
1607
|
-
|
|
1759
|
+
const bucket = this.arrayStore.findBucket(key);
|
|
1760
|
+
if (!bucket) return -1;
|
|
1761
|
+
if (index < 0 || index >= bucket.length) return -1;
|
|
1762
|
+
bucket[index] = slot;
|
|
1608
1763
|
this.emitUpdate([key]);
|
|
1609
1764
|
return index;
|
|
1610
1765
|
}
|
|
@@ -1614,52 +1769,49 @@ var OIMIndexManualOrderedArrayBased = class extends OIMIndexArrayBased {
|
|
|
1614
1769
|
* Returns the number actually moved (0 if a no-op / out of bounds).
|
|
1615
1770
|
*/
|
|
1616
1771
|
moveRange(key, from, to, count) {
|
|
1617
|
-
const
|
|
1618
|
-
if (!
|
|
1619
|
-
if (from < 0 || from >=
|
|
1620
|
-
const actual = Math.min(count,
|
|
1621
|
-
const insertAt = Math.max(0, Math.min(to,
|
|
1772
|
+
const bucket = this.arrayStore.findBucket(key);
|
|
1773
|
+
if (!bucket) return 0;
|
|
1774
|
+
if (from < 0 || from >= bucket.length || count <= 0) return 0;
|
|
1775
|
+
const actual = Math.min(count, bucket.length - from);
|
|
1776
|
+
const insertAt = Math.max(0, Math.min(to, bucket.length - actual));
|
|
1622
1777
|
if (insertAt === from) return 0;
|
|
1623
|
-
const block =
|
|
1624
|
-
|
|
1778
|
+
const block = bucket.splice(from, actual);
|
|
1779
|
+
bucket.splice(insertAt, 0, ...block);
|
|
1625
1780
|
this.emitUpdate([key]);
|
|
1626
1781
|
return actual;
|
|
1627
1782
|
}
|
|
1628
1783
|
resetSlots(key, slots) {
|
|
1629
1784
|
if (slots.length === 0) {
|
|
1630
|
-
|
|
1631
|
-
|
|
1785
|
+
const bucket2 = this.arrayStore.findBucket(key);
|
|
1786
|
+
if (bucket2 && bucket2.length > 0) {
|
|
1787
|
+
bucket2.length = 0;
|
|
1788
|
+
this.arrayStore.releaseBucket(bucket2);
|
|
1632
1789
|
this.emitUpdate([key]);
|
|
1633
1790
|
}
|
|
1634
1791
|
return;
|
|
1635
1792
|
}
|
|
1636
|
-
this.
|
|
1793
|
+
const bucket = this.arrayStore.getOrReserveBucket(key);
|
|
1794
|
+
bucket.length = 0;
|
|
1795
|
+
for (let i = 0; i < slots.length; i++) bucket.push(slots[i]);
|
|
1796
|
+
this.arrayStore.retainBucket(bucket);
|
|
1637
1797
|
this.emitUpdate([key]);
|
|
1638
1798
|
}
|
|
1639
|
-
getOrCreateList(key) {
|
|
1640
|
-
let list = this.store.getOneByKey(key);
|
|
1641
|
-
if (!list) {
|
|
1642
|
-
list = [];
|
|
1643
|
-
this.store.setOneByKey(key, list);
|
|
1644
|
-
}
|
|
1645
|
-
return list;
|
|
1646
|
-
}
|
|
1647
1799
|
};
|
|
1648
1800
|
|
|
1649
1801
|
// src/core/OIMCollectionIndexManualOrderedArrayBased.ts
|
|
1650
1802
|
var OIMCollectionIndexManualOrderedArrayBased = class extends OIMIndexManualOrderedArrayBased {
|
|
1651
1803
|
constructor(opts) {
|
|
1652
1804
|
super();
|
|
1653
|
-
this.
|
|
1805
|
+
this.getSlot = opts.collection !== void 0 ? (pk) => opts.collection.getSlotByPk(pk) : opts.getSlot;
|
|
1654
1806
|
}
|
|
1655
1807
|
push(key, pk) {
|
|
1656
|
-
return this.pushSlot(key, this.
|
|
1808
|
+
return this.pushSlot(key, this.getRequiredSlot(pk));
|
|
1657
1809
|
}
|
|
1658
1810
|
insertAt(key, index, pk) {
|
|
1659
|
-
return this.insertSlotAt(key, index, this.
|
|
1811
|
+
return this.insertSlotAt(key, index, this.getRequiredSlot(pk));
|
|
1660
1812
|
}
|
|
1661
1813
|
reset(key, pks) {
|
|
1662
|
-
this.resetSlots(key, this.
|
|
1814
|
+
this.resetSlots(key, this.getRequiredSlots(pks));
|
|
1663
1815
|
}
|
|
1664
1816
|
getEntitiesByKey(key) {
|
|
1665
1817
|
return super.getEntitiesByKey(key);
|
|
@@ -1667,26 +1819,25 @@ var OIMCollectionIndexManualOrderedArrayBased = class extends OIMIndexManualOrde
|
|
|
1667
1819
|
getEntitiesByKeys(keys) {
|
|
1668
1820
|
return super.getEntitiesByKeys(keys);
|
|
1669
1821
|
}
|
|
1670
|
-
|
|
1671
|
-
|
|
1822
|
+
// Gets the slot for a pk, throwing if the (custom) getter has none — this
|
|
1823
|
+
// ordered index requires a real slot to place in order.
|
|
1824
|
+
getRequiredSlot(pk) {
|
|
1825
|
+
const slot = this.getSlot(pk);
|
|
1826
|
+
if (!slot) {
|
|
1827
|
+
throw new Error(
|
|
1828
|
+
`[OIMCollectionIndexManualOrderedArrayBased]: no slot for PK "${String(pk)}".`
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1831
|
+
return slot;
|
|
1672
1832
|
}
|
|
1673
|
-
|
|
1833
|
+
getRequiredSlots(pks) {
|
|
1674
1834
|
const slots = [];
|
|
1675
1835
|
slots.length = pks.length;
|
|
1676
1836
|
for (let i = 0; i < pks.length; i++) {
|
|
1677
|
-
slots[i] = this.
|
|
1837
|
+
slots[i] = this.getRequiredSlot(pks[i]);
|
|
1678
1838
|
}
|
|
1679
1839
|
return slots;
|
|
1680
1840
|
}
|
|
1681
|
-
resolveRequiredSlot(pk) {
|
|
1682
|
-
const slot = this.resolveSlot(pk);
|
|
1683
|
-
if (!slot) {
|
|
1684
|
-
throw new Error(
|
|
1685
|
-
`[OIMCollectionIndexManualOrderedArrayBased]: Unable to resolve slot for PK "${String(pk)}".`
|
|
1686
|
-
);
|
|
1687
|
-
}
|
|
1688
|
-
return slot;
|
|
1689
|
-
}
|
|
1690
1841
|
};
|
|
1691
1842
|
|
|
1692
1843
|
// src/enums/EOIMEventQueueEventType.ts
|
|
@@ -2105,18 +2256,18 @@ var OIMOrderedListCommandStream = class extends OIMOrderedListCommandBuffer {
|
|
|
2105
2256
|
var OIMCollectionOrderedListCommandStream = class extends OIMOrderedListCommandStream {
|
|
2106
2257
|
constructor(queue, opts) {
|
|
2107
2258
|
const index = opts.index ?? new OIMCollectionIndexManualOrderedArrayBased(
|
|
2108
|
-
opts.collection !== void 0 ? { collection: opts.collection } : {
|
|
2259
|
+
opts.collection !== void 0 ? { collection: opts.collection } : { getSlot: opts.getSlot }
|
|
2109
2260
|
);
|
|
2110
2261
|
super(queue, index);
|
|
2111
2262
|
this.index = index;
|
|
2112
2263
|
}
|
|
2113
2264
|
push(key, pk) {
|
|
2114
|
-
const slot = this.
|
|
2265
|
+
const slot = this.getRequiredSlot(pk);
|
|
2115
2266
|
const index = this.index.pushSlot(key, slot);
|
|
2116
2267
|
this.appendCommand(key, { type: "insert", index, item: slot });
|
|
2117
2268
|
}
|
|
2118
2269
|
insertAt(key, index, pk) {
|
|
2119
|
-
const slot = this.
|
|
2270
|
+
const slot = this.getRequiredSlot(pk);
|
|
2120
2271
|
const safeIndex = this.index.insertSlotAt(key, index, slot);
|
|
2121
2272
|
this.appendCommand(key, {
|
|
2122
2273
|
type: "insert",
|
|
@@ -2126,7 +2277,7 @@ var OIMCollectionOrderedListCommandStream = class extends OIMOrderedListCommandS
|
|
|
2126
2277
|
}
|
|
2127
2278
|
/** Replace the element at `index` with the slot for `pk`, in place. */
|
|
2128
2279
|
setAt(key, index, pk) {
|
|
2129
|
-
const slot = this.
|
|
2280
|
+
const slot = this.getRequiredSlot(pk);
|
|
2130
2281
|
const safeIndex = this.index.setSlotAt(key, index, slot);
|
|
2131
2282
|
if (safeIndex < 0) return;
|
|
2132
2283
|
this.appendCommand(key, {
|
|
@@ -2136,7 +2287,7 @@ var OIMCollectionOrderedListCommandStream = class extends OIMOrderedListCommandS
|
|
|
2136
2287
|
});
|
|
2137
2288
|
}
|
|
2138
2289
|
set(key, pks) {
|
|
2139
|
-
const slots = pks.map((pk) => this.
|
|
2290
|
+
const slots = pks.map((pk) => this.getRequiredSlot(pk));
|
|
2140
2291
|
this.index.resetSlots(key, slots);
|
|
2141
2292
|
this.appendResetCommand(key, slots);
|
|
2142
2293
|
}
|
|
@@ -2148,8 +2299,8 @@ var OIMCollectionOrderedListCommandStream = class extends OIMOrderedListCommandS
|
|
|
2148
2299
|
getEntitiesByKey(key) {
|
|
2149
2300
|
return this.index.getEntitiesByKey(key);
|
|
2150
2301
|
}
|
|
2151
|
-
|
|
2152
|
-
return this.index.
|
|
2302
|
+
getRequiredSlot(pk) {
|
|
2303
|
+
return this.index.getRequiredSlot(
|
|
2153
2304
|
pk
|
|
2154
2305
|
);
|
|
2155
2306
|
}
|
|
@@ -2161,43 +2312,68 @@ var OIMIndexManualArrayBased = class extends OIMIndexArrayBased {
|
|
|
2161
2312
|
super(options);
|
|
2162
2313
|
}
|
|
2163
2314
|
setSlots(key, slots) {
|
|
2164
|
-
const
|
|
2165
|
-
if (
|
|
2166
|
-
|
|
2167
|
-
|
|
2315
|
+
const bucket = this.arrayStore.getOrReserveBucket(key);
|
|
2316
|
+
if (this.bucketMatchesComparator(bucket, slots)) return;
|
|
2317
|
+
bucket.length = 0;
|
|
2318
|
+
for (let i = 0; i < slots.length; i++) bucket.push(slots[i]);
|
|
2319
|
+
if (bucket.length > 0) this.arrayStore.retainBucket(bucket);
|
|
2320
|
+
else this.arrayStore.releaseBucket(bucket);
|
|
2321
|
+
this.emitBucketChanged(bucket);
|
|
2168
2322
|
}
|
|
2169
2323
|
/**
|
|
2170
|
-
* Appends pre-deduplicated slots to a key's bucket IN PLACE
|
|
2171
|
-
*
|
|
2172
|
-
* not O(bucket)); used by collection-bound indexes for fast `addPks`.
|
|
2324
|
+
* Appends pre-deduplicated slots to a key's bucket IN PLACE and emits once.
|
|
2325
|
+
* O(added); callers own dedup.
|
|
2173
2326
|
*/
|
|
2174
2327
|
appendSlots(key, slots) {
|
|
2175
2328
|
if (slots.length === 0) return;
|
|
2176
|
-
|
|
2177
|
-
if (!bucket) {
|
|
2178
|
-
bucket = [];
|
|
2179
|
-
this.store.setOneByKey(key, bucket);
|
|
2180
|
-
}
|
|
2329
|
+
const bucket = this.arrayStore.getOrReserveBucket(key);
|
|
2181
2330
|
for (let i = 0; i < slots.length; i++) bucket.push(slots[i]);
|
|
2182
|
-
this.
|
|
2331
|
+
this.arrayStore.retainBucket(bucket);
|
|
2332
|
+
this.emitBucketChanged(bucket);
|
|
2183
2333
|
}
|
|
2184
2334
|
/**
|
|
2185
|
-
* Clear all primary keys for a specific index key, or all keys if
|
|
2335
|
+
* Clear all primary keys for a specific index key, or all keys if none given.
|
|
2186
2336
|
*/
|
|
2187
2337
|
clear(key) {
|
|
2188
2338
|
if (key === void 0) {
|
|
2189
|
-
const allKeys = this.
|
|
2339
|
+
const allKeys = this.arrayStore.getAllKeys();
|
|
2190
2340
|
if (allKeys.length > 0) {
|
|
2191
|
-
this.
|
|
2341
|
+
this.arrayStore.clear();
|
|
2192
2342
|
this.emitUpdate(allKeys);
|
|
2193
2343
|
}
|
|
2194
2344
|
} else {
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2345
|
+
const bucket = this.arrayStore.findBucket(key);
|
|
2346
|
+
if (bucket && bucket.length > 0) {
|
|
2347
|
+
bucket.length = 0;
|
|
2348
|
+
this.arrayStore.releaseBucket(bucket);
|
|
2349
|
+
this.emitBucketChanged(bucket);
|
|
2198
2350
|
}
|
|
2199
2351
|
}
|
|
2200
2352
|
}
|
|
2353
|
+
/**
|
|
2354
|
+
* Emit that a bucket changed. Base (non-reactive) path emits by key on the
|
|
2355
|
+
* plain event emitter; the reactive subclass overrides this to mark the
|
|
2356
|
+
* bucket carrier directly (O(1), no key→carrier lookup).
|
|
2357
|
+
*/
|
|
2358
|
+
emitBucketChanged(bucket) {
|
|
2359
|
+
this.emitUpdateOne(bucket.key);
|
|
2360
|
+
}
|
|
2361
|
+
};
|
|
2362
|
+
|
|
2363
|
+
// src/core/OIMBucketCarrierProvider.ts
|
|
2364
|
+
var OIMBucketCarrierProvider = class {
|
|
2365
|
+
constructor(store) {
|
|
2366
|
+
this.store = store;
|
|
2367
|
+
}
|
|
2368
|
+
getOrReserveCarrier(key) {
|
|
2369
|
+
return this.store.getOrReserveBucket(key);
|
|
2370
|
+
}
|
|
2371
|
+
findCarrier(key) {
|
|
2372
|
+
return this.store.findBucket(key);
|
|
2373
|
+
}
|
|
2374
|
+
onCarrierEmptied(carrier) {
|
|
2375
|
+
this.store.dropIfReserved(carrier.key);
|
|
2376
|
+
}
|
|
2201
2377
|
};
|
|
2202
2378
|
|
|
2203
2379
|
// src/core/OIMReactiveIndexManualArrayBased.ts
|
|
@@ -2206,6 +2382,10 @@ var OIMIndexManualArrayBasedReactive = class extends OIMIndexManualArrayBased {
|
|
|
2206
2382
|
super(opts);
|
|
2207
2383
|
this.updateEmitter = updateEmitter;
|
|
2208
2384
|
}
|
|
2385
|
+
// Deliver straight off the bucket the write just touched — O(1).
|
|
2386
|
+
emitBucketChanged(bucket) {
|
|
2387
|
+
this.updateEmitter.markUpdatedCarrier(bucket);
|
|
2388
|
+
}
|
|
2209
2389
|
emitUpdate(keys) {
|
|
2210
2390
|
this.updateEmitter.markUpdatedKeys(keys);
|
|
2211
2391
|
}
|
|
@@ -2215,12 +2395,15 @@ var OIMIndexManualArrayBasedReactive = class extends OIMIndexManualArrayBased {
|
|
|
2215
2395
|
};
|
|
2216
2396
|
var OIMReactiveIndexManualArrayBased = class extends OIMReactiveIndexArrayBased {
|
|
2217
2397
|
constructor(queue, opts) {
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2398
|
+
const store = opts?.indexOptions?.store ?? new OIMIndexStoreMapDrivenArrayBased();
|
|
2399
|
+
super(
|
|
2400
|
+
queue,
|
|
2401
|
+
(updateEmitter) => new OIMIndexManualArrayBasedReactive(updateEmitter, {
|
|
2402
|
+
comparePks: opts?.indexOptions?.comparePks,
|
|
2403
|
+
store
|
|
2404
|
+
}),
|
|
2405
|
+
() => new OIMBucketCarrierProvider(store)
|
|
2406
|
+
);
|
|
2224
2407
|
}
|
|
2225
2408
|
setSlots(key, slots) {
|
|
2226
2409
|
this.index.setSlots(key, slots);
|
|
@@ -2236,50 +2419,61 @@ var OIMReactiveIndexManualArrayBased = class extends OIMReactiveIndexArrayBased
|
|
|
2236
2419
|
// src/core/OIMReactiveCollectionIndexManualArrayBased.ts
|
|
2237
2420
|
var OIMReactiveCollectionIndexManualArrayBased = class extends OIMReactiveIndexManualArrayBased {
|
|
2238
2421
|
constructor(queue, opts) {
|
|
2239
|
-
const
|
|
2422
|
+
const getSlot = opts.collection !== void 0 ? (pk) => opts.collection.getOrReserveSlotByPk(pk) : opts.getSlot;
|
|
2240
2423
|
super(queue, {
|
|
2241
2424
|
indexOptions: opts.indexOptions
|
|
2242
2425
|
});
|
|
2243
|
-
// Persistent per-key
|
|
2244
|
-
//
|
|
2245
|
-
|
|
2246
|
-
this.
|
|
2426
|
+
// Persistent per-key membership for O(1) `addPks` dedup, keyed by the
|
|
2427
|
+
// canonical slot reference (correct for composite pks with a native Set — no
|
|
2428
|
+
// content-addressing needed, since slots are one reference per logical key).
|
|
2429
|
+
this.slotsByKey = /* @__PURE__ */ new Map();
|
|
2430
|
+
this.getSlot = getSlot;
|
|
2431
|
+
this.findSlotForRemoval = opts.collection !== void 0 ? (pk) => opts.collection.findSlotByPk(pk) : opts.getSlot;
|
|
2247
2432
|
}
|
|
2248
2433
|
setPks(key, pks) {
|
|
2249
|
-
const
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
super.setSlots(key, this.resolveSlots(pks));
|
|
2434
|
+
const slots = this.getSlotsOrTransient(pks);
|
|
2435
|
+
this.slotsByKey.set(key, new Set(slots));
|
|
2436
|
+
super.setSlots(key, slots);
|
|
2253
2437
|
}
|
|
2254
2438
|
addPks(key, pks) {
|
|
2255
2439
|
if (pks.length === 0) return;
|
|
2256
|
-
const
|
|
2440
|
+
const slotSet = this.membershipOf(key);
|
|
2257
2441
|
const newSlots = [];
|
|
2258
2442
|
for (const pk of pks) {
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2443
|
+
const slot = this.getSlotOrTransient(pk);
|
|
2444
|
+
if (slotSet.has(slot)) continue;
|
|
2445
|
+
slotSet.add(slot);
|
|
2446
|
+
newSlots.push(slot);
|
|
2262
2447
|
}
|
|
2263
2448
|
if (newSlots.length > 0) this.appendSlots(key, newSlots);
|
|
2264
2449
|
}
|
|
2265
2450
|
removePks(key, pks) {
|
|
2266
2451
|
if (pks.length === 0) return;
|
|
2267
|
-
const
|
|
2452
|
+
const slotsToRemove = /* @__PURE__ */ new Set();
|
|
2453
|
+
const pksToRemove = /* @__PURE__ */ new Set();
|
|
2454
|
+
for (let i = 0; i < pks.length; i++) {
|
|
2455
|
+
const slot = this.findSlotForRemoval(pks[i]);
|
|
2456
|
+
if (slot) slotsToRemove.add(slot);
|
|
2457
|
+
else pksToRemove.add(pks[i]);
|
|
2458
|
+
}
|
|
2268
2459
|
const existingSlots = this.index.getSlotsByKey(key);
|
|
2269
|
-
const
|
|
2270
|
-
|
|
2271
|
-
)
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2460
|
+
const slotSet = this.slotsByKey.get(key);
|
|
2461
|
+
const nextSlots = [];
|
|
2462
|
+
for (let i = 0; i < existingSlots.length; i++) {
|
|
2463
|
+
const slot = existingSlots[i];
|
|
2464
|
+
if (slotsToRemove.has(slot) || pksToRemove.has(slot.pk)) {
|
|
2465
|
+
slotSet?.delete(slot);
|
|
2466
|
+
} else {
|
|
2467
|
+
nextSlots.push(slot);
|
|
2468
|
+
}
|
|
2276
2469
|
}
|
|
2470
|
+
if (nextSlots.length === existingSlots.length) return;
|
|
2277
2471
|
if (nextSlots.length === 0) this.clear(key);
|
|
2278
2472
|
else super.setSlots(key, nextSlots);
|
|
2279
2473
|
}
|
|
2280
2474
|
clear(key) {
|
|
2281
|
-
if (key === void 0) this.
|
|
2282
|
-
else this.
|
|
2475
|
+
if (key === void 0) this.slotsByKey.clear();
|
|
2476
|
+
else this.slotsByKey.delete(key);
|
|
2283
2477
|
super.clear(key);
|
|
2284
2478
|
}
|
|
2285
2479
|
/**
|
|
@@ -2287,16 +2481,12 @@ var OIMReactiveCollectionIndexManualArrayBased = class extends OIMReactiveIndexM
|
|
|
2287
2481
|
* stays correct even if slots were set through a lower-level path.
|
|
2288
2482
|
*/
|
|
2289
2483
|
membershipOf(key) {
|
|
2290
|
-
let
|
|
2291
|
-
if (!
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
for (let i = 0; i < existing.length; i++) {
|
|
2295
|
-
pkSet.add(existing[i].pk);
|
|
2296
|
-
}
|
|
2297
|
-
this.pksByKey.set(key, pkSet);
|
|
2484
|
+
let slotSet = this.slotsByKey.get(key);
|
|
2485
|
+
if (!slotSet) {
|
|
2486
|
+
slotSet = new Set(this.index.getSlotsByKey(key));
|
|
2487
|
+
this.slotsByKey.set(key, slotSet);
|
|
2298
2488
|
}
|
|
2299
|
-
return
|
|
2489
|
+
return slotSet;
|
|
2300
2490
|
}
|
|
2301
2491
|
getEntitiesByKey(key) {
|
|
2302
2492
|
return super.getEntitiesByKey(key);
|
|
@@ -2304,16 +2494,16 @@ var OIMReactiveCollectionIndexManualArrayBased = class extends OIMReactiveIndexM
|
|
|
2304
2494
|
getEntitiesByKeys(keys) {
|
|
2305
2495
|
return super.getEntitiesByKeys(keys);
|
|
2306
2496
|
}
|
|
2307
|
-
|
|
2497
|
+
getSlotsOrTransient(pks) {
|
|
2308
2498
|
const slots = [];
|
|
2309
2499
|
slots.length = pks.length;
|
|
2310
2500
|
for (let i = 0; i < pks.length; i++) {
|
|
2311
|
-
slots[i] = this.
|
|
2501
|
+
slots[i] = this.getSlotOrTransient(pks[i]);
|
|
2312
2502
|
}
|
|
2313
2503
|
return slots;
|
|
2314
2504
|
}
|
|
2315
|
-
|
|
2316
|
-
const slot = this.
|
|
2505
|
+
getSlotOrTransient(pk) {
|
|
2506
|
+
const slot = this.getSlot(pk);
|
|
2317
2507
|
if (!slot) return { pk, item: void 0 };
|
|
2318
2508
|
return slot;
|
|
2319
2509
|
}
|
|
@@ -2325,22 +2515,101 @@ var OIMIndexManualSetBased = class extends OIMIndexSetBased {
|
|
|
2325
2515
|
super(options);
|
|
2326
2516
|
}
|
|
2327
2517
|
setSlots(key, slots) {
|
|
2328
|
-
const
|
|
2329
|
-
|
|
2330
|
-
|
|
2518
|
+
const bucket = this.setStore.getOrReserveBucket(key);
|
|
2519
|
+
this.replaceBucketContents(bucket, slots);
|
|
2520
|
+
}
|
|
2521
|
+
// --- pk-oriented writes: resolve the bucket ONCE and use its own membership
|
|
2522
|
+
// (pk → slot) for dedup/removal, so a composite (trie) key is walked a single
|
|
2523
|
+
// time instead of once for the bucket and once for a separate membership map.
|
|
2524
|
+
setPks(key, pks, getSlot) {
|
|
2525
|
+
const bucket = this.setStore.getOrReserveBucket(key);
|
|
2526
|
+
const slots = [];
|
|
2527
|
+
for (let i = 0; i < pks.length; i++) slots.push(getSlot(pks[i]));
|
|
2528
|
+
this.replaceBucketContents(bucket, slots);
|
|
2529
|
+
const membership = bucket.membership ?? (bucket.membership = /* @__PURE__ */ new Map());
|
|
2530
|
+
membership.clear();
|
|
2531
|
+
for (let i = 0; i < slots.length; i++) {
|
|
2532
|
+
if (!membership.has(slots[i].pk)) {
|
|
2533
|
+
membership.set(slots[i].pk, slots[i]);
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
addPks(key, pks, getSlot) {
|
|
2538
|
+
if (pks.length === 0) return;
|
|
2539
|
+
const bucket = this.setStore.getOrReserveBucket(key);
|
|
2540
|
+
const membership = this.membershipOf(bucket);
|
|
2541
|
+
let changed = false;
|
|
2542
|
+
for (let i = 0; i < pks.length; i++) {
|
|
2543
|
+
const slot = getSlot(pks[i]);
|
|
2544
|
+
if (membership.has(slot.pk)) continue;
|
|
2545
|
+
membership.set(slot.pk, slot);
|
|
2546
|
+
if (!bucket.has(slot)) {
|
|
2547
|
+
bucket.add(slot);
|
|
2548
|
+
changed = true;
|
|
2549
|
+
}
|
|
2331
2550
|
}
|
|
2551
|
+
if (!changed) return;
|
|
2552
|
+
this.setStore.retainBucket(bucket);
|
|
2553
|
+
this.emitBucketChanged(bucket);
|
|
2332
2554
|
}
|
|
2333
2555
|
/**
|
|
2334
|
-
*
|
|
2335
|
-
*
|
|
2556
|
+
* Removes by pk. `pks` must be canonical `slot.pk` references (membership is
|
|
2557
|
+
* keyed by them): for primitive pks that is just the pk; a collection-bound
|
|
2558
|
+
* composite index canonicalizes raw pks to `slot.pk` before calling this.
|
|
2559
|
+
*/
|
|
2560
|
+
removePks(key, pks) {
|
|
2561
|
+
if (pks.length === 0) return;
|
|
2562
|
+
const bucket = this.setStore.findBucket(key);
|
|
2563
|
+
if (!bucket || bucket.size === 0) return;
|
|
2564
|
+
const membership = this.membershipOf(bucket);
|
|
2565
|
+
let changed = false;
|
|
2566
|
+
for (let i = 0; i < pks.length; i++) {
|
|
2567
|
+
const slot = membership.get(pks[i]);
|
|
2568
|
+
if (slot) {
|
|
2569
|
+
membership.delete(pks[i]);
|
|
2570
|
+
if (bucket.delete(slot)) changed = true;
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
if (!changed) return;
|
|
2574
|
+
if (bucket.size === 0) this.setStore.releaseBucket(bucket);
|
|
2575
|
+
this.emitBucketChanged(bucket);
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* The bucket's pk → slot membership, lazily created and seeded from the
|
|
2579
|
+
* bucket's current slots (so it stays correct even if slots were written
|
|
2580
|
+
* through the lower-level `setSlots` path).
|
|
2581
|
+
*/
|
|
2582
|
+
membershipOf(bucket) {
|
|
2583
|
+
let membership = bucket.membership;
|
|
2584
|
+
if (!membership) {
|
|
2585
|
+
membership = /* @__PURE__ */ new Map();
|
|
2586
|
+
bucket.membership = membership;
|
|
2587
|
+
}
|
|
2588
|
+
if (membership.size === 0 && bucket.size > 0) {
|
|
2589
|
+
for (const slot of bucket) membership.set(slot.pk, slot);
|
|
2590
|
+
}
|
|
2591
|
+
return membership;
|
|
2592
|
+
}
|
|
2593
|
+
replaceBucketContents(bucket, slots) {
|
|
2594
|
+
if (this.comparePks) {
|
|
2595
|
+
const newSet = slots instanceof Set ? slots : new Set(slots);
|
|
2596
|
+
if (this.bucketMatchesComparator(bucket, newSet)) return;
|
|
2597
|
+
bucket.clear();
|
|
2598
|
+
for (const slot of newSet) bucket.add(slot);
|
|
2599
|
+
} else {
|
|
2600
|
+
bucket.clear();
|
|
2601
|
+
for (const slot of slots) bucket.add(slot);
|
|
2602
|
+
}
|
|
2603
|
+
if (bucket.size > 0) this.setStore.retainBucket(bucket);
|
|
2604
|
+
else this.setStore.releaseBucket(bucket);
|
|
2605
|
+
this.emitBucketChanged(bucket);
|
|
2606
|
+
}
|
|
2607
|
+
/**
|
|
2608
|
+
* Adds slots to a key's bucket IN PLACE and emits once. O(added).
|
|
2336
2609
|
*/
|
|
2337
2610
|
addSlots(key, slots) {
|
|
2338
2611
|
if (slots.length === 0) return;
|
|
2339
|
-
|
|
2340
|
-
if (!bucket) {
|
|
2341
|
-
bucket = /* @__PURE__ */ new Set();
|
|
2342
|
-
this.store.setOneByKey(key, bucket);
|
|
2343
|
-
}
|
|
2612
|
+
const bucket = this.setStore.getOrReserveBucket(key);
|
|
2344
2613
|
let changed = false;
|
|
2345
2614
|
for (let i = 0; i < slots.length; i++) {
|
|
2346
2615
|
if (!bucket.has(slots[i])) {
|
|
@@ -2348,25 +2617,27 @@ var OIMIndexManualSetBased = class extends OIMIndexSetBased {
|
|
|
2348
2617
|
changed = true;
|
|
2349
2618
|
}
|
|
2350
2619
|
}
|
|
2351
|
-
if (changed)
|
|
2620
|
+
if (!changed) return;
|
|
2621
|
+
this.setStore.retainBucket(bucket);
|
|
2622
|
+
this.emitBucketChanged(bucket);
|
|
2352
2623
|
}
|
|
2353
2624
|
/**
|
|
2354
2625
|
* Removes slots from a key's bucket IN PLACE (O(removed)) and emits once.
|
|
2355
2626
|
*/
|
|
2356
2627
|
removeSlots(key, slots) {
|
|
2357
2628
|
if (slots.length === 0) return;
|
|
2358
|
-
const bucket = this.
|
|
2629
|
+
const bucket = this.setStore.findBucket(key);
|
|
2359
2630
|
if (!bucket) return;
|
|
2360
2631
|
let changed = false;
|
|
2361
2632
|
for (let i = 0; i < slots.length; i++) {
|
|
2362
2633
|
if (bucket.delete(slots[i])) changed = true;
|
|
2363
2634
|
}
|
|
2364
2635
|
if (!changed) return;
|
|
2365
|
-
if (bucket.size === 0) this.
|
|
2366
|
-
this.
|
|
2636
|
+
if (bucket.size === 0) this.setStore.releaseBucket(bucket);
|
|
2637
|
+
this.emitBucketChanged(bucket);
|
|
2367
2638
|
}
|
|
2368
2639
|
/**
|
|
2369
|
-
* Clear all primary keys for a specific index key, or all keys if
|
|
2640
|
+
* Clear all primary keys for a specific index key, or all keys if none given.
|
|
2370
2641
|
*/
|
|
2371
2642
|
clear(key) {
|
|
2372
2643
|
if (key === void 0) {
|
|
@@ -2376,12 +2647,22 @@ var OIMIndexManualSetBased = class extends OIMIndexSetBased {
|
|
|
2376
2647
|
this.emitUpdate(allKeys);
|
|
2377
2648
|
}
|
|
2378
2649
|
} else {
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2650
|
+
const bucket = this.setStore.findBucket(key);
|
|
2651
|
+
if (bucket && bucket.size > 0) {
|
|
2652
|
+
bucket.clear();
|
|
2653
|
+
this.setStore.releaseBucket(bucket);
|
|
2654
|
+
this.emitBucketChanged(bucket);
|
|
2382
2655
|
}
|
|
2383
2656
|
}
|
|
2384
2657
|
}
|
|
2658
|
+
/**
|
|
2659
|
+
* Emit that a bucket changed. Base (non-reactive) path emits by key on the
|
|
2660
|
+
* plain event emitter; the reactive subclass overrides this to mark the
|
|
2661
|
+
* bucket carrier directly (O(1), no key→carrier lookup).
|
|
2662
|
+
*/
|
|
2663
|
+
emitBucketChanged(bucket) {
|
|
2664
|
+
this.emitUpdateOne(bucket.key);
|
|
2665
|
+
}
|
|
2385
2666
|
};
|
|
2386
2667
|
|
|
2387
2668
|
// src/core/OIMReactiveIndexManualSetBased.ts
|
|
@@ -2390,6 +2671,12 @@ var OIMIndexManualSetBasedReactive = class extends OIMIndexManualSetBased {
|
|
|
2390
2671
|
super(opts);
|
|
2391
2672
|
this.updateEmitter = updateEmitter;
|
|
2392
2673
|
}
|
|
2674
|
+
// Deliver straight off the bucket the write just touched — O(1), no
|
|
2675
|
+
// key→carrier lookup (the whole point of bucket-as-carrier).
|
|
2676
|
+
emitBucketChanged(bucket) {
|
|
2677
|
+
this.updateEmitter.markUpdatedCarrier(bucket);
|
|
2678
|
+
}
|
|
2679
|
+
// clear(all) still emits by key set (rare path).
|
|
2393
2680
|
emitUpdate(keys) {
|
|
2394
2681
|
this.updateEmitter.markUpdatedKeys(keys);
|
|
2395
2682
|
}
|
|
@@ -2399,12 +2686,15 @@ var OIMIndexManualSetBasedReactive = class extends OIMIndexManualSetBased {
|
|
|
2399
2686
|
};
|
|
2400
2687
|
var OIMReactiveIndexManualSetBased = class extends OIMReactiveIndexSetBased {
|
|
2401
2688
|
constructor(queue, opts) {
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2689
|
+
const store = opts?.indexOptions?.store ?? new OIMIndexStoreMapDrivenSetBased();
|
|
2690
|
+
super(
|
|
2691
|
+
queue,
|
|
2692
|
+
(updateEmitter) => new OIMIndexManualSetBasedReactive(updateEmitter, {
|
|
2693
|
+
comparePks: opts?.indexOptions?.comparePks,
|
|
2694
|
+
store
|
|
2695
|
+
}),
|
|
2696
|
+
() => new OIMBucketCarrierProvider(store)
|
|
2697
|
+
);
|
|
2408
2698
|
}
|
|
2409
2699
|
setSlots(key, slots) {
|
|
2410
2700
|
this.index.setSlots(key, slots);
|
|
@@ -2423,73 +2713,439 @@ var OIMReactiveIndexManualSetBased = class extends OIMReactiveIndexSetBased {
|
|
|
2423
2713
|
// src/core/OIMReactiveCollectionIndexManualSetBased.ts
|
|
2424
2714
|
var OIMReactiveCollectionIndexManualSetBased = class extends OIMReactiveIndexManualSetBased {
|
|
2425
2715
|
constructor(queue, opts) {
|
|
2426
|
-
const
|
|
2716
|
+
const getSlot = opts.collection !== void 0 ? (pk) => opts.collection.getOrReserveSlotByPk(pk) : opts.getSlot;
|
|
2427
2717
|
super(queue, {
|
|
2428
2718
|
indexOptions: opts.indexOptions
|
|
2429
2719
|
});
|
|
2430
|
-
//
|
|
2431
|
-
//
|
|
2432
|
-
this.
|
|
2433
|
-
|
|
2720
|
+
// Bound once so the hot pk-write path passes a stable function (no per-call
|
|
2721
|
+
// closure allocation).
|
|
2722
|
+
this.getSlotOrTransient = (pk) => {
|
|
2723
|
+
const slot = this.getSlot(pk);
|
|
2724
|
+
if (!slot) return { pk, item: void 0 };
|
|
2725
|
+
return slot;
|
|
2726
|
+
};
|
|
2727
|
+
this.getSlot = getSlot;
|
|
2728
|
+
this.findSlotForRemoval = opts.collection !== void 0 ? (pk) => opts.collection.findSlotByPk(pk) : opts.getSlot;
|
|
2434
2729
|
}
|
|
2435
2730
|
setPks(key, pks) {
|
|
2436
|
-
|
|
2437
|
-
|
|
2731
|
+
this.index.setPks(key, pks, this.getSlotOrTransient);
|
|
2732
|
+
}
|
|
2733
|
+
addPks(key, pks) {
|
|
2734
|
+
this.index.addPks(key, pks, this.getSlotOrTransient);
|
|
2735
|
+
}
|
|
2736
|
+
removePks(key, pks) {
|
|
2737
|
+
const canonical = [];
|
|
2438
2738
|
for (let i = 0; i < pks.length; i++) {
|
|
2439
|
-
const
|
|
2440
|
-
|
|
2441
|
-
if (!map.has(pk)) map.set(pk, slot);
|
|
2442
|
-
slots.push(slot);
|
|
2739
|
+
const slot = this.findSlotForRemoval(pks[i]);
|
|
2740
|
+
canonical.push(slot ? slot.pk : pks[i]);
|
|
2443
2741
|
}
|
|
2444
|
-
this.
|
|
2445
|
-
|
|
2742
|
+
this.index.removePks(key, canonical);
|
|
2743
|
+
}
|
|
2744
|
+
getEntitiesByKey(key) {
|
|
2745
|
+
return super.getEntitiesByKey(key);
|
|
2746
|
+
}
|
|
2747
|
+
getEntitiesByKeys(keys) {
|
|
2748
|
+
return super.getEntitiesByKeys(keys);
|
|
2749
|
+
}
|
|
2750
|
+
};
|
|
2751
|
+
|
|
2752
|
+
// src/core/OIMTrieMap.ts
|
|
2753
|
+
var OIMTrieMap = class {
|
|
2754
|
+
constructor() {
|
|
2755
|
+
this.root = { hasValue: false };
|
|
2756
|
+
this._size = 0;
|
|
2757
|
+
}
|
|
2758
|
+
/** Number of stored paths (terminal nodes), not the number of trie nodes. */
|
|
2759
|
+
get size() {
|
|
2760
|
+
return this._size;
|
|
2761
|
+
}
|
|
2762
|
+
set(path, value) {
|
|
2763
|
+
let node = this.root;
|
|
2764
|
+
for (let i = 0; i < path.length; i++) {
|
|
2765
|
+
let children = node.children;
|
|
2766
|
+
if (!children) {
|
|
2767
|
+
children = /* @__PURE__ */ new Map();
|
|
2768
|
+
node.children = children;
|
|
2769
|
+
}
|
|
2770
|
+
let next = children.get(path[i]);
|
|
2771
|
+
if (!next) {
|
|
2772
|
+
next = { hasValue: false };
|
|
2773
|
+
children.set(path[i], next);
|
|
2774
|
+
}
|
|
2775
|
+
node = next;
|
|
2776
|
+
}
|
|
2777
|
+
if (!node.hasValue) {
|
|
2778
|
+
node.hasValue = true;
|
|
2779
|
+
this._size++;
|
|
2780
|
+
}
|
|
2781
|
+
node.value = value;
|
|
2782
|
+
}
|
|
2783
|
+
get(path) {
|
|
2784
|
+
const node = this.findNode(path);
|
|
2785
|
+
return node && node.hasValue ? node.value : void 0;
|
|
2786
|
+
}
|
|
2787
|
+
has(path) {
|
|
2788
|
+
const node = this.findNode(path);
|
|
2789
|
+
return !!node && node.hasValue;
|
|
2790
|
+
}
|
|
2791
|
+
delete(path) {
|
|
2792
|
+
const parents = [];
|
|
2793
|
+
let node = this.root;
|
|
2794
|
+
for (let i = 0; i < path.length; i++) {
|
|
2795
|
+
const next = node.children?.get(path[i]);
|
|
2796
|
+
if (!next) return false;
|
|
2797
|
+
parents.push(node);
|
|
2798
|
+
node = next;
|
|
2799
|
+
}
|
|
2800
|
+
if (!node.hasValue) return false;
|
|
2801
|
+
node.hasValue = false;
|
|
2802
|
+
node.value = void 0;
|
|
2803
|
+
this._size--;
|
|
2804
|
+
let child = node;
|
|
2805
|
+
for (let i = parents.length - 1; i >= 0; i--) {
|
|
2806
|
+
if (child.hasValue || child.children && child.children.size > 0) {
|
|
2807
|
+
break;
|
|
2808
|
+
}
|
|
2809
|
+
const parent = parents[i];
|
|
2810
|
+
parent.children.delete(path[i]);
|
|
2811
|
+
if (parent.children.size === 0) parent.children = void 0;
|
|
2812
|
+
child = parent;
|
|
2813
|
+
}
|
|
2814
|
+
return true;
|
|
2815
|
+
}
|
|
2816
|
+
clear() {
|
|
2817
|
+
this.root.children = void 0;
|
|
2818
|
+
this.root.value = void 0;
|
|
2819
|
+
this.root.hasValue = false;
|
|
2820
|
+
this._size = 0;
|
|
2821
|
+
}
|
|
2822
|
+
/** Depth-first iteration over `[path, value]` for every stored path. */
|
|
2823
|
+
*entries() {
|
|
2824
|
+
const stack = [{ node: this.root, path: [] }];
|
|
2825
|
+
while (stack.length > 0) {
|
|
2826
|
+
const frame = stack.pop();
|
|
2827
|
+
const { node, path } = frame;
|
|
2828
|
+
if (node.hasValue) {
|
|
2829
|
+
yield [path, node.value];
|
|
2830
|
+
}
|
|
2831
|
+
if (node.children) {
|
|
2832
|
+
for (const [segment, child] of node.children) {
|
|
2833
|
+
stack.push({ node: child, path: [...path, segment] });
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2838
|
+
*keys() {
|
|
2839
|
+
for (const [path] of this.entries()) yield path;
|
|
2840
|
+
}
|
|
2841
|
+
*values() {
|
|
2842
|
+
for (const [, value] of this.entries()) yield value;
|
|
2843
|
+
}
|
|
2844
|
+
findNode(path) {
|
|
2845
|
+
let node = this.root;
|
|
2846
|
+
for (let i = 0; i < path.length; i++) {
|
|
2847
|
+
node = node.children?.get(path[i]);
|
|
2848
|
+
if (!node) return void 0;
|
|
2849
|
+
}
|
|
2850
|
+
return node;
|
|
2851
|
+
}
|
|
2852
|
+
};
|
|
2853
|
+
|
|
2854
|
+
// src/core/OIMIndexStoreTrieDrivenSetBased.ts
|
|
2855
|
+
var OIMIndexStoreTrieDrivenSetBased = class extends OIMIndexStoreSetBased {
|
|
2856
|
+
constructor() {
|
|
2857
|
+
super(...arguments);
|
|
2858
|
+
this.slots = new OIMTrieMap();
|
|
2859
|
+
this.reservedBuckets = new OIMTrieMap();
|
|
2860
|
+
}
|
|
2861
|
+
getOrReserveBucket(key) {
|
|
2862
|
+
const live = this.slots.get(key);
|
|
2863
|
+
if (live) return live;
|
|
2864
|
+
let reserved = this.reservedBuckets.get(key);
|
|
2865
|
+
if (!reserved) {
|
|
2866
|
+
reserved = new OIMKeyedBucketSetBased(key);
|
|
2867
|
+
this.reservedBuckets.set(key, reserved);
|
|
2868
|
+
}
|
|
2869
|
+
return reserved;
|
|
2870
|
+
}
|
|
2871
|
+
findBucket(key) {
|
|
2872
|
+
return this.slots.get(key) ?? this.reservedBuckets.get(key);
|
|
2873
|
+
}
|
|
2874
|
+
retainBucket(bucket) {
|
|
2875
|
+
if (bucket.size === 0) return;
|
|
2876
|
+
this.reservedBuckets.delete(bucket.key);
|
|
2877
|
+
if (!this.slots.has(bucket.key)) this.slots.set(bucket.key, bucket);
|
|
2878
|
+
}
|
|
2879
|
+
releaseBucket(bucket) {
|
|
2880
|
+
if (bucket.size > 0) return;
|
|
2881
|
+
this.slots.delete(bucket.key);
|
|
2882
|
+
if (bucket.hasSubscribers()) {
|
|
2883
|
+
this.reservedBuckets.set(bucket.key, bucket);
|
|
2884
|
+
} else {
|
|
2885
|
+
this.reservedBuckets.delete(bucket.key);
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
dropIfReserved(key) {
|
|
2889
|
+
const reserved = this.reservedBuckets.get(key);
|
|
2890
|
+
if (reserved && reserved.size === 0 && !reserved.hasSubscribers()) {
|
|
2891
|
+
this.reservedBuckets.delete(key);
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
setOneByKey(key, slots) {
|
|
2895
|
+
const bucket = this.getOrReserveBucket(key);
|
|
2896
|
+
if (bucket !== slots) {
|
|
2897
|
+
bucket.clear();
|
|
2898
|
+
for (const slot of slots) bucket.add(slot);
|
|
2899
|
+
}
|
|
2900
|
+
if (bucket.size > 0) this.retainBucket(bucket);
|
|
2901
|
+
else this.releaseBucket(bucket);
|
|
2902
|
+
}
|
|
2903
|
+
removeOneByKey(key) {
|
|
2904
|
+
this.slots.delete(key);
|
|
2905
|
+
this.reservedBuckets.delete(key);
|
|
2906
|
+
}
|
|
2907
|
+
removeManyByKeys(keys) {
|
|
2908
|
+
for (let i = 0; i < keys.length; i++) {
|
|
2909
|
+
this.slots.delete(keys[i]);
|
|
2910
|
+
this.reservedBuckets.delete(keys[i]);
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
getOneByKey(key) {
|
|
2914
|
+
return this.slots.get(key);
|
|
2915
|
+
}
|
|
2916
|
+
getManyByKeys(keys) {
|
|
2917
|
+
const result = /* @__PURE__ */ new Map();
|
|
2918
|
+
for (let i = 0; i < keys.length; i++) {
|
|
2919
|
+
const slots = this.slots.get(keys[i]);
|
|
2920
|
+
if (slots !== void 0) result.set(keys[i], slots);
|
|
2921
|
+
}
|
|
2922
|
+
return result;
|
|
2923
|
+
}
|
|
2924
|
+
getAllKeys() {
|
|
2925
|
+
return Array.from(this.slots.keys());
|
|
2926
|
+
}
|
|
2927
|
+
getAll() {
|
|
2928
|
+
const result = /* @__PURE__ */ new Map();
|
|
2929
|
+
for (const [path, bucket] of this.slots.entries()) {
|
|
2930
|
+
result.set(path, bucket);
|
|
2931
|
+
}
|
|
2932
|
+
return result;
|
|
2933
|
+
}
|
|
2934
|
+
countAll() {
|
|
2935
|
+
return this.slots.size;
|
|
2936
|
+
}
|
|
2937
|
+
clear() {
|
|
2938
|
+
for (const bucket of this.slots.values()) {
|
|
2939
|
+
bucket.clear();
|
|
2940
|
+
if (bucket.hasSubscribers()) {
|
|
2941
|
+
this.reservedBuckets.set(bucket.key, bucket);
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
this.slots.clear();
|
|
2945
|
+
}
|
|
2946
|
+
};
|
|
2947
|
+
|
|
2948
|
+
// src/core/OIMReactiveCollectionIndexCompositeTrieSetBased.ts
|
|
2949
|
+
var OIMReactiveCollectionIndexCompositeTrieSetBased = class extends OIMReactiveIndexManualSetBased {
|
|
2950
|
+
constructor(queue, opts) {
|
|
2951
|
+
const getSlot = opts.collection !== void 0 ? (pk) => opts.collection.getOrReserveSlotByPk(pk) : opts.getSlot;
|
|
2952
|
+
super(queue, {
|
|
2953
|
+
indexOptions: {
|
|
2954
|
+
comparePks: opts.indexOptions?.comparePks,
|
|
2955
|
+
store: opts.indexOptions?.store ?? new OIMIndexStoreTrieDrivenSetBased()
|
|
2956
|
+
}
|
|
2957
|
+
});
|
|
2958
|
+
this.getSlotOrTransient = (pk) => {
|
|
2959
|
+
const slot = this.getSlot(pk);
|
|
2960
|
+
if (!slot) return { pk, item: void 0 };
|
|
2961
|
+
return slot;
|
|
2962
|
+
};
|
|
2963
|
+
this.getSlot = getSlot;
|
|
2964
|
+
this.findSlotForRemoval = opts.collection !== void 0 ? (pk) => opts.collection.findSlotByPk(pk) : opts.getSlot;
|
|
2965
|
+
}
|
|
2966
|
+
setPks(key, pks) {
|
|
2967
|
+
this.index.setPks(key, pks, this.getSlotOrTransient);
|
|
2968
|
+
}
|
|
2969
|
+
addPks(key, pks) {
|
|
2970
|
+
this.index.addPks(key, pks, this.getSlotOrTransient);
|
|
2971
|
+
}
|
|
2972
|
+
removePks(key, pks) {
|
|
2973
|
+
const canonical = [];
|
|
2974
|
+
for (let i = 0; i < pks.length; i++) {
|
|
2975
|
+
const slot = this.findSlotForRemoval(pks[i]);
|
|
2976
|
+
canonical.push(slot ? slot.pk : pks[i]);
|
|
2977
|
+
}
|
|
2978
|
+
this.index.removePks(key, canonical);
|
|
2979
|
+
}
|
|
2980
|
+
getEntitiesByKey(key) {
|
|
2981
|
+
return super.getEntitiesByKey(key);
|
|
2982
|
+
}
|
|
2983
|
+
getEntitiesByKeys(keys) {
|
|
2984
|
+
return super.getEntitiesByKeys(keys);
|
|
2985
|
+
}
|
|
2986
|
+
};
|
|
2987
|
+
|
|
2988
|
+
// src/core/OIMIndexStoreTrieDrivenArrayBased.ts
|
|
2989
|
+
var OIMIndexStoreTrieDrivenArrayBased = class extends OIMIndexStoreArrayBased {
|
|
2990
|
+
constructor() {
|
|
2991
|
+
super(...arguments);
|
|
2992
|
+
this.slots = new OIMTrieMap();
|
|
2993
|
+
this.reservedBuckets = new OIMTrieMap();
|
|
2994
|
+
}
|
|
2995
|
+
getOrReserveBucket(key) {
|
|
2996
|
+
const live = this.slots.get(key);
|
|
2997
|
+
if (live) return live;
|
|
2998
|
+
let reserved = this.reservedBuckets.get(key);
|
|
2999
|
+
if (!reserved) {
|
|
3000
|
+
reserved = new OIMKeyedBucketArrayBased(key);
|
|
3001
|
+
this.reservedBuckets.set(key, reserved);
|
|
3002
|
+
}
|
|
3003
|
+
return reserved;
|
|
3004
|
+
}
|
|
3005
|
+
findBucket(key) {
|
|
3006
|
+
return this.slots.get(key) ?? this.reservedBuckets.get(key);
|
|
3007
|
+
}
|
|
3008
|
+
retainBucket(bucket) {
|
|
3009
|
+
if (bucket.length === 0) return;
|
|
3010
|
+
this.reservedBuckets.delete(bucket.key);
|
|
3011
|
+
if (!this.slots.has(bucket.key)) this.slots.set(bucket.key, bucket);
|
|
3012
|
+
}
|
|
3013
|
+
releaseBucket(bucket) {
|
|
3014
|
+
if (bucket.length > 0) return;
|
|
3015
|
+
this.slots.delete(bucket.key);
|
|
3016
|
+
if (bucket.hasSubscribers()) {
|
|
3017
|
+
this.reservedBuckets.set(bucket.key, bucket);
|
|
3018
|
+
} else {
|
|
3019
|
+
this.reservedBuckets.delete(bucket.key);
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
dropIfReserved(key) {
|
|
3023
|
+
const reserved = this.reservedBuckets.get(key);
|
|
3024
|
+
if (reserved && reserved.length === 0 && !reserved.hasSubscribers()) {
|
|
3025
|
+
this.reservedBuckets.delete(key);
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
setOneByKey(key, slots) {
|
|
3029
|
+
const bucket = this.getOrReserveBucket(key);
|
|
3030
|
+
if (bucket !== slots) {
|
|
3031
|
+
bucket.length = 0;
|
|
3032
|
+
for (let i = 0; i < slots.length; i++) bucket.push(slots[i]);
|
|
3033
|
+
}
|
|
3034
|
+
if (bucket.length > 0) this.retainBucket(bucket);
|
|
3035
|
+
else this.releaseBucket(bucket);
|
|
3036
|
+
}
|
|
3037
|
+
removeOneByKey(key) {
|
|
3038
|
+
this.slots.delete(key);
|
|
3039
|
+
this.reservedBuckets.delete(key);
|
|
3040
|
+
}
|
|
3041
|
+
removeManyByKeys(keys) {
|
|
3042
|
+
for (let i = 0; i < keys.length; i++) {
|
|
3043
|
+
this.slots.delete(keys[i]);
|
|
3044
|
+
this.reservedBuckets.delete(keys[i]);
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
getOneByKey(key) {
|
|
3048
|
+
return this.slots.get(key);
|
|
3049
|
+
}
|
|
3050
|
+
getManyByKeys(keys) {
|
|
3051
|
+
const result = /* @__PURE__ */ new Map();
|
|
3052
|
+
for (let i = 0; i < keys.length; i++) {
|
|
3053
|
+
const slots = this.slots.get(keys[i]);
|
|
3054
|
+
if (slots !== void 0) result.set(keys[i], slots);
|
|
3055
|
+
}
|
|
3056
|
+
return result;
|
|
3057
|
+
}
|
|
3058
|
+
getAllKeys() {
|
|
3059
|
+
return Array.from(this.slots.keys());
|
|
3060
|
+
}
|
|
3061
|
+
getAll() {
|
|
3062
|
+
const result = /* @__PURE__ */ new Map();
|
|
3063
|
+
for (const [path, bucket] of this.slots.entries()) {
|
|
3064
|
+
result.set(path, bucket);
|
|
3065
|
+
}
|
|
3066
|
+
return result;
|
|
3067
|
+
}
|
|
3068
|
+
countAll() {
|
|
3069
|
+
return this.slots.size;
|
|
3070
|
+
}
|
|
3071
|
+
clear() {
|
|
3072
|
+
for (const bucket of this.slots.values()) {
|
|
3073
|
+
bucket.length = 0;
|
|
3074
|
+
if (bucket.hasSubscribers()) {
|
|
3075
|
+
this.reservedBuckets.set(bucket.key, bucket);
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
this.slots.clear();
|
|
3079
|
+
}
|
|
3080
|
+
};
|
|
3081
|
+
|
|
3082
|
+
// src/core/OIMReactiveCollectionIndexCompositeTrieArrayBased.ts
|
|
3083
|
+
var OIMReactiveCollectionIndexCompositeTrieArrayBased = class extends OIMReactiveIndexManualArrayBased {
|
|
3084
|
+
constructor(queue, opts) {
|
|
3085
|
+
const getSlot = opts.collection !== void 0 ? (pk) => opts.collection.getOrReserveSlotByPk(pk) : opts.getSlot;
|
|
3086
|
+
super(queue, {
|
|
3087
|
+
indexOptions: {
|
|
3088
|
+
comparePks: opts.indexOptions?.comparePks,
|
|
3089
|
+
store: opts.indexOptions?.store ?? new OIMIndexStoreTrieDrivenArrayBased()
|
|
3090
|
+
}
|
|
3091
|
+
});
|
|
3092
|
+
// Persistent per-key-path pk membership for O(1) `addPks` dedup. Trie-keyed
|
|
3093
|
+
// so a rebuilt key path matches by content.
|
|
3094
|
+
this.pksByKey = new OIMTrieMap();
|
|
3095
|
+
this.getSlot = getSlot;
|
|
3096
|
+
}
|
|
3097
|
+
setPks(key, pks) {
|
|
3098
|
+
const pkSet = /* @__PURE__ */ new Set();
|
|
3099
|
+
for (let i = 0; i < pks.length; i++) pkSet.add(pks[i]);
|
|
3100
|
+
this.pksByKey.set(key, pkSet);
|
|
3101
|
+
super.setSlots(key, this.getSlotsOrTransient(pks));
|
|
2446
3102
|
}
|
|
2447
3103
|
addPks(key, pks) {
|
|
2448
3104
|
if (pks.length === 0) return;
|
|
2449
|
-
const
|
|
3105
|
+
const pkSet = this.membershipOf(key);
|
|
2450
3106
|
const newSlots = [];
|
|
2451
3107
|
for (const pk of pks) {
|
|
2452
|
-
if (
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
newSlots.push(slot);
|
|
3108
|
+
if (pkSet.has(pk)) continue;
|
|
3109
|
+
pkSet.add(pk);
|
|
3110
|
+
newSlots.push(this.getSlotOrTransient(pk));
|
|
2456
3111
|
}
|
|
2457
|
-
if (newSlots.length > 0) this.
|
|
3112
|
+
if (newSlots.length > 0) this.appendSlots(key, newSlots);
|
|
2458
3113
|
}
|
|
2459
3114
|
removePks(key, pks) {
|
|
2460
3115
|
if (pks.length === 0) return;
|
|
2461
|
-
const
|
|
2462
|
-
|
|
2463
|
-
const
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
3116
|
+
const pksToRemove = new Set(pks);
|
|
3117
|
+
const existingSlots = this.index.getSlotsByKey(key);
|
|
3118
|
+
const nextSlots = existingSlots.filter(
|
|
3119
|
+
(slot) => !pksToRemove.has(slot.pk)
|
|
3120
|
+
);
|
|
3121
|
+
if (nextSlots.length === existingSlots.length) return;
|
|
3122
|
+
const pkSet = this.pksByKey.get(key);
|
|
3123
|
+
if (pkSet) {
|
|
3124
|
+
for (let i = 0; i < pks.length; i++) pkSet.delete(pks[i]);
|
|
2470
3125
|
}
|
|
2471
|
-
if (
|
|
2472
|
-
|
|
2473
|
-
this.removeSlots(key, removed);
|
|
3126
|
+
if (nextSlots.length === 0) this.clear(key);
|
|
3127
|
+
else super.setSlots(key, nextSlots);
|
|
2474
3128
|
}
|
|
2475
3129
|
clear(key) {
|
|
2476
|
-
if (key === void 0) this.
|
|
2477
|
-
else this.
|
|
3130
|
+
if (key === void 0) this.pksByKey.clear();
|
|
3131
|
+
else this.pksByKey.delete(key);
|
|
2478
3132
|
super.clear(key);
|
|
2479
3133
|
}
|
|
2480
3134
|
/**
|
|
2481
|
-
* The
|
|
2482
|
-
* stays correct even if slots were set through a lower-level path.
|
|
3135
|
+
* The membership set for a key path, lazily seeded from the current bucket so
|
|
3136
|
+
* it stays correct even if slots were set through a lower-level path.
|
|
2483
3137
|
*/
|
|
2484
3138
|
membershipOf(key) {
|
|
2485
|
-
let
|
|
2486
|
-
if (!
|
|
2487
|
-
|
|
3139
|
+
let pkSet = this.pksByKey.get(key);
|
|
3140
|
+
if (!pkSet) {
|
|
3141
|
+
pkSet = /* @__PURE__ */ new Set();
|
|
2488
3142
|
const existing = this.index.getSlotsByKey(key);
|
|
2489
|
-
for (
|
|
2490
|
-
|
|
3143
|
+
for (let i = 0; i < existing.length; i++) {
|
|
3144
|
+
pkSet.add(existing[i].pk);
|
|
3145
|
+
}
|
|
3146
|
+
this.pksByKey.set(key, pkSet);
|
|
2491
3147
|
}
|
|
2492
|
-
return
|
|
3148
|
+
return pkSet;
|
|
2493
3149
|
}
|
|
2494
3150
|
getEntitiesByKey(key) {
|
|
2495
3151
|
return super.getEntitiesByKey(key);
|
|
@@ -2497,8 +3153,16 @@ var OIMReactiveCollectionIndexManualSetBased = class extends OIMReactiveIndexMan
|
|
|
2497
3153
|
getEntitiesByKeys(keys) {
|
|
2498
3154
|
return super.getEntitiesByKeys(keys);
|
|
2499
3155
|
}
|
|
2500
|
-
|
|
2501
|
-
const
|
|
3156
|
+
getSlotsOrTransient(pks) {
|
|
3157
|
+
const slots = [];
|
|
3158
|
+
slots.length = pks.length;
|
|
3159
|
+
for (let i = 0; i < pks.length; i++) {
|
|
3160
|
+
slots[i] = this.getSlotOrTransient(pks[i]);
|
|
3161
|
+
}
|
|
3162
|
+
return slots;
|
|
3163
|
+
}
|
|
3164
|
+
getSlotOrTransient(pk) {
|
|
3165
|
+
const slot = this.getSlot(pk);
|
|
2502
3166
|
if (!slot) return { pk, item: void 0 };
|
|
2503
3167
|
return slot;
|
|
2504
3168
|
}
|
|
@@ -2811,20 +3475,20 @@ var OIMReactiveGlobalIndexManualArrayBased = class extends OIMReactiveGlobalInde
|
|
|
2811
3475
|
// src/core/OIMReactiveCollectionGlobalIndexManualArrayBased.ts
|
|
2812
3476
|
var OIMReactiveCollectionGlobalIndexManualArrayBased = class extends OIMReactiveGlobalIndexManualArrayBased {
|
|
2813
3477
|
constructor(queue, opts) {
|
|
2814
|
-
const
|
|
3478
|
+
const getSlot = opts.collection !== void 0 ? (pk) => opts.collection.getOrReserveSlotByPk(pk) : opts.getSlot;
|
|
2815
3479
|
super(queue, { indexOptions: opts.indexOptions });
|
|
2816
3480
|
// Single pk membership set for O(1) `addPks` dedup. Lazily seeded from the
|
|
2817
3481
|
// bucket so it stays correct even after a raw `setSlots` (e.g. derived
|
|
2818
3482
|
// rebuild), matching the keyed index's `membershipOf`.
|
|
2819
3483
|
this.membership = /* @__PURE__ */ new Set();
|
|
2820
3484
|
this.membershipSeeded = false;
|
|
2821
|
-
this.
|
|
3485
|
+
this.getSlot = getSlot;
|
|
2822
3486
|
}
|
|
2823
3487
|
setPks(pks) {
|
|
2824
3488
|
this.membership.clear();
|
|
2825
3489
|
for (let i = 0; i < pks.length; i++) this.membership.add(pks[i]);
|
|
2826
3490
|
this.membershipSeeded = true;
|
|
2827
|
-
super.setSlots(this.
|
|
3491
|
+
super.setSlots(this.getSlotsOrTransient(pks));
|
|
2828
3492
|
}
|
|
2829
3493
|
addPks(pks) {
|
|
2830
3494
|
if (pks.length === 0) return;
|
|
@@ -2833,7 +3497,7 @@ var OIMReactiveCollectionGlobalIndexManualArrayBased = class extends OIMReactive
|
|
|
2833
3497
|
for (const pk of pks) {
|
|
2834
3498
|
if (membership.has(pk)) continue;
|
|
2835
3499
|
membership.add(pk);
|
|
2836
|
-
newSlots.push(this.
|
|
3500
|
+
newSlots.push(this.getSlotOrTransient(pk));
|
|
2837
3501
|
}
|
|
2838
3502
|
if (newSlots.length > 0) super.appendSlots(newSlots);
|
|
2839
3503
|
}
|
|
@@ -2870,16 +3534,16 @@ var OIMReactiveCollectionGlobalIndexManualArrayBased = class extends OIMReactive
|
|
|
2870
3534
|
getEntities() {
|
|
2871
3535
|
return super.getEntities();
|
|
2872
3536
|
}
|
|
2873
|
-
|
|
3537
|
+
getSlotsOrTransient(pks) {
|
|
2874
3538
|
const slots = [];
|
|
2875
3539
|
slots.length = pks.length;
|
|
2876
3540
|
for (let i = 0; i < pks.length; i++) {
|
|
2877
|
-
slots[i] = this.
|
|
3541
|
+
slots[i] = this.getSlotOrTransient(pks[i]);
|
|
2878
3542
|
}
|
|
2879
3543
|
return slots;
|
|
2880
3544
|
}
|
|
2881
|
-
|
|
2882
|
-
const slot = this.
|
|
3545
|
+
getSlotOrTransient(pk) {
|
|
3546
|
+
const slot = this.getSlot(pk);
|
|
2883
3547
|
if (!slot) return { pk, item: void 0 };
|
|
2884
3548
|
return slot;
|
|
2885
3549
|
}
|
|
@@ -2959,18 +3623,18 @@ var OIMReactiveGlobalIndexManualSetBased = class extends OIMReactiveGlobalIndexS
|
|
|
2959
3623
|
// src/core/OIMReactiveCollectionGlobalIndexManualSetBased.ts
|
|
2960
3624
|
var OIMReactiveCollectionGlobalIndexManualSetBased = class extends OIMReactiveGlobalIndexManualSetBased {
|
|
2961
3625
|
constructor(queue, opts) {
|
|
2962
|
-
const
|
|
3626
|
+
const getSlot = opts.collection !== void 0 ? (pk) => opts.collection.getOrReserveSlotByPk(pk) : opts.getSlot;
|
|
2963
3627
|
super(queue, { indexOptions: opts.indexOptions });
|
|
2964
3628
|
this.membership = /* @__PURE__ */ new Map();
|
|
2965
3629
|
this.membershipSeeded = false;
|
|
2966
|
-
this.
|
|
3630
|
+
this.getSlot = getSlot;
|
|
2967
3631
|
}
|
|
2968
3632
|
setPks(pks) {
|
|
2969
3633
|
this.membership.clear();
|
|
2970
3634
|
const slots = [];
|
|
2971
3635
|
for (let i = 0; i < pks.length; i++) {
|
|
2972
3636
|
const pk = pks[i];
|
|
2973
|
-
const slot = this.
|
|
3637
|
+
const slot = this.getSlotOrTransient(pk);
|
|
2974
3638
|
if (!this.membership.has(pk)) this.membership.set(pk, slot);
|
|
2975
3639
|
slots.push(slot);
|
|
2976
3640
|
}
|
|
@@ -2983,7 +3647,7 @@ var OIMReactiveCollectionGlobalIndexManualSetBased = class extends OIMReactiveGl
|
|
|
2983
3647
|
const newSlots = [];
|
|
2984
3648
|
for (const pk of pks) {
|
|
2985
3649
|
if (membership.has(pk)) continue;
|
|
2986
|
-
const slot = this.
|
|
3650
|
+
const slot = this.getSlotOrTransient(pk);
|
|
2987
3651
|
membership.set(pk, slot);
|
|
2988
3652
|
newSlots.push(slot);
|
|
2989
3653
|
}
|
|
@@ -3022,8 +3686,8 @@ var OIMReactiveCollectionGlobalIndexManualSetBased = class extends OIMReactiveGl
|
|
|
3022
3686
|
getEntities() {
|
|
3023
3687
|
return super.getEntities();
|
|
3024
3688
|
}
|
|
3025
|
-
|
|
3026
|
-
const slot = this.
|
|
3689
|
+
getSlotOrTransient(pk) {
|
|
3690
|
+
const slot = this.getSlot(pk);
|
|
3027
3691
|
if (!slot) return { pk, item: void 0 };
|
|
3028
3692
|
return slot;
|
|
3029
3693
|
}
|
|
@@ -3202,6 +3866,30 @@ var OIMCollectionIndexFactory = class {
|
|
|
3202
3866
|
indexOptions: opts.indexOptions
|
|
3203
3867
|
});
|
|
3204
3868
|
}
|
|
3869
|
+
/**
|
|
3870
|
+
* Composite (trie-backed) manual Set-based index keyed by an
|
|
3871
|
+
* arbitrary-length key path, e.g. `setPks([userId, projectId, role], pks)`.
|
|
3872
|
+
* Key paths are matched by content in O(arity) — no string concatenation,
|
|
3873
|
+
* no separator collisions, each segment keeps its type. Primitive-keyed
|
|
3874
|
+
* indexes are unaffected and keep their native-`Map` fast path.
|
|
3875
|
+
*/
|
|
3876
|
+
compositeSetIndex(opts = {}) {
|
|
3877
|
+
return new OIMReactiveCollectionIndexCompositeTrieSetBased(this.queue, {
|
|
3878
|
+
collection: this.collection,
|
|
3879
|
+
indexOptions: opts.indexOptions
|
|
3880
|
+
});
|
|
3881
|
+
}
|
|
3882
|
+
/**
|
|
3883
|
+
* Composite (trie-backed) manual Array-based (ordered) index keyed by an
|
|
3884
|
+
* arbitrary-length key path, e.g. `setPks([channelId, threadId], pks)`.
|
|
3885
|
+
* Ordered counterpart of `compositeSetIndex`.
|
|
3886
|
+
*/
|
|
3887
|
+
compositeArrayIndex(opts = {}) {
|
|
3888
|
+
return new OIMReactiveCollectionIndexCompositeTrieArrayBased(this.queue, {
|
|
3889
|
+
collection: this.collection,
|
|
3890
|
+
indexOptions: opts.indexOptions
|
|
3891
|
+
});
|
|
3892
|
+
}
|
|
3205
3893
|
derivedSetIndex(selectIndexKeys, opts = {}) {
|
|
3206
3894
|
return new OIMDerivedCollectionIndexSetBased(
|
|
3207
3895
|
this.queue,
|
|
@@ -3408,7 +4096,7 @@ var OIMObject = class {
|
|
|
3408
4096
|
var OIMReactiveObject = class extends OIMObject {
|
|
3409
4097
|
constructor(queue, opts) {
|
|
3410
4098
|
super(opts);
|
|
3411
|
-
this.updateEmitter = new OIMCarrierKeyedEmitter(queue, new
|
|
4099
|
+
this.updateEmitter = new OIMCarrierKeyedEmitter(queue, new OIMKeyedCarrierProvider());
|
|
3412
4100
|
}
|
|
3413
4101
|
/**
|
|
3414
4102
|
* Mark the written key(s) on the keyed emitter directly — no general-event
|
|
@@ -3450,6 +4138,148 @@ var OIMReactiveObject = class extends OIMObject {
|
|
|
3450
4138
|
}
|
|
3451
4139
|
};
|
|
3452
4140
|
|
|
4141
|
+
// src/core/OIMCollectionStoreTrieDriven.ts
|
|
4142
|
+
var OIMCollectionStoreTrieDriven = class extends OIMCollectionStore {
|
|
4143
|
+
constructor() {
|
|
4144
|
+
super(...arguments);
|
|
4145
|
+
this.slots = new OIMTrieMap();
|
|
4146
|
+
this.reservedSlots = new OIMTrieMap();
|
|
4147
|
+
}
|
|
4148
|
+
setOneByPk(pk, entity) {
|
|
4149
|
+
const slot = this.slots.get(pk);
|
|
4150
|
+
if (slot) {
|
|
4151
|
+
slot.item = entity;
|
|
4152
|
+
return slot;
|
|
4153
|
+
}
|
|
4154
|
+
const reserved = this.reservedSlots.get(pk);
|
|
4155
|
+
if (reserved) {
|
|
4156
|
+
reserved.item = entity;
|
|
4157
|
+
this.reservedSlots.delete(pk);
|
|
4158
|
+
this.slots.set(pk, reserved);
|
|
4159
|
+
return reserved;
|
|
4160
|
+
}
|
|
4161
|
+
const nextSlot = {
|
|
4162
|
+
pk,
|
|
4163
|
+
item: entity
|
|
4164
|
+
};
|
|
4165
|
+
this.slots.set(pk, nextSlot);
|
|
4166
|
+
return nextSlot;
|
|
4167
|
+
}
|
|
4168
|
+
getOrReserveSlotByPk(pk) {
|
|
4169
|
+
const slot = this.slots.get(pk);
|
|
4170
|
+
if (slot) return slot;
|
|
4171
|
+
let reserved = this.reservedSlots.get(pk);
|
|
4172
|
+
if (!reserved) {
|
|
4173
|
+
reserved = { pk, item: void 0 };
|
|
4174
|
+
this.reservedSlots.set(pk, reserved);
|
|
4175
|
+
}
|
|
4176
|
+
return reserved;
|
|
4177
|
+
}
|
|
4178
|
+
setManyByPks(pks, entities) {
|
|
4179
|
+
const slots = [];
|
|
4180
|
+
slots.length = pks.length;
|
|
4181
|
+
for (let i = 0; i < pks.length; i++) {
|
|
4182
|
+
slots[i] = this.setOneByPk(pks[i], entities[i]);
|
|
4183
|
+
}
|
|
4184
|
+
return slots;
|
|
4185
|
+
}
|
|
4186
|
+
getSlotByPk(pk) {
|
|
4187
|
+
return this.slots.get(pk);
|
|
4188
|
+
}
|
|
4189
|
+
findSlotByPk(pk) {
|
|
4190
|
+
return this.slots.get(pk) ?? this.reservedSlots.get(pk);
|
|
4191
|
+
}
|
|
4192
|
+
hasSubscribers(slot) {
|
|
4193
|
+
return slot.subscribers !== void 0 && slot.subscribers.size > 0;
|
|
4194
|
+
}
|
|
4195
|
+
getSlotsByPks(pks) {
|
|
4196
|
+
const result = [];
|
|
4197
|
+
result.length = pks.length;
|
|
4198
|
+
let writeIndex = 0;
|
|
4199
|
+
for (let i = 0; i < pks.length; i++) {
|
|
4200
|
+
const slot = this.slots.get(pks[i]);
|
|
4201
|
+
if (slot !== void 0) result[writeIndex++] = slot;
|
|
4202
|
+
}
|
|
4203
|
+
result.length = writeIndex;
|
|
4204
|
+
return result;
|
|
4205
|
+
}
|
|
4206
|
+
getAllSlots() {
|
|
4207
|
+
return Array.from(this.slots.values());
|
|
4208
|
+
}
|
|
4209
|
+
removeOneByPk(pk) {
|
|
4210
|
+
const slot = this.slots.get(pk);
|
|
4211
|
+
if (slot) {
|
|
4212
|
+
slot.item = void 0;
|
|
4213
|
+
this.slots.delete(pk);
|
|
4214
|
+
if (this.hasSubscribers(slot)) {
|
|
4215
|
+
this.reservedSlots.set(pk, slot);
|
|
4216
|
+
}
|
|
4217
|
+
return;
|
|
4218
|
+
}
|
|
4219
|
+
const reserved = this.reservedSlots.get(pk);
|
|
4220
|
+
if (reserved) {
|
|
4221
|
+
reserved.item = void 0;
|
|
4222
|
+
if (!this.hasSubscribers(reserved)) {
|
|
4223
|
+
this.reservedSlots.delete(pk);
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
}
|
|
4227
|
+
removeManyByPks(pks) {
|
|
4228
|
+
for (const pk of pks) this.removeOneByPk(pk);
|
|
4229
|
+
}
|
|
4230
|
+
getOneByPk(pk) {
|
|
4231
|
+
return this.slots.get(pk)?.item;
|
|
4232
|
+
}
|
|
4233
|
+
getManyByPks(pks) {
|
|
4234
|
+
const result = [];
|
|
4235
|
+
result.length = pks.length;
|
|
4236
|
+
let writeIndex = 0;
|
|
4237
|
+
for (let i = 0; i < pks.length; i++) {
|
|
4238
|
+
const entity = this.getOneByPk(pks[i]);
|
|
4239
|
+
if (entity !== void 0) result[writeIndex++] = entity;
|
|
4240
|
+
}
|
|
4241
|
+
result.length = writeIndex;
|
|
4242
|
+
return result;
|
|
4243
|
+
}
|
|
4244
|
+
getAll() {
|
|
4245
|
+
const result = [];
|
|
4246
|
+
for (const slot of this.slots.values()) {
|
|
4247
|
+
if (slot.item !== void 0) result.push(slot.item);
|
|
4248
|
+
}
|
|
4249
|
+
return result;
|
|
4250
|
+
}
|
|
4251
|
+
countAll() {
|
|
4252
|
+
return this.slots.size;
|
|
4253
|
+
}
|
|
4254
|
+
clear() {
|
|
4255
|
+
const retained = [];
|
|
4256
|
+
for (const slot of this.slots.values()) {
|
|
4257
|
+
slot.item = void 0;
|
|
4258
|
+
if (this.hasSubscribers(slot)) retained.push(slot);
|
|
4259
|
+
}
|
|
4260
|
+
this.slots.clear();
|
|
4261
|
+
for (const slot of this.reservedSlots.values()) {
|
|
4262
|
+
slot.item = void 0;
|
|
4263
|
+
if (this.hasSubscribers(slot)) retained.push(slot);
|
|
4264
|
+
}
|
|
4265
|
+
this.reservedSlots.clear();
|
|
4266
|
+
for (const slot of retained) {
|
|
4267
|
+
this.reservedSlots.set(slot.pk, slot);
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
getAllPks() {
|
|
4271
|
+
return Array.from(this.slots.keys());
|
|
4272
|
+
}
|
|
4273
|
+
destroy() {
|
|
4274
|
+
this.clear();
|
|
4275
|
+
for (const slot of this.reservedSlots.values()) {
|
|
4276
|
+
slot.subscribers?.clear();
|
|
4277
|
+
slot.subscribers = void 0;
|
|
4278
|
+
}
|
|
4279
|
+
this.reservedSlots.clear();
|
|
4280
|
+
}
|
|
4281
|
+
};
|
|
4282
|
+
|
|
3453
4283
|
// src/core/OIMObjectStoreMapDriven.ts
|
|
3454
4284
|
var OIMObjectStoreMapDriven = class extends OIMObjectStore {
|
|
3455
4285
|
constructor() {
|
|
@@ -3497,6 +4327,27 @@ var OIMObjectStoreMapDriven = class extends OIMObjectStore {
|
|
|
3497
4327
|
}
|
|
3498
4328
|
};
|
|
3499
4329
|
|
|
4330
|
+
// src/core/OIMKeyPathCarrierProvider.ts
|
|
4331
|
+
var OIMKeyPathCarrierProvider = class {
|
|
4332
|
+
constructor() {
|
|
4333
|
+
this.carriers = new OIMTrieMap();
|
|
4334
|
+
}
|
|
4335
|
+
getOrReserveCarrier(key) {
|
|
4336
|
+
let carrier = this.carriers.get(key);
|
|
4337
|
+
if (!carrier) {
|
|
4338
|
+
carrier = { key };
|
|
4339
|
+
this.carriers.set(key, carrier);
|
|
4340
|
+
}
|
|
4341
|
+
return carrier;
|
|
4342
|
+
}
|
|
4343
|
+
findCarrier(key) {
|
|
4344
|
+
return this.carriers.get(key);
|
|
4345
|
+
}
|
|
4346
|
+
onCarrierEmptied(carrier) {
|
|
4347
|
+
this.carriers.delete(carrier.key);
|
|
4348
|
+
}
|
|
4349
|
+
};
|
|
4350
|
+
|
|
3500
4351
|
// src/core/OIMComparatorFactory.ts
|
|
3501
4352
|
var OIMComparatorFactory = class {
|
|
3502
4353
|
createShallowComparator() {
|
|
@@ -3715,6 +4566,103 @@ var OIMMap2Keys = class {
|
|
|
3715
4566
|
}
|
|
3716
4567
|
};
|
|
3717
4568
|
|
|
4569
|
+
// src/core/OIMDisposeScope.ts
|
|
4570
|
+
var OIMDisposeScope = class _OIMDisposeScope {
|
|
4571
|
+
constructor() {
|
|
4572
|
+
this.disposables = [];
|
|
4573
|
+
this.disposed = false;
|
|
4574
|
+
}
|
|
4575
|
+
/** Number of not-yet-disposed items currently held. */
|
|
4576
|
+
get size() {
|
|
4577
|
+
return this.disposables.length;
|
|
4578
|
+
}
|
|
4579
|
+
get isDisposed() {
|
|
4580
|
+
return this.disposed;
|
|
4581
|
+
}
|
|
4582
|
+
/**
|
|
4583
|
+
* Register a disposable (object with `destroy()` or an unsubscribe function)
|
|
4584
|
+
* and return it unchanged, so it can be captured inline. If the scope is
|
|
4585
|
+
* already disposed the item is disposed immediately, so nothing leaks.
|
|
4586
|
+
*/
|
|
4587
|
+
add(disposable) {
|
|
4588
|
+
if (this.disposed) {
|
|
4589
|
+
this.disposeOne(disposable);
|
|
4590
|
+
return disposable;
|
|
4591
|
+
}
|
|
4592
|
+
this.disposables.push(disposable);
|
|
4593
|
+
return disposable;
|
|
4594
|
+
}
|
|
4595
|
+
/** A nested scope, itself registered here — dispose it early or with the parent. */
|
|
4596
|
+
child() {
|
|
4597
|
+
return this.add(new _OIMDisposeScope());
|
|
4598
|
+
}
|
|
4599
|
+
/**
|
|
4600
|
+
* Dispose everything in reverse registration order, then clear. Idempotent.
|
|
4601
|
+
* If any `destroy()`/unsubscribe throws, the rest are still disposed and the
|
|
4602
|
+
* first error is rethrown once teardown completes.
|
|
4603
|
+
*/
|
|
4604
|
+
destroy() {
|
|
4605
|
+
if (this.disposed) return;
|
|
4606
|
+
this.disposed = true;
|
|
4607
|
+
let firstError;
|
|
4608
|
+
let hasError = false;
|
|
4609
|
+
for (let i = this.disposables.length - 1; i >= 0; i--) {
|
|
4610
|
+
try {
|
|
4611
|
+
this.disposeOne(this.disposables[i]);
|
|
4612
|
+
} catch (error) {
|
|
4613
|
+
if (!hasError) {
|
|
4614
|
+
hasError = true;
|
|
4615
|
+
firstError = error;
|
|
4616
|
+
}
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
this.disposables.length = 0;
|
|
4620
|
+
if (hasError) throw firstError;
|
|
4621
|
+
}
|
|
4622
|
+
disposeOne(disposable) {
|
|
4623
|
+
if (typeof disposable === "function") disposable();
|
|
4624
|
+
else disposable.destroy();
|
|
4625
|
+
}
|
|
4626
|
+
};
|
|
4627
|
+
function createOIMDisposeScope() {
|
|
4628
|
+
return new OIMDisposeScope();
|
|
4629
|
+
}
|
|
4630
|
+
|
|
4631
|
+
// src/core/OIMTrieSet.ts
|
|
4632
|
+
var OIMTrieSet = class {
|
|
4633
|
+
constructor() {
|
|
4634
|
+
this.map = new OIMTrieMap();
|
|
4635
|
+
}
|
|
4636
|
+
get size() {
|
|
4637
|
+
return this.map.size;
|
|
4638
|
+
}
|
|
4639
|
+
add(key) {
|
|
4640
|
+
this.map.set(key, true);
|
|
4641
|
+
}
|
|
4642
|
+
has(key) {
|
|
4643
|
+
return this.map.has(key);
|
|
4644
|
+
}
|
|
4645
|
+
delete(key) {
|
|
4646
|
+
return this.map.delete(key);
|
|
4647
|
+
}
|
|
4648
|
+
*values() {
|
|
4649
|
+
yield* this.map.keys();
|
|
4650
|
+
}
|
|
4651
|
+
clear() {
|
|
4652
|
+
this.map.clear();
|
|
4653
|
+
}
|
|
4654
|
+
};
|
|
4655
|
+
|
|
4656
|
+
// src/core/OIMPkCodecKeyPath.ts
|
|
4657
|
+
var OIMPkCodecKeyPath = class {
|
|
4658
|
+
encode(pk) {
|
|
4659
|
+
return JSON.stringify(pk);
|
|
4660
|
+
}
|
|
4661
|
+
decode(encoded) {
|
|
4662
|
+
return JSON.parse(encoded);
|
|
4663
|
+
}
|
|
4664
|
+
};
|
|
4665
|
+
|
|
3718
4666
|
// src/modules/compute/core/OIMComputeRuntime.ts
|
|
3719
4667
|
var OIMComputeRuntime = class {
|
|
3720
4668
|
constructor(queue) {
|
|
@@ -4318,6 +5266,27 @@ var OIMCollectionSelectors = class {
|
|
|
4318
5266
|
key
|
|
4319
5267
|
);
|
|
4320
5268
|
}
|
|
5269
|
+
/**
|
|
5270
|
+
* Entities of a composite (key-path) set-based index for one key path, e.g.
|
|
5271
|
+
* `entitiesByCompositeSetIndexKey(index, [projectId, role])`.
|
|
5272
|
+
*/
|
|
5273
|
+
entitiesByCompositeSetIndexKey(index, key) {
|
|
5274
|
+
return new OIMEntitiesByIndexKeySetBasedSelector(
|
|
5275
|
+
this.runtime,
|
|
5276
|
+
this.collection,
|
|
5277
|
+
index,
|
|
5278
|
+
key
|
|
5279
|
+
);
|
|
5280
|
+
}
|
|
5281
|
+
/** Entities of a composite (key-path) array-based index for one key path. */
|
|
5282
|
+
entitiesByCompositeArrayIndexKey(index, key) {
|
|
5283
|
+
return new OIMEntitiesByIndexKeyArrayBasedSelector(
|
|
5284
|
+
this.runtime,
|
|
5285
|
+
this.collection,
|
|
5286
|
+
index,
|
|
5287
|
+
key
|
|
5288
|
+
);
|
|
5289
|
+
}
|
|
4321
5290
|
/** Entities of a keyless (whole-collection) array-based index, ordered. */
|
|
4322
5291
|
entitiesByArrayGlobalIndex(index) {
|
|
4323
5292
|
return new OIMEntitiesByGlobalIndexArrayBasedSelector(
|
|
@@ -4341,7 +5310,16 @@ function createOIMCollectionKit(queue, opts) {
|
|
|
4341
5310
|
const collection = new OIMReactiveCollection(queue, opts);
|
|
4342
5311
|
const indexFactory = new OIMCollectionIndexFactory(queue, collection);
|
|
4343
5312
|
const select = new OIMCollectionSelectors(queue, collection);
|
|
4344
|
-
|
|
5313
|
+
const scope = new OIMDisposeScope();
|
|
5314
|
+
scope.add(collection);
|
|
5315
|
+
return {
|
|
5316
|
+
queue,
|
|
5317
|
+
collection,
|
|
5318
|
+
indexFactory,
|
|
5319
|
+
select,
|
|
5320
|
+
scope,
|
|
5321
|
+
destroy: () => scope.destroy()
|
|
5322
|
+
};
|
|
4345
5323
|
}
|
|
4346
5324
|
|
|
4347
5325
|
// src/modules/wrapper/collection/OIMCollectionChangedFields.ts
|
|
@@ -5322,35 +6300,20 @@ var OIMComputed = class {
|
|
|
5322
6300
|
};
|
|
5323
6301
|
|
|
5324
6302
|
// src/modules/effect/core/OIMEffectDependencyKeyed.ts
|
|
5325
|
-
function isReadonlyArray(value) {
|
|
5326
|
-
return Array.isArray(value);
|
|
5327
|
-
}
|
|
5328
6303
|
var OIMEffectDependencyKeyed = class {
|
|
5329
|
-
constructor(source,
|
|
6304
|
+
constructor(source, key) {
|
|
5330
6305
|
this.source = source;
|
|
5331
|
-
|
|
5332
|
-
this.keys = keyOrKeys;
|
|
5333
|
-
} else {
|
|
5334
|
-
this.key = keyOrKeys;
|
|
5335
|
-
}
|
|
6306
|
+
this.key = key;
|
|
5336
6307
|
}
|
|
5337
6308
|
subscribe(onUpdate) {
|
|
5338
|
-
if (this.keys !== void 0) {
|
|
5339
|
-
return this.source.subscribeOnKeys(this.keys, onUpdate);
|
|
5340
|
-
}
|
|
5341
|
-
if (this.key === void 0) return () => {
|
|
5342
|
-
};
|
|
5343
6309
|
return this.source.subscribeOnKey(this.key, onUpdate);
|
|
5344
6310
|
}
|
|
5345
6311
|
};
|
|
5346
6312
|
|
|
5347
6313
|
// src/modules/effect/core/OIMEffectDependencyKeyedObject.ts
|
|
5348
6314
|
var OIMEffectDependencyKeyedObject = class {
|
|
5349
|
-
constructor(object,
|
|
5350
|
-
this.dep = new OIMEffectDependencyKeyed(
|
|
5351
|
-
object,
|
|
5352
|
-
keyOrKeys
|
|
5353
|
-
);
|
|
6315
|
+
constructor(object, key) {
|
|
6316
|
+
this.dep = new OIMEffectDependencyKeyed(object, key);
|
|
5354
6317
|
}
|
|
5355
6318
|
get source() {
|
|
5356
6319
|
return this.dep.source;
|
|
@@ -5362,11 +6325,8 @@ var OIMEffectDependencyKeyedObject = class {
|
|
|
5362
6325
|
|
|
5363
6326
|
// src/modules/effect/core/OIMEffectDependencyKeyedCollection.ts
|
|
5364
6327
|
var OIMEffectDependencyKeyedCollection = class {
|
|
5365
|
-
constructor(collection,
|
|
5366
|
-
this.dep = new OIMEffectDependencyKeyed(
|
|
5367
|
-
collection,
|
|
5368
|
-
pkOrPks
|
|
5369
|
-
);
|
|
6328
|
+
constructor(collection, pk) {
|
|
6329
|
+
this.dep = new OIMEffectDependencyKeyed(collection, pk);
|
|
5370
6330
|
}
|
|
5371
6331
|
get source() {
|
|
5372
6332
|
return this.dep.source;
|
|
@@ -5378,11 +6338,8 @@ var OIMEffectDependencyKeyedCollection = class {
|
|
|
5378
6338
|
|
|
5379
6339
|
// src/modules/effect/core/OIMEffectDependencyKeyedIndex.ts
|
|
5380
6340
|
var OIMEffectDependencyKeyedIndex = class {
|
|
5381
|
-
constructor(index,
|
|
5382
|
-
this.dep = new OIMEffectDependencyKeyed(
|
|
5383
|
-
index,
|
|
5384
|
-
keyOrKeys
|
|
5385
|
-
);
|
|
6341
|
+
constructor(index, key) {
|
|
6342
|
+
this.dep = new OIMEffectDependencyKeyed(index, key);
|
|
5386
6343
|
}
|
|
5387
6344
|
get source() {
|
|
5388
6345
|
return this.dep.source;
|
|
@@ -5530,6 +6487,7 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
5530
6487
|
EOIMEventQueueSchedulerEventType,
|
|
5531
6488
|
EOIMIndexEventType,
|
|
5532
6489
|
EOIMObjectEventType,
|
|
6490
|
+
OIMBucketCarrierProvider,
|
|
5533
6491
|
OIMCarrierKeyedEmitter,
|
|
5534
6492
|
OIMCarrierSingleEmitter,
|
|
5535
6493
|
OIMCollection,
|
|
@@ -5542,6 +6500,7 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
5542
6500
|
OIMCollectionSelectors,
|
|
5543
6501
|
OIMCollectionStore,
|
|
5544
6502
|
OIMCollectionStoreMapDriven,
|
|
6503
|
+
OIMCollectionStoreTrieDriven,
|
|
5545
6504
|
OIMComparatorFactory,
|
|
5546
6505
|
OIMComputeRuntime,
|
|
5547
6506
|
OIMComputed,
|
|
@@ -5550,6 +6509,7 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
5550
6509
|
OIMDerivedCollectionGlobalIndexSetBased,
|
|
5551
6510
|
OIMDerivedCollectionIndexArrayBased,
|
|
5552
6511
|
OIMDerivedCollectionIndexSetBased,
|
|
6512
|
+
OIMDisposeScope,
|
|
5553
6513
|
OIMEffect,
|
|
5554
6514
|
OIMEffectDependencyComputed,
|
|
5555
6515
|
OIMEffectDependencyKeyed,
|
|
@@ -5592,6 +6552,11 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
5592
6552
|
OIMIndexStoreMapDrivenArrayBased,
|
|
5593
6553
|
OIMIndexStoreMapDrivenSetBased,
|
|
5594
6554
|
OIMIndexStoreSetBased,
|
|
6555
|
+
OIMIndexStoreTrieDrivenArrayBased,
|
|
6556
|
+
OIMIndexStoreTrieDrivenSetBased,
|
|
6557
|
+
OIMKeyPathCarrierProvider,
|
|
6558
|
+
OIMKeyedBucketArrayBased,
|
|
6559
|
+
OIMKeyedBucketSetBased,
|
|
5595
6560
|
OIMMap2Keys,
|
|
5596
6561
|
OIMObject,
|
|
5597
6562
|
OIMObjectStore,
|
|
@@ -5603,10 +6568,13 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
5603
6568
|
OIMOrderedListCommandStream,
|
|
5604
6569
|
OIMOrderedListCommandStreamDiffDriven,
|
|
5605
6570
|
OIMOrderedListMappedCommandStream,
|
|
6571
|
+
OIMPkCodecKeyPath,
|
|
5606
6572
|
OIMPkSelectorFactory,
|
|
5607
6573
|
OIMReactiveCollection,
|
|
5608
6574
|
OIMReactiveCollectionGlobalIndexManualArrayBased,
|
|
5609
6575
|
OIMReactiveCollectionGlobalIndexManualSetBased,
|
|
6576
|
+
OIMReactiveCollectionIndexCompositeTrieArrayBased,
|
|
6577
|
+
OIMReactiveCollectionIndexCompositeTrieSetBased,
|
|
5610
6578
|
OIMReactiveCollectionIndexManualArrayBased,
|
|
5611
6579
|
OIMReactiveCollectionIndexManualSetBased,
|
|
5612
6580
|
OIMReactiveGlobalIndex,
|
|
@@ -5621,10 +6589,13 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
5621
6589
|
OIMReactiveIndexSetBased,
|
|
5622
6590
|
OIMReactiveObject,
|
|
5623
6591
|
OIMSelector,
|
|
6592
|
+
OIMTrieMap,
|
|
6593
|
+
OIMTrieSet,
|
|
5624
6594
|
createInPlaceEntityUpdater,
|
|
5625
6595
|
createMergeEntityUpdater,
|
|
5626
6596
|
createOIMCollectionIndexFactory,
|
|
5627
6597
|
createOIMCollectionKit,
|
|
6598
|
+
createOIMDisposeScope,
|
|
5628
6599
|
createOIMGlobalIndexSlotMap,
|
|
5629
6600
|
createOIMIndexSlotMap,
|
|
5630
6601
|
createOIMOrderedListCommandStreamDiffDriven,
|