@oimdb/react 1.0.8 → 1.1.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/README.md CHANGED
@@ -29,8 +29,8 @@ npm install @oimdb/react @oimdb/core
29
29
  import { OIMEventQueue, OIMRICollection, OIMReactiveIndexManual } from '@oimdb/core';
30
30
  import {
31
31
  useSelectEntitiesByPks,
32
- selectEntitiesByIndexKey,
33
- selectEntityByPk
32
+ useSelectEntitiesByIndexKey,
33
+ useSelectEntityByPk
34
34
  } from '@oimdb/react';
35
35
 
36
36
  // Create event queue and reactive collections
@@ -46,7 +46,7 @@ const usersCollection = new OIMRICollection(queue, {
46
46
 
47
47
  ```typescript
48
48
  function UserProfile({ userId }: { userId: string }) {
49
- const user = selectEntityByPk(usersCollection, userId);
49
+ const user = useSelectEntityByPk(usersCollection, userId);
50
50
 
51
51
  if (!user) return <div>Loading...</div>;
52
52
 
@@ -81,7 +81,7 @@ function UserList({ userIds }: { userIds: string[] }) {
81
81
 
82
82
  ```typescript
83
83
  function TeamMembers({ teamId }: { teamId: string }) {
84
- const teamUsers = selectEntitiesByIndexKey(
84
+ const teamUsers = useSelectEntitiesByIndexKey(
85
85
  usersCollection,
86
86
  usersCollection.indexes.byTeam,
87
87
  teamId
@@ -108,8 +108,7 @@ For applications with multiple collections, use the React Context pattern for ce
108
108
  ```typescript
109
109
  import {
110
110
  OIMRICollectionsProvider,
111
- useOIMCollectionsContext,
112
- StrictCollectionsDictionary
111
+ useOIMCollectionsContext
113
112
  } from '@oimdb/react';
114
113
 
115
114
  interface User {
@@ -140,9 +139,148 @@ function createCollections() {
140
139
  return { users: usersCollection, teams: teamsCollection } as const;
141
140
  }
142
141
 
143
- type AppCollections = StrictCollectionsDictionary<ReturnType<typeof createCollections>>;
142
+ type AppCollections = ReturnType<typeof createCollections>;
144
143
  ```
145
144
 
145
+ ## TypeScript Typing Strategies
146
+
147
+ For maximum type safety, you should properly type your collections dictionary. There are two main approaches, similar to how Redux handles state typing:
148
+
149
+ ### Approach 1: Using `typeof` (Recommended for Simple Cases)
150
+
151
+ The simplest approach is to use TypeScript's `typeof` operator to infer types from your collection instances:
152
+
153
+ ```typescript
154
+ import { OIMEventQueue, OIMRICollection, OIMReactiveIndexManual } from '@oimdb/core';
155
+
156
+ interface User {
157
+ id: string;
158
+ name: string;
159
+ teamId: string;
160
+ }
161
+
162
+ interface Team {
163
+ id: string;
164
+ name: string;
165
+ }
166
+
167
+ // Create collections
168
+ const queue = new OIMEventQueue();
169
+ const userTeamIndex = new OIMReactiveIndexManual<string, string>(queue);
170
+ const usersCollection = new OIMRICollection(queue, {
171
+ collectionOpts: { selectPk: (user: User) => user.id },
172
+ indexes: { byTeam: userTeamIndex },
173
+ });
174
+
175
+ const teamsCollection = new OIMRICollection(queue, {
176
+ collectionOpts: { selectPk: (team: Team) => team.id },
177
+ indexes: {},
178
+ });
179
+
180
+ // Infer types using typeof
181
+ const collections = {
182
+ users: usersCollection,
183
+ teams: teamsCollection,
184
+ } as const;
185
+
186
+ // Extract the type
187
+ type AppCollections = typeof collections;
188
+ ```
189
+
190
+ **Usage:**
191
+ ```typescript
192
+ function MyComponent() {
193
+ const { users, teams } = useOIMCollectionsContext<AppCollections>();
194
+ // users and teams are fully typed with all their generics preserved
195
+ }
196
+ ```
197
+
198
+ ### Approach 2: Creating Explicit Types (Recommended for Complex Projects)
199
+
200
+ For larger applications or when you need more control, create explicit type definitions similar to Redux's approach:
201
+
202
+ ```typescript
203
+ import { OIMEventQueue, OIMRICollection, OIMReactiveIndexManual } from '@oimdb/core';
204
+ import type { TOIMPk, OIMIndex, OIMReactiveIndex } from '@oimdb/core';
205
+
206
+ interface User {
207
+ id: string;
208
+ name: string;
209
+ teamId: string;
210
+ }
211
+
212
+ interface Team {
213
+ id: string;
214
+ name: string;
215
+ }
216
+
217
+ // Define your collection types explicitly
218
+ type UserCollection = OIMRICollection<
219
+ User,
220
+ string,
221
+ 'byTeam',
222
+ string,
223
+ OIMIndex<string, string>,
224
+ OIMReactiveIndex<string, string, OIMIndex<string, string>>
225
+ >;
226
+
227
+ type TeamCollection = OIMRICollection<
228
+ Team,
229
+ string,
230
+ never,
231
+ never,
232
+ OIMIndex<never, never>,
233
+ OIMReactiveIndex<never, never, OIMIndex<never, never>>
234
+ >;
235
+
236
+ // Define your collections dictionary type
237
+ interface AppCollections {
238
+ users: UserCollection;
239
+ teams: TeamCollection;
240
+ }
241
+
242
+ // Factory function that returns properly typed collections
243
+ function createCollections(): AppCollections {
244
+ const queue = new OIMEventQueue();
245
+ const userTeamIndex = new OIMReactiveIndexManual<string, string>(queue);
246
+
247
+ return {
248
+ users: new OIMRICollection(queue, {
249
+ collectionOpts: { selectPk: (user: User) => user.id },
250
+ indexes: { byTeam: userTeamIndex },
251
+ }) as UserCollection,
252
+
253
+ teams: new OIMRICollection(queue, {
254
+ collectionOpts: { selectPk: (team: Team) => team.id },
255
+ indexes: {},
256
+ }) as TeamCollection,
257
+ };
258
+ }
259
+ ```
260
+
261
+ **Usage:**
262
+ ```typescript
263
+ function MyComponent() {
264
+ const { users, teams } = useOIMCollectionsContext<AppCollections>();
265
+ // Full type safety with explicit types
266
+ }
267
+ ```
268
+
269
+ ### When to Use Each Approach
270
+
271
+ - **Use `typeof`** when:
272
+ - You have simple collection setups
273
+ - You want TypeScript to infer everything automatically
274
+ - You prefer less boilerplate
275
+ - Your collections are created in one place
276
+
277
+ - **Use explicit types** when:
278
+ - You need to share types across multiple files
279
+ - You want to document your data structure explicitly
280
+ - You're building a library or shared module
281
+ - You need to ensure type consistency across your application
282
+ - You prefer Redux-style explicit typing patterns
283
+
146
284
  ### Provider Setup
147
285
 
148
286
  ```typescript
@@ -165,7 +303,7 @@ function UserDashboard() {
165
303
 
166
304
  // Use collections with hooks
167
305
  const allUsers = useSelectEntitiesByPks(users, []);
168
- const teamMembers = selectEntitiesByIndexKey(
306
+ const teamMembers = useSelectEntitiesByIndexKey(
169
307
  users,
170
308
  users.indexes.byTeam,
171
309
  'team1'
@@ -205,7 +343,7 @@ function UserComponent() {
205
343
 
206
344
  ## API Reference
207
345
 
208
- ### `selectEntityByPk(reactiveCollection, pk)`
346
+ ### `useSelectEntityByPk(reactiveCollection, pk)`
209
347
 
210
348
  Subscribes to a single entity from a reactive collection.
211
349
 
@@ -227,7 +365,7 @@ Subscribes to multiple entities from a reactive collection.
227
365
  **Returns:**
228
366
  - `(TEntity | undefined)[]` - Array of entities (undefined for missing entities)
229
367
 
230
- ### `selectEntitiesByIndexKey(reactiveCollection, reactiveIndex, key)`
368
+ ### `useSelectEntitiesByIndexKey(reactiveCollection, reactiveIndex, key)`
231
369
 
232
370
  Subscribes to entities indexed by a specific key.
233
371
 
@@ -239,7 +377,7 @@ Subscribes to entities indexed by a specific key.
239
377
  **Returns:**
240
378
  - `(TEntity | undefined)[]` - Array of entities for the given index key
241
379
 
242
- ### `selectEntitiesByIndexKeys(reactiveCollection, reactiveIndex, keys)`
380
+ ### `useSelectEntitiesByIndexKeys(reactiveCollection, reactiveIndex, keys)`
243
381
 
244
382
  Subscribes to entities indexed by multiple keys.
245
383
 
@@ -306,17 +444,9 @@ Creates a custom collections context with specific typing.
306
444
 
307
445
  ### Type Utilities
308
446
 
309
- #### `StrictCollectionsDictionary<T>`
310
-
311
- Ensures collections dictionary maintains exact types.
312
-
313
447
  #### `CollectionsDictionary`
314
448
 
315
- Base type for any collections dictionary.
316
-
317
- #### `ExtractEntityType<T>`, `ExtractPkType<T>`, etc.
318
-
319
- Type utilities for extracting specific types from collections.
449
+ Base type for any collections dictionary. Use `typeof` to extract types from your collection instances, or define explicit types using `OIMRICollection` generics.
320
450
 
321
451
  ## Architecture
322
452
 
@@ -326,8 +456,8 @@ The hooks work directly with OIMDB reactive objects:
326
456
 
327
457
  ```typescript
328
458
  // Use reactive collections and indexes directly
329
- const user = selectEntityByPk(reactiveCollection, 'user123');
330
- const posts = selectEntitiesByIndexKey(reactiveCollection, reactiveIndex, 'tech');
459
+ const user = useSelectEntityByPk(reactiveCollection, 'user123');
460
+ const posts = useSelectEntitiesByIndexKey(reactiveCollection, reactiveIndex, 'tech');
331
461
  ```
332
462
 
333
463
  ### Event Subscription
@@ -354,7 +484,7 @@ Hooks automatically subscribe to OIMDB reactive events using `useSyncExternalSto
354
484
  ```typescript
355
485
  import React from 'react';
356
486
  import { OIMEventQueue, OIMRICollection, OIMReactiveIndexManual } from '@oimdb/core';
357
- import { selectEntityByPk, useSelectEntitiesByPks, selectEntitiesByIndexKey } from '@oimdb/react';
487
+ import { useSelectEntityByPk, useSelectEntitiesByPks, useSelectEntitiesByIndexKey } from '@oimdb/react';
358
488
 
359
489
  interface User {
360
490
  id: string;
@@ -378,7 +508,7 @@ const usersCollection = createUserCollection();
378
508
 
379
509
  // Component
380
510
  function UserProfile({ userId }: { userId: string }) {
381
- const user = selectEntityByPk(usersCollection, userId);
511
+ const user = useSelectEntityByPk(usersCollection, userId);
382
512
 
383
513
  if (!user) return <div>Loading...</div>;
384
514
 
@@ -386,7 +516,7 @@ function UserProfile({ userId }: { userId: string }) {
386
516
  }
387
517
 
388
518
  function TeamDashboard({ teamId }: { teamId: string }) {
389
- const teamMembers = selectEntitiesByIndexKey(
519
+ const teamMembers = useSelectEntitiesByIndexKey(
390
520
  usersCollection,
391
521
  usersCollection.indexes.byTeam,
392
522
  teamId
@@ -445,9 +575,9 @@ const users = useEntities(userStorage, userIds);
445
575
  const posts = useIndex(postStorage, categoryIndex, 'tech');
446
576
 
447
577
  // v1.x - Reactive collections
448
- const user = selectEntityByPk(reactiveCollection, 'user123');
578
+ const user = useSelectEntityByPk(reactiveCollection, 'user123');
449
579
  const users = useSelectEntitiesByPks(reactiveCollection, userIds);
450
- const posts = selectEntitiesByIndexKey(reactiveCollection, reactiveIndex, 'tech');
580
+ const posts = useSelectEntitiesByIndexKey(reactiveCollection, reactiveIndex, 'tech');
451
581
  ```
452
582
 
453
583
  ### Collection Creation
@@ -464,7 +594,7 @@ const usersCollection = new OIMRICollection(queue, {
464
594
  collectionOpts: { selectPk: (user: User) => user.id },
465
595
  indexes: {},
466
596
  });
467
- const user = selectEntityByPk(usersCollection, userId);
597
+ const user = useSelectEntityByPk(usersCollection, userId);
468
598
  ```
469
599
 
470
600
  ### Context API
@@ -481,7 +611,7 @@ const collections = { users: usersCollection };
481
611
 
482
612
  ### Key Changes
483
613
 
484
- - **Hook naming**: More explicit names like `selectEntityByPk` vs `useEntity`
614
+ - **Hook naming**: More explicit names like `useSelectEntityByPk` vs `useEntity`
485
615
  - **Parameters**: Direct reactive collection objects instead of storage abstractions
486
616
  - **Context**: New context API for centralized collection management
487
617
  - **Type safety**: Enhanced TypeScript support with better inference
package/dist/index.cjs CHANGED
@@ -23,11 +23,11 @@ __export(index_exports, {
23
23
  OIMRICollectionsContext: () => OIMRICollectionsContext,
24
24
  OIMRICollectionsProvider: () => OIMRICollectionsProvider,
25
25
  createOIMCollectionsContext: () => createOIMCollectionsContext,
26
- selectEntitiesByIndexKey: () => selectEntitiesByIndexKey,
27
- selectEntitiesByIndexKeys: () => selectEntitiesByIndexKeys,
28
- selectEntityByPk: () => selectEntityByPk,
29
26
  useOIMCollectionsContext: () => useOIMCollectionsContext,
27
+ useSelectEntitiesByIndexKey: () => useSelectEntitiesByIndexKey,
28
+ useSelectEntitiesByIndexKeys: () => useSelectEntitiesByIndexKeys,
30
29
  useSelectEntitiesByPks: () => useSelectEntitiesByPks,
30
+ useSelectEntityByPk: () => useSelectEntityByPk,
31
31
  useSelectPksByIndexKey: () => useSelectPksByIndexKey,
32
32
  useSelectPksByIndexKeys: () => useSelectPksByIndexKeys
33
33
  });
@@ -38,6 +38,7 @@ var import_react = require("react");
38
38
  var import_react2 = require("react");
39
39
  var EMPTY_ARRAY = [];
40
40
  var useSelectPksByIndexKeys = (reactiveIndex, keys) => {
41
+ const isInitialized = (0, import_react.useRef)(false);
41
42
  const snapshotValueRef = (0, import_react.useRef)(
42
43
  keys.map((key) => Array.from(reactiveIndex.getPksByKey(key))).flat()
43
44
  );
@@ -56,6 +57,12 @@ var useSelectPksByIndexKeys = (reactiveIndex, keys) => {
56
57
  osc.current();
57
58
  };
58
59
  reactiveIndex.updateEventEmitter.subscribeOnKeys(keys, list);
60
+ if (!isInitialized.current) {
61
+ isInitialized.current = true;
62
+ } else {
63
+ snapshotValueRef.current = keys.map((key) => Array.from(reactiveIndex.getPksByKey(key))).flat();
64
+ osc.current();
65
+ }
59
66
  return () => {
60
67
  reactiveIndex.updateEventEmitter.unsubscribeFromKeys(keys, list);
61
68
  };
@@ -73,6 +80,7 @@ var useSelectPksByIndexKeys = (reactiveIndex, keys) => {
73
80
  return snapshot;
74
81
  };
75
82
  var useSelectPksByIndexKey = (reactiveIndex, key) => {
83
+ const isInitialized = (0, import_react.useRef)(false);
76
84
  const snapshotValueRef = (0, import_react.useRef)(
77
85
  Array.from(reactiveIndex.getPksByKey(key))
78
86
  );
@@ -93,6 +101,14 @@ var useSelectPksByIndexKey = (reactiveIndex, key) => {
93
101
  osc.current();
94
102
  };
95
103
  reactiveIndex.updateEventEmitter.subscribeOnKey(key, list);
104
+ if (!isInitialized.current) {
105
+ isInitialized.current = true;
106
+ } else {
107
+ snapshotValueRef.current = Array.from(
108
+ reactiveIndex.getPksByKey(key)
109
+ );
110
+ osc.current();
111
+ }
96
112
  return () => {
97
113
  reactiveIndex.updateEventEmitter.unsubscribeFromKey(key, list);
98
114
  };
@@ -109,7 +125,8 @@ var useSelectPksByIndexKey = (reactiveIndex, key) => {
109
125
  );
110
126
  return snapshot;
111
127
  };
112
- var selectEntityByPk = (reactiveCollection, pk) => {
128
+ var useSelectEntityByPk = (reactiveCollection, pk) => {
129
+ const isInitialized = (0, import_react.useRef)(false);
113
130
  const snapshotValueRef = (0, import_react.useRef)(
114
131
  reactiveCollection.getOneByPk(pk)
115
132
  );
@@ -128,6 +145,12 @@ var selectEntityByPk = (reactiveCollection, pk) => {
128
145
  osc.current();
129
146
  };
130
147
  reactiveCollection.updateEventEmitter.subscribeOnKey(pk, list);
148
+ if (!isInitialized.current) {
149
+ isInitialized.current = true;
150
+ } else {
151
+ snapshotValueRef.current = reactiveCollection.getOneByPk(pk);
152
+ osc.current();
153
+ }
131
154
  return () => {
132
155
  reactiveCollection.updateEventEmitter.unsubscribeFromKey(pk, list);
133
156
  };
@@ -141,6 +164,7 @@ var selectEntityByPk = (reactiveCollection, pk) => {
141
164
  return snapshot;
142
165
  };
143
166
  var useSelectEntitiesByPks = (reactiveCollection, pks) => {
167
+ const isInitialized = (0, import_react.useRef)(false);
144
168
  const snapshotValueRef = (0, import_react.useRef)(
145
169
  pks.map((pk) => reactiveCollection.getOneByPk(pk))
146
170
  );
@@ -161,6 +185,14 @@ var useSelectEntitiesByPks = (reactiveCollection, pks) => {
161
185
  osc.current();
162
186
  };
163
187
  reactiveCollection.updateEventEmitter.subscribeOnKeys(pks, list);
188
+ if (!isInitialized.current) {
189
+ isInitialized.current = true;
190
+ } else {
191
+ snapshotValueRef.current = pks.map(
192
+ (pk) => reactiveCollection.getOneByPk(pk)
193
+ );
194
+ osc.current();
195
+ }
164
196
  return () => {
165
197
  reactiveCollection.updateEventEmitter.unsubscribeFromKeys(
166
198
  pks,
@@ -180,7 +212,7 @@ var useSelectEntitiesByPks = (reactiveCollection, pks) => {
180
212
  );
181
213
  return snapshot;
182
214
  };
183
- var selectEntitiesByIndexKey = (reactiveCollection, reactiveIndex, key) => {
215
+ var useSelectEntitiesByIndexKey = (reactiveCollection, reactiveIndex, key) => {
184
216
  const pks = useSelectPksByIndexKey(reactiveIndex, key);
185
217
  return useSelectEntitiesByPks(
186
218
  reactiveCollection,
@@ -190,7 +222,7 @@ var selectEntitiesByIndexKey = (reactiveCollection, reactiveIndex, key) => {
190
222
  var unique = (array) => {
191
223
  return Array.from(new Set(array));
192
224
  };
193
- var selectEntitiesByIndexKeys = (reactiveCollection, reactiveIndex, keys) => {
225
+ var useSelectEntitiesByIndexKeys = (reactiveCollection, reactiveIndex, keys) => {
194
226
  const pks = useSelectPksByIndexKeys(reactiveIndex, keys) || EMPTY_ARRAY;
195
227
  return useSelectEntitiesByPks(reactiveCollection, unique(Array.from(pks)));
196
228
  };
@@ -225,11 +257,11 @@ function useOIMCollectionsContext(context) {
225
257
  OIMRICollectionsContext,
226
258
  OIMRICollectionsProvider,
227
259
  createOIMCollectionsContext,
228
- selectEntitiesByIndexKey,
229
- selectEntitiesByIndexKeys,
230
- selectEntityByPk,
231
260
  useOIMCollectionsContext,
261
+ useSelectEntitiesByIndexKey,
262
+ useSelectEntitiesByIndexKeys,
232
263
  useSelectEntitiesByPks,
264
+ useSelectEntityByPk,
233
265
  useSelectPksByIndexKey,
234
266
  useSelectPksByIndexKeys
235
267
  });
package/dist/index.d.cts CHANGED
@@ -5,14 +5,12 @@ import { ReactNode } from 'react';
5
5
 
6
6
  declare const useSelectPksByIndexKeys: <TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, keys: readonly TKey[]) => readonly TPk[] | null;
7
7
  declare const useSelectPksByIndexKey: <TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, key: TKey) => readonly TPk[] | null;
8
- declare const selectEntityByPk: <TEntity extends object, TPk extends TOIMPk>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, pk: TPk) => TEntity | undefined;
8
+ declare const useSelectEntityByPk: <TEntity extends object, TPk extends TOIMPk>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, pk: TPk) => TEntity | undefined;
9
9
  declare const useSelectEntitiesByPks: <TEntity extends object, TPk extends TOIMPk>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]) => readonly TEntity[] | null;
10
- declare const selectEntitiesByIndexKey: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, key: TKey) => readonly TEntity[] | null;
11
- declare const selectEntitiesByIndexKeys: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, keys: readonly TKey[]) => readonly TEntity[] | null;
10
+ declare const useSelectEntitiesByIndexKey: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, key: TKey) => readonly TEntity[] | null;
11
+ declare const useSelectEntitiesByIndexKeys: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, keys: readonly TKey[]) => readonly TEntity[] | null;
12
12
 
13
- type AnyOIMRICollection = OIMRICollection<object, TOIMPk, string, TOIMPk, any, any>;
14
- type CollectionsDictionary = Record<string, AnyOIMRICollection>;
15
- type TypedCollectionsDictionary<T extends CollectionsDictionary> = T;
13
+ type CollectionsDictionary = Record<string, OIMRICollection<object, string, string, string, never, never>>;
16
14
  type OIMContextValue<T extends CollectionsDictionary = CollectionsDictionary> = T | null;
17
15
  declare const OIMRICollectionsContext: React.Context<OIMContextValue<CollectionsDictionary>>;
18
16
  declare function createOIMCollectionsContext<T extends CollectionsDictionary>(): React.Context<OIMContextValue<T>>;
@@ -23,23 +21,5 @@ interface OIMRICollectionsProviderProps<T extends CollectionsDictionary> {
23
21
  }
24
22
  declare function OIMRICollectionsProvider<T extends CollectionsDictionary>({ collections, children, context, }: OIMRICollectionsProviderProps<T>): react_jsx_runtime.JSX.Element;
25
23
  declare function useOIMCollectionsContext<T extends CollectionsDictionary = CollectionsDictionary>(context?: React.Context<OIMContextValue<T>>): T;
26
- type ExtractEntityType<T> = T extends OIMRICollection<infer E, TOIMPk, string, TOIMPk, any, any> ? E : never;
27
- type ExtractPkType<T> = T extends OIMRICollection<object, infer P, string, TOIMPk, any, any> ? P : never;
28
- type ExtractIndexNameType<T> = T extends OIMRICollection<object, TOIMPk, infer IN, TOIMPk, any, any> ? IN : never;
29
- type ExtractIndexKeyType<T> = T extends OIMRICollection<object, TOIMPk, string, infer IK, any, any> ? IK : never;
30
- type CreateCollectionsDictionary<T extends Record<string, AnyOIMRICollection>> = {
31
- [K in keyof T]: T[K];
32
- };
33
- type ExtractCollectionSignature<T> = T extends OIMRICollection<infer E, infer P, infer IN, infer IK, infer I, infer RI> ? {
34
- entity: E;
35
- pk: P;
36
- indexName: IN;
37
- indexKey: IK;
38
- index: I;
39
- reactiveIndex: RI;
40
- } : never;
41
- type StrictCollectionsDictionary<T> = {
42
- [K in keyof T]: T[K] extends OIMRICollection<infer E, infer P, infer IN, infer IK, infer I, infer RI> ? OIMRICollection<E, P, IN, IK, I, RI> : never;
43
- };
44
24
 
45
- export { type AnyOIMRICollection, type CollectionsDictionary, type CreateCollectionsDictionary, type ExtractCollectionSignature, type ExtractEntityType, type ExtractIndexKeyType, type ExtractIndexNameType, type ExtractPkType, type OIMContextValue, OIMRICollectionsContext, OIMRICollectionsProvider, type OIMRICollectionsProviderProps, type StrictCollectionsDictionary, type TypedCollectionsDictionary, createOIMCollectionsContext, selectEntitiesByIndexKey, selectEntitiesByIndexKeys, selectEntityByPk, useOIMCollectionsContext, useSelectEntitiesByPks, useSelectPksByIndexKey, useSelectPksByIndexKeys };
25
+ export { type CollectionsDictionary, type OIMContextValue, OIMRICollectionsContext, OIMRICollectionsProvider, type OIMRICollectionsProviderProps, createOIMCollectionsContext, useOIMCollectionsContext, useSelectEntitiesByIndexKey, useSelectEntitiesByIndexKeys, useSelectEntitiesByPks, useSelectEntityByPk, useSelectPksByIndexKey, useSelectPksByIndexKeys };
package/dist/index.d.ts CHANGED
@@ -5,14 +5,12 @@ import { ReactNode } from 'react';
5
5
 
6
6
  declare const useSelectPksByIndexKeys: <TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, keys: readonly TKey[]) => readonly TPk[] | null;
7
7
  declare const useSelectPksByIndexKey: <TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, key: TKey) => readonly TPk[] | null;
8
- declare const selectEntityByPk: <TEntity extends object, TPk extends TOIMPk>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, pk: TPk) => TEntity | undefined;
8
+ declare const useSelectEntityByPk: <TEntity extends object, TPk extends TOIMPk>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, pk: TPk) => TEntity | undefined;
9
9
  declare const useSelectEntitiesByPks: <TEntity extends object, TPk extends TOIMPk>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]) => readonly TEntity[] | null;
10
- declare const selectEntitiesByIndexKey: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, key: TKey) => readonly TEntity[] | null;
11
- declare const selectEntitiesByIndexKeys: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, keys: readonly TKey[]) => readonly TEntity[] | null;
10
+ declare const useSelectEntitiesByIndexKey: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, key: TKey) => readonly TEntity[] | null;
11
+ declare const useSelectEntitiesByIndexKeys: <TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndex<TKey, TPk>>(reactiveCollection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndex<TKey, TPk, TIndex>, keys: readonly TKey[]) => readonly TEntity[] | null;
12
12
 
13
- type AnyOIMRICollection = OIMRICollection<object, TOIMPk, string, TOIMPk, any, any>;
14
- type CollectionsDictionary = Record<string, AnyOIMRICollection>;
15
- type TypedCollectionsDictionary<T extends CollectionsDictionary> = T;
13
+ type CollectionsDictionary = Record<string, OIMRICollection<object, string, string, string, never, never>>;
16
14
  type OIMContextValue<T extends CollectionsDictionary = CollectionsDictionary> = T | null;
17
15
  declare const OIMRICollectionsContext: React.Context<OIMContextValue<CollectionsDictionary>>;
18
16
  declare function createOIMCollectionsContext<T extends CollectionsDictionary>(): React.Context<OIMContextValue<T>>;
@@ -23,23 +21,5 @@ interface OIMRICollectionsProviderProps<T extends CollectionsDictionary> {
23
21
  }
24
22
  declare function OIMRICollectionsProvider<T extends CollectionsDictionary>({ collections, children, context, }: OIMRICollectionsProviderProps<T>): react_jsx_runtime.JSX.Element;
25
23
  declare function useOIMCollectionsContext<T extends CollectionsDictionary = CollectionsDictionary>(context?: React.Context<OIMContextValue<T>>): T;
26
- type ExtractEntityType<T> = T extends OIMRICollection<infer E, TOIMPk, string, TOIMPk, any, any> ? E : never;
27
- type ExtractPkType<T> = T extends OIMRICollection<object, infer P, string, TOIMPk, any, any> ? P : never;
28
- type ExtractIndexNameType<T> = T extends OIMRICollection<object, TOIMPk, infer IN, TOIMPk, any, any> ? IN : never;
29
- type ExtractIndexKeyType<T> = T extends OIMRICollection<object, TOIMPk, string, infer IK, any, any> ? IK : never;
30
- type CreateCollectionsDictionary<T extends Record<string, AnyOIMRICollection>> = {
31
- [K in keyof T]: T[K];
32
- };
33
- type ExtractCollectionSignature<T> = T extends OIMRICollection<infer E, infer P, infer IN, infer IK, infer I, infer RI> ? {
34
- entity: E;
35
- pk: P;
36
- indexName: IN;
37
- indexKey: IK;
38
- index: I;
39
- reactiveIndex: RI;
40
- } : never;
41
- type StrictCollectionsDictionary<T> = {
42
- [K in keyof T]: T[K] extends OIMRICollection<infer E, infer P, infer IN, infer IK, infer I, infer RI> ? OIMRICollection<E, P, IN, IK, I, RI> : never;
43
- };
44
24
 
45
- export { type AnyOIMRICollection, type CollectionsDictionary, type CreateCollectionsDictionary, type ExtractCollectionSignature, type ExtractEntityType, type ExtractIndexKeyType, type ExtractIndexNameType, type ExtractPkType, type OIMContextValue, OIMRICollectionsContext, OIMRICollectionsProvider, type OIMRICollectionsProviderProps, type StrictCollectionsDictionary, type TypedCollectionsDictionary, createOIMCollectionsContext, selectEntitiesByIndexKey, selectEntitiesByIndexKeys, selectEntityByPk, useOIMCollectionsContext, useSelectEntitiesByPks, useSelectPksByIndexKey, useSelectPksByIndexKeys };
25
+ export { type CollectionsDictionary, type OIMContextValue, OIMRICollectionsContext, OIMRICollectionsProvider, type OIMRICollectionsProviderProps, createOIMCollectionsContext, useOIMCollectionsContext, useSelectEntitiesByIndexKey, useSelectEntitiesByIndexKeys, useSelectEntitiesByPks, useSelectEntityByPk, useSelectPksByIndexKey, useSelectPksByIndexKeys };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { useMemo, useRef, useEffect } from "react";
3
3
  import { useSyncExternalStore } from "react";
4
4
  var EMPTY_ARRAY = [];
5
5
  var useSelectPksByIndexKeys = (reactiveIndex, keys) => {
6
+ const isInitialized = useRef(false);
6
7
  const snapshotValueRef = useRef(
7
8
  keys.map((key) => Array.from(reactiveIndex.getPksByKey(key))).flat()
8
9
  );
@@ -21,6 +22,12 @@ var useSelectPksByIndexKeys = (reactiveIndex, keys) => {
21
22
  osc.current();
22
23
  };
23
24
  reactiveIndex.updateEventEmitter.subscribeOnKeys(keys, list);
25
+ if (!isInitialized.current) {
26
+ isInitialized.current = true;
27
+ } else {
28
+ snapshotValueRef.current = keys.map((key) => Array.from(reactiveIndex.getPksByKey(key))).flat();
29
+ osc.current();
30
+ }
24
31
  return () => {
25
32
  reactiveIndex.updateEventEmitter.unsubscribeFromKeys(keys, list);
26
33
  };
@@ -38,6 +45,7 @@ var useSelectPksByIndexKeys = (reactiveIndex, keys) => {
38
45
  return snapshot;
39
46
  };
40
47
  var useSelectPksByIndexKey = (reactiveIndex, key) => {
48
+ const isInitialized = useRef(false);
41
49
  const snapshotValueRef = useRef(
42
50
  Array.from(reactiveIndex.getPksByKey(key))
43
51
  );
@@ -58,6 +66,14 @@ var useSelectPksByIndexKey = (reactiveIndex, key) => {
58
66
  osc.current();
59
67
  };
60
68
  reactiveIndex.updateEventEmitter.subscribeOnKey(key, list);
69
+ if (!isInitialized.current) {
70
+ isInitialized.current = true;
71
+ } else {
72
+ snapshotValueRef.current = Array.from(
73
+ reactiveIndex.getPksByKey(key)
74
+ );
75
+ osc.current();
76
+ }
61
77
  return () => {
62
78
  reactiveIndex.updateEventEmitter.unsubscribeFromKey(key, list);
63
79
  };
@@ -74,7 +90,8 @@ var useSelectPksByIndexKey = (reactiveIndex, key) => {
74
90
  );
75
91
  return snapshot;
76
92
  };
77
- var selectEntityByPk = (reactiveCollection, pk) => {
93
+ var useSelectEntityByPk = (reactiveCollection, pk) => {
94
+ const isInitialized = useRef(false);
78
95
  const snapshotValueRef = useRef(
79
96
  reactiveCollection.getOneByPk(pk)
80
97
  );
@@ -93,6 +110,12 @@ var selectEntityByPk = (reactiveCollection, pk) => {
93
110
  osc.current();
94
111
  };
95
112
  reactiveCollection.updateEventEmitter.subscribeOnKey(pk, list);
113
+ if (!isInitialized.current) {
114
+ isInitialized.current = true;
115
+ } else {
116
+ snapshotValueRef.current = reactiveCollection.getOneByPk(pk);
117
+ osc.current();
118
+ }
96
119
  return () => {
97
120
  reactiveCollection.updateEventEmitter.unsubscribeFromKey(pk, list);
98
121
  };
@@ -106,6 +129,7 @@ var selectEntityByPk = (reactiveCollection, pk) => {
106
129
  return snapshot;
107
130
  };
108
131
  var useSelectEntitiesByPks = (reactiveCollection, pks) => {
132
+ const isInitialized = useRef(false);
109
133
  const snapshotValueRef = useRef(
110
134
  pks.map((pk) => reactiveCollection.getOneByPk(pk))
111
135
  );
@@ -126,6 +150,14 @@ var useSelectEntitiesByPks = (reactiveCollection, pks) => {
126
150
  osc.current();
127
151
  };
128
152
  reactiveCollection.updateEventEmitter.subscribeOnKeys(pks, list);
153
+ if (!isInitialized.current) {
154
+ isInitialized.current = true;
155
+ } else {
156
+ snapshotValueRef.current = pks.map(
157
+ (pk) => reactiveCollection.getOneByPk(pk)
158
+ );
159
+ osc.current();
160
+ }
129
161
  return () => {
130
162
  reactiveCollection.updateEventEmitter.unsubscribeFromKeys(
131
163
  pks,
@@ -145,7 +177,7 @@ var useSelectEntitiesByPks = (reactiveCollection, pks) => {
145
177
  );
146
178
  return snapshot;
147
179
  };
148
- var selectEntitiesByIndexKey = (reactiveCollection, reactiveIndex, key) => {
180
+ var useSelectEntitiesByIndexKey = (reactiveCollection, reactiveIndex, key) => {
149
181
  const pks = useSelectPksByIndexKey(reactiveIndex, key);
150
182
  return useSelectEntitiesByPks(
151
183
  reactiveCollection,
@@ -155,7 +187,7 @@ var selectEntitiesByIndexKey = (reactiveCollection, reactiveIndex, key) => {
155
187
  var unique = (array) => {
156
188
  return Array.from(new Set(array));
157
189
  };
158
- var selectEntitiesByIndexKeys = (reactiveCollection, reactiveIndex, keys) => {
190
+ var useSelectEntitiesByIndexKeys = (reactiveCollection, reactiveIndex, keys) => {
159
191
  const pks = useSelectPksByIndexKeys(reactiveIndex, keys) || EMPTY_ARRAY;
160
192
  return useSelectEntitiesByPks(reactiveCollection, unique(Array.from(pks)));
161
193
  };
@@ -189,11 +221,11 @@ export {
189
221
  OIMRICollectionsContext,
190
222
  OIMRICollectionsProvider,
191
223
  createOIMCollectionsContext,
192
- selectEntitiesByIndexKey,
193
- selectEntitiesByIndexKeys,
194
- selectEntityByPk,
195
224
  useOIMCollectionsContext,
225
+ useSelectEntitiesByIndexKey,
226
+ useSelectEntitiesByIndexKeys,
196
227
  useSelectEntitiesByPks,
228
+ useSelectEntityByPk,
197
229
  useSelectPksByIndexKey,
198
230
  useSelectPksByIndexKeys
199
231
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oimdb/react",
3
- "version": "1.0.8",
3
+ "version": "1.1.1",
4
4
  "description": "React integration for OIMDB - Hooks for selection and subscription with external storage",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -24,22 +24,28 @@
24
24
  },
25
25
  "scripts": {
26
26
  "build": "tsup src/index.ts --dts --format esm,cjs",
27
+ "test": "jest",
28
+ "type-check": "tsc --noEmit",
27
29
  "clean": "rimraf dist",
28
- "prepublishOnly": "npm run build"
30
+ "prepublishOnly": "npm run type-check && npm test && npm run build"
29
31
  },
30
32
  "files": [
31
33
  "dist"
32
34
  ],
33
35
  "peerDependencies": {
34
- "@oimdb/core": "^1.0.6",
36
+ "@oimdb/core": "^1.1.0",
35
37
  "react": "^18.0.0"
36
38
  },
37
39
  "devDependencies": {
38
- "tsup": "^8.5.0",
39
- "typescript": "^5.2.2",
40
- "rimraf": "^5.0.5",
40
+ "@types/jest": "^29.5.8",
41
+ "@types/react": "^18.0.0",
42
+ "jest": "^29.7.0",
43
+ "jest-environment-jsdom": "^29.7.0",
41
44
  "react": "^18.0.0",
42
- "@types/react": "^18.0.0"
45
+ "rimraf": "^5.0.5",
46
+ "ts-jest": "^29.1.1",
47
+ "tsup": "^8.5.0",
48
+ "typescript": "^5.2.2"
43
49
  },
44
50
  "author": "Andrei Baikov",
45
51
  "license": "MIT"