@oimdb/core 1.2.1 → 1.3.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/dist/index.js CHANGED
@@ -2,6 +2,14 @@
2
2
  var OIMCollectionStore = class {
3
3
  };
4
4
 
5
+ // src/abstract/OIMIndexStoreSetBased.ts
6
+ var OIMIndexStoreSetBased = class {
7
+ };
8
+
9
+ // src/abstract/OIMIndexStoreArrayBased.ts
10
+ var OIMIndexStoreArrayBased = class {
11
+ };
12
+
5
13
  // src/core/OIMEventEmitter.ts
6
14
  var OIMEventEmitter = class {
7
15
  constructor() {
@@ -127,12 +135,8 @@ var EOIMIndexEventType = /* @__PURE__ */ ((EOIMIndexEventType2) => {
127
135
  return EOIMIndexEventType2;
128
136
  })(EOIMIndexEventType || {});
129
137
 
130
- // src/abstract/OIMIndexStore.ts
131
- var OIMIndexStore = class {
132
- };
133
-
134
- // src/core/OIMIndexStoreMapDriven.ts
135
- var OIMIndexStoreMapDriven = class extends OIMIndexStore {
138
+ // src/core/OIMIndexStoreMapDrivenSetBased.ts
139
+ var OIMIndexStoreMapDrivenSetBased = class extends OIMIndexStoreSetBased {
136
140
  constructor() {
137
141
  super(...arguments);
138
142
  this.pks = /* @__PURE__ */ new Map();
@@ -175,12 +179,12 @@ var OIMIndexStoreMapDriven = class extends OIMIndexStore {
175
179
  }
176
180
  };
177
181
 
178
- // src/abstract/OIMIndex.ts
179
- var OIMIndex = class {
182
+ // src/abstract/OIMIndexSetBased.ts
183
+ var OIMIndexSetBased = class {
180
184
  constructor(options = {}) {
181
185
  this.emitter = new OIMEventEmitter();
182
186
  this.comparePks = options.comparePks;
183
- this.store = options.store ?? new OIMIndexStoreMapDriven();
187
+ this.store = options.store ?? new OIMIndexStoreMapDrivenSetBased();
184
188
  }
185
189
  /**
186
190
  * Get primary keys for multiple index keys
@@ -289,6 +293,155 @@ var OIMIndex = class {
289
293
  }
290
294
  };
291
295
 
296
+ // src/core/OIMIndexStoreMapDrivenArrayBased.ts
297
+ var OIMIndexStoreMapDrivenArrayBased = class extends OIMIndexStoreArrayBased {
298
+ constructor() {
299
+ super(...arguments);
300
+ this.pks = /* @__PURE__ */ new Map();
301
+ }
302
+ setOneByKey(key, pks) {
303
+ this.pks.set(key, pks);
304
+ }
305
+ removeOneByKey(key) {
306
+ this.pks.delete(key);
307
+ }
308
+ removeManyByKeys(keys) {
309
+ for (const key of keys) {
310
+ this.pks.delete(key);
311
+ }
312
+ }
313
+ getOneByKey(key) {
314
+ return this.pks.get(key);
315
+ }
316
+ getManyByKeys(keys) {
317
+ const result = /* @__PURE__ */ new Map();
318
+ for (const key of keys) {
319
+ const pks = this.getOneByKey(key);
320
+ if (pks !== void 0) {
321
+ result.set(key, pks);
322
+ }
323
+ }
324
+ return result;
325
+ }
326
+ getAllKeys() {
327
+ return Array.from(this.pks.keys());
328
+ }
329
+ getAll() {
330
+ return new Map(this.pks);
331
+ }
332
+ countAll() {
333
+ return this.pks.size;
334
+ }
335
+ clear() {
336
+ this.pks.clear();
337
+ }
338
+ };
339
+
340
+ // src/abstract/OIMIndexArrayBased.ts
341
+ var OIMIndexArrayBased = class {
342
+ constructor(options = {}) {
343
+ this.emitter = new OIMEventEmitter();
344
+ this.comparePks = options.comparePks;
345
+ this.store = options.store ?? new OIMIndexStoreMapDrivenArrayBased();
346
+ }
347
+ /**
348
+ * Get primary keys for multiple index keys
349
+ */
350
+ getPksByKeys(keys) {
351
+ return this.store.getManyByKeys(keys);
352
+ }
353
+ /**
354
+ * Get primary keys for a specific index key
355
+ */
356
+ getPksByKey(key) {
357
+ const pksArray = this.store.getOneByKey(key);
358
+ return pksArray ? pksArray : [];
359
+ }
360
+ /**
361
+ * Check if an index key exists
362
+ */
363
+ hasKey(key) {
364
+ return this.store.getOneByKey(key) !== void 0;
365
+ }
366
+ /**
367
+ * Get all index keys
368
+ */
369
+ getKeys() {
370
+ return this.store.getAllKeys();
371
+ }
372
+ /**
373
+ * Get the number of primary keys for a specific index key
374
+ */
375
+ getKeySize(key) {
376
+ const pksArray = this.store.getOneByKey(key);
377
+ return pksArray ? pksArray.length : 0;
378
+ }
379
+ /**
380
+ * Get total number of index keys
381
+ */
382
+ get size() {
383
+ return this.store.countAll();
384
+ }
385
+ /**
386
+ * Check if the index is empty
387
+ */
388
+ get isEmpty() {
389
+ return this.store.countAll() === 0;
390
+ }
391
+ /**
392
+ * Get performance metrics for monitoring and debugging
393
+ */
394
+ getMetrics() {
395
+ let totalPks = 0;
396
+ let maxBucketSize = 0;
397
+ let minBucketSize = Infinity;
398
+ const allPks = this.store.getAll();
399
+ for (const pksArray of allPks.values()) {
400
+ totalPks += pksArray.length;
401
+ maxBucketSize = Math.max(maxBucketSize, pksArray.length);
402
+ minBucketSize = Math.min(minBucketSize, pksArray.length);
403
+ }
404
+ return {
405
+ totalKeys: allPks.size,
406
+ totalPks,
407
+ averagePksPerKey: allPks.size > 0 ? totalPks / allPks.size : 0,
408
+ maxBucketSize: maxBucketSize === -Infinity ? 0 : maxBucketSize,
409
+ minBucketSize: minBucketSize === Infinity ? 0 : minBucketSize
410
+ };
411
+ }
412
+ /**
413
+ * Clean up event listeners when index is no longer needed
414
+ */
415
+ destroy() {
416
+ this.emitter.offAll();
417
+ this.store.clear();
418
+ }
419
+ /**
420
+ * Set primary keys for a specific index key with optional comparison.
421
+ * If comparator is provided and returns true (no changes), skip the update.
422
+ */
423
+ setPksWithComparison(key, newPks) {
424
+ if (this.comparePks) {
425
+ const existingPksArray = this.store.getOneByKey(key);
426
+ if (existingPksArray && existingPksArray.length === newPks.length) {
427
+ if (this.comparePks(existingPksArray, newPks)) {
428
+ return false;
429
+ }
430
+ } else if (!existingPksArray && newPks.length === 0) {
431
+ return false;
432
+ }
433
+ }
434
+ this.store.setOneByKey(key, newPks);
435
+ return true;
436
+ }
437
+ /**
438
+ * Emit update event with changed keys
439
+ */
440
+ emitUpdate(keys) {
441
+ this.emitter.emit(0 /* UPDATE */, { keys });
442
+ }
443
+ };
444
+
292
445
  // src/enum/EOIMUpdateEventCoalescerEventType.ts
293
446
  var EOIMUpdateEventCoalescerEventType = /* @__PURE__ */ ((EOIMUpdateEventCoalescerEventType2) => {
294
447
  EOIMUpdateEventCoalescerEventType2[EOIMUpdateEventCoalescerEventType2["HAS_CHANGES"] = 0] = "HAS_CHANGES";
@@ -415,8 +568,8 @@ var OIMUpdateEventEmitter = class {
415
568
  }
416
569
  };
417
570
 
418
- // src/core/OIMIndexManual.ts
419
- var OIMIndexManual = class extends OIMIndex {
571
+ // src/core/OIMIndexManualSetBased.ts
572
+ var OIMIndexManualSetBased = class extends OIMIndexSetBased {
420
573
  constructor(options = {}) {
421
574
  super(options);
422
575
  }
@@ -508,8 +661,8 @@ var OIMUpdateEventCoalescer = class {
508
661
  constructor(index) {
509
662
  this.emitter = new OIMEventEmitter();
510
663
  this.hasEmittedChanges = false;
511
- this.updatedKeysIndex = index ?? new OIMIndexManual({
512
- store: new OIMIndexStoreMapDriven()
664
+ this.updatedKeysIndex = index ?? new OIMIndexManualSetBased({
665
+ store: new OIMIndexStoreMapDrivenSetBased()
513
666
  });
514
667
  if (!this.updatedKeysIndex.hasKey(OIMDBSettings.UPDATED_KEYS_INDEX_KEY)) {
515
668
  this.updatedKeysIndex.setPks(
@@ -579,8 +732,49 @@ var OIMUpdateEventCoalescerIndex = class extends OIMUpdateEventCoalescer {
579
732
  }
580
733
  };
581
734
 
582
- // src/abstract/OIMReactiveIndex.ts
583
- var OIMReactiveIndex = class {
735
+ // src/abstract/OIMReactiveIndexSetBased.ts
736
+ var OIMReactiveIndexSetBased = class {
737
+ constructor(queue, opts) {
738
+ this.index = opts?.index ?? this.createDefaultIndex();
739
+ this.coalescer = new OIMUpdateEventCoalescerIndex(
740
+ this.index.emitter
741
+ );
742
+ this.updateEventEmitter = new OIMUpdateEventEmitter({
743
+ coalescer: this.coalescer,
744
+ queue
745
+ });
746
+ }
747
+ getPksByKey(key) {
748
+ return this.index.getPksByKey(key);
749
+ }
750
+ getPksByKeys(keys) {
751
+ return this.index.getPksByKeys(keys);
752
+ }
753
+ hasKey(key) {
754
+ return this.index.hasKey(key);
755
+ }
756
+ getKeys() {
757
+ return this.index.getKeys();
758
+ }
759
+ getKeySize(key) {
760
+ return this.index.getKeySize(key);
761
+ }
762
+ get size() {
763
+ return this.index.size;
764
+ }
765
+ get isEmpty() {
766
+ return this.index.isEmpty;
767
+ }
768
+ getMetrics() {
769
+ return this.index.getMetrics();
770
+ }
771
+ destroy() {
772
+ this.index.destroy();
773
+ }
774
+ };
775
+
776
+ // src/abstract/OIMReactiveIndexArrayBased.ts
777
+ var OIMReactiveIndexArrayBased = class {
584
778
  constructor(queue, opts) {
585
779
  this.index = opts?.index ?? this.createDefaultIndex();
586
780
  this.coalescer = new OIMUpdateEventCoalescerIndex(
@@ -708,6 +902,10 @@ var OIMCollection = class {
708
902
  getManyByPks(pks) {
709
903
  return this.store.getManyByPks(pks);
710
904
  }
905
+ upsertOneByPk(pk, entity) {
906
+ this.upsertOneWithoutNotificationsByPk(pk, entity);
907
+ this.emitter.emit(0 /* UPDATE */, { pks: [pk] });
908
+ }
711
909
  upsertOne(entity) {
712
910
  const pk = this.upsertOneWithoutNotifications(entity);
713
911
  this.emitter.emit(0 /* UPDATE */, { pks: [pk] });
@@ -751,6 +949,15 @@ var OIMCollection = class {
751
949
  }
752
950
  upsertOneWithoutNotifications(entity) {
753
951
  const pk = this.selectPk(entity);
952
+ this.upsertOneWithoutNotificationsByPk(pk, entity);
953
+ return pk;
954
+ }
955
+ upsertOneWithoutNotificationsByPk(pk, entity) {
956
+ if (!pk) {
957
+ throw new Error(
958
+ `[OIMCollection]: PK is required to upsert an entity ${JSON.stringify(entity)}`
959
+ );
960
+ }
754
961
  const existingEntity = this.store.getOneByPk(pk);
755
962
  if (existingEntity) {
756
963
  this.store.setOneByPk(
@@ -760,7 +967,6 @@ var OIMCollection = class {
760
967
  } else {
761
968
  this.store.setOneByPk(pk, entity);
762
969
  }
763
- return pk;
764
970
  }
765
971
  };
766
972
 
@@ -804,13 +1010,111 @@ var OIMReactiveCollection = class extends OIMCollection {
804
1010
  }
805
1011
  };
806
1012
 
807
- // src/core/OIMReactiveIndexManual.ts
808
- var OIMReactiveIndexManual = class extends OIMReactiveIndex {
1013
+ // src/core/OIMReactiveIndexManualSetBased.ts
1014
+ var OIMReactiveIndexManualSetBased = class extends OIMReactiveIndexSetBased {
1015
+ constructor(queue, opts) {
1016
+ super(queue, opts);
1017
+ }
1018
+ createDefaultIndex() {
1019
+ return new OIMIndexManualSetBased();
1020
+ }
1021
+ setPks(key, pks) {
1022
+ this.index.setPks(key, pks);
1023
+ }
1024
+ addPks(key, pks) {
1025
+ this.index.addPks(key, pks);
1026
+ }
1027
+ removePks(key, pks) {
1028
+ this.index.removePks(key, pks);
1029
+ }
1030
+ clear(key) {
1031
+ this.index.clear(key);
1032
+ }
1033
+ };
1034
+
1035
+ // src/core/OIMIndexManualArrayBased.ts
1036
+ var OIMIndexManualArrayBased = class extends OIMIndexArrayBased {
1037
+ constructor(options = {}) {
1038
+ super(options);
1039
+ }
1040
+ /**
1041
+ * Set primary keys for a specific index key, replacing any existing values.
1042
+ * Uses optional comparator to skip updates if PKs haven't actually changed.
1043
+ */
1044
+ setPks(key, pks) {
1045
+ const hasChanges = this.setPksWithComparison(key, pks);
1046
+ if (hasChanges) {
1047
+ this.emitUpdate([key]);
1048
+ }
1049
+ }
1050
+ /**
1051
+ * Add primary keys to a specific index key
1052
+ */
1053
+ addPks(key, pks) {
1054
+ if (pks.length === 0) return;
1055
+ let pksArray = this.store.getOneByKey(key);
1056
+ if (!pksArray) {
1057
+ pksArray = [];
1058
+ this.store.setOneByKey(key, pksArray);
1059
+ }
1060
+ const pksSet = new Set(pksArray);
1061
+ let hasChanges = false;
1062
+ for (const pk of pks) {
1063
+ if (!pksSet.has(pk)) {
1064
+ pksSet.add(pk);
1065
+ hasChanges = true;
1066
+ }
1067
+ }
1068
+ if (hasChanges) {
1069
+ this.store.setOneByKey(key, Array.from(pksSet));
1070
+ this.emitUpdate([key]);
1071
+ }
1072
+ }
1073
+ /**
1074
+ * Remove primary keys from a specific index key
1075
+ */
1076
+ removePks(key, pks) {
1077
+ if (pks.length === 0) return;
1078
+ const pksArray = this.store.getOneByKey(key);
1079
+ if (!pksArray) return;
1080
+ const pksSet = new Set(pks);
1081
+ const filtered = pksArray.filter((pk) => !pksSet.has(pk));
1082
+ const hasChanges = filtered.length !== pksArray.length;
1083
+ if (hasChanges) {
1084
+ if (filtered.length === 0) {
1085
+ this.store.removeOneByKey(key);
1086
+ } else {
1087
+ this.store.setOneByKey(key, filtered);
1088
+ }
1089
+ this.emitUpdate([key]);
1090
+ }
1091
+ }
1092
+ /**
1093
+ * Clear all primary keys for a specific index key, or all keys if no key specified
1094
+ */
1095
+ clear(key) {
1096
+ if (key === void 0) {
1097
+ const allKeys = this.store.getAllKeys();
1098
+ if (allKeys.length > 0) {
1099
+ this.store.clear();
1100
+ this.emitUpdate(allKeys);
1101
+ }
1102
+ } else {
1103
+ if (this.store.getOneByKey(key) !== void 0) {
1104
+ this.store.removeOneByKey(key);
1105
+ this.emitUpdate([key]);
1106
+ }
1107
+ }
1108
+ }
1109
+ };
1110
+
1111
+ // src/core/OIMReactiveIndexManualArrayBased.ts
1112
+ var OIMReactiveIndexManualArrayBased = class extends OIMReactiveIndexArrayBased {
809
1113
  constructor(queue, opts) {
810
1114
  super(queue, opts);
811
1115
  }
812
1116
  createDefaultIndex() {
813
- return new OIMIndexManual();
1117
+ return new OIMIndexManualArrayBased();
814
1118
  }
815
1119
  setPks(key, pks) {
816
1120
  this.index.setPks(key, pks);
@@ -1217,15 +1521,23 @@ export {
1217
1521
  OIMEventQueueSchedulerImmediate,
1218
1522
  OIMEventQueueSchedulerMicrotask,
1219
1523
  OIMEventQueueSchedulerTimeout,
1220
- OIMIndex,
1524
+ OIMIndexArrayBased,
1221
1525
  OIMIndexComparatorFactory,
1222
- OIMIndexManual,
1526
+ OIMIndexManualArrayBased,
1527
+ OIMIndexManualSetBased,
1528
+ OIMIndexSetBased,
1529
+ OIMIndexStoreArrayBased,
1530
+ OIMIndexStoreMapDrivenArrayBased,
1531
+ OIMIndexStoreMapDrivenSetBased,
1532
+ OIMIndexStoreSetBased,
1223
1533
  OIMMap2Keys,
1224
1534
  OIMPkSelectorFactory,
1225
1535
  OIMRICollection,
1226
1536
  OIMReactiveCollection,
1227
- OIMReactiveIndex,
1228
- OIMReactiveIndexManual,
1537
+ OIMReactiveIndexArrayBased,
1538
+ OIMReactiveIndexManualArrayBased,
1539
+ OIMReactiveIndexManualSetBased,
1540
+ OIMReactiveIndexSetBased,
1229
1541
  OIMUpdateEventCoalescer,
1230
1542
  OIMUpdateEventCoalescerCollection,
1231
1543
  OIMUpdateEventCoalescerIndex,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oimdb/core",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Core in-memory data library with type-safe indices, reactive subscriptions, and event processing",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -32,6 +32,18 @@
32
32
  "files": [
33
33
  "dist"
34
34
  ],
35
+ "keywords": [
36
+ "oimdb",
37
+ "in-memory",
38
+ "database",
39
+ "reactive",
40
+ "typescript",
41
+ "type-safe",
42
+ "indices",
43
+ "subscriptions",
44
+ "event-processing",
45
+ "state-management"
46
+ ],
35
47
  "author": "Andrei Baikov",
36
48
  "license": "MIT",
37
49
  "devDependencies": {