react-redux-cache 0.0.12 → 0.2.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 CHANGED
@@ -1,3 +1,11 @@
1
+ ### Donations 🙌
2
+
3
+ **BTC:** bc1qs0sq7agz5j30qnqz9m60xj4tt8th6aazgw7kxr \
4
+ **ETH:** 0x1D834755b5e889703930AC9b784CB625B3cd833E \
5
+ **USDT(Tron):** TPrCq8LxGykQ4as3o1oB8V7x1w2YPU2o5n \
6
+ **TON:** EQAtBuFWI3H_LpHfEToil4iYemtfmyzlaJpahM3tFSoxojvV \
7
+ **DOGE:** D7GMQdKhKC9ymbT9PtcetSFTQjyPRRfkwT
8
+
1
9
  # react-redux-cache
2
10
 
3
11
  **Powerful** yet **lightweight** data fetching and caching library that supports **normalization** unlike `react-query` and `rtk-query`, while having similar but very simple interface. Built on top of `redux`, fully typed and written on Typescript. Can be considered as `ApolloClient` for protocols other than `GraphQL`.
@@ -6,8 +14,6 @@
6
14
 
7
15
  Remains **full control** of redux state with ability to write custom selectors, actions and reducers to manage cached state.
8
16
 
9
- Usage example can be found in `example/` folder and run by `npm run example` command from the root folder.
10
-
11
17
  ### Table of contents
12
18
 
13
19
  - [Installation](https://github.com/gentlee/react-redux-cache#Installation)
@@ -21,7 +27,8 @@ Usage example can be found in `example/` folder and run by `npm run example` com
21
27
  - [Infinite scroll pagination](https://github.com/gentlee/react-redux-cache#infinite-scroll-pagination)
22
28
  - [redux-persist](https://github.com/gentlee/react-redux-cache#redux-persist)
23
29
  - [FAQ](https://github.com/gentlee/react-redux-cache#faq)
24
- - [What is cache key?](https://github.com/gentlee/react-redux-cache#what-is-cache-key)
30
+ - [What is a query cache key?](https://github.com/gentlee/react-redux-cache#what-is-a-query-cache-key)
31
+ - [How mutation fetching differs from queries?](https://github.com/gentlee/react-redux-cache#how-mutation-fetching-differs-from-queries)
25
32
 
26
33
  ### Installation
27
34
  `react`, `redux` and `react-redux` are peer dependencies.
@@ -29,21 +36,28 @@ Usage example can be found in `example/` folder and run by `npm run example` com
29
36
  npm add react-redux-cache react redux react-redux
30
37
  ```
31
38
  ### Initialization
32
- The only function that needs to be imported is `createCache`, which creates fully typed reducer, hooks, actions, selectors and utils to be used in the app.
39
+ The only function that needs to be imported is `createCache`, which creates fully typed reducer, hooks, actions, selectors and utils to be used in the app. You can create as many caches as needed, but keep in mind that normalization is not shared between them.
33
40
  All typenames, queries and mutations should be passed while initializing the cache for proper typing.
34
41
  #### cache.ts
35
42
  ```typescript
36
43
  export const {
44
+ cache,
37
45
  reducer,
38
46
  hooks: {useClient, useMutation, useQuery, useSelectEntityById},
39
47
  // Actions, selectors and utils may be not used at all
40
48
  selectors: {entitiesSelector, entitiesByTypenameSelector},
41
- actions: {setQueryStateAndEntities, setMutationStateAndEntities, mergeEntityChanges},
49
+ actions: {
50
+ updateQueryStateAndEntities,
51
+ updateMutationStateAndEntities,
52
+ mergeEntityChanges,
53
+ clearQueryState,
54
+ clearMutationState,
55
+ },
42
56
  utils: {applyEntityChanges},
43
57
  } = createCache({
44
- // This selector should return the cache state based on the path to its reducer.
45
- cacheStateSelector: (state) => state.cache,
46
- // Typenames provide a mapping of all typenames to their entity types, which is needed for normalization.
58
+ // Used as prefix for actions and in default cacheStateSelector for selecting cache state from redux state.
59
+ name: 'cache',
60
+ // Typenames provide a mapping of all typenames to their entity types, which is needed for proper typing and normalization.
47
61
  // Empty objects with type casting can be used as values.
48
62
  typenames: {
49
63
  users: {} as User, // here `users` entities will have type `User`
@@ -61,11 +75,12 @@ export const {
61
75
  ```
62
76
  #### store.ts
63
77
  ```typescript
64
- // Create store as usual, passing the new cache reducer
65
- // under the key, previously used in cacheStateSelector
78
+ // Create store as usual, passing the new cache reducer under the name of the cache.
79
+ // If some other redux structure is needed, provide custom cacheStateSelector when creating cache.
66
80
  const store = configureStore({
67
81
  reducer: {
68
- cache: reducer,
82
+ [cache.name]: reducer,
83
+ ...
69
84
  }
70
85
  })
71
86
  ```
@@ -111,6 +126,9 @@ export const removeUser = async (id: number) => {
111
126
  ```
112
127
 
113
128
  ### Usage
129
+
130
+ Please check `example/` folder (`npm run example` to run).
131
+
114
132
  #### UserScreen.tsx
115
133
  ```typescript
116
134
  export const UserScreen = () => {
@@ -271,7 +289,7 @@ const persistedReducer = persistReducer(
271
289
 
272
290
  ### FAQ
273
291
 
274
- #### What is cache key?
292
+ #### What is a query cache key?
275
293
 
276
294
  **Cache key** is used for storing the query state and for performing a fetch when it changes. Queries with the same cache key share their state.
277
295
 
@@ -293,3 +311,9 @@ export const defaultGetCacheKey = <P = unknown>(params: P): Key => {
293
311
  It is recommended to override it when default implementation is not optimal or when keys in params object can be sorted in random order.
294
312
 
295
313
  As example, can be overriden when implementing pagination.
314
+
315
+ #### How mutation fetching differs from queries?
316
+
317
+ **Queries:** For each cache key (= unique params by default) of each query fetch is running in parallel. If fetch is already running for specific cache key, all next fetches are cancelled until it finishes.
318
+
319
+ **Mutations:** Only one mutation can be run for each mutation key at a time. If another one called, previous is aborted.
@@ -0,0 +1,50 @@
1
+ import type { EntityChanges, Key, QueryMutationState, Typenames } from './types';
2
+ export type ActionMap<N extends string, T extends Typenames, QR, MR> = ReturnType<typeof createActions<N, T, QR, MR>>;
3
+ export declare const createActions: <N extends string, T extends Typenames, QR, MR>(name: N) => {
4
+ updateQueryStateAndEntities: {
5
+ <K extends keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<QueryMutationState<QR[K]>> | undefined, entityChagnes?: EntityChanges<T> | undefined): {
6
+ type: `@rrc/${N}/updateQueryStateAndEntities`;
7
+ queryKey: K;
8
+ queryCacheKey: Key;
9
+ state: Partial<QueryMutationState<QR[K]>> | undefined;
10
+ entityChagnes: EntityChanges<T> | undefined;
11
+ };
12
+ type: `@rrc/${N}/updateQueryStateAndEntities`;
13
+ };
14
+ updateMutationStateAndEntities: {
15
+ <K_1 extends keyof MR>(mutationKey: K_1, state?: Partial<QueryMutationState<MR[K_1]>> | undefined, entityChagnes?: EntityChanges<T> | undefined): {
16
+ type: `@rrc/${N}/updateMutationStateAndEntities`;
17
+ mutationKey: K_1;
18
+ state: Partial<QueryMutationState<MR[K_1]>> | undefined;
19
+ entityChagnes: EntityChanges<T> | undefined;
20
+ };
21
+ type: `@rrc/${N}/updateMutationStateAndEntities`;
22
+ };
23
+ mergeEntityChanges: {
24
+ (changes: EntityChanges<T>): {
25
+ type: `@rrc/${N}/mergeEntityChanges`;
26
+ changes: EntityChanges<T>;
27
+ };
28
+ type: `@rrc/${N}/mergeEntityChanges`;
29
+ };
30
+ clearQueryState: {
31
+ <K_2 extends keyof QR>(queryKeys: {
32
+ key: K_2;
33
+ cacheKey?: Key | undefined;
34
+ }[]): {
35
+ type: `@rrc/${N}/clearQueryState`;
36
+ queryKeys: {
37
+ key: K_2;
38
+ cacheKey?: Key | undefined;
39
+ }[];
40
+ };
41
+ type: `@rrc/${N}/clearQueryState`;
42
+ };
43
+ clearMutationState: {
44
+ <K_3 extends keyof MR>(mutationKeys: K_3[]): {
45
+ type: `@rrc/${N}/clearMutationState`;
46
+ mutationKeys: K_3[];
47
+ };
48
+ type: `@rrc/${N}/clearMutationState`;
49
+ };
50
+ };
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createActions = void 0;
4
+ const utilsAndConstants_1 = require("./utilsAndConstants");
5
+ const createActions = (name) => {
6
+ const actionPrefix = `@${utilsAndConstants_1.PACKAGE_SHORT_NAME}/${name}/`;
7
+ const updateQueryStateAndEntitiesType = `${actionPrefix}updateQueryStateAndEntities`;
8
+ /** Updates query state, and optionally merges entity changes in a single action. */
9
+ const updateQueryStateAndEntities = (queryKey, queryCacheKey, state, entityChagnes) => ({
10
+ type: updateQueryStateAndEntitiesType,
11
+ queryKey,
12
+ queryCacheKey,
13
+ state,
14
+ entityChagnes,
15
+ });
16
+ updateQueryStateAndEntities.type = updateQueryStateAndEntitiesType;
17
+ const updateMutationStateAndEntitiesType = `${actionPrefix}updateMutationStateAndEntities`;
18
+ /** Updates mutation state, and optionally merges entity changes in a single action. */
19
+ const updateMutationStateAndEntities = (mutationKey, state, entityChagnes) => ({
20
+ type: updateMutationStateAndEntitiesType,
21
+ mutationKey,
22
+ state,
23
+ entityChagnes,
24
+ });
25
+ updateMutationStateAndEntities.type = updateMutationStateAndEntitiesType;
26
+ const mergeEntityChangesType = `${actionPrefix}mergeEntityChanges`;
27
+ /** Merge EntityChanges to the state. */
28
+ const mergeEntityChanges = (changes) => ({
29
+ type: mergeEntityChangesType,
30
+ changes,
31
+ });
32
+ mergeEntityChanges.type = mergeEntityChangesType;
33
+ const clearQueryStateType = `${actionPrefix}clearQueryState`;
34
+ /** Clear states for provided query keys and cache keys.
35
+ * If cache key for query key is not provided, the whole state for query key is cleared. */
36
+ const clearQueryState = (queryKeys) => ({
37
+ type: clearQueryStateType,
38
+ queryKeys,
39
+ });
40
+ clearQueryState.type = clearQueryStateType;
41
+ const clearMutationStateType = `${actionPrefix}clearMutationState`;
42
+ /** Clear states for provided mutation keys. */
43
+ const clearMutationState = (mutationKeys) => ({
44
+ type: clearMutationStateType,
45
+ mutationKeys,
46
+ });
47
+ clearMutationState.type = clearMutationStateType;
48
+ return {
49
+ updateQueryStateAndEntities,
50
+ updateMutationStateAndEntities,
51
+ mergeEntityChanges,
52
+ clearQueryState,
53
+ clearMutationState,
54
+ };
55
+ };
56
+ exports.createActions = createActions;
@@ -1,80 +1,116 @@
1
- import { mergeEntityChanges, setMutationStateAndEntities, setQueryStateAndEntities } from './reducer';
2
- import { Cache, EntitiesMap, Key, MutationResult, OptionalPartial, QueryOptions, QueryResult, Typenames } from './types';
1
+ import type { Cache, EntitiesMap, Key, MutationResult, OptionalPartial, QueryOptions, QueryResult, Typenames } from './types';
3
2
  import { useMutation } from './useMutation';
4
3
  import { useQuery } from './useQuery';
5
4
  import { applyEntityChanges } from './utilsAndConstants';
6
5
  /**
7
6
  * Creates reducer, actions and hooks for managing queries and mutations through redux cache.
8
7
  */
9
- export declare const createCache: <T extends Typenames, QP, QR, MP, MR>(cache: OptionalPartial<Cache<T, QP, QR, MP, MR>, "queries" | "mutations" | "options">) => {
10
- cache: Cache<T, QP, QR, MP, MR>;
8
+ export declare const createCache: <N extends string, T extends Typenames, QP, QR, MP, MR>(partialCache: OptionalPartial<Cache<N, T, QP, QR, MP, MR>, "options" | "queries" | "mutations" | "cacheStateSelector">) => {
9
+ cache: Cache<N, T, QP, QR, MP, MR>;
11
10
  /** Reducer of the cache, should be added to redux store. */
12
11
  reducer: (state: {
13
12
  entities: EntitiesMap<T>;
14
13
  queries: { [QK in keyof QR]: import("./types").Dict<import("./types").QueryMutationState<QR[QK]>>; };
15
14
  mutations: { [MK in keyof MR]: import("./types").QueryMutationState<MR[MK]>; };
16
15
  } | undefined, action: {
17
- type: `${string}MERGE_ENTITY_CHANGES`;
18
- changes: import("./types").EntityChanges<T>;
19
- } | {
20
- type: `${string}SET_QUERY_STATE_AND_ENTITIES`;
16
+ type: `@rrc/${N}/updateQueryStateAndEntities`;
21
17
  queryKey: keyof QR;
22
18
  queryCacheKey: Key;
23
19
  state: Partial<import("./types").QueryMutationState<QR[keyof QR]>> | undefined;
24
20
  entityChagnes: import("./types").EntityChanges<T> | undefined;
25
21
  } | {
26
- type: `${string}SET_MUTATION_STATE_AND_ENTITIES`;
22
+ type: `@rrc/${N}/updateMutationStateAndEntities`;
27
23
  mutationKey: keyof MR;
28
24
  state: Partial<import("./types").QueryMutationState<MR[keyof MR]>> | undefined;
29
25
  entityChagnes: import("./types").EntityChanges<T> | undefined;
26
+ } | {
27
+ type: `@rrc/${N}/mergeEntityChanges`;
28
+ changes: import("./types").EntityChanges<T>;
29
+ } | {
30
+ type: `@rrc/${N}/clearQueryState`;
31
+ queryKeys: {
32
+ key: keyof QR;
33
+ cacheKey?: Key | undefined;
34
+ }[];
35
+ } | {
36
+ type: `@rrc/${N}/clearMutationState`;
37
+ mutationKeys: (keyof MR)[]; /** Select all entities of provided typename. */
30
38
  }) => {
31
39
  entities: EntitiesMap<T>;
32
40
  queries: { [QK in keyof QR]: import("./types").Dict<import("./types").QueryMutationState<QR[QK]>>; };
33
41
  mutations: { [MK in keyof MR]: import("./types").QueryMutationState<MR[MK]>; };
34
42
  };
35
43
  actions: {
36
- /** Updates query state, and optionally merges entity changes in a single action. */
37
- setQueryStateAndEntities: <K extends keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<import("./types").QueryMutationState<QR[K]>> | undefined, entityChagnes?: import("./types").EntityChanges<T> | undefined) => {
38
- type: `${string}SET_QUERY_STATE_AND_ENTITIES`;
39
- queryKey: K;
40
- queryCacheKey: Key;
41
- state: Partial<import("./types").QueryMutationState<QR[K]>> | undefined;
42
- entityChagnes: import("./types").EntityChanges<T> | undefined;
44
+ updateQueryStateAndEntities: {
45
+ <K extends keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<import("./types").QueryMutationState<QR[K]>> | undefined, entityChagnes?: import("./types").EntityChanges<T> | undefined): {
46
+ type: `@rrc/${N}/updateQueryStateAndEntities`;
47
+ queryKey: K;
48
+ queryCacheKey: Key;
49
+ state: Partial<import("./types").QueryMutationState<QR[K]>> | undefined;
50
+ entityChagnes: import("./types").EntityChanges<T> | undefined;
51
+ };
52
+ type: `@rrc/${N}/updateQueryStateAndEntities`;
53
+ };
54
+ updateMutationStateAndEntities: {
55
+ <K_1 extends keyof MR>(mutationKey: K_1, state?: Partial<import("./types").QueryMutationState<MR[K_1]>> | undefined, entityChagnes?: import("./types").EntityChanges<T> | undefined): {
56
+ type: `@rrc/${N}/updateMutationStateAndEntities`;
57
+ mutationKey: K_1;
58
+ state: Partial<import("./types").QueryMutationState<MR[K_1]>> | undefined;
59
+ entityChagnes: import("./types").EntityChanges<T> | undefined;
60
+ };
61
+ type: `@rrc/${N}/updateMutationStateAndEntities`;
62
+ };
63
+ mergeEntityChanges: {
64
+ (changes: import("./types").EntityChanges<T>): {
65
+ type: `@rrc/${N}/mergeEntityChanges`;
66
+ changes: import("./types").EntityChanges<T>;
67
+ };
68
+ type: `@rrc/${N}/mergeEntityChanges`;
43
69
  };
44
- /** Updates mutation state, and optionally merges entity changes in a single action. */
45
- setMutationStateAndEntities: <K_1 extends keyof MR>(mutationKey: K_1, state?: Partial<import("./types").QueryMutationState<MR[K_1]>> | undefined, entityChagnes?: import("./types").EntityChanges<T> | undefined) => {
46
- type: `${string}SET_MUTATION_STATE_AND_ENTITIES`;
47
- mutationKey: K_1;
48
- state: Partial<import("./types").QueryMutationState<MR[K_1]>> | undefined;
49
- entityChagnes: import("./types").EntityChanges<T> | undefined;
70
+ clearQueryState: {
71
+ <K_2 extends keyof QR>(queryKeys: {
72
+ key: K_2;
73
+ cacheKey?: Key | undefined;
74
+ }[]): {
75
+ type: `@rrc/${N}/clearQueryState`;
76
+ queryKeys: {
77
+ key: K_2;
78
+ cacheKey?: Key | undefined;
79
+ }[];
80
+ };
81
+ type: `@rrc/${N}/clearQueryState`;
50
82
  };
51
- /** Merge EntityChanges to the state. */
52
- mergeEntityChanges: (changes: import("./types").EntityChanges<T>) => {
53
- type: `${string}MERGE_ENTITY_CHANGES`;
54
- changes: import("./types").EntityChanges<T>;
83
+ clearMutationState: {
84
+ <K_3 extends keyof MR>(mutationKeys: K_3[]): {
85
+ type: `@rrc/${N}/clearMutationState`;
86
+ mutationKeys: K_3[]; /** Select all entities of provided typename. */
87
+ };
88
+ type: `@rrc/${N}/clearMutationState`;
55
89
  };
56
90
  };
57
91
  selectors: {
92
+ /** Select all entities from the state. */
58
93
  entitiesSelector: (state: unknown) => EntitiesMap<T>;
59
- entitiesByTypenameSelector: <TN extends keyof T>(typename: TN) => { [K_2 in keyof T]: (state: unknown) => EntitiesMap<T>[K_2]; }[TN];
94
+ /** Select all entities of provided typename. */
95
+ entitiesByTypenameSelector: <TN extends keyof T>(typename: TN) => { [K_4 in keyof T]: (state: unknown) => EntitiesMap<T>[K_4]; }[TN];
60
96
  };
61
97
  hooks: {
62
98
  /** Returns client object with query function */
63
99
  useClient: () => {
64
- query: <QK_1 extends keyof QP | keyof QR>(options: QueryOptions<T, QP, QR, MP, MR, QK_1>) => Promise<QueryResult<QK_1 extends keyof QP & keyof QR ? QR[QK_1] : never>>;
100
+ query: <QK_1 extends keyof QR | keyof QP>(options: QueryOptions<T, QP, QR, MR, QK_1>) => Promise<QueryResult<QK_1 extends keyof QP & keyof QR ? QR[QK_1] : never>>;
65
101
  mutate: <MK_1 extends keyof MP | keyof MR>(options: {
66
102
  mutation: MK_1;
67
103
  params: MK_1 extends keyof MP & keyof MR ? MP[MK_1] : never;
68
104
  }) => Promise<MutationResult<MK_1 extends keyof MP & keyof MR ? MR[MK_1] : never>>;
69
105
  };
70
106
  /** Fetches query when params change and subscribes to query state. */
71
- useQuery: <QK_2 extends keyof QP | keyof QR>(options: import("./types").UseQueryOptions<T, QP, QR, MP, MR, QK_2>) => readonly [import("./types").QueryMutationState<QK_2 extends keyof QP & keyof QR ? QR[QK_2] : never>, () => Promise<void>];
107
+ useQuery: <QK_2 extends keyof QR | keyof QP>(options: import("./types").UseQueryOptions<T, QP, QR, MR, QK_2>) => readonly [import("./types").QueryMutationState<QK_2 extends keyof QP & keyof QR ? QR[QK_2] : never>, () => Promise<void>];
72
108
  /** Subscribes to provided mutation state and provides mutate function. */
73
109
  useMutation: <MK_2 extends keyof MP | keyof MR>(options: {
74
110
  mutation: MK_2;
75
111
  }) => readonly [(params: MK_2 extends keyof MP & keyof MR ? MP[MK_2] : never) => Promise<void>, import("./types").QueryMutationState<MK_2 extends keyof MP & keyof MR ? MP[MK_2] : never>, () => boolean];
76
112
  /** Selects entity by id and subscribes to the changes. */
77
- useSelectEntityById: <K_3 extends keyof T>(id: Key | null | undefined, typename: K_3) => T[K_3] | undefined;
113
+ useSelectEntityById: <TN_1 extends keyof T>(id: Key | null | undefined, typename: TN_1) => T[TN_1] | undefined;
78
114
  };
79
115
  utils: {
80
116
  applyEntityChanges: (entities: EntitiesMap<T>, changes: import("./types").EntityChanges<T>) => EntitiesMap<T> | undefined;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createCache = void 0;
4
4
  const react_1 = require("react");
5
5
  const react_redux_1 = require("react-redux");
6
+ const createActions_1 = require("./createActions");
6
7
  const mutate_1 = require("./mutate");
7
8
  const query_1 = require("./query");
8
9
  const reducer_1 = require("./reducer");
@@ -12,41 +13,39 @@ const utilsAndConstants_1 = require("./utilsAndConstants");
12
13
  /**
13
14
  * Creates reducer, actions and hooks for managing queries and mutations through redux cache.
14
15
  */
15
- const createCache = (cache) => {
16
- var _a, _b, _c, _d, _e;
17
- var _f, _g;
16
+ const createCache = (partialCache) => {
17
+ var _a, _b, _c, _d, _e, _f;
18
+ var _g, _h;
18
19
  const abortControllers = new WeakMap();
19
20
  // provide all optional fields
20
- (_a = cache.options) !== null && _a !== void 0 ? _a : (cache.options = {});
21
- (_b = (_f = cache.options).logsEnabled) !== null && _b !== void 0 ? _b : (_f.logsEnabled = false);
22
- (_c = (_g = cache.options).validateFunctionArguments) !== null && _c !== void 0 ? _c : (_g.validateFunctionArguments = utilsAndConstants_1.isDev);
23
- (_d = cache.queries) !== null && _d !== void 0 ? _d : (cache.queries = {});
24
- (_e = cache.mutations) !== null && _e !== void 0 ? _e : (cache.mutations = {});
25
- // @ts-expect-error for testing
26
- cache.abortControllers = abortControllers;
27
- const nonPartialCache = cache;
21
+ (_a = partialCache.options) !== null && _a !== void 0 ? _a : (partialCache.options = {});
22
+ (_b = (_g = partialCache.options).logsEnabled) !== null && _b !== void 0 ? _b : (_g.logsEnabled = false);
23
+ (_c = (_h = partialCache.options).validateFunctionArguments) !== null && _c !== void 0 ? _c : (_h.validateFunctionArguments = utilsAndConstants_1.IS_DEV);
24
+ (_d = partialCache.queries) !== null && _d !== void 0 ? _d : (partialCache.queries = {});
25
+ (_e = partialCache.mutations) !== null && _e !== void 0 ? _e : (partialCache.mutations = {});
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ (_f = partialCache.cacheStateSelector) !== null && _f !== void 0 ? _f : (partialCache.cacheStateSelector = (state) => state[cache.name]);
28
+ // @ts-expect-error private field for testing
29
+ partialCache.abortControllers = abortControllers;
30
+ const cache = partialCache;
28
31
  // make selectors
29
32
  const entitiesSelector = (state) => {
30
- return nonPartialCache.cacheStateSelector(state).entities;
33
+ return cache.cacheStateSelector(state).entities;
31
34
  };
32
- const enitityMapSelectorByTypename = Object.keys(cache.typenames).reduce((result, x) => {
33
- result[x] = (state) => nonPartialCache.cacheStateSelector(state).entities[x];
35
+ const enitityMapSelectorByTypename = Object.keys(partialCache.typenames).reduce((result, x) => {
36
+ result[x] = (state) => cache.cacheStateSelector(state).entities[x];
34
37
  return result;
35
38
  }, {});
39
+ const actions = (0, createActions_1.createActions)(cache.name);
36
40
  return {
37
- cache: nonPartialCache,
41
+ cache,
38
42
  /** Reducer of the cache, should be added to redux store. */
39
- reducer: (0, reducer_1.createCacheReducer)(nonPartialCache.typenames, nonPartialCache.queries, nonPartialCache.mutations, nonPartialCache.options),
40
- actions: {
41
- /** Updates query state, and optionally merges entity changes in a single action. */
42
- setQueryStateAndEntities: reducer_1.setQueryStateAndEntities,
43
- /** Updates mutation state, and optionally merges entity changes in a single action. */
44
- setMutationStateAndEntities: reducer_1.setMutationStateAndEntities,
45
- /** Merge EntityChanges to the state. */
46
- mergeEntityChanges: reducer_1.mergeEntityChanges,
47
- },
43
+ reducer: (0, reducer_1.createCacheReducer)(actions, cache.typenames, Object.keys(cache.queries), cache.options),
44
+ actions,
48
45
  selectors: {
46
+ /** Select all entities from the state. */
49
47
  entitiesSelector,
48
+ /** Select all entities of provided typename. */
50
49
  entitiesByTypenameSelector: (typename) => {
51
50
  return enitityMapSelectorByTypename[typename];
52
51
  },
@@ -60,30 +59,32 @@ const createCache = (cache) => {
60
59
  query: (options) => {
61
60
  var _a;
62
61
  const { query: queryKey, params } = options;
63
- const getCacheKey = (_a = nonPartialCache.queries[queryKey].getCacheKey) !== null && _a !== void 0 ? _a : (utilsAndConstants_1.defaultGetCacheKey);
62
+ const getCacheKey = (_a = cache.queries[queryKey].getCacheKey) !== null && _a !== void 0 ? _a : (utilsAndConstants_1.defaultGetCacheKey);
64
63
  // @ts-expect-error fix later
65
64
  const cacheKey = getCacheKey(params);
66
- return (0, query_1.query)('query', true, store, nonPartialCache, queryKey, cacheKey, params);
65
+ return (0, query_1.query)('query', true, store, cache, actions, queryKey, cacheKey, params);
67
66
  },
68
67
  mutate: (options) => {
69
- return (0, mutate_1.mutate)('mutate', true, store, nonPartialCache, options.mutation, options.params, abortControllers);
68
+ return (0, mutate_1.mutate)('mutate', true, store, cache, actions, options.mutation, options.params, abortControllers);
70
69
  },
71
70
  };
72
71
  return client;
73
72
  }, [store]);
74
73
  },
75
74
  /** Fetches query when params change and subscribes to query state. */
76
- useQuery: (options) => (0, useQuery_1.useQuery)(nonPartialCache, options),
75
+ useQuery: (options) => (0, useQuery_1.useQuery)(cache, actions, options),
77
76
  /** Subscribes to provided mutation state and provides mutate function. */
78
- useMutation: (options) => (0, useMutation_1.useMutation)(nonPartialCache, options, abortControllers),
77
+ useMutation: (options) => (0, useMutation_1.useMutation)(cache, actions, options, abortControllers),
79
78
  /** Selects entity by id and subscribes to the changes. */
80
79
  useSelectEntityById: (id, typename) => {
81
- return (0, react_redux_1.useSelector)((state) => id == null ? undefined : nonPartialCache.cacheStateSelector(state).entities[typename][id]);
80
+ return (0, react_redux_1.useSelector)((state) =>
81
+ // TODO move to selectors?
82
+ id == null ? undefined : cache.cacheStateSelector(state).entities[typename][id]);
82
83
  },
83
84
  },
84
85
  utils: {
85
86
  applyEntityChanges: (entities, changes) => {
86
- return (0, utilsAndConstants_1.applyEntityChanges)(entities, changes, nonPartialCache.options);
87
+ return (0, utilsAndConstants_1.applyEntityChanges)(entities, changes, cache.options);
87
88
  },
88
89
  },
89
90
  };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { createCache } from './createCache';
2
2
  export type { ReduxCacheState } from './reducer';
3
3
  export * from './types';
4
- export { defaultGetCacheKey, defaultQueryMutationState } from './utilsAndConstants';
4
+ export { defaultGetCacheKey, DEFAULT_QUERY_MUTATION_STATE as defaultQueryMutationState, } from './utilsAndConstants';
package/dist/index.js CHANGED
@@ -20,45 +20,38 @@ Object.defineProperty(exports, "createCache", { enumerable: true, get: function
20
20
  __exportStar(require("./types"), exports);
21
21
  var utilsAndConstants_1 = require("./utilsAndConstants");
22
22
  Object.defineProperty(exports, "defaultGetCacheKey", { enumerable: true, get: function () { return utilsAndConstants_1.defaultGetCacheKey; } });
23
- Object.defineProperty(exports, "defaultQueryMutationState", { enumerable: true, get: function () { return utilsAndConstants_1.defaultQueryMutationState; } });
23
+ Object.defineProperty(exports, "defaultQueryMutationState", { enumerable: true, get: function () { return utilsAndConstants_1.DEFAULT_QUERY_MUTATION_STATE; } });
24
24
  // Backlog
25
25
  // ! high
26
+ // screenshot of redux state to README
27
+ // optimistic response
26
28
  // cover with tests
29
+ // try use skip for refreshing strategy?
30
+ // add example without normalization
31
+ // make query key / cache key difference more clear in the docs
32
+ // support multiple caches = reducers
27
33
  // ! medium
28
- // allow multiple mutation with sam keys?
34
+ // make named caches to produce named hooks, actions etc (same as slices in RTK)?
35
+ // allow multiple mutation with same keys?
29
36
  // type extractors from cache
30
37
  // custom useStore
31
38
  // return back deserialize selector?
32
- // resultSelector - return also boolean that result is full enough
39
+ // resultSelector - return also boolean that result is full enough or make cache policy as a function
33
40
  // selector for entities by typename
34
- // provide call query/mutation function to call them without hooks, but with all state updates
35
- // get typenames from schema? (useSelectDenormalized)
36
41
  // callback option on error / success?
37
- // cache policy as function? needsRefetch
38
- // add verbose debug logs
39
- // refetch queries on query / mutation success?
40
- // remove state when it finished without errors
41
- // set default options like getParams
42
- // selectors for loading state of similar query or mutation (wihout using params as key)
42
+ // refetch queries on mutation success
43
+ // remove query/mutation state when it finished without errors
43
44
  // deep equal entities while merging state
44
- // support multiple stores
45
- // add validation if entity is full enough
46
- // optimistic response
47
45
  // make error type generic
48
- // proper types, remove as, any, todo
46
+ // don't cache result if resultSelector set? throw error if mergeResult set with resultSelector?
49
47
  // ! low
50
- // make types readonly
51
- // support changing query key?
52
- // remove defaultState and keep values undefined?
53
48
  // add params to the state?
54
49
  // cancellation to queries
55
50
  // if mutation & query alrady loading - make options: last, throttle, debounce, parallel?
56
51
  // add time-to-live option, and/or time-to-refresh
57
- // add getUpdateTime option to check entities while merging
58
- // useLocalMutation - uses local component state, or make store option - redux or component state or context? 1 version: redux only
52
+ // add refresh interval for queries that are mounted
59
53
  // replace try/catch with returned error
60
54
  // support any store, not only redux
61
- // QueryInfo.defaultOptions
62
- // set options in refresh/mutate functions
63
- // multiple reducers instead of 1?
64
- // don't cache result if resultSelector set? throw error if mergeResult set with resultSelector?
55
+ // readonly types?
56
+ // proper types, remove as, any, todo
57
+ // add number of retries param?
package/dist/mutate.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { Store } from 'redux';
2
- import { Cache, Key, MutationResult, Typenames } from './types';
3
- export declare const mutate: <T extends Typenames, QP, QR, MP, MR, MK extends keyof MP | keyof MR>(logTag: string, returnResult: boolean, store: Store, cache: Cache<T, QP, QR, MP, MR>, mutationKey: MK, params: MK extends keyof MP & keyof MR ? MP[MK] : never, abortControllers: WeakMap<Store, Record<Key, AbortController>>) => Promise<void | MutationResult<MK extends keyof MP & keyof MR ? MR[MK] : never>>;
2
+ import type { ActionMap } from './createActions';
3
+ import type { Cache, Key, MutationResult, Typenames } from './types';
4
+ export declare const mutate: <N extends string, T extends Typenames, QP, QR, MP, MR, MK extends keyof MP | keyof MR>(logTag: string, returnResult: boolean, store: Store, cache: Cache<N, T, QP, QR, MP, MR>, { updateMutationStateAndEntities }: Pick<ActionMap<N, T, QR, MR>, "updateMutationStateAndEntities">, mutationKey: MK, params: MK extends keyof MP & keyof MR ? MP[MK] : never, abortControllers: WeakMap<Store, Record<Key, AbortController>>) => Promise<void | MutationResult<MK extends keyof MP & keyof MR ? MR[MK] : never>>;
package/dist/mutate.js CHANGED
@@ -10,9 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.mutate = void 0;
13
- const reducer_1 = require("./reducer");
14
13
  const utilsAndConstants_1 = require("./utilsAndConstants");
15
- const mutate = (logTag, returnResult, store, cache, mutationKey, params, abortControllers) => __awaiter(void 0, void 0, void 0, function* () {
14
+ const mutate = (logTag, returnResult, store, cache, { updateMutationStateAndEntities }, mutationKey, params, abortControllers) => __awaiter(void 0, void 0, void 0, function* () {
16
15
  let abortControllersOfStore = abortControllers.get(store);
17
16
  if (abortControllersOfStore === undefined) {
18
17
  abortControllersOfStore = {};
@@ -30,7 +29,7 @@ const mutate = (logTag, returnResult, store, cache, mutationKey, params, abortCo
30
29
  abortController.abort();
31
30
  }
32
31
  else {
33
- store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
32
+ store.dispatch(updateMutationStateAndEntities(mutationKey, {
34
33
  loading: true,
35
34
  result: undefined,
36
35
  }));
@@ -60,14 +59,14 @@ const mutate = (logTag, returnResult, store, cache, mutationKey, params, abortCo
60
59
  }
61
60
  delete abortControllersOfStore[mutationKey];
62
61
  if (error) {
63
- store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
62
+ store.dispatch(updateMutationStateAndEntities(mutationKey, {
64
63
  error: error,
65
64
  loading: false,
66
65
  }));
67
66
  return { error };
68
67
  }
69
68
  if (response) {
70
- store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
69
+ store.dispatch(updateMutationStateAndEntities(mutationKey, {
71
70
  error: undefined,
72
71
  loading: false,
73
72
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
package/dist/query.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { Store } from 'redux';
2
- import { Cache, Key, QueryResult, Typenames } from './types';
3
- export declare const query: <T extends Typenames, QP, QR, MP, MR, QK extends keyof QP | keyof QR>(logTag: string, returnResult: boolean, store: Store, cache: Cache<T, QP, QR, MP, MR>, queryKey: QK, cacheKey: Key, params: QK extends keyof QP & keyof QR ? QP[QK] : never) => Promise<void | QueryResult<QK extends keyof QP & keyof QR ? QR[QK] : never>>;
2
+ import type { ActionMap } from './createActions';
3
+ import type { Cache, Key, QueryResult, Typenames } from './types';
4
+ export declare const query: <N extends string, T extends Typenames, QP, QR, MP, MR, QK extends keyof QP | keyof QR>(logTag: string, returnResult: boolean, store: Store, cache: Cache<N, T, QP, QR, MP, MR>, { updateQueryStateAndEntities }: Pick<ActionMap<N, T, QR, MR>, "updateQueryStateAndEntities">, queryKey: QK, cacheKey: Key, params: QK extends keyof QP & keyof QR ? QP[QK] : never) => Promise<void | QueryResult<QK extends keyof QP & keyof QR ? QR[QK] : never>>;
package/dist/query.js CHANGED
@@ -10,9 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.query = void 0;
13
- const reducer_1 = require("./reducer");
14
13
  const utilsAndConstants_1 = require("./utilsAndConstants");
15
- const query = (logTag, returnResult, store, cache, queryKey, cacheKey, params) => __awaiter(void 0, void 0, void 0, function* () {
14
+ const query = (logTag, returnResult, store, cache, { updateQueryStateAndEntities }, queryKey, cacheKey, params) => __awaiter(void 0, void 0, void 0, function* () {
16
15
  var _a;
17
16
  const logsEnabled = cache.options.logsEnabled;
18
17
  const cacheStateSelector = cache.cacheStateSelector;
@@ -28,7 +27,7 @@ const query = (logTag, returnResult, store, cache, queryKey, cacheKey, params) =
28
27
  });
29
28
  return returnResult ? { cancelled: true } : undefined;
30
29
  }
31
- store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, {
30
+ store.dispatch(updateQueryStateAndEntities(queryKey, cacheKey, {
32
31
  loading: true,
33
32
  }));
34
33
  logsEnabled && (0, utilsAndConstants_1.log)(`${logTag} started`, { queryStateOnStart, params, cacheKey });
@@ -40,7 +39,7 @@ const query = (logTag, returnResult, store, cache, queryKey, cacheKey, params) =
40
39
  params);
41
40
  }
42
41
  catch (error) {
43
- store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, {
42
+ store.dispatch(updateQueryStateAndEntities(queryKey, cacheKey, {
44
43
  error: error,
45
44
  loading: false,
46
45
  }));
@@ -57,7 +56,7 @@ const query = (logTag, returnResult, store, cache, queryKey, cacheKey, params) =
57
56
  (_a = cacheStateSelector(store.getState()).queries[queryKey][cacheKey]) === null || _a === void 0 ? void 0 : _a.result, response, params)
58
57
  : response.result,
59
58
  };
60
- store.dispatch((0, reducer_1.setQueryStateAndEntities)(queryKey, cacheKey, newState, response));
59
+ store.dispatch(updateQueryStateAndEntities(queryKey, cacheKey, newState, response));
61
60
  // @ts-expect-error fix types
62
61
  return returnResult
63
62
  ? {
package/dist/reducer.d.ts CHANGED
@@ -1,46 +1,35 @@
1
- import { Cache, Dict, EntitiesMap, EntityChanges, Key, QueryMutationState, Typenames } from './types';
2
- export type ReduxCacheState<T extends Typenames, QP, QR, MP, MR> = ReturnType<ReturnType<typeof createCacheReducer<T, QP, QR, MP, MR>>>;
3
- export declare const createCacheReducer: <T extends Typenames, QP, QR, MP, MR>(typenames: T, queries: QP & QR extends infer T_1 ? { [QK in keyof T_1]: QK extends keyof QP & keyof QR ? import("./types").QueryInfo<T, QP[QK], QR[QK], {
1
+ import type { ActionMap } from './createActions';
2
+ import type { CacheOptions, Dict, EntitiesMap, QueryMutationState, Typenames } from './types';
3
+ export type ReduxCacheState<T extends Typenames, QR, MR> = ReturnType<ReturnType<typeof createCacheReducer<string, T, QR, MR>>>;
4
+ export declare const createCacheReducer: <N extends string, T extends Typenames, QR, MR>(actions: ActionMap<N, T, QR, MR>, typenames: T, queryKeys: (keyof QR)[], cacheOptions: CacheOptions) => (state: {
4
5
  entities: EntitiesMap<T>;
5
- queries: { [QK_1 in keyof QR]: Dict<QueryMutationState<QR[QK_1]>>; };
6
- mutations: { [MK in keyof MR]: QueryMutationState<MR[MK]>; };
7
- }> : never; } : never, mutations: MP & MR extends infer T_2 ? { [MK_1 in keyof T_2]: MK_1 extends keyof MP & keyof MR ? import("./types").MutationInfo<T, MP[MK_1], MR[MK_1]> : never; } : never, cacheOptions: import("./types").CacheOptions) => (state: {
8
- entities: EntitiesMap<T>;
9
- queries: { [QK_1 in keyof QR]: Dict<QueryMutationState<QR[QK_1]>>; };
6
+ queries: { [QK in keyof QR]: Dict<QueryMutationState<QR[QK]>>; };
10
7
  mutations: { [MK in keyof MR]: QueryMutationState<MR[MK]>; };
11
8
  } | undefined, action: {
12
- type: `${string}SET_QUERY_STATE_AND_ENTITIES`;
9
+ type: `@rrc/${N}/updateQueryStateAndEntities`;
13
10
  queryKey: keyof QR;
14
- queryCacheKey: Key;
11
+ queryCacheKey: import("./types").Key;
15
12
  state: Partial<QueryMutationState<QR[keyof QR]>> | undefined;
16
- entityChagnes: EntityChanges<T> | undefined;
13
+ entityChagnes: import("./types").EntityChanges<T> | undefined;
17
14
  } | {
18
- type: `${string}SET_MUTATION_STATE_AND_ENTITIES`;
15
+ type: `@rrc/${N}/updateMutationStateAndEntities`;
19
16
  mutationKey: keyof MR;
20
17
  state: Partial<QueryMutationState<MR[keyof MR]>> | undefined;
21
- entityChagnes: EntityChanges<T> | undefined;
18
+ entityChagnes: import("./types").EntityChanges<T> | undefined;
19
+ } | {
20
+ type: `@rrc/${N}/mergeEntityChanges`;
21
+ changes: import("./types").EntityChanges<T>;
22
+ } | {
23
+ type: `@rrc/${N}/clearQueryState`;
24
+ queryKeys: {
25
+ key: keyof QR;
26
+ cacheKey?: import("./types").Key | undefined;
27
+ }[];
22
28
  } | {
23
- type: `${string}MERGE_ENTITY_CHANGES`;
24
- changes: EntityChanges<T>;
29
+ type: `@rrc/${N}/clearMutationState`;
30
+ mutationKeys: (keyof MR)[];
25
31
  }) => {
26
32
  entities: EntitiesMap<T>;
27
- queries: { [QK_1 in keyof QR]: Dict<QueryMutationState<QR[QK_1]>>; };
33
+ queries: { [QK in keyof QR]: Dict<QueryMutationState<QR[QK]>>; };
28
34
  mutations: { [MK in keyof MR]: QueryMutationState<MR[MK]>; };
29
35
  };
30
- export declare const setQueryStateAndEntities: <T extends Typenames, QR, K extends keyof QR>(queryKey: K, queryCacheKey: Key, state?: Partial<QueryMutationState<QR[K]>> | undefined, entityChagnes?: EntityChanges<T> | undefined) => {
31
- type: `${string}SET_QUERY_STATE_AND_ENTITIES`;
32
- queryKey: K;
33
- queryCacheKey: Key;
34
- state: Partial<QueryMutationState<QR[K]>> | undefined;
35
- entityChagnes: EntityChanges<T> | undefined;
36
- };
37
- export declare const setMutationStateAndEntities: <T extends Typenames, MR, K extends keyof MR>(mutationKey: K, state?: Partial<QueryMutationState<MR[K]>> | undefined, entityChagnes?: EntityChanges<T> | undefined) => {
38
- type: `${string}SET_MUTATION_STATE_AND_ENTITIES`;
39
- mutationKey: K;
40
- state: Partial<QueryMutationState<MR[K]>> | undefined;
41
- entityChagnes: EntityChanges<T> | undefined;
42
- };
43
- export declare const mergeEntityChanges: <T extends Typenames>(changes: EntityChanges<T>) => {
44
- type: `${string}MERGE_ENTITY_CHANGES`;
45
- changes: EntityChanges<T>;
46
- };
package/dist/reducer.js CHANGED
@@ -1,75 +1,96 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mergeEntityChanges = exports.setMutationStateAndEntities = exports.setQueryStateAndEntities = exports.createCacheReducer = void 0;
3
+ exports.createCacheReducer = void 0;
4
4
  const utilsAndConstants_1 = require("./utilsAndConstants");
5
- const createCacheReducer = (typenames, queries, mutations, cacheOptions) => {
5
+ const EMPTY_QUERY_STATE = Object.freeze({});
6
+ const createCacheReducer = (actions, typenames, queryKeys, cacheOptions) => {
6
7
  const entitiesMap = {};
7
8
  for (const key in typenames) {
8
- entitiesMap[key] = {};
9
+ entitiesMap[key] = EMPTY_QUERY_STATE;
9
10
  }
10
- const queriesMap = {};
11
- for (const key in queries) {
12
- queriesMap[key] = {};
11
+ const queryStateMap = {};
12
+ for (const key of queryKeys) {
13
+ queryStateMap[key] = {};
13
14
  }
14
- const mutationsMap = {};
15
+ const mutationStateMap = {};
15
16
  const initialState = {
16
17
  entities: entitiesMap,
17
- queries: queriesMap,
18
- mutations: mutationsMap,
18
+ queries: queryStateMap,
19
+ mutations: mutationStateMap,
19
20
  };
20
21
  cacheOptions.logsEnabled &&
21
22
  (0, utilsAndConstants_1.log)('createCacheReducer', {
22
23
  typenames,
23
- queries,
24
- mutations,
24
+ queryKeys,
25
25
  initialState,
26
26
  });
27
27
  return (state = initialState, action) => {
28
+ var _a, _b;
28
29
  switch (action.type) {
29
- case '@RRC/SET_QUERY_STATE_AND_ENTITIES': {
30
- const { queryKey, queryCacheKey, state: queryState, entityChagnes } = action;
30
+ case actions.updateQueryStateAndEntities.type: {
31
+ const { queryKey, queryCacheKey, state: queryState, entityChagnes, } = action;
31
32
  const newEntities = entityChagnes && (0, utilsAndConstants_1.applyEntityChanges)(state.entities, entityChagnes, cacheOptions);
32
33
  if (!queryState && !newEntities) {
33
34
  return state;
34
35
  }
35
- return Object.assign(Object.assign(Object.assign({}, state), (newEntities ? { entities: newEntities } : null)), { queries: Object.assign(Object.assign({}, state.queries), { [queryKey]: Object.assign(Object.assign({}, state.queries[queryKey]), { [queryCacheKey]: Object.assign(Object.assign({}, state.queries[queryKey][queryCacheKey]), queryState) }) }) });
36
+ return Object.assign(Object.assign(Object.assign({}, state), (newEntities ? { entities: newEntities } : null)), { queries: Object.assign(Object.assign({}, state.queries), { [queryKey]: Object.assign(Object.assign({}, state.queries[queryKey]), { [queryCacheKey]: Object.assign(Object.assign({}, ((_a = state.queries[queryKey][queryCacheKey]) !== null && _a !== void 0 ? _a : utilsAndConstants_1.DEFAULT_QUERY_MUTATION_STATE)), queryState) }) }) });
36
37
  }
37
- case '@RRC/SET_MUTATION_STATE_AND_ENTITIES': {
38
- const { mutationKey, state: mutationState, entityChagnes } = action;
38
+ case actions.updateMutationStateAndEntities.type: {
39
+ const { mutationKey, state: mutationState, entityChagnes, } = action;
39
40
  const newEntities = entityChagnes && (0, utilsAndConstants_1.applyEntityChanges)(state.entities, entityChagnes, cacheOptions);
40
41
  if (!mutationState && !newEntities) {
41
42
  return state;
42
43
  }
43
- return Object.assign(Object.assign(Object.assign({}, state), (newEntities ? { entities: newEntities } : null)), { mutations: Object.assign(Object.assign({}, state.mutations), { [mutationKey]: Object.assign(Object.assign({}, state.mutations[mutationKey]), mutationState) }) });
44
+ return Object.assign(Object.assign(Object.assign({}, state), (newEntities ? { entities: newEntities } : null)), { mutations: Object.assign(Object.assign({}, state.mutations), { [mutationKey]: Object.assign(Object.assign({}, ((_b = state.mutations[mutationKey]) !== null && _b !== void 0 ? _b : utilsAndConstants_1.DEFAULT_QUERY_MUTATION_STATE)), mutationState) }) });
44
45
  }
45
- case '@RRC/MERGE_ENTITY_CHANGES': {
46
+ case actions.mergeEntityChanges.type: {
46
47
  const { changes } = action;
47
48
  const newEntities = (0, utilsAndConstants_1.applyEntityChanges)(state.entities, changes, cacheOptions);
48
49
  return newEntities ? Object.assign(Object.assign({}, state), { entities: newEntities }) : state;
49
50
  }
51
+ case actions.clearQueryState.type: {
52
+ const { queryKeys: queryKeysToClear } = action;
53
+ if (!queryKeysToClear.length) {
54
+ return state;
55
+ }
56
+ let newQueries = undefined;
57
+ for (const query of queryKeysToClear) {
58
+ if (query.cacheKey != null) {
59
+ if ((newQueries !== null && newQueries !== void 0 ? newQueries : state.queries)[query.key][query.cacheKey]) {
60
+ newQueries !== null && newQueries !== void 0 ? newQueries : (newQueries = Object.assign({}, state.queries));
61
+ newQueries[query.key] = Object.assign({}, newQueries[query.key]);
62
+ delete newQueries[query.key][query.cacheKey];
63
+ }
64
+ }
65
+ else if ((newQueries !== null && newQueries !== void 0 ? newQueries : state.queries)[query.key] !== EMPTY_QUERY_STATE) {
66
+ newQueries !== null && newQueries !== void 0 ? newQueries : (newQueries = Object.assign({}, state.queries));
67
+ newQueries[query.key] = EMPTY_QUERY_STATE;
68
+ }
69
+ }
70
+ if (!newQueries) {
71
+ return state;
72
+ }
73
+ return Object.assign(Object.assign({}, state), { queries: newQueries });
74
+ }
75
+ case actions.clearMutationState.type: {
76
+ const { mutationKeys } = action;
77
+ if (!mutationKeys.length) {
78
+ return state;
79
+ }
80
+ let newMutations = undefined;
81
+ for (const mutation of mutationKeys) {
82
+ if (state.mutations[mutation]) {
83
+ newMutations !== null && newMutations !== void 0 ? newMutations : (newMutations = Object.assign({}, state.mutations));
84
+ delete newMutations[mutation];
85
+ }
86
+ }
87
+ if (!newMutations) {
88
+ return state;
89
+ }
90
+ return Object.assign(Object.assign({}, state), { mutations: newMutations });
91
+ }
50
92
  }
51
93
  return state;
52
94
  };
53
95
  };
54
96
  exports.createCacheReducer = createCacheReducer;
55
- const actionPrefix = `@${utilsAndConstants_1.PACKAGE_SHORT_NAME}/`;
56
- const setQueryStateAndEntities = (queryKey, queryCacheKey, state, entityChagnes) => ({
57
- type: `${actionPrefix}SET_QUERY_STATE_AND_ENTITIES`,
58
- queryKey,
59
- queryCacheKey,
60
- state,
61
- entityChagnes,
62
- });
63
- exports.setQueryStateAndEntities = setQueryStateAndEntities;
64
- const setMutationStateAndEntities = (mutationKey, state, entityChagnes) => ({
65
- type: `${actionPrefix}SET_MUTATION_STATE_AND_ENTITIES`,
66
- mutationKey,
67
- state,
68
- entityChagnes,
69
- });
70
- exports.setMutationStateAndEntities = setMutationStateAndEntities;
71
- const mergeEntityChanges = (changes) => ({
72
- type: `${actionPrefix}MERGE_ENTITY_CHANGES`,
73
- changes,
74
- });
75
- exports.mergeEntityChanges = mergeEntityChanges;
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { createCacheReducer, ReduxCacheState } from './reducer';
1
+ import type { ReduxCacheState } from './reducer';
2
2
  export type Key = string | number | symbol;
3
3
  export type Dict<T> = Record<Key, T>;
4
4
  export type OptionalPartial<T, K extends keyof T> = Partial<{
@@ -17,17 +17,26 @@ export type EntityChanges<T extends Typenames> = {
17
17
  };
18
18
  /** Record of typename and its corresponding entity type */
19
19
  export type Typenames = Record<string, object>;
20
- export type Cache<T extends Typenames, QP, QR, MP, MR> = {
20
+ export type Cache<N extends string, T extends Typenames, QP, QR, MP, MR> = {
21
+ /** Used as prefix for actions and in default cacheStateSelector for selecting cache state from redux state. */
22
+ name: N;
23
+ /** Mapping of all typenames to their entity types, which is needed for proper typing and normalization.
24
+ * Empty objects with type casting can be used as values.
25
+ * @example
26
+ * typenames: {
27
+ users: {} as User, // here `users` entities will have type `User`
28
+ banks: {} as Bank,
29
+ } */
21
30
  typenames: T;
22
31
  queries: {
23
- [QK in keyof (QP & QR)]: QK extends keyof (QP | QR) ? QueryInfo<T, QP[QK], QR[QK], ReturnType<ReturnType<typeof createCacheReducer<T, QP, QR, MP, MR>>>> : never;
32
+ [QK in keyof (QP & QR)]: QK extends keyof (QP | QR) ? QueryInfo<T, QP[QK], QR[QK], ReduxCacheState<T, QR, MR>> : never;
24
33
  };
25
34
  mutations: {
26
35
  [MK in keyof (MP & MR)]: MK extends keyof (MP | MR) ? MutationInfo<T, MP[MK], MR[MK]> : never;
27
36
  };
28
37
  options: CacheOptions;
29
- /** Returns cache state from redux root state. */
30
- cacheStateSelector: (state: any) => ReduxCacheState<T, QP, QR, MP, MR>;
38
+ /** Should return cache state from redux root state. Default implementation returns `state[name]`. */
39
+ cacheStateSelector: (state: any) => ReduxCacheState<T, QR, MR>;
31
40
  };
32
41
  export type CacheOptions = {
33
42
  /**
@@ -73,11 +82,11 @@ export type QueryInfo<T extends Typenames, P, R, S> = {
73
82
  * */
74
83
  getCacheKey?: (params?: P) => Key;
75
84
  };
76
- export type UseQueryOptions<T extends Typenames, QP, QR, MP, MR, QK extends keyof (QP & QR)> = {
85
+ export type UseQueryOptions<T extends Typenames, QP, QR, MR, QK extends keyof (QP & QR)> = {
77
86
  query: QK;
78
87
  params: QK extends keyof (QP | QR) ? QP[QK] : never;
79
88
  skip?: boolean;
80
- } & Pick<QK extends keyof (QP | QR) ? QueryInfo<T, QP[QK], QR[QK], ReduxCacheState<T, QP, QR, MP, MR>> : never, 'cachePolicy' | 'mergeResults' | 'getCacheKey'>;
89
+ } & Pick<QK extends keyof (QP | QR) ? QueryInfo<T, QP[QK], QR[QK], ReduxCacheState<T, QR, MR>> : never, 'cachePolicy' | 'mergeResults' | 'getCacheKey'>;
81
90
  /**
82
91
  * @param cache-first for each params key fetch is not called if cache exists.
83
92
  * @param cache-and-fetch for each params key result is taken from cache and fetch is called.
@@ -92,7 +101,7 @@ export type QueryResult<R> = {
92
101
  cancelled?: true;
93
102
  result?: R;
94
103
  };
95
- export type QueryOptions<T extends Typenames, QP, QR, MP, MR, QK extends keyof (QP & QR)> = Omit<UseQueryOptions<T, QP, QR, MP, MR, QK>, 'skip'>;
104
+ export type QueryOptions<T extends Typenames, QP, QR, MR, QK extends keyof (QP & QR)> = Omit<UseQueryOptions<T, QP, QR, MR, QK>, 'skip'>;
96
105
  export type Mutation<T extends Typenames, P, R> = (params: P,
97
106
  /** Signal is aborted for current mutation when the same mutation was called once again. */
98
107
  abortSignal: AbortSignal) => Promise<MutationResponse<T, R>>;
@@ -1,5 +1,6 @@
1
1
  import { Store } from 'redux';
2
+ import { ActionMap } from './createActions';
2
3
  import { Cache, Key, QueryMutationState, Typenames } from './types';
3
- export declare const useMutation: <T extends Typenames, MP, MR, MK extends keyof MP | keyof MR>(cache: Cache<T, unknown, unknown, MP, MR>, options: {
4
+ export declare const useMutation: <N extends string, T extends Typenames, MP, MR, MK extends keyof MP | keyof MR>(cache: Cache<N, T, unknown, unknown, MP, MR>, actions: Pick<ActionMap<N, T, unknown, MR>, "updateMutationStateAndEntities">, options: {
4
5
  mutation: MK;
5
6
  }, abortControllers: WeakMap<Store, Record<Key, AbortController>>) => readonly [(params: MK extends keyof MP & keyof MR ? MP[MK] : never) => Promise<void>, QueryMutationState<MK extends keyof MP & keyof MR ? MP[MK] : never>, () => boolean];
@@ -13,9 +13,8 @@ exports.useMutation = void 0;
13
13
  const react_1 = require("react");
14
14
  const react_redux_1 = require("react-redux");
15
15
  const mutate_1 = require("./mutate");
16
- const reducer_1 = require("./reducer");
17
16
  const utilsAndConstants_1 = require("./utilsAndConstants");
18
- const useMutation = (cache, options, abortControllers) => {
17
+ const useMutation = (cache, actions, options, abortControllers) => {
19
18
  var _a;
20
19
  const { mutation: mutationKey } = options;
21
20
  const store = (0, react_redux_1.useStore)();
@@ -33,7 +32,7 @@ const useMutation = (cache, options, abortControllers) => {
33
32
  },
34
33
  // mutate
35
34
  (params) => __awaiter(void 0, void 0, void 0, function* () {
36
- yield (0, mutate_1.mutate)('useMutation.mutate', false, store, cache, mutationKey, params, abortControllers);
35
+ yield (0, mutate_1.mutate)('useMutation.mutate', false, store, cache, actions, mutationKey, params, abortControllers);
37
36
  }),
38
37
  // abort
39
38
  () => {
@@ -43,7 +42,7 @@ const useMutation = (cache, options, abortControllers) => {
43
42
  return false;
44
43
  }
45
44
  abortController.abort();
46
- store.dispatch((0, reducer_1.setMutationStateAndEntities)(mutationKey, {
45
+ store.dispatch(actions.updateMutationStateAndEntities(mutationKey, {
47
46
  loading: false,
48
47
  }));
49
48
  return true;
@@ -52,7 +51,7 @@ const useMutation = (cache, options, abortControllers) => {
52
51
  // eslint-disable-next-line react-hooks/exhaustive-deps
53
52
  }, [mutationKey, store]);
54
53
  // @ts-expect-error fix later
55
- const mutationState = (_a = (0, react_redux_1.useSelector)(mutationStateSelector)) !== null && _a !== void 0 ? _a : utilsAndConstants_1.defaultQueryMutationState;
54
+ const mutationState = (_a = (0, react_redux_1.useSelector)(mutationStateSelector)) !== null && _a !== void 0 ? _a : utilsAndConstants_1.DEFAULT_QUERY_MUTATION_STATE;
56
55
  cache.options.logsEnabled &&
57
56
  (0, utilsAndConstants_1.log)('useMutation', {
58
57
  options,
@@ -1,2 +1,3 @@
1
+ import { ActionMap } from './createActions';
1
2
  import { Cache, QueryMutationState, Typenames, UseQueryOptions } from './types';
2
- export declare const useQuery: <T extends Typenames, QP, QR, MP, MR, QK extends keyof QP | keyof QR>(cache: Cache<T, QP, QR, MP, MR>, options: UseQueryOptions<T, QP, QR, MP, MR, QK>) => readonly [QueryMutationState<QK extends keyof QP & keyof QR ? QR[QK] : never>, () => Promise<void>];
3
+ export declare const useQuery: <N extends string, T extends Typenames, QP, QR, MP, MR, QK extends keyof QP | keyof QR>(cache: Cache<N, T, QP, QR, MP, MR>, actions: Pick<ActionMap<N, T, QR, MR>, "updateQueryStateAndEntities">, options: UseQueryOptions<T, QP, QR, MR, QK>) => readonly [QueryMutationState<QK extends keyof QP & keyof QR ? QR[QK] : never>, () => Promise<void>];
package/dist/useQuery.js CHANGED
@@ -14,7 +14,7 @@ const react_1 = require("react");
14
14
  const react_redux_1 = require("react-redux");
15
15
  const query_1 = require("./query");
16
16
  const utilsAndConstants_1 = require("./utilsAndConstants");
17
- const useQuery = (cache, options) => {
17
+ const useQuery = (cache, actions, options) => {
18
18
  var _a, _b, _c;
19
19
  const { query: queryKey, skip, params, cachePolicy = (_a = cache.queries[queryKey].cachePolicy) !== null && _a !== void 0 ? _a : 'cache-first', getCacheKey = (_b = cache.queries[queryKey].getCacheKey) !== null && _b !== void 0 ? _b : (utilsAndConstants_1.defaultGetCacheKey), } = options;
20
20
  const logsEnabled = cache.options.logsEnabled;
@@ -34,13 +34,13 @@ const useQuery = (cache, options) => {
34
34
  const resultFromSelector = (resultSelector && (0, react_redux_1.useSelector)(resultSelector));
35
35
  const hasResultFromSelector = resultFromSelector !== undefined;
36
36
  const fetch = (0, react_1.useCallback)(() => __awaiter(void 0, void 0, void 0, function* () {
37
- yield (0, query_1.query)('useQuery.fetch', false, store, cache, queryKey, cacheKey, params);
37
+ yield (0, query_1.query)('useQuery.fetch', false, store, cache, actions, queryKey, cacheKey, params);
38
38
  // eslint-disable-next-line react-hooks/exhaustive-deps
39
39
  }), [store, queryKey, cacheKey]);
40
40
  const queryStateFromSelector = (_c = (0, react_redux_1.useSelector)((state) => {
41
41
  const queryState = cacheStateSelector(state).queries[queryKey][cacheKey];
42
42
  return queryState; // TODO proper type
43
- })) !== null && _c !== void 0 ? _c : utilsAndConstants_1.defaultQueryMutationState;
43
+ })) !== null && _c !== void 0 ? _c : utilsAndConstants_1.DEFAULT_QUERY_MUTATION_STATE;
44
44
  const queryState = hasResultFromSelector
45
45
  ? (Object.assign(Object.assign({}, queryStateFromSelector), { result: resultFromSelector }))
46
46
  : queryStateFromSelector;
@@ -1,7 +1,7 @@
1
- import { CacheOptions, EntitiesMap, EntityChanges, Key, Typenames } from './types';
2
- export declare const PACKAGE_SHORT_NAME = "RRC";
3
- export declare const isDev: boolean;
4
- export declare const defaultQueryMutationState: {
1
+ import type { CacheOptions, EntitiesMap, EntityChanges, Key, Typenames } from './types';
2
+ export declare const PACKAGE_SHORT_NAME = "rrc";
3
+ export declare const IS_DEV: boolean;
4
+ export declare const DEFAULT_QUERY_MUTATION_STATE: {
5
5
  readonly loading: false;
6
6
  readonly error: undefined;
7
7
  };
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.applyEntityChanges = exports.log = exports.defaultGetCacheKey = exports.defaultQueryMutationState = exports.isDev = exports.PACKAGE_SHORT_NAME = void 0;
4
- exports.PACKAGE_SHORT_NAME = 'RRC';
5
- exports.isDev = (() => {
3
+ exports.applyEntityChanges = exports.log = exports.defaultGetCacheKey = exports.DEFAULT_QUERY_MUTATION_STATE = exports.IS_DEV = exports.PACKAGE_SHORT_NAME = void 0;
4
+ exports.PACKAGE_SHORT_NAME = 'rrc';
5
+ exports.IS_DEV = (() => {
6
6
  try {
7
7
  // @ts-expect-error __DEV__ is only for React Native
8
8
  return __DEV__;
@@ -11,7 +11,7 @@ exports.isDev = (() => {
11
11
  return process.env.NODE_ENV === 'development';
12
12
  }
13
13
  })();
14
- exports.defaultQueryMutationState = { loading: false, error: undefined };
14
+ exports.DEFAULT_QUERY_MUTATION_STATE = { loading: false, error: undefined };
15
15
  const defaultGetCacheKey = (params) => {
16
16
  switch (typeof params) {
17
17
  case 'string':
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "react-redux-cache",
3
3
  "author": "Alexander Danilov",
4
4
  "license": "MIT",
5
- "version": "0.0.12",
5
+ "version": "0.2.0",
6
6
  "description": "Powerful data fetching and caching library that supports normalization, built on top of redux",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",
@@ -10,7 +10,7 @@
10
10
  "example": "(cd example && yarn && yarn start)",
11
11
  "clean": "rm -rf dist",
12
12
  "lint": "yarn eslint src",
13
- "build": "yarn clean && yarn lint && tsc && yarn pack -f package.tgz",
13
+ "build": "yarn clean && yarn lint && tsc",
14
14
  "test": "node node_modules/jest/bin/jest.js",
15
15
  "prepublishOnly": "yarn build && yarn test"
16
16
  },
@@ -38,7 +38,7 @@
38
38
  "redux": "4.2.1",
39
39
  "redux-logger": "3.0.6",
40
40
  "ts-jest": "29.1.0",
41
- "typescript": "5.0.4"
41
+ "typescript": "5.0"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "react": "^16",