@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/README.md
CHANGED
|
@@ -185,6 +185,25 @@ const multipleUsers = users.getManyByPks(['user1', 'user2']);
|
|
|
185
185
|
const userSlot = users.getSlotByPk('user1');
|
|
186
186
|
```
|
|
187
187
|
|
|
188
|
+
#### Composite primary key
|
|
189
|
+
|
|
190
|
+
Instead of a primitive PK, a collection can be keyed by a **composite key path** — an arbitrary-length tuple of primitive segments. Pass a trie-backed store:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import { OIMReactiveCollection, OIMCollectionStoreTrieDriven, TOIMKeyPath } from '@oimdb/core';
|
|
194
|
+
|
|
195
|
+
const memberships = new OIMReactiveCollection<Membership, TOIMKeyPath>(queue, {
|
|
196
|
+
selectPk: (m) => [m.userId, m.projectId],
|
|
197
|
+
store: new OIMCollectionStoreTrieDriven<Membership>(),
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
memberships.getOneByPk([1, 10]); // matched by content — a fresh array works
|
|
201
|
+
memberships.subscribeOnKey([1, 10], render);
|
|
202
|
+
memberships.removeOneByPk([1, 10]);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Key paths match **by content** (the store interns each logical PK to one canonical `slot.pk`). Indexes work over such a collection too (`indexFactory.setBasedIndex()` indexes composite PKs). Primitive-PK collections keep the native-`Map` store untouched. At serialization boundaries a composite PK needs an `IOIMPkCodec` (`OIMPkCodecKeyPath`) — `@oimdb/persist`/`@oimdb/snapshot-manager` need none; `@oimdb/redux-adapter` takes it.
|
|
206
|
+
|
|
188
207
|
### Creating a Reactive Index
|
|
189
208
|
|
|
190
209
|
OIMDB provides two types of indexes optimized for different use cases:
|
|
@@ -634,6 +653,24 @@ users.upsertOne({ id: 'user1', role: 'admin' });
|
|
|
634
653
|
// This prevents unnecessary re-renders and improves performance
|
|
635
654
|
```
|
|
636
655
|
|
|
656
|
+
### Disposing everything at once — `OIMDisposeScope`
|
|
657
|
+
|
|
658
|
+
Teardown is LIFO: dispose dependents before what they depend on (indexes / streams / selectors → collection → queue). Instead of tracking that order by hand, register into an `OIMDisposeScope` as you build and tear it all down in one call:
|
|
659
|
+
|
|
660
|
+
```typescript
|
|
661
|
+
import { OIMDisposeScope, OIMEventQueue, OIMReactiveCollection } from '@oimdb/core';
|
|
662
|
+
|
|
663
|
+
const scope = new OIMDisposeScope();
|
|
664
|
+
const queue = scope.add(new OIMEventQueue());
|
|
665
|
+
const users = scope.add(new OIMReactiveCollection(queue, { selectPk: u => u.id }));
|
|
666
|
+
const byTeam = scope.add(usersIndexFactory.setBasedIndex());
|
|
667
|
+
scope.add(selector.watch(render)); // bare unsubscribe fn works too
|
|
668
|
+
|
|
669
|
+
scope.destroy(); // disposes byTeam → users → queue (reverse order), no bookkeeping
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
`add(x)` returns `x` for inline capture. Accepts both `{ destroy(): void }` objects and bare `() => void` unsubscribe functions (selectors, per-key subscriptions and scheduler tasks expose only the latter). Idempotent; every item is disposed even if one throws (first error rethrown after); `child()` nests a sub-scope. Factory: `createOIMDisposeScope()`. Related exports: `IOIMDisposable`, `TOIMDisposable`.
|
|
673
|
+
|
|
637
674
|
### Effects, Computed, and the Event Lifecycle
|
|
638
675
|
|
|
639
676
|
OIMDB uses a single-pass flush boundary: `queue.flush()` executes the current batch of pending work.
|
|
@@ -1361,6 +1398,8 @@ createOIMCollectionIndexFactory(queue, collection)
|
|
|
1361
1398
|
|
|
1362
1399
|
**Methods:**
|
|
1363
1400
|
- `setBasedIndex<TKey>()` - Create `OIMReactiveCollectionIndexManualSetBased<TKey, TPk, TEntity>`
|
|
1401
|
+
- `compositeSetIndex()` - Create `OIMReactiveCollectionIndexCompositeTrieSetBased<TPk, TEntity>` — set-based index keyed by a composite **key path** (`TOIMKeyPath`, an arbitrary-length tuple of primitive segments, e.g. `setPks([projectId, role], pks)`). Matched by content in O(arity), no string concatenation. Primitive-keyed indexes keep their native-`Map` fast path.
|
|
1402
|
+
- `compositeArrayIndex()` - Create `OIMReactiveCollectionIndexCompositeTrieArrayBased<TPk, TEntity>` — ordered counterpart of `compositeSetIndex`, buckets are ordered slot arrays per key path.
|
|
1364
1403
|
- `derivedSetIndex<TKey>(selectIndexKeys)` - Create `OIMDerivedCollectionIndexSetBased<TKey, TPk, TEntity>`
|
|
1365
1404
|
- `arrayBasedIndex<TKey>()` - Create `OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity>`
|
|
1366
1405
|
- `derivedArrayIndex<TKey>(selectIndexKeys, { orderBy?, compareEntities? })` - Create `OIMDerivedCollectionIndexArrayBased<TKey, TPk, TEntity>`
|
|
@@ -1404,7 +1443,7 @@ new OIMReactiveCollectionIndexManualSetBased(queue: OIMEventQueue, opts: {
|
|
|
1404
1443
|
store?: OIMIndexStoreSetBased<TKey, TPk>;
|
|
1405
1444
|
};
|
|
1406
1445
|
} | {
|
|
1407
|
-
|
|
1446
|
+
getSlot: TOIMEntitySlotGetter<TPk>;
|
|
1408
1447
|
indexOptions?: {
|
|
1409
1448
|
comparePks?: TOIMIndexComparator<TPk>;
|
|
1410
1449
|
store?: OIMIndexStoreSetBased<TKey, TPk>;
|
|
@@ -1412,7 +1451,7 @@ new OIMReactiveCollectionIndexManualSetBased(queue: OIMEventQueue, opts: {
|
|
|
1412
1451
|
})
|
|
1413
1452
|
```
|
|
1414
1453
|
|
|
1415
|
-
Pass exactly one binding: `collection` for normal collection-bound indexes, or `
|
|
1454
|
+
Pass exactly one binding: `collection` for normal collection-bound indexes, or `getSlot` for custom slot lookup.
|
|
1416
1455
|
|
|
1417
1456
|
**Methods:**
|
|
1418
1457
|
- `setPks(key: TKey, pks: readonly TPk[]): void` - Set primary keys for index key
|
|
@@ -1502,7 +1541,7 @@ new OIMReactiveCollectionIndexManualArrayBased(queue: OIMEventQueue, opts: {
|
|
|
1502
1541
|
store?: OIMIndexStoreArrayBased<TKey, TPk>;
|
|
1503
1542
|
};
|
|
1504
1543
|
} | {
|
|
1505
|
-
|
|
1544
|
+
getSlot: TOIMEntitySlotGetter<TPk>;
|
|
1506
1545
|
indexOptions?: {
|
|
1507
1546
|
comparePks?: TOIMIndexComparator<TPk>;
|
|
1508
1547
|
store?: OIMIndexStoreArrayBased<TKey, TPk>;
|
|
@@ -1510,7 +1549,7 @@ new OIMReactiveCollectionIndexManualArrayBased(queue: OIMEventQueue, opts: {
|
|
|
1510
1549
|
})
|
|
1511
1550
|
```
|
|
1512
1551
|
|
|
1513
|
-
Pass exactly one binding: `collection` for normal collection-bound indexes, or `
|
|
1552
|
+
Pass exactly one binding: `collection` for normal collection-bound indexes, or `getSlot` for custom slot lookup.
|
|
1514
1553
|
|
|
1515
1554
|
**Methods:**
|
|
1516
1555
|
- `setPks(key: TKey, pks: readonly TPk[]): void` - Set primary keys for index key
|