@oimdb/core 1.0.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 +562 -0
- package/dist/index.cjs +1186 -0
- package/dist/index.d.cts +588 -0
- package/dist/index.d.ts +588 -0
- package/dist/index.js +1130 -0
- package/package.json +39 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1130 @@
|
|
|
1
|
+
// src/abstract/OIMCollectionStore.ts
|
|
2
|
+
var OIMCollectionStore = class {
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
// src/core/OIMEventEmitter.ts
|
|
6
|
+
var OIMEventEmitter = class {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.buckets = {};
|
|
9
|
+
}
|
|
10
|
+
getOrCreateBucket(event) {
|
|
11
|
+
let bucket = this.buckets[event];
|
|
12
|
+
if (!bucket) {
|
|
13
|
+
bucket = {
|
|
14
|
+
handlers: [],
|
|
15
|
+
indexByHandler: /* @__PURE__ */ new Map(),
|
|
16
|
+
tombstoneCount: 0,
|
|
17
|
+
isEmitting: 0
|
|
18
|
+
};
|
|
19
|
+
this.buckets[event] = bucket;
|
|
20
|
+
}
|
|
21
|
+
return bucket;
|
|
22
|
+
}
|
|
23
|
+
compactBucket(bucket) {
|
|
24
|
+
const handlers = bucket.handlers;
|
|
25
|
+
const length = handlers.length;
|
|
26
|
+
const newHandlers = [];
|
|
27
|
+
bucket.indexByHandler.clear();
|
|
28
|
+
if (bucket.tombstoneCount < length >> 2) {
|
|
29
|
+
newHandlers.length = length - bucket.tombstoneCount;
|
|
30
|
+
}
|
|
31
|
+
let writeIndex = 0;
|
|
32
|
+
for (let i = 0; i < length; i++) {
|
|
33
|
+
const handler = handlers[i];
|
|
34
|
+
if (handler) {
|
|
35
|
+
newHandlers[writeIndex] = handler;
|
|
36
|
+
bucket.indexByHandler.set(handler, writeIndex);
|
|
37
|
+
writeIndex++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (newHandlers.length !== writeIndex) {
|
|
41
|
+
newHandlers.length = writeIndex;
|
|
42
|
+
}
|
|
43
|
+
bucket.handlers = newHandlers;
|
|
44
|
+
bucket.tombstoneCount = 0;
|
|
45
|
+
}
|
|
46
|
+
on(event, handler) {
|
|
47
|
+
const bucket = this.getOrCreateBucket(event);
|
|
48
|
+
if (bucket.indexByHandler.has(handler)) return;
|
|
49
|
+
const index = bucket.handlers.length;
|
|
50
|
+
bucket.handlers.push(handler);
|
|
51
|
+
bucket.indexByHandler.set(handler, index);
|
|
52
|
+
}
|
|
53
|
+
emit(event, payload) {
|
|
54
|
+
const bucket = this.buckets[event];
|
|
55
|
+
if (!bucket) return;
|
|
56
|
+
const handlers = bucket.handlers;
|
|
57
|
+
const length = handlers.length;
|
|
58
|
+
if (length === 0) return;
|
|
59
|
+
bucket.isEmitting++;
|
|
60
|
+
for (let i = 0; i < length; i++) {
|
|
61
|
+
const handler = handlers[i];
|
|
62
|
+
if (handler) handler(payload);
|
|
63
|
+
}
|
|
64
|
+
bucket.isEmitting--;
|
|
65
|
+
if (bucket.isEmitting === 0 && bucket.tombstoneCount > 0) {
|
|
66
|
+
if (bucket.tombstoneCount >= length >> 1) {
|
|
67
|
+
this.compactBucket(bucket);
|
|
68
|
+
} else if (length === bucket.tombstoneCount) {
|
|
69
|
+
delete this.buckets[event];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
off(event, handler) {
|
|
74
|
+
const bucket = this.buckets[event];
|
|
75
|
+
if (!bucket) return;
|
|
76
|
+
const index = bucket.indexByHandler.get(handler);
|
|
77
|
+
if (index === void 0) return;
|
|
78
|
+
bucket.handlers[index] = null;
|
|
79
|
+
bucket.tombstoneCount++;
|
|
80
|
+
bucket.indexByHandler.delete(handler);
|
|
81
|
+
if (bucket.isEmitting === 0) {
|
|
82
|
+
const length = bucket.handlers.length;
|
|
83
|
+
if (bucket.tombstoneCount >= length >> 1) {
|
|
84
|
+
this.compactBucket(bucket);
|
|
85
|
+
} else if (length === bucket.tombstoneCount) {
|
|
86
|
+
delete this.buckets[event];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
offAll(event) {
|
|
91
|
+
if (event !== void 0) {
|
|
92
|
+
delete this.buckets[event];
|
|
93
|
+
} else {
|
|
94
|
+
this.buckets = {};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// src/enum/EOIMEventQueueSchedulerEventType.ts
|
|
100
|
+
var EOIMEventQueueSchedulerEventType = /* @__PURE__ */ ((EOIMEventQueueSchedulerEventType2) => {
|
|
101
|
+
EOIMEventQueueSchedulerEventType2[EOIMEventQueueSchedulerEventType2["FLUSH"] = 0] = "FLUSH";
|
|
102
|
+
return EOIMEventQueueSchedulerEventType2;
|
|
103
|
+
})(EOIMEventQueueSchedulerEventType || {});
|
|
104
|
+
|
|
105
|
+
// src/abstract/OIMEventQueueScheduler.ts
|
|
106
|
+
var OIMEventQueueScheduler = class {
|
|
107
|
+
constructor() {
|
|
108
|
+
this.emitter = new OIMEventEmitter();
|
|
109
|
+
}
|
|
110
|
+
on(event, handler) {
|
|
111
|
+
this.emitter.on(event, handler);
|
|
112
|
+
}
|
|
113
|
+
off(event, handler) {
|
|
114
|
+
this.emitter.off(event, handler);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Trigger a flush event. Should be called by subclasses when they execute the scheduled flush.
|
|
118
|
+
*/
|
|
119
|
+
flush() {
|
|
120
|
+
this.emitter.emit(0 /* FLUSH */, void 0);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// src/enum/EOIMIndexEventType.ts
|
|
125
|
+
var EOIMIndexEventType = /* @__PURE__ */ ((EOIMIndexEventType2) => {
|
|
126
|
+
EOIMIndexEventType2[EOIMIndexEventType2["UPDATE"] = 0] = "UPDATE";
|
|
127
|
+
return EOIMIndexEventType2;
|
|
128
|
+
})(EOIMIndexEventType || {});
|
|
129
|
+
|
|
130
|
+
// src/abstract/OIMIndex.ts
|
|
131
|
+
var OIMIndex = class {
|
|
132
|
+
constructor(options = {}) {
|
|
133
|
+
this.pks = /* @__PURE__ */ new Map();
|
|
134
|
+
this.emitter = new OIMEventEmitter();
|
|
135
|
+
this.comparePks = options.comparePks;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get primary keys for multiple index keys
|
|
139
|
+
*/
|
|
140
|
+
getPksByKeys(keys) {
|
|
141
|
+
return new Map(keys.map((key) => [key, this.getPks(key)]));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* @deprecated Use getPksByKey instead
|
|
145
|
+
* Get primary keys for a specific index key
|
|
146
|
+
*/
|
|
147
|
+
getPks(key) {
|
|
148
|
+
return this.getPksByKey(key);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get primary keys for a specific index key
|
|
152
|
+
*/
|
|
153
|
+
getPksByKey(key) {
|
|
154
|
+
const pksSet = this.pks.get(key);
|
|
155
|
+
return pksSet ? Array.from(pksSet) : [];
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Check if an index key exists
|
|
159
|
+
*/
|
|
160
|
+
hasKey(key) {
|
|
161
|
+
return this.pks.has(key);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get all index keys
|
|
165
|
+
*/
|
|
166
|
+
getKeys() {
|
|
167
|
+
return Array.from(this.pks.keys());
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get the number of primary keys for a specific index key
|
|
171
|
+
*/
|
|
172
|
+
getKeySize(key) {
|
|
173
|
+
const pksSet = this.pks.get(key);
|
|
174
|
+
return pksSet ? pksSet.size : 0;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Get total number of index keys
|
|
178
|
+
*/
|
|
179
|
+
get size() {
|
|
180
|
+
return this.pks.size;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Check if the index is empty
|
|
184
|
+
*/
|
|
185
|
+
get isEmpty() {
|
|
186
|
+
return this.pks.size === 0;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get performance metrics for monitoring and debugging
|
|
190
|
+
*/
|
|
191
|
+
getMetrics() {
|
|
192
|
+
let totalPks = 0;
|
|
193
|
+
let maxBucketSize = 0;
|
|
194
|
+
let minBucketSize = Infinity;
|
|
195
|
+
for (const pksSet of this.pks.values()) {
|
|
196
|
+
totalPks += pksSet.size;
|
|
197
|
+
maxBucketSize = Math.max(maxBucketSize, pksSet.size);
|
|
198
|
+
minBucketSize = Math.min(minBucketSize, pksSet.size);
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
totalKeys: this.pks.size,
|
|
202
|
+
totalPks,
|
|
203
|
+
averagePksPerKey: this.pks.size > 0 ? totalPks / this.pks.size : 0,
|
|
204
|
+
maxBucketSize: maxBucketSize === -Infinity ? 0 : maxBucketSize,
|
|
205
|
+
minBucketSize: minBucketSize === Infinity ? 0 : minBucketSize
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Clean up event listeners when index is no longer needed
|
|
210
|
+
*/
|
|
211
|
+
destroy() {
|
|
212
|
+
this.emitter.offAll();
|
|
213
|
+
this.pks.clear();
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Set primary keys for a specific index key with optional comparison.
|
|
217
|
+
* If comparator is provided and returns true (no changes), skip the update.
|
|
218
|
+
*/
|
|
219
|
+
setPksWithComparison(key, newPks) {
|
|
220
|
+
const existingPks = this.getPks(key);
|
|
221
|
+
if (this.comparePks && this.comparePks(existingPks, newPks)) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
this.pks.set(key, new Set(newPks));
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Emit update event with changed keys
|
|
229
|
+
*/
|
|
230
|
+
emitUpdate(keys) {
|
|
231
|
+
this.emitter.emit(0 /* UPDATE */, { keys });
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// src/enum/EOIMUpdateEventCoalescerEventType.ts
|
|
236
|
+
var EOIMUpdateEventCoalescerEventType = /* @__PURE__ */ ((EOIMUpdateEventCoalescerEventType2) => {
|
|
237
|
+
EOIMUpdateEventCoalescerEventType2[EOIMUpdateEventCoalescerEventType2["HAS_CHANGES"] = 0] = "HAS_CHANGES";
|
|
238
|
+
return EOIMUpdateEventCoalescerEventType2;
|
|
239
|
+
})(EOIMUpdateEventCoalescerEventType || {});
|
|
240
|
+
|
|
241
|
+
// src/core/OIMUpdateEventEmitter.ts
|
|
242
|
+
var OIMUpdateEventEmitter = class {
|
|
243
|
+
constructor(opts) {
|
|
244
|
+
this.keyHandlers = /* @__PURE__ */ new Map();
|
|
245
|
+
this.handleHasChanges = () => {
|
|
246
|
+
this.queue.enqueue(() => {
|
|
247
|
+
const updatedKeys = this.coalescer.getUpdatedKeys();
|
|
248
|
+
if (this.keyHandlers.size === 0) {
|
|
249
|
+
this.coalescer.clearUpdatedKeys();
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (updatedKeys.size * 2 < this.keyHandlers.size) {
|
|
253
|
+
for (const key of updatedKeys) {
|
|
254
|
+
const handlers = this.keyHandlers.get(key);
|
|
255
|
+
if (handlers) {
|
|
256
|
+
for (const handler of handlers) {
|
|
257
|
+
handler();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
for (const [key, handlers] of this.keyHandlers) {
|
|
263
|
+
if (updatedKeys.has(key)) {
|
|
264
|
+
for (const handler of handlers) {
|
|
265
|
+
handler();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
this.coalescer.clearUpdatedKeys();
|
|
271
|
+
});
|
|
272
|
+
};
|
|
273
|
+
this.coalescer = opts.coalescer;
|
|
274
|
+
this.coalescer.emitter.on(
|
|
275
|
+
0 /* HAS_CHANGES */,
|
|
276
|
+
this.handleHasChanges
|
|
277
|
+
);
|
|
278
|
+
this.queue = opts.queue;
|
|
279
|
+
}
|
|
280
|
+
destroy() {
|
|
281
|
+
this.coalescer.emitter.off(
|
|
282
|
+
0 /* HAS_CHANGES */,
|
|
283
|
+
this.handleHasChanges
|
|
284
|
+
);
|
|
285
|
+
this.keyHandlers.clear();
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Get performance metrics for monitoring and debugging
|
|
289
|
+
*/
|
|
290
|
+
getMetrics() {
|
|
291
|
+
let totalHandlers = 0;
|
|
292
|
+
for (const handlers of this.keyHandlers.values()) {
|
|
293
|
+
totalHandlers += handlers.size;
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
totalKeys: this.keyHandlers.size,
|
|
297
|
+
totalHandlers,
|
|
298
|
+
averageHandlersPerKey: this.keyHandlers.size > 0 ? totalHandlers / this.keyHandlers.size : 0,
|
|
299
|
+
queueLength: this.queue.length
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Check if there are any active subscriptions
|
|
304
|
+
*/
|
|
305
|
+
hasSubscriptions() {
|
|
306
|
+
return this.keyHandlers.size > 0;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Get the number of handlers for a specific key
|
|
310
|
+
*/
|
|
311
|
+
getHandlerCount(key) {
|
|
312
|
+
return this.keyHandlers.get(key)?.size ?? 0;
|
|
313
|
+
}
|
|
314
|
+
subscribeOnKey(key, handler) {
|
|
315
|
+
let handlers = this.keyHandlers.get(key);
|
|
316
|
+
if (!handlers) {
|
|
317
|
+
handlers = /* @__PURE__ */ new Set();
|
|
318
|
+
this.keyHandlers.set(key, handlers);
|
|
319
|
+
}
|
|
320
|
+
handlers.add(handler);
|
|
321
|
+
return () => {
|
|
322
|
+
this.unsubscribeFromKey(key, handler);
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
unsubscribeFromKey(key, handler) {
|
|
326
|
+
const handlers = this.keyHandlers.get(key);
|
|
327
|
+
if (!handlers) return;
|
|
328
|
+
handlers.delete(handler);
|
|
329
|
+
if (handlers.size === 0) {
|
|
330
|
+
this.keyHandlers.delete(key);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
subscribeOnKeys(keys, handler) {
|
|
334
|
+
const subscribedKeys = [];
|
|
335
|
+
for (const key of keys) {
|
|
336
|
+
let handlers = this.keyHandlers.get(key);
|
|
337
|
+
if (!handlers) {
|
|
338
|
+
handlers = /* @__PURE__ */ new Set();
|
|
339
|
+
this.keyHandlers.set(key, handlers);
|
|
340
|
+
}
|
|
341
|
+
if (!handlers.has(handler)) {
|
|
342
|
+
handlers.add(handler);
|
|
343
|
+
subscribedKeys.push(key);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return () => {
|
|
347
|
+
for (const key of subscribedKeys) {
|
|
348
|
+
this.unsubscribeFromKey(key, handler);
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
unsubscribeFromKeys(keys, handler) {
|
|
353
|
+
for (const key of keys) {
|
|
354
|
+
this.unsubscribeFromKey(key, handler);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// src/core/OIMUpdateEventCoalescer.ts
|
|
360
|
+
var OIMUpdateEventCoalescer = class {
|
|
361
|
+
constructor() {
|
|
362
|
+
this.emitter = new OIMEventEmitter();
|
|
363
|
+
this.updatedKeys = /* @__PURE__ */ new Set();
|
|
364
|
+
this.hasEmittedChanges = false;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Get the set of keys that have been updated since last clear
|
|
368
|
+
*/
|
|
369
|
+
getUpdatedKeys() {
|
|
370
|
+
return this.updatedKeys;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Clear all updated keys and reset the changed state
|
|
374
|
+
*/
|
|
375
|
+
clearUpdatedKeys() {
|
|
376
|
+
this.updatedKeys.clear();
|
|
377
|
+
this.hasEmittedChanges = false;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Add keys to the updated set and emit HAS_CHANGES event if needed
|
|
381
|
+
*/
|
|
382
|
+
addUpdatedKeys(keys) {
|
|
383
|
+
const hadChanges = this.updatedKeys.size > 0;
|
|
384
|
+
for (const key of keys) {
|
|
385
|
+
this.updatedKeys.add(key);
|
|
386
|
+
}
|
|
387
|
+
if (!hadChanges && this.updatedKeys.size > 0 && !this.hasEmittedChanges) {
|
|
388
|
+
this.hasEmittedChanges = true;
|
|
389
|
+
this.emitter.emit(
|
|
390
|
+
0 /* HAS_CHANGES */,
|
|
391
|
+
void 0
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
// src/core/OIMUpdateEventCoalescerIndex.ts
|
|
398
|
+
var OIMUpdateEventCoalescerIndex = class extends OIMUpdateEventCoalescer {
|
|
399
|
+
constructor(indexEmitter) {
|
|
400
|
+
super();
|
|
401
|
+
this.indexEmitter = indexEmitter;
|
|
402
|
+
/**
|
|
403
|
+
* When the index is updated, we keep track of the updated keys.
|
|
404
|
+
*/
|
|
405
|
+
this.handleUpdate = (payload) => {
|
|
406
|
+
const hadChanges = this.updatedKeys.size > 0;
|
|
407
|
+
for (const key of payload.keys) {
|
|
408
|
+
this.updatedKeys.add(key);
|
|
409
|
+
}
|
|
410
|
+
if (!hadChanges && this.updatedKeys.size > 0) {
|
|
411
|
+
this.emitter.emit(
|
|
412
|
+
0 /* HAS_CHANGES */,
|
|
413
|
+
void 0
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
this.indexEmitter.on(0 /* UPDATE */, this.handleUpdate);
|
|
418
|
+
}
|
|
419
|
+
destroy() {
|
|
420
|
+
this.indexEmitter.off(0 /* UPDATE */, this.handleUpdate);
|
|
421
|
+
this.emitter.offAll();
|
|
422
|
+
this.updatedKeys.clear();
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// src/abstract/OIMReactiveIndex.ts
|
|
427
|
+
var OIMReactiveIndex = class {
|
|
428
|
+
constructor(queue, opts) {
|
|
429
|
+
this.index = opts?.index ?? this.createDefaultIndex();
|
|
430
|
+
this.coalescer = new OIMUpdateEventCoalescerIndex(
|
|
431
|
+
this.index.emitter
|
|
432
|
+
);
|
|
433
|
+
this.updateEventEmitter = new OIMUpdateEventEmitter({
|
|
434
|
+
coalescer: this.coalescer,
|
|
435
|
+
queue
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
getPksByKey(key) {
|
|
439
|
+
return this.index.getPksByKey(key);
|
|
440
|
+
}
|
|
441
|
+
getPksByKeys(keys) {
|
|
442
|
+
return this.index.getPksByKeys(keys);
|
|
443
|
+
}
|
|
444
|
+
hasKey(key) {
|
|
445
|
+
return this.index.hasKey(key);
|
|
446
|
+
}
|
|
447
|
+
getKeys() {
|
|
448
|
+
return this.index.getKeys();
|
|
449
|
+
}
|
|
450
|
+
getKeySize(key) {
|
|
451
|
+
return this.index.getKeySize(key);
|
|
452
|
+
}
|
|
453
|
+
get size() {
|
|
454
|
+
return this.index.size;
|
|
455
|
+
}
|
|
456
|
+
get isEmpty() {
|
|
457
|
+
return this.index.isEmpty;
|
|
458
|
+
}
|
|
459
|
+
getMetrics() {
|
|
460
|
+
return this.index.getMetrics();
|
|
461
|
+
}
|
|
462
|
+
destroy() {
|
|
463
|
+
this.index.destroy();
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
// src/core/OIMPkSelectorFactory.ts
|
|
468
|
+
var OIMPkSelectorFactory = class {
|
|
469
|
+
createIdSelector() {
|
|
470
|
+
return (entity) => entity.id;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
// src/core/OIMCollectionStoreMapDriven.ts
|
|
475
|
+
var OIMCollectionStoreMapDriven = class extends OIMCollectionStore {
|
|
476
|
+
constructor() {
|
|
477
|
+
super(...arguments);
|
|
478
|
+
this.entities = /* @__PURE__ */ new Map();
|
|
479
|
+
}
|
|
480
|
+
setOneByPk(pk, entity) {
|
|
481
|
+
this.entities.set(pk, entity);
|
|
482
|
+
}
|
|
483
|
+
setManyByPks(pks, entities) {
|
|
484
|
+
for (let i = 0; i < pks.length; i++) {
|
|
485
|
+
this.entities.set(pks[i], entities[i]);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
removeOneByPk(pk) {
|
|
489
|
+
this.entities.delete(pk);
|
|
490
|
+
}
|
|
491
|
+
removeManyByPks(pks) {
|
|
492
|
+
for (const pk of pks) {
|
|
493
|
+
this.removeOneByPk(pk);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
getOneByPk(pk) {
|
|
497
|
+
return this.entities.get(pk);
|
|
498
|
+
}
|
|
499
|
+
getManyByPks(pks) {
|
|
500
|
+
return new Map(pks.map((pk) => [pk, this.getOneByPk(pk)]));
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
// src/core/OIMEntityUpdaterFactory.ts
|
|
505
|
+
var OIMEntityUpdaterFactory = class {
|
|
506
|
+
createMergeEntityUpdater() {
|
|
507
|
+
return (draft, prev) => {
|
|
508
|
+
return { ...prev, ...draft };
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
// src/enum/EOIMCollectionEventType.ts
|
|
514
|
+
var EOIMCollectionEventType = /* @__PURE__ */ ((EOIMCollectionEventType2) => {
|
|
515
|
+
EOIMCollectionEventType2[EOIMCollectionEventType2["UPDATE"] = 0] = "UPDATE";
|
|
516
|
+
return EOIMCollectionEventType2;
|
|
517
|
+
})(EOIMCollectionEventType || {});
|
|
518
|
+
|
|
519
|
+
// src/core/OIMCollection.ts
|
|
520
|
+
var OIMCollection = class {
|
|
521
|
+
constructor(opts) {
|
|
522
|
+
this.emitter = new OIMEventEmitter();
|
|
523
|
+
this.selectPk = opts?.selectPk ?? new OIMPkSelectorFactory().createIdSelector();
|
|
524
|
+
this.store = opts?.store ?? new OIMCollectionStoreMapDriven();
|
|
525
|
+
this.updateEntity = opts?.updateEntity ?? new OIMEntityUpdaterFactory().createMergeEntityUpdater();
|
|
526
|
+
}
|
|
527
|
+
getOneByPk(pk) {
|
|
528
|
+
return this.store.getOneByPk(pk);
|
|
529
|
+
}
|
|
530
|
+
getManyByPks(pks) {
|
|
531
|
+
return this.store.getManyByPks(pks);
|
|
532
|
+
}
|
|
533
|
+
upsertOne(entity) {
|
|
534
|
+
const pk = this.upsertOneWithoutNotifications(entity);
|
|
535
|
+
this.emitter.emit(0 /* UPDATE */, { pks: [pk] });
|
|
536
|
+
}
|
|
537
|
+
upsertMany(entities) {
|
|
538
|
+
const pks = entities.map(
|
|
539
|
+
(entity) => this.upsertOneWithoutNotifications(entity)
|
|
540
|
+
);
|
|
541
|
+
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
542
|
+
}
|
|
543
|
+
removeOne(entity) {
|
|
544
|
+
const pk = this.selectPk(entity);
|
|
545
|
+
this.store.removeOneByPk(pk);
|
|
546
|
+
this.emitter.emit(0 /* UPDATE */, { pks: [pk] });
|
|
547
|
+
}
|
|
548
|
+
removeMany(entities) {
|
|
549
|
+
const pks = entities.map(this.selectPk);
|
|
550
|
+
this.store.removeManyByPks(pks);
|
|
551
|
+
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
552
|
+
}
|
|
553
|
+
upsertOneWithoutNotifications(entity) {
|
|
554
|
+
const pk = this.selectPk(entity);
|
|
555
|
+
const existingEntity = this.store.getOneByPk(pk);
|
|
556
|
+
if (existingEntity) {
|
|
557
|
+
this.store.setOneByPk(
|
|
558
|
+
pk,
|
|
559
|
+
this.updateEntity(entity, existingEntity)
|
|
560
|
+
);
|
|
561
|
+
} else {
|
|
562
|
+
this.store.setOneByPk(pk, entity);
|
|
563
|
+
}
|
|
564
|
+
return pk;
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
// src/core/OIMUpdateEventCoalescerCollection.ts
|
|
569
|
+
var OIMUpdateEventCoalescerCollection = class extends OIMUpdateEventCoalescer {
|
|
570
|
+
constructor(collectionEmitter) {
|
|
571
|
+
super();
|
|
572
|
+
this.collectionEmitter = collectionEmitter;
|
|
573
|
+
/**
|
|
574
|
+
* When the collection is updated, we keep track of the updated pks.
|
|
575
|
+
*/
|
|
576
|
+
this.handleUpdate = (payload) => {
|
|
577
|
+
const hadChanges = this.updatedKeys.size > 0;
|
|
578
|
+
for (const pk of payload.pks) {
|
|
579
|
+
this.updatedKeys.add(pk);
|
|
580
|
+
}
|
|
581
|
+
if (!hadChanges && this.updatedKeys.size > 0) {
|
|
582
|
+
this.emitter.emit(
|
|
583
|
+
0 /* HAS_CHANGES */,
|
|
584
|
+
void 0
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
this.collectionEmitter.on(
|
|
589
|
+
0 /* UPDATE */,
|
|
590
|
+
this.handleUpdate
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
destroy() {
|
|
594
|
+
this.collectionEmitter.off(
|
|
595
|
+
0 /* UPDATE */,
|
|
596
|
+
this.handleUpdate
|
|
597
|
+
);
|
|
598
|
+
this.emitter.offAll();
|
|
599
|
+
this.updatedKeys.clear();
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
// src/core/OIMReactiveCollection.ts
|
|
604
|
+
var OIMReactiveCollection = class {
|
|
605
|
+
constructor(queue, opts) {
|
|
606
|
+
this.collection = new OIMCollection(opts?.collectionOpts);
|
|
607
|
+
this.coalescer = new OIMUpdateEventCoalescerCollection(
|
|
608
|
+
this.collection.emitter
|
|
609
|
+
);
|
|
610
|
+
this.updateEventEmitter = new OIMUpdateEventEmitter({
|
|
611
|
+
coalescer: this.coalescer,
|
|
612
|
+
queue
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
upsertMany(entities) {
|
|
616
|
+
this.collection.upsertMany(entities);
|
|
617
|
+
}
|
|
618
|
+
upsertOne(entity) {
|
|
619
|
+
this.collection.upsertOne(entity);
|
|
620
|
+
}
|
|
621
|
+
removeMany(entities) {
|
|
622
|
+
this.collection.removeMany(entities);
|
|
623
|
+
}
|
|
624
|
+
removeOne(entity) {
|
|
625
|
+
this.collection.removeOne(entity);
|
|
626
|
+
}
|
|
627
|
+
getOneByPk(pk) {
|
|
628
|
+
return this.collection.getOneByPk(pk);
|
|
629
|
+
}
|
|
630
|
+
getManyByPks(pks) {
|
|
631
|
+
return this.collection.getManyByPks(pks);
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
// src/core/OIMIndexManual.ts
|
|
636
|
+
var OIMIndexManual = class extends OIMIndex {
|
|
637
|
+
constructor(options = {}) {
|
|
638
|
+
super(options);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Set primary keys for a specific index key, replacing any existing values.
|
|
642
|
+
* Uses optional comparator to skip updates if PKs haven't actually changed.
|
|
643
|
+
*/
|
|
644
|
+
setPks(key, pks) {
|
|
645
|
+
const hasChanges = this.setPksWithComparison(key, pks);
|
|
646
|
+
if (hasChanges) {
|
|
647
|
+
this.emitUpdate([key]);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Add primary keys to a specific index key
|
|
652
|
+
*/
|
|
653
|
+
addPks(key, pks) {
|
|
654
|
+
if (pks.length === 0) return;
|
|
655
|
+
let pksSet = this.pks.get(key);
|
|
656
|
+
if (!pksSet) {
|
|
657
|
+
pksSet = /* @__PURE__ */ new Set();
|
|
658
|
+
this.pks.set(key, pksSet);
|
|
659
|
+
}
|
|
660
|
+
let hasChanges = false;
|
|
661
|
+
for (const pk of pks) {
|
|
662
|
+
const sizeBefore = pksSet.size;
|
|
663
|
+
pksSet.add(pk);
|
|
664
|
+
if (pksSet.size > sizeBefore) {
|
|
665
|
+
hasChanges = true;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
if (hasChanges) {
|
|
669
|
+
this.emitUpdate([key]);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Remove primary keys from a specific index key
|
|
674
|
+
*/
|
|
675
|
+
removePks(key, pks) {
|
|
676
|
+
if (pks.length === 0) return;
|
|
677
|
+
const pksSet = this.pks.get(key);
|
|
678
|
+
if (!pksSet) return;
|
|
679
|
+
let hasChanges = false;
|
|
680
|
+
for (const pk of pks) {
|
|
681
|
+
if (pksSet.delete(pk)) {
|
|
682
|
+
hasChanges = true;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (pksSet.size === 0) {
|
|
686
|
+
this.pks.delete(key);
|
|
687
|
+
hasChanges = true;
|
|
688
|
+
}
|
|
689
|
+
if (hasChanges) {
|
|
690
|
+
this.emitUpdate([key]);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Clear all primary keys for a specific index key, or all keys if no key specified
|
|
695
|
+
*/
|
|
696
|
+
clear(key) {
|
|
697
|
+
if (key === void 0) {
|
|
698
|
+
if (this.pks.size > 0) {
|
|
699
|
+
const allKeys = Array.from(this.pks.keys());
|
|
700
|
+
this.pks.clear();
|
|
701
|
+
this.emitUpdate(allKeys);
|
|
702
|
+
}
|
|
703
|
+
} else {
|
|
704
|
+
if (this.pks.has(key)) {
|
|
705
|
+
this.pks.delete(key);
|
|
706
|
+
this.emitUpdate([key]);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
// src/core/OIMReactiveIndexManual.ts
|
|
713
|
+
var OIMReactiveIndexManual = class extends OIMReactiveIndex {
|
|
714
|
+
constructor(queue, opts) {
|
|
715
|
+
super(queue, opts);
|
|
716
|
+
}
|
|
717
|
+
createDefaultIndex() {
|
|
718
|
+
return new OIMIndexManual();
|
|
719
|
+
}
|
|
720
|
+
setPks(key, pks) {
|
|
721
|
+
this.index.setPks(key, pks);
|
|
722
|
+
}
|
|
723
|
+
addPks(key, pks) {
|
|
724
|
+
this.index.addPks(key, pks);
|
|
725
|
+
}
|
|
726
|
+
removePks(key, pks) {
|
|
727
|
+
this.index.removePks(key, pks);
|
|
728
|
+
}
|
|
729
|
+
clear(key) {
|
|
730
|
+
this.index.clear(key);
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
// src/core/OIMRICollection.ts
|
|
735
|
+
var OIMRICollection = class extends OIMReactiveCollection {
|
|
736
|
+
constructor(queue, opts) {
|
|
737
|
+
super(queue, {
|
|
738
|
+
collectionOpts: opts.collectionOpts
|
|
739
|
+
});
|
|
740
|
+
this.indexes = opts.indexes || {};
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
// src/core/OIMComparatorFactory.ts
|
|
745
|
+
var OIMComparatorFactory = class {
|
|
746
|
+
createShallowComparator() {
|
|
747
|
+
return (a, b) => {
|
|
748
|
+
if (a === b) return false;
|
|
749
|
+
const ka = Object.keys(a);
|
|
750
|
+
const kb = Object.keys(b);
|
|
751
|
+
if (ka.length !== kb.length) return true;
|
|
752
|
+
for (let i = 0; i < ka.length; i++) {
|
|
753
|
+
const k = ka[i];
|
|
754
|
+
if (b[k] !== a[k])
|
|
755
|
+
return true;
|
|
756
|
+
}
|
|
757
|
+
return false;
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
// src/core/OIMEventQueue.ts
|
|
763
|
+
var OIMEventQueue = class {
|
|
764
|
+
constructor(options = {}) {
|
|
765
|
+
this.queue = [];
|
|
766
|
+
this.scheduler = options.scheduler;
|
|
767
|
+
if (this.scheduler) {
|
|
768
|
+
this.flushBound = () => this.flush();
|
|
769
|
+
this.scheduler.on(
|
|
770
|
+
0 /* FLUSH */,
|
|
771
|
+
this.flushBound
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Add a function to the queue. If scheduler is configured and autoSchedule is enabled,
|
|
777
|
+
* automatically schedules a flush operation.
|
|
778
|
+
*/
|
|
779
|
+
enqueue(fn) {
|
|
780
|
+
this.queue.push(fn);
|
|
781
|
+
if (this.scheduler && this.queue.length === 1) {
|
|
782
|
+
this.scheduler.schedule();
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Execute all queued functions and clear the queue.
|
|
787
|
+
* This method is safe to call multiple times and handles reentrancy.
|
|
788
|
+
*/
|
|
789
|
+
flush() {
|
|
790
|
+
if (this.queue.length === 0) return;
|
|
791
|
+
const currentQueue = this.queue.slice();
|
|
792
|
+
this.queue.length = 0;
|
|
793
|
+
for (let i = 0; i < currentQueue.length; i++) {
|
|
794
|
+
currentQueue[i]();
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Get the current number of queued functions.
|
|
799
|
+
*/
|
|
800
|
+
get length() {
|
|
801
|
+
return this.queue.length;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Check if the queue is empty.
|
|
805
|
+
*/
|
|
806
|
+
get isEmpty() {
|
|
807
|
+
return this.queue.length === 0;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Clear the queue without executing functions and cancel any scheduled flush.
|
|
811
|
+
*/
|
|
812
|
+
clear() {
|
|
813
|
+
this.queue.length = 0;
|
|
814
|
+
this.scheduler?.cancel();
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Clean up scheduler subscription when queue is no longer needed.
|
|
818
|
+
*/
|
|
819
|
+
destroy() {
|
|
820
|
+
if (this.scheduler && this.flushBound) {
|
|
821
|
+
this.scheduler.off(
|
|
822
|
+
0 /* FLUSH */,
|
|
823
|
+
this.flushBound
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
this.clear();
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
// src/core/OIMIndexComparatorFactory.ts
|
|
831
|
+
var OIMIndexComparatorFactory = class {
|
|
832
|
+
/**
|
|
833
|
+
* Create an element-wise comparator that checks arrays for strict equality.
|
|
834
|
+
* Compares array lengths and each element using strict equality (===).
|
|
835
|
+
*/
|
|
836
|
+
static createElementWiseComparator() {
|
|
837
|
+
return (existingPks, newPks) => {
|
|
838
|
+
if (existingPks.length !== newPks.length) {
|
|
839
|
+
return false;
|
|
840
|
+
}
|
|
841
|
+
for (let i = 0; i < existingPks.length; i++) {
|
|
842
|
+
if (existingPks[i] !== newPks[i]) {
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
return true;
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* Create a set-based comparator that checks if arrays contain the same elements.
|
|
851
|
+
* Order doesn't matter, only the presence of elements.
|
|
852
|
+
*/
|
|
853
|
+
static createSetBasedComparator() {
|
|
854
|
+
return (existingPks, newPks) => {
|
|
855
|
+
if (existingPks.length !== newPks.length) {
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
const existingSet = new Set(existingPks);
|
|
859
|
+
const newSet = new Set(newPks);
|
|
860
|
+
if (existingSet.size !== newSet.size || existingSet.size !== existingPks.length) {
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
const setValues = Array.from(existingSet);
|
|
864
|
+
for (let i = 0; i < setValues.length; i++) {
|
|
865
|
+
const pk = setValues[i];
|
|
866
|
+
if (!newSet.has(pk)) {
|
|
867
|
+
return false;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
return true;
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Create a shallow comparator that only checks array references.
|
|
875
|
+
* Fastest but only works if you're reusing the same array instances.
|
|
876
|
+
*/
|
|
877
|
+
static createShallowComparator() {
|
|
878
|
+
return (existingPks, newPks) => {
|
|
879
|
+
return existingPks === newPks;
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Create a no-comparison comparator that always returns false (always updates).
|
|
884
|
+
* Useful for disabling comparison while keeping the same interface.
|
|
885
|
+
*/
|
|
886
|
+
static createAlwaysUpdateComparator() {
|
|
887
|
+
return () => false;
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
// src/core/OIMMap2Keys.ts
|
|
892
|
+
var OIMMap2Keys = class {
|
|
893
|
+
constructor() {
|
|
894
|
+
this.map = /* @__PURE__ */ new Map();
|
|
895
|
+
this._size = 0;
|
|
896
|
+
}
|
|
897
|
+
get size() {
|
|
898
|
+
return this._size;
|
|
899
|
+
}
|
|
900
|
+
set(k1, k2, v) {
|
|
901
|
+
let m = this.map.get(k1);
|
|
902
|
+
if (!m) {
|
|
903
|
+
m = /* @__PURE__ */ new Map();
|
|
904
|
+
this.map.set(k1, m);
|
|
905
|
+
}
|
|
906
|
+
if (!m.has(k2)) this._size++;
|
|
907
|
+
m.set(k2, v);
|
|
908
|
+
}
|
|
909
|
+
get(k1, k2) {
|
|
910
|
+
return this.map.get(k1)?.get(k2);
|
|
911
|
+
}
|
|
912
|
+
has(k1, k2) {
|
|
913
|
+
return this.map.get(k1)?.has(k2);
|
|
914
|
+
}
|
|
915
|
+
delete(k1, k2) {
|
|
916
|
+
const m = this.map.get(k1);
|
|
917
|
+
if (!m) return false;
|
|
918
|
+
const had = m.delete(k2);
|
|
919
|
+
if (had) {
|
|
920
|
+
this._size--;
|
|
921
|
+
if (m.size === 0) this.map.delete(k1);
|
|
922
|
+
}
|
|
923
|
+
return had;
|
|
924
|
+
}
|
|
925
|
+
clear() {
|
|
926
|
+
this.map.clear();
|
|
927
|
+
this._size = 0;
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
|
|
931
|
+
// src/core/event-queue-scheduler/OIMEventQueueSchedulerAnimationFrame.ts
|
|
932
|
+
var OIMEventQueueSchedulerAnimationFrame = class extends OIMEventQueueScheduler {
|
|
933
|
+
constructor() {
|
|
934
|
+
super();
|
|
935
|
+
this.useRequestAnimationFrame = typeof requestAnimationFrame !== "undefined";
|
|
936
|
+
}
|
|
937
|
+
schedule() {
|
|
938
|
+
if (this.frameId !== void 0) return;
|
|
939
|
+
if (this.useRequestAnimationFrame) {
|
|
940
|
+
this.frameId = requestAnimationFrame(() => {
|
|
941
|
+
this.frameId = void 0;
|
|
942
|
+
this.flush();
|
|
943
|
+
});
|
|
944
|
+
} else {
|
|
945
|
+
this.frameId = setTimeout(() => {
|
|
946
|
+
this.frameId = void 0;
|
|
947
|
+
this.flush();
|
|
948
|
+
}, 16);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
cancel() {
|
|
952
|
+
if (this.frameId === void 0) return;
|
|
953
|
+
if (this.useRequestAnimationFrame) {
|
|
954
|
+
cancelAnimationFrame(this.frameId);
|
|
955
|
+
} else {
|
|
956
|
+
clearTimeout(this.frameId);
|
|
957
|
+
}
|
|
958
|
+
this.frameId = void 0;
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
|
|
962
|
+
// src/core/event-queue-scheduler/OIMEventQueueSchedulerMicrotask.ts
|
|
963
|
+
var OIMEventQueueSchedulerMicrotask = class extends OIMEventQueueScheduler {
|
|
964
|
+
constructor() {
|
|
965
|
+
super(...arguments);
|
|
966
|
+
this.scheduled = false;
|
|
967
|
+
}
|
|
968
|
+
schedule() {
|
|
969
|
+
if (this.scheduled) return;
|
|
970
|
+
this.scheduled = true;
|
|
971
|
+
Promise.resolve().then(() => {
|
|
972
|
+
if (!this.scheduled) return;
|
|
973
|
+
this.scheduled = false;
|
|
974
|
+
this.flush();
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
cancel() {
|
|
978
|
+
if (!this.scheduled) return;
|
|
979
|
+
this.scheduled = false;
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
|
|
983
|
+
// src/core/event-queue-scheduler/OIMEventQueueSchedulerTimeout.ts
|
|
984
|
+
var OIMEventQueueSchedulerTimeout = class extends OIMEventQueueScheduler {
|
|
985
|
+
/**
|
|
986
|
+
* @param delay - Delay in milliseconds before executing the flush (default: 0)
|
|
987
|
+
*/
|
|
988
|
+
constructor(delay = 0) {
|
|
989
|
+
super();
|
|
990
|
+
this.delay = Math.max(0, delay);
|
|
991
|
+
}
|
|
992
|
+
schedule() {
|
|
993
|
+
if (this.timeoutId !== void 0) return;
|
|
994
|
+
this.timeoutId = setTimeout(() => {
|
|
995
|
+
this.timeoutId = void 0;
|
|
996
|
+
this.flush();
|
|
997
|
+
}, this.delay);
|
|
998
|
+
}
|
|
999
|
+
cancel() {
|
|
1000
|
+
if (this.timeoutId === void 0) return;
|
|
1001
|
+
clearTimeout(this.timeoutId);
|
|
1002
|
+
this.timeoutId = void 0;
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
|
|
1006
|
+
// src/core/event-queue-scheduler/OIMEventQueueSchedulerImmediate.ts
|
|
1007
|
+
var OIMEventQueueSchedulerImmediate = class extends OIMEventQueueScheduler {
|
|
1008
|
+
constructor() {
|
|
1009
|
+
super();
|
|
1010
|
+
this.useSetImmediate = typeof setImmediate !== "undefined";
|
|
1011
|
+
this.useMessageChannel = !this.useSetImmediate && typeof MessageChannel !== "undefined" && typeof window !== "undefined";
|
|
1012
|
+
if (this.useMessageChannel) {
|
|
1013
|
+
this.messageChannel = new MessageChannel();
|
|
1014
|
+
this.messageChannel.port2.onmessage = () => {
|
|
1015
|
+
if (this.pendingCallback && this.immediateId !== void 0) {
|
|
1016
|
+
const callback = this.pendingCallback;
|
|
1017
|
+
this.pendingCallback = void 0;
|
|
1018
|
+
this.immediateId = void 0;
|
|
1019
|
+
callback();
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
schedule() {
|
|
1025
|
+
if (this.immediateId !== void 0) return;
|
|
1026
|
+
const callback = () => {
|
|
1027
|
+
this.immediateId = void 0;
|
|
1028
|
+
this.flush();
|
|
1029
|
+
};
|
|
1030
|
+
if (this.useSetImmediate) {
|
|
1031
|
+
this.immediateId = setImmediate(callback);
|
|
1032
|
+
} else if (this.useMessageChannel && this.messageChannel) {
|
|
1033
|
+
this.immediateId = 1;
|
|
1034
|
+
this.pendingCallback = callback;
|
|
1035
|
+
this.messageChannel.port1.postMessage(null);
|
|
1036
|
+
} else {
|
|
1037
|
+
this.immediateId = setTimeout(callback, 0);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
cancel() {
|
|
1041
|
+
if (this.immediateId === void 0) return;
|
|
1042
|
+
if (this.useSetImmediate) {
|
|
1043
|
+
clearImmediate(this.immediateId);
|
|
1044
|
+
} else if (this.useMessageChannel) {
|
|
1045
|
+
this.pendingCallback = void 0;
|
|
1046
|
+
} else {
|
|
1047
|
+
clearTimeout(this.immediateId);
|
|
1048
|
+
}
|
|
1049
|
+
this.immediateId = void 0;
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
// src/core/event-queue-scheduler/OIMEventQueueSchedulerFactory.ts
|
|
1054
|
+
var OIMEventQueueSchedulerFactory = class {
|
|
1055
|
+
/**
|
|
1056
|
+
* Create a scheduler of the specified type with optional configuration.
|
|
1057
|
+
*/
|
|
1058
|
+
static create(type, ...args) {
|
|
1059
|
+
switch (type) {
|
|
1060
|
+
case "microtask":
|
|
1061
|
+
return new OIMEventQueueSchedulerMicrotask();
|
|
1062
|
+
case "animationFrame":
|
|
1063
|
+
return new OIMEventQueueSchedulerAnimationFrame();
|
|
1064
|
+
case "timeout": {
|
|
1065
|
+
const options = args[0];
|
|
1066
|
+
return new OIMEventQueueSchedulerTimeout(options?.delay);
|
|
1067
|
+
}
|
|
1068
|
+
case "immediate":
|
|
1069
|
+
return new OIMEventQueueSchedulerImmediate();
|
|
1070
|
+
default:
|
|
1071
|
+
throw new Error(`Unknown scheduler type: ${type}`);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Create a microtask scheduler (most common for general use).
|
|
1076
|
+
*/
|
|
1077
|
+
static createMicrotask() {
|
|
1078
|
+
return new OIMEventQueueSchedulerMicrotask();
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Create an animation frame scheduler (ideal for UI updates).
|
|
1082
|
+
*/
|
|
1083
|
+
static createAnimationFrame() {
|
|
1084
|
+
return new OIMEventQueueSchedulerAnimationFrame();
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Create a timeout scheduler with optional delay.
|
|
1088
|
+
*/
|
|
1089
|
+
static createTimeout(delay) {
|
|
1090
|
+
return new OIMEventQueueSchedulerTimeout(delay);
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Create an immediate scheduler (fastest execution).
|
|
1094
|
+
*/
|
|
1095
|
+
static createImmediate() {
|
|
1096
|
+
return new OIMEventQueueSchedulerImmediate();
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
export {
|
|
1100
|
+
EOIMCollectionEventType,
|
|
1101
|
+
EOIMEventQueueSchedulerEventType,
|
|
1102
|
+
EOIMIndexEventType,
|
|
1103
|
+
EOIMUpdateEventCoalescerEventType,
|
|
1104
|
+
OIMCollection,
|
|
1105
|
+
OIMCollectionStore,
|
|
1106
|
+
OIMCollectionStoreMapDriven,
|
|
1107
|
+
OIMComparatorFactory,
|
|
1108
|
+
OIMEntityUpdaterFactory,
|
|
1109
|
+
OIMEventEmitter,
|
|
1110
|
+
OIMEventQueue,
|
|
1111
|
+
OIMEventQueueScheduler,
|
|
1112
|
+
OIMEventQueueSchedulerAnimationFrame,
|
|
1113
|
+
OIMEventQueueSchedulerFactory,
|
|
1114
|
+
OIMEventQueueSchedulerImmediate,
|
|
1115
|
+
OIMEventQueueSchedulerMicrotask,
|
|
1116
|
+
OIMEventQueueSchedulerTimeout,
|
|
1117
|
+
OIMIndex,
|
|
1118
|
+
OIMIndexComparatorFactory,
|
|
1119
|
+
OIMIndexManual,
|
|
1120
|
+
OIMMap2Keys,
|
|
1121
|
+
OIMPkSelectorFactory,
|
|
1122
|
+
OIMRICollection,
|
|
1123
|
+
OIMReactiveCollection,
|
|
1124
|
+
OIMReactiveIndex,
|
|
1125
|
+
OIMReactiveIndexManual,
|
|
1126
|
+
OIMUpdateEventCoalescer,
|
|
1127
|
+
OIMUpdateEventCoalescerCollection,
|
|
1128
|
+
OIMUpdateEventCoalescerIndex,
|
|
1129
|
+
OIMUpdateEventEmitter
|
|
1130
|
+
};
|