@oimdb/core 2.2.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +447 -109
- package/dist/index.d.cts +163 -19
- package/dist/index.d.ts +163 -19
- package/dist/index.js +445 -109
- package/llms.txt +30 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -177,10 +177,18 @@ var OIMIndex = class {
|
|
|
177
177
|
emitUpdateOne(key) {
|
|
178
178
|
this.emitUpdate([key]);
|
|
179
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Maps a bucket's slots to entities, preserving positional holes: a slot
|
|
182
|
+
* whose entity is not present yet (reserved by an index ahead of its data)
|
|
183
|
+
* or was removed yields `undefined` at its position rather than being
|
|
184
|
+
* dropped. This keeps the result aligned with `getPksByKey`, so callers can
|
|
185
|
+
* render a per-item loading/placeholder state instead of a silently shorter
|
|
186
|
+
* list.
|
|
187
|
+
*/
|
|
180
188
|
slotsToEntities(slots) {
|
|
181
189
|
const entities = [];
|
|
182
190
|
for (const slot of slots) {
|
|
183
|
-
|
|
191
|
+
entities.push(slot.item);
|
|
184
192
|
}
|
|
185
193
|
return entities;
|
|
186
194
|
}
|
|
@@ -436,12 +444,7 @@ var OIMUpdateEventEmitter = class {
|
|
|
436
444
|
this.updatedKeys.clear();
|
|
437
445
|
return;
|
|
438
446
|
}
|
|
439
|
-
|
|
440
|
-
const snapshot = [];
|
|
441
|
-
handlers.forEach((h) => snapshot.push(h));
|
|
442
|
-
return snapshot;
|
|
443
|
-
};
|
|
444
|
-
this.runSinglePass(makeHandlerSnapshot);
|
|
447
|
+
this.runSinglePass();
|
|
445
448
|
};
|
|
446
449
|
this.onAfterFlush = () => {
|
|
447
450
|
if (!this.isAfterFlushDeliveryScheduled) return;
|
|
@@ -536,18 +539,32 @@ var OIMUpdateEventEmitter = class {
|
|
|
536
539
|
this.dequeueFlush = this.queue.enqueue(this.onFlush);
|
|
537
540
|
}
|
|
538
541
|
deliverImmediate() {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
542
|
+
this.runSinglePass();
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Notifies all handlers for a key. The overwhelmingly common case is a
|
|
546
|
+
* single subscriber per key (one component per pk), handled without any
|
|
547
|
+
* allocation. For multiple subscribers a snapshot is taken so a handler may
|
|
548
|
+
* (un)subscribe during iteration without corrupting the walk.
|
|
549
|
+
*/
|
|
550
|
+
notifyHandlers(handlers) {
|
|
551
|
+
if (handlers.size === 1) {
|
|
552
|
+
const only = handlers.values().next().value;
|
|
553
|
+
if (only) only();
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const snapshot = [];
|
|
557
|
+
handlers.forEach((h) => snapshot.push(h));
|
|
558
|
+
for (let i = 0; i < snapshot.length; i++) {
|
|
559
|
+
const handler = snapshot[i];
|
|
560
|
+
if (handlers.has(handler)) handler();
|
|
561
|
+
}
|
|
545
562
|
}
|
|
546
563
|
/**
|
|
547
564
|
* Deliver updated keys and notify handlers once.
|
|
548
565
|
* Re-entrant updates during delivery are forbidden and will throw in markUpdatedKeys().
|
|
549
566
|
*/
|
|
550
|
-
runSinglePass(
|
|
567
|
+
runSinglePass() {
|
|
551
568
|
if (this.updatedKeys.size === 0) return;
|
|
552
569
|
const flushingKeys = this.updatedKeys;
|
|
553
570
|
this.updatedKeys = /* @__PURE__ */ new Set();
|
|
@@ -556,21 +573,13 @@ var OIMUpdateEventEmitter = class {
|
|
|
556
573
|
flushingKeys.forEach((key) => {
|
|
557
574
|
const handlers = this.keyHandlers.get(key);
|
|
558
575
|
if (!handlers || handlers.size === 0) return;
|
|
559
|
-
|
|
560
|
-
for (let i = 0; i < handlerSnapshot.length; i++) {
|
|
561
|
-
const handler = handlerSnapshot[i];
|
|
562
|
-
if (handlers.has(handler)) handler();
|
|
563
|
-
}
|
|
576
|
+
this.notifyHandlers(handlers);
|
|
564
577
|
});
|
|
565
578
|
} else {
|
|
566
579
|
this.keyHandlers.forEach((handlers, key) => {
|
|
567
580
|
if (!flushingKeys.has(key)) return;
|
|
568
581
|
if (!handlers || handlers.size === 0) return;
|
|
569
|
-
|
|
570
|
-
for (let i = 0; i < handlerSnapshot.length; i++) {
|
|
571
|
-
const handler = handlerSnapshot[i];
|
|
572
|
-
if (handlers.has(handler)) handler();
|
|
573
|
-
}
|
|
582
|
+
this.notifyHandlers(handlers);
|
|
574
583
|
});
|
|
575
584
|
}
|
|
576
585
|
}
|
|
@@ -824,6 +833,12 @@ var OIMCollectionStoreMapDriven = class extends OIMCollectionStore {
|
|
|
824
833
|
getSlotByPk(pk) {
|
|
825
834
|
return this.slots.get(pk);
|
|
826
835
|
}
|
|
836
|
+
findSlotByPk(pk) {
|
|
837
|
+
return this.slots.get(pk) ?? this.reservedSlots.get(pk);
|
|
838
|
+
}
|
|
839
|
+
hasSubscribers(slot) {
|
|
840
|
+
return slot.subscribers !== void 0 && slot.subscribers.size > 0;
|
|
841
|
+
}
|
|
827
842
|
getSlotsByPks(pks) {
|
|
828
843
|
const result = [];
|
|
829
844
|
result.length = pks.length;
|
|
@@ -842,12 +857,20 @@ var OIMCollectionStoreMapDriven = class extends OIMCollectionStore {
|
|
|
842
857
|
}
|
|
843
858
|
removeOneByPk(pk) {
|
|
844
859
|
const slot = this.slots.get(pk);
|
|
845
|
-
if (slot)
|
|
846
|
-
|
|
860
|
+
if (slot) {
|
|
861
|
+
slot.item = void 0;
|
|
862
|
+
this.slots.delete(pk);
|
|
863
|
+
if (this.hasSubscribers(slot)) {
|
|
864
|
+
this.reservedSlots.set(pk, slot);
|
|
865
|
+
}
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
847
868
|
const reserved = this.reservedSlots.get(pk);
|
|
848
869
|
if (reserved) {
|
|
849
870
|
reserved.item = void 0;
|
|
850
|
-
this.
|
|
871
|
+
if (!this.hasSubscribers(reserved)) {
|
|
872
|
+
this.reservedSlots.delete(pk);
|
|
873
|
+
}
|
|
851
874
|
}
|
|
852
875
|
}
|
|
853
876
|
removeManyByPks(pks) {
|
|
@@ -882,20 +905,31 @@ var OIMCollectionStoreMapDriven = class extends OIMCollectionStore {
|
|
|
882
905
|
return this.slots.size;
|
|
883
906
|
}
|
|
884
907
|
clear() {
|
|
908
|
+
const retained = [];
|
|
885
909
|
for (const slot of this.slots.values()) {
|
|
886
910
|
slot.item = void 0;
|
|
911
|
+
if (this.hasSubscribers(slot)) retained.push(slot);
|
|
887
912
|
}
|
|
888
913
|
this.slots.clear();
|
|
889
914
|
for (const slot of this.reservedSlots.values()) {
|
|
890
915
|
slot.item = void 0;
|
|
916
|
+
if (this.hasSubscribers(slot)) retained.push(slot);
|
|
891
917
|
}
|
|
892
918
|
this.reservedSlots.clear();
|
|
919
|
+
for (const slot of retained) {
|
|
920
|
+
this.reservedSlots.set(slot.pk, slot);
|
|
921
|
+
}
|
|
893
922
|
}
|
|
894
923
|
getAllPks() {
|
|
895
924
|
return Array.from(this.slots.keys());
|
|
896
925
|
}
|
|
897
926
|
destroy() {
|
|
898
927
|
this.clear();
|
|
928
|
+
for (const slot of this.reservedSlots.values()) {
|
|
929
|
+
slot.subscribers?.clear();
|
|
930
|
+
slot.subscribers = void 0;
|
|
931
|
+
}
|
|
932
|
+
this.reservedSlots.clear();
|
|
899
933
|
}
|
|
900
934
|
};
|
|
901
935
|
|
|
@@ -1018,6 +1052,153 @@ var OIMCollection = class {
|
|
|
1018
1052
|
}
|
|
1019
1053
|
};
|
|
1020
1054
|
|
|
1055
|
+
// src/core/OIMCarrierKeyedEmitter.ts
|
|
1056
|
+
var OIMCarrierKeyedEmitter = class {
|
|
1057
|
+
constructor(queue, resolver) {
|
|
1058
|
+
// Carriers with at least one subscriber — for markAllUpdated / metrics.
|
|
1059
|
+
this.subscribedCarriers = /* @__PURE__ */ new Set();
|
|
1060
|
+
this.dirtyCarriers = /* @__PURE__ */ new Set();
|
|
1061
|
+
this.isFlushEnqueued = false;
|
|
1062
|
+
this.onFlush = () => {
|
|
1063
|
+
this.isFlushEnqueued = false;
|
|
1064
|
+
this.dequeueFlush = void 0;
|
|
1065
|
+
if (this.dirtyCarriers.size === 0) return;
|
|
1066
|
+
const flushing = this.dirtyCarriers;
|
|
1067
|
+
this.dirtyCarriers = /* @__PURE__ */ new Set();
|
|
1068
|
+
flushing.forEach((carrier) => this.notify(carrier));
|
|
1069
|
+
};
|
|
1070
|
+
this.queue = queue;
|
|
1071
|
+
this.resolver = resolver;
|
|
1072
|
+
}
|
|
1073
|
+
subscribeOnKey(key, handler) {
|
|
1074
|
+
const carrier = this.resolver.getOrReserveCarrier(key);
|
|
1075
|
+
this.addHandler(carrier, handler);
|
|
1076
|
+
return () => this.removeHandler(carrier, handler);
|
|
1077
|
+
}
|
|
1078
|
+
subscribeOnKeys(keys, handler) {
|
|
1079
|
+
const carriers = [];
|
|
1080
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1081
|
+
const carrier = this.resolver.getOrReserveCarrier(keys[i]);
|
|
1082
|
+
this.addHandler(carrier, handler);
|
|
1083
|
+
carriers.push(carrier);
|
|
1084
|
+
}
|
|
1085
|
+
return () => {
|
|
1086
|
+
for (let i = 0; i < carriers.length; i++) {
|
|
1087
|
+
this.removeHandler(carriers[i], handler);
|
|
1088
|
+
}
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
unsubscribeFromKey(key, handler) {
|
|
1092
|
+
const carrier = this.resolver.findCarrier(key);
|
|
1093
|
+
if (carrier) this.removeHandler(carrier, handler);
|
|
1094
|
+
}
|
|
1095
|
+
unsubscribeFromKeys(keys, handler) {
|
|
1096
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1097
|
+
this.unsubscribeFromKey(keys[i], handler);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
addHandler(carrier, handler) {
|
|
1101
|
+
let subscribers = carrier.subscribers;
|
|
1102
|
+
if (!subscribers) {
|
|
1103
|
+
subscribers = /* @__PURE__ */ new Set();
|
|
1104
|
+
carrier.subscribers = subscribers;
|
|
1105
|
+
}
|
|
1106
|
+
subscribers.add(handler);
|
|
1107
|
+
this.subscribedCarriers.add(carrier);
|
|
1108
|
+
}
|
|
1109
|
+
removeHandler(carrier, handler) {
|
|
1110
|
+
const subscribers = carrier.subscribers;
|
|
1111
|
+
if (!subscribers) return;
|
|
1112
|
+
subscribers.delete(handler);
|
|
1113
|
+
if (subscribers.size === 0) {
|
|
1114
|
+
this.subscribedCarriers.delete(carrier);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
/** Fast path: the writer already holds the carrier. */
|
|
1118
|
+
markUpdatedCarrier(carrier) {
|
|
1119
|
+
this.assertNotInFlush();
|
|
1120
|
+
const subscribers = carrier.subscribers;
|
|
1121
|
+
if (!subscribers || subscribers.size === 0) return;
|
|
1122
|
+
this.dirtyCarriers.add(carrier);
|
|
1123
|
+
this.scheduleFlush();
|
|
1124
|
+
}
|
|
1125
|
+
markUpdatedKey(key) {
|
|
1126
|
+
const carrier = this.resolver.findCarrier(key);
|
|
1127
|
+
if (carrier) this.markUpdatedCarrier(carrier);
|
|
1128
|
+
else this.assertNotInFlush();
|
|
1129
|
+
}
|
|
1130
|
+
markUpdatedKeys(keys) {
|
|
1131
|
+
for (let i = 0; i < keys.length; i++) this.markUpdatedKey(keys[i]);
|
|
1132
|
+
}
|
|
1133
|
+
markAllUpdated() {
|
|
1134
|
+
this.assertNotInFlush();
|
|
1135
|
+
if (this.subscribedCarriers.size === 0) return;
|
|
1136
|
+
this.subscribedCarriers.forEach(
|
|
1137
|
+
(carrier) => this.dirtyCarriers.add(carrier)
|
|
1138
|
+
);
|
|
1139
|
+
this.scheduleFlush();
|
|
1140
|
+
}
|
|
1141
|
+
hasSubscriptions() {
|
|
1142
|
+
return this.subscribedCarriers.size > 0;
|
|
1143
|
+
}
|
|
1144
|
+
getHandlerCount(key) {
|
|
1145
|
+
return this.resolver.findCarrier(key)?.subscribers?.size ?? 0;
|
|
1146
|
+
}
|
|
1147
|
+
getMetrics() {
|
|
1148
|
+
let totalHandlers = 0;
|
|
1149
|
+
this.subscribedCarriers.forEach((carrier) => {
|
|
1150
|
+
totalHandlers += carrier.subscribers?.size ?? 0;
|
|
1151
|
+
});
|
|
1152
|
+
const totalKeys = this.subscribedCarriers.size;
|
|
1153
|
+
return {
|
|
1154
|
+
totalKeys,
|
|
1155
|
+
totalHandlers,
|
|
1156
|
+
averageHandlersPerKey: totalKeys > 0 ? totalHandlers / totalKeys : 0,
|
|
1157
|
+
queueLength: this.dirtyCarriers.size
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
destroy() {
|
|
1161
|
+
if (this.dequeueFlush) {
|
|
1162
|
+
this.dequeueFlush();
|
|
1163
|
+
this.dequeueFlush = void 0;
|
|
1164
|
+
}
|
|
1165
|
+
this.subscribedCarriers.forEach((carrier) => {
|
|
1166
|
+
carrier.subscribers?.clear();
|
|
1167
|
+
carrier.subscribers = void 0;
|
|
1168
|
+
});
|
|
1169
|
+
this.subscribedCarriers.clear();
|
|
1170
|
+
this.dirtyCarriers.clear();
|
|
1171
|
+
this.isFlushEnqueued = false;
|
|
1172
|
+
}
|
|
1173
|
+
assertNotInFlush() {
|
|
1174
|
+
if (this.queue.isInFlush) {
|
|
1175
|
+
throw new Error(
|
|
1176
|
+
"OIMCarrierKeyedEmitter: updates during queue.flush() are not allowed. Finish all writes before calling queue.flush()."
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
scheduleFlush() {
|
|
1181
|
+
if (this.isFlushEnqueued) return;
|
|
1182
|
+
this.isFlushEnqueued = true;
|
|
1183
|
+
this.dequeueFlush = this.queue.enqueue(this.onFlush);
|
|
1184
|
+
}
|
|
1185
|
+
notify(carrier) {
|
|
1186
|
+
const subscribers = carrier.subscribers;
|
|
1187
|
+
if (!subscribers || subscribers.size === 0) return;
|
|
1188
|
+
if (subscribers.size === 1) {
|
|
1189
|
+
const only = subscribers.values().next().value;
|
|
1190
|
+
if (only) only();
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
const snapshot = [];
|
|
1194
|
+
subscribers.forEach((h) => snapshot.push(h));
|
|
1195
|
+
for (let i = 0; i < snapshot.length; i++) {
|
|
1196
|
+
const handler = snapshot[i];
|
|
1197
|
+
if (subscribers.has(handler)) handler();
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1021
1202
|
// src/core/OIMReactiveCollection.ts
|
|
1022
1203
|
var OIMReactiveCollection = class extends OIMCollection {
|
|
1023
1204
|
constructor(queue, opts) {
|
|
@@ -1037,7 +1218,10 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1037
1218
|
for (let i = 0; i < snapshot.length; i++) snapshot[i](pks);
|
|
1038
1219
|
};
|
|
1039
1220
|
this.queue = queue;
|
|
1040
|
-
this.updateEmitter = new
|
|
1221
|
+
this.updateEmitter = new OIMCarrierKeyedEmitter(queue, {
|
|
1222
|
+
getOrReserveCarrier: (pk) => this.store.getOrReserveSlotByPk(pk),
|
|
1223
|
+
findCarrier: (pk) => this.store.findSlotByPk(pk)
|
|
1224
|
+
});
|
|
1041
1225
|
}
|
|
1042
1226
|
subscribeOnKey(pk, handler) {
|
|
1043
1227
|
return this.updateEmitter.subscribeOnKey(pk, handler);
|
|
@@ -1069,17 +1253,31 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1069
1253
|
this.anyUpdateHandlers.delete(handler);
|
|
1070
1254
|
};
|
|
1071
1255
|
}
|
|
1256
|
+
// The legacy `emitter` (EOIMCollectionEventType.UPDATE) coexists with the
|
|
1257
|
+
// keyed `updateEmitter`. Build its payload only when something is actually
|
|
1258
|
+
// subscribed — otherwise every upsert/remove allocates a throwaway
|
|
1259
|
+
// `{ pks }` object (and array) that nobody reads.
|
|
1260
|
+
notifyLegacy(pk) {
|
|
1261
|
+
if (this.emitter.hasHandlers(0 /* UPDATE */)) {
|
|
1262
|
+
this.emitter.emit(0 /* UPDATE */, { pks: [pk] });
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
notifyLegacyMany(pks) {
|
|
1266
|
+
if (this.emitter.hasHandlers(0 /* UPDATE */)) {
|
|
1267
|
+
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1072
1270
|
upsertOneByPk(pk, entity) {
|
|
1073
1271
|
const slot = this.upsertOneWithoutNotificationsByPk(pk, entity);
|
|
1074
|
-
this.
|
|
1075
|
-
this.updateEmitter.
|
|
1272
|
+
this.notifyLegacy(pk);
|
|
1273
|
+
this.updateEmitter.markUpdatedCarrier(slot);
|
|
1076
1274
|
this.trackAnyUpdatePk(pk);
|
|
1077
1275
|
return slot;
|
|
1078
1276
|
}
|
|
1079
1277
|
upsertOne(entity) {
|
|
1080
1278
|
const slot = this.upsertOneWithoutNotifications(entity);
|
|
1081
|
-
this.
|
|
1082
|
-
this.updateEmitter.
|
|
1279
|
+
this.notifyLegacy(slot.pk);
|
|
1280
|
+
this.updateEmitter.markUpdatedCarrier(slot);
|
|
1083
1281
|
this.trackAnyUpdatePk(slot.pk);
|
|
1084
1282
|
return slot;
|
|
1085
1283
|
}
|
|
@@ -1089,15 +1287,17 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1089
1287
|
(entity) => this.upsertOneWithoutNotifications(entity)
|
|
1090
1288
|
);
|
|
1091
1289
|
const pks = slots.map((slot) => slot.pk);
|
|
1092
|
-
this.
|
|
1093
|
-
|
|
1290
|
+
this.notifyLegacyMany(pks);
|
|
1291
|
+
for (let i = 0; i < slots.length; i++) {
|
|
1292
|
+
this.updateEmitter.markUpdatedCarrier(slots[i]);
|
|
1293
|
+
}
|
|
1094
1294
|
this.trackAnyUpdatePks(pks);
|
|
1095
1295
|
return slots;
|
|
1096
1296
|
}
|
|
1097
1297
|
removeOne(entity) {
|
|
1098
1298
|
const pk = this.selectPk(entity);
|
|
1099
1299
|
this.store.removeOneByPk(pk);
|
|
1100
|
-
this.
|
|
1300
|
+
this.notifyLegacy(pk);
|
|
1101
1301
|
this.updateEmitter.markUpdatedKey(pk);
|
|
1102
1302
|
this.trackAnyUpdatePk(pk);
|
|
1103
1303
|
}
|
|
@@ -1105,26 +1305,28 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1105
1305
|
if (entities.length === 0) return;
|
|
1106
1306
|
const pks = entities.map(this.selectPk);
|
|
1107
1307
|
this.store.removeManyByPks(pks);
|
|
1108
|
-
this.
|
|
1308
|
+
this.notifyLegacyMany(pks);
|
|
1109
1309
|
this.updateEmitter.markUpdatedKeys(pks);
|
|
1110
1310
|
this.trackAnyUpdatePks(pks);
|
|
1111
1311
|
}
|
|
1112
1312
|
removeOneByPk(pk) {
|
|
1113
1313
|
this.store.removeOneByPk(pk);
|
|
1114
|
-
this.
|
|
1314
|
+
this.notifyLegacy(pk);
|
|
1115
1315
|
this.updateEmitter.markUpdatedKey(pk);
|
|
1116
1316
|
this.trackAnyUpdatePk(pk);
|
|
1117
1317
|
}
|
|
1118
1318
|
removeManyByPks(pks) {
|
|
1119
1319
|
if (pks.length === 0) return;
|
|
1120
1320
|
this.store.removeManyByPks(pks);
|
|
1121
|
-
this.
|
|
1321
|
+
this.notifyLegacyMany(pks);
|
|
1122
1322
|
this.updateEmitter.markUpdatedKeys(pks);
|
|
1123
1323
|
this.trackAnyUpdatePks(pks);
|
|
1124
1324
|
}
|
|
1125
1325
|
clear() {
|
|
1126
1326
|
this.store.clear();
|
|
1127
|
-
this.emitter.
|
|
1327
|
+
if (this.emitter.hasHandlers(0 /* UPDATE */)) {
|
|
1328
|
+
this.emitter.emit(0 /* UPDATE */, { pks: [] });
|
|
1329
|
+
}
|
|
1128
1330
|
this.updateEmitter.markAllUpdated();
|
|
1129
1331
|
this.trackAnyUpdateClear();
|
|
1130
1332
|
}
|
|
@@ -1507,6 +1709,21 @@ var OIMIndexManualArrayBased = class extends OIMIndexArrayBased {
|
|
|
1507
1709
|
this.emitUpdateOne(key);
|
|
1508
1710
|
}
|
|
1509
1711
|
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Appends pre-deduplicated slots to a key's bucket IN PLACE (no copy of the
|
|
1714
|
+
* existing bucket) and emits once. Callers own dedup (so this stays O(added),
|
|
1715
|
+
* not O(bucket)); used by collection-bound indexes for fast `addPks`.
|
|
1716
|
+
*/
|
|
1717
|
+
appendSlots(key, slots) {
|
|
1718
|
+
if (slots.length === 0) return;
|
|
1719
|
+
let bucket = this.store.getOneByKey(key);
|
|
1720
|
+
if (!bucket) {
|
|
1721
|
+
bucket = [];
|
|
1722
|
+
this.store.setOneByKey(key, bucket);
|
|
1723
|
+
}
|
|
1724
|
+
for (let i = 0; i < slots.length; i++) bucket.push(slots[i]);
|
|
1725
|
+
this.emitUpdateOne(key);
|
|
1726
|
+
}
|
|
1510
1727
|
/**
|
|
1511
1728
|
* Clear all primary keys for a specific index key, or all keys if no key specified
|
|
1512
1729
|
*/
|
|
@@ -1551,6 +1768,9 @@ var OIMReactiveIndexManualArrayBased = class extends OIMReactiveIndexArrayBased
|
|
|
1551
1768
|
setSlots(key, slots) {
|
|
1552
1769
|
this.index.setSlots(key, slots);
|
|
1553
1770
|
}
|
|
1771
|
+
appendSlots(key, slots) {
|
|
1772
|
+
this.index.appendSlots(key, slots);
|
|
1773
|
+
}
|
|
1554
1774
|
clear(key) {
|
|
1555
1775
|
this.index.clear(key);
|
|
1556
1776
|
}
|
|
@@ -1563,24 +1783,27 @@ var OIMReactiveCollectionIndexManualArrayBased = class extends OIMReactiveIndexM
|
|
|
1563
1783
|
super(queue, {
|
|
1564
1784
|
indexOptions: opts.indexOptions
|
|
1565
1785
|
});
|
|
1786
|
+
// Persistent per-key pk membership for O(1) `addPks` dedup (avoids rebuilding
|
|
1787
|
+
// a Set from the whole bucket on every call). Kept in sync by setSlots/clear.
|
|
1788
|
+
this.pksByKey = /* @__PURE__ */ new Map();
|
|
1566
1789
|
this.resolveSlot = resolveSlot;
|
|
1567
1790
|
}
|
|
1568
1791
|
setPks(key, pks) {
|
|
1569
|
-
|
|
1792
|
+
const pkSet = /* @__PURE__ */ new Set();
|
|
1793
|
+
for (let i = 0; i < pks.length; i++) pkSet.add(pks[i]);
|
|
1794
|
+
this.pksByKey.set(key, pkSet);
|
|
1795
|
+
super.setSlots(key, this.resolveSlots(pks));
|
|
1570
1796
|
}
|
|
1571
1797
|
addPks(key, pks) {
|
|
1572
1798
|
if (pks.length === 0) return;
|
|
1573
|
-
const
|
|
1574
|
-
const
|
|
1575
|
-
const nextSlots = existingSlots.slice();
|
|
1576
|
-
let hasChanges = false;
|
|
1799
|
+
const pkSet = this.membershipOf(key);
|
|
1800
|
+
const newSlots = [];
|
|
1577
1801
|
for (const pk of pks) {
|
|
1578
|
-
if (
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
hasChanges = true;
|
|
1802
|
+
if (pkSet.has(pk)) continue;
|
|
1803
|
+
pkSet.add(pk);
|
|
1804
|
+
newSlots.push(this.resolveRequiredSlot(pk));
|
|
1582
1805
|
}
|
|
1583
|
-
if (
|
|
1806
|
+
if (newSlots.length > 0) this.appendSlots(key, newSlots);
|
|
1584
1807
|
}
|
|
1585
1808
|
removePks(key, pks) {
|
|
1586
1809
|
if (pks.length === 0) return;
|
|
@@ -1590,8 +1813,33 @@ var OIMReactiveCollectionIndexManualArrayBased = class extends OIMReactiveIndexM
|
|
|
1590
1813
|
(slot) => !pksToRemove.has(slot.pk)
|
|
1591
1814
|
);
|
|
1592
1815
|
if (nextSlots.length === existingSlots.length) return;
|
|
1816
|
+
const pkSet = this.pksByKey.get(key);
|
|
1817
|
+
if (pkSet) {
|
|
1818
|
+
for (let i = 0; i < pks.length; i++) pkSet.delete(pks[i]);
|
|
1819
|
+
}
|
|
1593
1820
|
if (nextSlots.length === 0) this.clear(key);
|
|
1594
|
-
else
|
|
1821
|
+
else super.setSlots(key, nextSlots);
|
|
1822
|
+
}
|
|
1823
|
+
clear(key) {
|
|
1824
|
+
if (key === void 0) this.pksByKey.clear();
|
|
1825
|
+
else this.pksByKey.delete(key);
|
|
1826
|
+
super.clear(key);
|
|
1827
|
+
}
|
|
1828
|
+
/**
|
|
1829
|
+
* The membership set for a key, lazily seeded from the current bucket so it
|
|
1830
|
+
* stays correct even if slots were set through a lower-level path.
|
|
1831
|
+
*/
|
|
1832
|
+
membershipOf(key) {
|
|
1833
|
+
let pkSet = this.pksByKey.get(key);
|
|
1834
|
+
if (!pkSet) {
|
|
1835
|
+
pkSet = /* @__PURE__ */ new Set();
|
|
1836
|
+
const existing = this.index.getSlotsByKey(key);
|
|
1837
|
+
for (let i = 0; i < existing.length; i++) {
|
|
1838
|
+
pkSet.add(existing[i].pk);
|
|
1839
|
+
}
|
|
1840
|
+
this.pksByKey.set(key, pkSet);
|
|
1841
|
+
}
|
|
1842
|
+
return pkSet;
|
|
1595
1843
|
}
|
|
1596
1844
|
getEntitiesByKey(key) {
|
|
1597
1845
|
return super.getEntitiesByKey(key);
|
|
@@ -1625,6 +1873,41 @@ var OIMIndexManualSetBased = class extends OIMIndexSetBased {
|
|
|
1625
1873
|
this.emitUpdateOne(key);
|
|
1626
1874
|
}
|
|
1627
1875
|
}
|
|
1876
|
+
/**
|
|
1877
|
+
* Adds slots to a key's bucket IN PLACE (no copy of the existing Set) and
|
|
1878
|
+
* emits once. O(added). Used by collection-bound indexes for fast `addPks`.
|
|
1879
|
+
*/
|
|
1880
|
+
addSlots(key, slots) {
|
|
1881
|
+
if (slots.length === 0) return;
|
|
1882
|
+
let bucket = this.store.getOneByKey(key);
|
|
1883
|
+
if (!bucket) {
|
|
1884
|
+
bucket = /* @__PURE__ */ new Set();
|
|
1885
|
+
this.store.setOneByKey(key, bucket);
|
|
1886
|
+
}
|
|
1887
|
+
let changed = false;
|
|
1888
|
+
for (let i = 0; i < slots.length; i++) {
|
|
1889
|
+
if (!bucket.has(slots[i])) {
|
|
1890
|
+
bucket.add(slots[i]);
|
|
1891
|
+
changed = true;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
if (changed) this.emitUpdateOne(key);
|
|
1895
|
+
}
|
|
1896
|
+
/**
|
|
1897
|
+
* Removes slots from a key's bucket IN PLACE (O(removed)) and emits once.
|
|
1898
|
+
*/
|
|
1899
|
+
removeSlots(key, slots) {
|
|
1900
|
+
if (slots.length === 0) return;
|
|
1901
|
+
const bucket = this.store.getOneByKey(key);
|
|
1902
|
+
if (!bucket) return;
|
|
1903
|
+
let changed = false;
|
|
1904
|
+
for (let i = 0; i < slots.length; i++) {
|
|
1905
|
+
if (bucket.delete(slots[i])) changed = true;
|
|
1906
|
+
}
|
|
1907
|
+
if (!changed) return;
|
|
1908
|
+
if (bucket.size === 0) this.store.removeOneByKey(key);
|
|
1909
|
+
this.emitUpdateOne(key);
|
|
1910
|
+
}
|
|
1628
1911
|
/**
|
|
1629
1912
|
* Clear all primary keys for a specific index key, or all keys if no key specified
|
|
1630
1913
|
*/
|
|
@@ -1669,6 +1952,12 @@ var OIMReactiveIndexManualSetBased = class extends OIMReactiveIndexSetBased {
|
|
|
1669
1952
|
setSlots(key, slots) {
|
|
1670
1953
|
this.index.setSlots(key, slots);
|
|
1671
1954
|
}
|
|
1955
|
+
addSlots(key, slots) {
|
|
1956
|
+
this.index.addSlots(key, slots);
|
|
1957
|
+
}
|
|
1958
|
+
removeSlots(key, slots) {
|
|
1959
|
+
this.index.removeSlots(key, slots);
|
|
1960
|
+
}
|
|
1672
1961
|
clear(key) {
|
|
1673
1962
|
this.index.clear(key);
|
|
1674
1963
|
}
|
|
@@ -1681,42 +1970,69 @@ var OIMReactiveCollectionIndexManualSetBased = class extends OIMReactiveIndexMan
|
|
|
1681
1970
|
super(queue, {
|
|
1682
1971
|
indexOptions: opts.indexOptions
|
|
1683
1972
|
});
|
|
1973
|
+
// Persistent per-key pk → slot map for O(1) add (dedup) and O(1) remove
|
|
1974
|
+
// (slot lookup by pk). Kept in sync by setPks/addPks/removePks/clear.
|
|
1975
|
+
this.slotByPk = /* @__PURE__ */ new Map();
|
|
1684
1976
|
this.resolveSlot = resolveSlot;
|
|
1685
1977
|
}
|
|
1686
1978
|
setPks(key, pks) {
|
|
1687
|
-
|
|
1979
|
+
const map = /* @__PURE__ */ new Map();
|
|
1980
|
+
const slots = [];
|
|
1981
|
+
for (let i = 0; i < pks.length; i++) {
|
|
1982
|
+
const pk = pks[i];
|
|
1983
|
+
const slot = this.resolveRequiredSlot(pk);
|
|
1984
|
+
if (!map.has(pk)) map.set(pk, slot);
|
|
1985
|
+
slots.push(slot);
|
|
1986
|
+
}
|
|
1987
|
+
this.slotByPk.set(key, map);
|
|
1988
|
+
super.setSlots(key, slots);
|
|
1688
1989
|
}
|
|
1689
1990
|
addPks(key, pks) {
|
|
1690
1991
|
if (pks.length === 0) return;
|
|
1691
|
-
const
|
|
1692
|
-
const
|
|
1693
|
-
const nextSlots = new Set(existingSlots);
|
|
1694
|
-
let hasChanges = false;
|
|
1992
|
+
const map = this.membershipOf(key);
|
|
1993
|
+
const newSlots = [];
|
|
1695
1994
|
for (const pk of pks) {
|
|
1696
|
-
if (
|
|
1995
|
+
if (map.has(pk)) continue;
|
|
1697
1996
|
const slot = this.resolveRequiredSlot(pk);
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
hasChanges = true;
|
|
1997
|
+
map.set(pk, slot);
|
|
1998
|
+
newSlots.push(slot);
|
|
1701
1999
|
}
|
|
1702
|
-
if (
|
|
2000
|
+
if (newSlots.length > 0) this.addSlots(key, newSlots);
|
|
1703
2001
|
}
|
|
1704
2002
|
removePks(key, pks) {
|
|
1705
2003
|
if (pks.length === 0) return;
|
|
1706
|
-
const
|
|
1707
|
-
|
|
1708
|
-
const
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
if (
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
nextSlots.add(slot);
|
|
2004
|
+
const map = this.membershipOf(key);
|
|
2005
|
+
if (map.size === 0) return;
|
|
2006
|
+
const removed = [];
|
|
2007
|
+
for (const pk of pks) {
|
|
2008
|
+
const slot = map.get(pk);
|
|
2009
|
+
if (slot) {
|
|
2010
|
+
map.delete(pk);
|
|
2011
|
+
removed.push(slot);
|
|
1715
2012
|
}
|
|
1716
2013
|
}
|
|
1717
|
-
if (
|
|
1718
|
-
if (
|
|
1719
|
-
|
|
2014
|
+
if (removed.length === 0) return;
|
|
2015
|
+
if (map.size === 0) this.slotByPk.delete(key);
|
|
2016
|
+
this.removeSlots(key, removed);
|
|
2017
|
+
}
|
|
2018
|
+
clear(key) {
|
|
2019
|
+
if (key === void 0) this.slotByPk.clear();
|
|
2020
|
+
else this.slotByPk.delete(key);
|
|
2021
|
+
super.clear(key);
|
|
2022
|
+
}
|
|
2023
|
+
/**
|
|
2024
|
+
* The pk→slot map for a key, lazily seeded from the current bucket so it
|
|
2025
|
+
* stays correct even if slots were set through a lower-level path.
|
|
2026
|
+
*/
|
|
2027
|
+
membershipOf(key) {
|
|
2028
|
+
let map = this.slotByPk.get(key);
|
|
2029
|
+
if (!map) {
|
|
2030
|
+
map = /* @__PURE__ */ new Map();
|
|
2031
|
+
const existing = this.index.getSlotsByKey(key);
|
|
2032
|
+
for (const slot of existing) map.set(slot.pk, slot);
|
|
2033
|
+
this.slotByPk.set(key, map);
|
|
2034
|
+
}
|
|
2035
|
+
return map;
|
|
1720
2036
|
}
|
|
1721
2037
|
getEntitiesByKey(key) {
|
|
1722
2038
|
return super.getEntitiesByKey(key);
|
|
@@ -1724,11 +2040,6 @@ var OIMReactiveCollectionIndexManualSetBased = class extends OIMReactiveIndexMan
|
|
|
1724
2040
|
getEntitiesByKeys(keys) {
|
|
1725
2041
|
return super.getEntitiesByKeys(keys);
|
|
1726
2042
|
}
|
|
1727
|
-
resolveSlots(pks) {
|
|
1728
|
-
const slots = /* @__PURE__ */ new Set();
|
|
1729
|
-
for (const pk of pks) slots.add(this.resolveRequiredSlot(pk));
|
|
1730
|
-
return slots;
|
|
1731
|
-
}
|
|
1732
2043
|
resolveRequiredSlot(pk) {
|
|
1733
2044
|
const slot = this.resolveSlot(pk);
|
|
1734
2045
|
if (!slot) return { pk, item: void 0 };
|
|
@@ -1846,17 +2157,56 @@ var OIMDerivedCollectionIndexArrayBased = class extends OIMReactiveCollectionInd
|
|
|
1846
2157
|
indexOptions: opts.indexOptions
|
|
1847
2158
|
});
|
|
1848
2159
|
this.keysByPk = /* @__PURE__ */ new Map();
|
|
2160
|
+
// Last known sort value per pk (only when `orderBy` is used), so an update
|
|
2161
|
+
// touching an unrelated field can skip re-sorting when the value is unchanged.
|
|
2162
|
+
this.orderValueByPk = /* @__PURE__ */ new Map();
|
|
1849
2163
|
this.onCollectionUpdate = (pks) => {
|
|
1850
2164
|
if (pks.length === 0) {
|
|
1851
2165
|
this.rebuildFromCollection();
|
|
1852
2166
|
return;
|
|
1853
2167
|
}
|
|
1854
|
-
const
|
|
2168
|
+
const ordered = !!(this.compareEntities || this.orderBy);
|
|
2169
|
+
const keysToSort = ordered ? /* @__PURE__ */ new Set() : null;
|
|
1855
2170
|
for (const pk of pks) {
|
|
1856
|
-
this.
|
|
2171
|
+
const prevKeys = this.keysByPk.get(pk) ?? /* @__PURE__ */ new Set();
|
|
2172
|
+
const slot = this.collection.getSlotByPk(pk);
|
|
2173
|
+
const entity = slot?.item;
|
|
2174
|
+
const nextKeys = entity === void 0 ? /* @__PURE__ */ new Set() : new Set(this.normalizeKeys(this.selectIndexKeys(entity)));
|
|
2175
|
+
let orderChanged = false;
|
|
2176
|
+
if (this.orderBy) {
|
|
2177
|
+
if (entity === void 0 || nextKeys.size === 0) {
|
|
2178
|
+
this.orderValueByPk.delete(pk);
|
|
2179
|
+
} else {
|
|
2180
|
+
const value = this.orderBy(entity);
|
|
2181
|
+
orderChanged = !this.orderValueByPk.has(pk) || this.orderValueByPk.get(pk) !== value;
|
|
2182
|
+
this.orderValueByPk.set(pk, value);
|
|
2183
|
+
}
|
|
2184
|
+
} else if (this.compareEntities && entity !== void 0) {
|
|
2185
|
+
orderChanged = true;
|
|
2186
|
+
}
|
|
2187
|
+
for (const key of prevKeys) {
|
|
2188
|
+
if (!nextKeys.has(key)) this.removePks(key, [pk]);
|
|
2189
|
+
}
|
|
2190
|
+
if (entity !== void 0) {
|
|
2191
|
+
for (const key of nextKeys) {
|
|
2192
|
+
if (!prevKeys.has(key)) {
|
|
2193
|
+
this.addPks(key, [pk]);
|
|
2194
|
+
keysToSort?.add(key);
|
|
2195
|
+
} else if (orderChanged) {
|
|
2196
|
+
keysToSort?.add(key);
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
if (nextKeys.size === 0) this.keysByPk.delete(pk);
|
|
2201
|
+
else this.keysByPk.set(pk, nextKeys);
|
|
1857
2202
|
}
|
|
1858
|
-
|
|
1859
|
-
|
|
2203
|
+
if (keysToSort) {
|
|
2204
|
+
for (const key of keysToSort) {
|
|
2205
|
+
this.setSlots(
|
|
2206
|
+
key,
|
|
2207
|
+
this.sortSlots(this.index.getSlotsByKey(key))
|
|
2208
|
+
);
|
|
2209
|
+
}
|
|
1860
2210
|
}
|
|
1861
2211
|
};
|
|
1862
2212
|
this.collection = collection;
|
|
@@ -1873,6 +2223,7 @@ var OIMDerivedCollectionIndexArrayBased = class extends OIMReactiveCollectionInd
|
|
|
1873
2223
|
}
|
|
1874
2224
|
rebuildFromCollection() {
|
|
1875
2225
|
this.keysByPk.clear();
|
|
2226
|
+
this.orderValueByPk.clear();
|
|
1876
2227
|
super.clear();
|
|
1877
2228
|
const slotsByKey = /* @__PURE__ */ new Map();
|
|
1878
2229
|
const slots = this.collection.getAllSlots();
|
|
@@ -1881,6 +2232,9 @@ var OIMDerivedCollectionIndexArrayBased = class extends OIMReactiveCollectionInd
|
|
|
1881
2232
|
const keys = this.normalizeKeys(this.selectIndexKeys(slot.item));
|
|
1882
2233
|
if (keys.length === 0) continue;
|
|
1883
2234
|
this.keysByPk.set(slot.pk, new Set(keys));
|
|
2235
|
+
if (this.orderBy) {
|
|
2236
|
+
this.orderValueByPk.set(slot.pk, this.orderBy(slot.item));
|
|
2237
|
+
}
|
|
1884
2238
|
for (const key of keys) {
|
|
1885
2239
|
let slotsForKey = slotsByKey.get(key);
|
|
1886
2240
|
if (!slotsForKey) {
|
|
@@ -1897,6 +2251,7 @@ var OIMDerivedCollectionIndexArrayBased = class extends OIMReactiveCollectionInd
|
|
|
1897
2251
|
clear(key) {
|
|
1898
2252
|
if (key === void 0) {
|
|
1899
2253
|
this.keysByPk.clear();
|
|
2254
|
+
this.orderValueByPk.clear();
|
|
1900
2255
|
} else {
|
|
1901
2256
|
for (const keys of this.keysByPk.values()) {
|
|
1902
2257
|
keys.delete(key);
|
|
@@ -1907,37 +2262,11 @@ var OIMDerivedCollectionIndexArrayBased = class extends OIMReactiveCollectionInd
|
|
|
1907
2262
|
destroy() {
|
|
1908
2263
|
this.unsubscribeFromCollection();
|
|
1909
2264
|
this.keysByPk.clear();
|
|
2265
|
+
this.orderValueByPk.clear();
|
|
1910
2266
|
super.destroy();
|
|
1911
2267
|
}
|
|
1912
|
-
trackPkKeys(pk, affectedKeys) {
|
|
1913
|
-
const prevKeys = this.keysByPk.get(pk) ?? /* @__PURE__ */ new Set();
|
|
1914
|
-
for (const key of prevKeys) affectedKeys.add(key);
|
|
1915
|
-
const slot = this.collection.getSlotByPk(pk);
|
|
1916
|
-
const entity = slot?.item;
|
|
1917
|
-
const nextKeys = entity === void 0 ? /* @__PURE__ */ new Set() : new Set(this.normalizeKeys(this.selectIndexKeys(entity)));
|
|
1918
|
-
for (const key of nextKeys) affectedKeys.add(key);
|
|
1919
|
-
if (nextKeys.size === 0) {
|
|
1920
|
-
this.keysByPk.delete(pk);
|
|
1921
|
-
} else {
|
|
1922
|
-
this.keysByPk.set(pk, nextKeys);
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
rebuildKey(key) {
|
|
1926
|
-
const keySlots = [];
|
|
1927
|
-
const slots = this.collection.getAllSlots();
|
|
1928
|
-
for (const slot of slots) {
|
|
1929
|
-
if (slot.item === void 0) continue;
|
|
1930
|
-
const keys = this.keysByPk.get(slot.pk);
|
|
1931
|
-
if (keys?.has(key)) keySlots.push(slot);
|
|
1932
|
-
}
|
|
1933
|
-
if (keySlots.length === 0) {
|
|
1934
|
-
super.clear(key);
|
|
1935
|
-
} else {
|
|
1936
|
-
this.setSlots(key, this.sortSlots(keySlots));
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1939
2268
|
sortSlots(slots) {
|
|
1940
|
-
if (!this.compareEntities && !this.orderBy) return slots;
|
|
2269
|
+
if (!this.compareEntities && !this.orderBy) return slots.slice();
|
|
1941
2270
|
return slots.slice().sort((a, b) => {
|
|
1942
2271
|
const aItem = a.item;
|
|
1943
2272
|
const bItem = b.item;
|
|
@@ -2220,6 +2549,11 @@ var OIMComparatorFactory = class {
|
|
|
2220
2549
|
}
|
|
2221
2550
|
};
|
|
2222
2551
|
|
|
2552
|
+
// src/core/createInPlaceEntityUpdater.ts
|
|
2553
|
+
function createInPlaceEntityUpdater() {
|
|
2554
|
+
return (draft, prev) => Object.assign(prev, draft);
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2223
2557
|
// src/core/OIMEventQueue.ts
|
|
2224
2558
|
var OIMEventQueue = class {
|
|
2225
2559
|
constructor(options = {}) {
|
|
@@ -3654,6 +3988,7 @@ export {
|
|
|
3654
3988
|
EOIMEventQueueSchedulerEventType,
|
|
3655
3989
|
EOIMIndexEventType,
|
|
3656
3990
|
EOIMObjectEventType,
|
|
3991
|
+
OIMCarrierKeyedEmitter,
|
|
3657
3992
|
OIMCollection,
|
|
3658
3993
|
OIMCollectionByPkSelector,
|
|
3659
3994
|
OIMCollectionByPksSelector,
|
|
@@ -3721,6 +4056,7 @@ export {
|
|
|
3721
4056
|
OIMReactiveIndexSetBased,
|
|
3722
4057
|
OIMReactiveObject,
|
|
3723
4058
|
OIMSelector,
|
|
4059
|
+
createInPlaceEntityUpdater,
|
|
3724
4060
|
createOIMCollectionIndexFactory,
|
|
3725
4061
|
createOIMCollectionKit
|
|
3726
4062
|
};
|