react-redux-cache 0.21.0 → 0.22.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
@@ -21,9 +21,9 @@ Can be considered as `ApolloClient` for protocols other than `GraphQL`, but with
21
21
  |Supports all kinds of queries / mutations|REST, GraphQL, databases - any async operations can be cached.|
22
22
  |Fully typed|Written on TypeScript, everything is checked by compiler.|
23
23
  |Not overengineered|Simplicity is the main goal.|
24
- |Performance|Every function is heavily optimized, Immer is not used ([RTK [Query] issue](https://github.com/reduxjs/redux-toolkit/issues/4793)).|
24
+ |Performance|Every function is heavily optimized. Immer is not used ([RTK performance issue](https://github.com/reduxjs/redux-toolkit/issues/4793)). Supports mutable collections (O(n) > O(1)).|
25
25
  |Reliability|High test coverage, zero issue policy.|
26
- |Lightweight|`npx minified-size dist/esm/*.js`<br/>minified: 18.2 kB<br/>gzipped: 7.91 kB<br/>brotlied: 7.03 kB
26
+ |Lightweight|`npx minified-size dist/esm/*.js`<br/>minified: 19.1 kB<br/>gzipped: 8.29 kB<br/>brotlied: 7.41 kB
27
27
 
28
28
  |Feature|Description|
29
29
  |--|--|
@@ -35,6 +35,7 @@ Can be considered as `ApolloClient` for protocols other than `GraphQL`, but with
35
35
  |Fetch policies|Decide if data is full enough or need to be fetched.|
36
36
  |Normalization|Consistent state accross the app - better UX, minimum loading states and lower traffic consumption.|
37
37
  |Minimal state|Default values such as `undefined` or default query states are removed from the state tree.|
38
+ |BETA: Mutable collections|Optimizes state merges from O(n) to O(1) by using mutable collections. Separate entities, query and mutation states are still immutable.|
38
39
 
39
40
  #### Examples of states, generated by cache reducer from `/example` project:
40
41
  <details>
@@ -140,6 +141,7 @@ Can be considered as `ApolloClient` for protocols other than `GraphQL`, but with
140
141
  - [api.ts](https://github.com/gentlee/react-redux-cache#apits)
141
142
  - [Usage](https://github.com/gentlee/react-redux-cache#usage)
142
143
  - [Advanced](https://github.com/gentlee/react-redux-cache#advanced)
144
+ - [Mutable collections](https://github.com/gentlee/react-redux-cache#mutable-collections)
143
145
  - [Error handling](https://github.com/gentlee/react-redux-cache#error-handling)
144
146
  - [Invalidation](https://github.com/gentlee/react-redux-cache#invalidation)
145
147
  - [Extended & custom fetch policy](https://github.com/gentlee/react-redux-cache#extended--custom-fetch-policy)
@@ -323,6 +325,38 @@ export const UserScreen = () => {
323
325
 
324
326
  ### Advanced
325
327
 
328
+ #### Mutable collections
329
+
330
+ For huge collections (> 1000 items, see benchmark) immutable approach may be a bottleneck - every merge of entity, query or mutation state is O(n). There is an option `mutableCollections` that makes it O(1) by using mutable approach when working with collections, while still keeping separate entities, query and mutation states immutable.
331
+
332
+ [Benchmark](https://github.com/gentlee/react-redux-cache/blob/main/benchmark.ts) results of adding item to collection depending on collection size, in microseconds (less is better):
333
+
334
+ | Collection size | 0 | 1000 | 10000 | 100000 | 1000000 |
335
+ |-|-|-|-|-|-|
336
+ | immutable | 1.78 | 1.69 | 5.64 | 117.4 | 1284.6 |
337
+ | mutable | 1.68 | 0.92 | 0.98 | 0.98 | 0.99 |
338
+
339
+ Well written code should not subcribe to whole collections, so just enabling this options most of the times should not break anything. But if it is still needed, you should subscribe to both collection (it may still change e.g. when clearing state) and to its `_changeKey`.
340
+
341
+ ```tsx
342
+ const Component = () => {
343
+ // It is usually a bad idea to subscribe to whole collections, consider using order of ids and subscribe to a single entity in each cell.
344
+ const allUsers = useSelector((state) => selectEntitiesByTypename(state, 'users'))
345
+ const allUsersChangeKey = useSelector((state) => selectEntitiesByTypename(state, 'users')._changeKey) // <-- Add this line while subscribing to collections
346
+
347
+ // For memoized components you should also pass it as extra prop to cause its re-render.
348
+ return <List data={allUsers} extra={allUsersChangeKey}/>
349
+ }
350
+
351
+ // Or just use existing hook.
352
+
353
+ const Component = () => {
354
+ const allUsers = useEntitiesByTypename('users')
355
+
356
+ return <List data={allUsers} extra={allUsers._changeKey}>
357
+ }
358
+ ```
359
+
326
360
  #### Error handling
327
361
 
328
362
  Queries and mutations are wrapped in try/catch, so any error will lead to cancelling of any updates to the state except loading state and the caught error. If you still want to make some state updates, or just want to use thrown errors only for unexpected cases, consider returning expected errors as a part of the result:
@@ -14,36 +14,39 @@ const utilsAndConstants_1 = require('./utilsAndConstants')
14
14
  const withTypenames = () => {
15
15
  return {
16
16
  createCache: (partialCache) => {
17
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m
18
- var _o, _p, _q, _r, _s, _t
17
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o
18
+ var _p, _q, _r, _s, _t, _u, _v
19
19
  const abortControllers = new WeakMap()
20
20
  ;(_a = partialCache.options) !== null && _a !== void 0 ? _a : (partialCache.options = {})
21
- ;(_b = (_o = partialCache.options).logsEnabled) !== null && _b !== void 0
21
+ ;(_b = (_p = partialCache.options).mutableCollections) !== null && _b !== void 0
22
22
  ? _b
23
- : (_o.logsEnabled = false)
24
- ;(_c = (_p = partialCache.options).additionalValidation) !== null && _c !== void 0
23
+ : (_p.mutableCollections = false)
24
+ ;(_c = (_q = partialCache.options).logsEnabled) !== null && _c !== void 0
25
25
  ? _c
26
- : (_p.additionalValidation = utilsAndConstants_1.IS_DEV)
27
- ;(_d = (_q = partialCache.options).deepComparisonEnabled) !== null && _d !== void 0
26
+ : (_q.logsEnabled = false)
27
+ ;(_d = (_r = partialCache.options).additionalValidation) !== null && _d !== void 0
28
28
  ? _d
29
- : (_q.deepComparisonEnabled = true)
30
- ;(_e = partialCache.globals) !== null && _e !== void 0 ? _e : (partialCache.globals = {})
31
- ;(_f = (_r = partialCache.globals).queries) !== null && _f !== void 0 ? _f : (_r.queries = {})
32
- ;(_g = (_s = partialCache.globals.queries).fetchPolicy) !== null && _g !== void 0
33
- ? _g
34
- : (_s.fetchPolicy = utilsAndConstants_1.FetchPolicy.NoCacheOrExpired)
35
- ;(_h = (_t = partialCache.globals.queries).skipFetch) !== null && _h !== void 0
29
+ : (_r.additionalValidation = utilsAndConstants_1.IS_DEV)
30
+ ;(_e = (_s = partialCache.options).deepComparisonEnabled) !== null && _e !== void 0
31
+ ? _e
32
+ : (_s.deepComparisonEnabled = true)
33
+ ;(_f = partialCache.globals) !== null && _f !== void 0 ? _f : (partialCache.globals = {})
34
+ ;(_g = (_t = partialCache.globals).queries) !== null && _g !== void 0 ? _g : (_t.queries = {})
35
+ ;(_h = (_u = partialCache.globals.queries).fetchPolicy) !== null && _h !== void 0
36
36
  ? _h
37
- : (_t.skipFetch = false)
38
- ;(_j = partialCache.cacheStateSelector) !== null && _j !== void 0
37
+ : (_u.fetchPolicy = utilsAndConstants_1.FetchPolicy.NoCacheOrExpired)
38
+ ;(_j = (_v = partialCache.globals.queries).skipFetch) !== null && _j !== void 0
39
39
  ? _j
40
+ : (_v.skipFetch = false)
41
+ ;(_k = partialCache.cacheStateSelector) !== null && _k !== void 0
42
+ ? _k
40
43
  : (partialCache.cacheStateSelector = (state) => state[cache.name])
41
- ;(_k = partialCache.mutations) !== null && _k !== void 0 ? _k : (partialCache.mutations = {})
42
- ;(_l = partialCache.queries) !== null && _l !== void 0 ? _l : (partialCache.queries = {})
44
+ ;(_l = partialCache.mutations) !== null && _l !== void 0 ? _l : (partialCache.mutations = {})
45
+ ;(_m = partialCache.queries) !== null && _m !== void 0 ? _m : (partialCache.queries = {})
43
46
  partialCache.abortControllers = abortControllers
44
47
  try {
45
- ;(_m = partialCache.storeHooks) !== null && _m !== void 0
46
- ? _m
48
+ ;(_o = partialCache.storeHooks) !== null && _o !== void 0
49
+ ? _o
47
50
  : (partialCache.storeHooks = {
48
51
  useStore: require('react-redux').useStore,
49
52
  useSelector: require('react-redux').useSelector,
@@ -188,6 +191,17 @@ const withTypenames = () => {
188
191
  useSelectEntityById: (id, typename) => {
189
192
  return cache.storeHooks.useSelector((state) => selectEntityById(state, id, typename))
190
193
  },
194
+ useEntitiesByTypename: (typename) => {
195
+ if (cache.options.mutableCollections) {
196
+ cache.storeHooks.useSelector((state) => {
197
+ var _a
198
+ return (_a = selectEntitiesByTypename(state, typename)) === null || _a === void 0
199
+ ? void 0
200
+ : _a._changeKey
201
+ })
202
+ }
203
+ return cache.storeHooks.useSelector((state) => selectEntitiesByTypename(state, typename))
204
+ },
191
205
  },
192
206
  utils: {
193
207
  createClient,
@@ -3,48 +3,65 @@ var __rest =
3
3
  (this && this.__rest) ||
4
4
  function (s, e) {
5
5
  var t = {}
6
- for (var p in s) {
7
- if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) {
8
- t[p] = s[p]
9
- }
10
- }
11
- if (s != null && typeof Object.getOwnPropertySymbols === 'function') {
6
+ for (var p in s) {if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
7
+ t[p] = s[p];}
8
+ if (s != null && typeof Object.getOwnPropertySymbols === 'function')
12
9
  for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
13
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) {
14
- t[p[i]] = s[p[i]]
15
- }
10
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]
16
11
  }
17
- }
18
12
  return t
19
13
  }
20
14
  Object.defineProperty(exports, '__esModule', {value: true})
21
15
  exports.createReducer = void 0
22
16
  const utilsAndConstants_1 = require('./utilsAndConstants')
23
-
24
17
  const optionalQueryKeys = ['error', 'expiresAt', 'result', 'params', 'loading']
25
18
  const optionalMutationKeys = ['error', 'result', 'params', 'loading']
26
19
  const createReducer = (actions, queryKeys, cacheOptions) => {
27
- const initialState = Object.freeze({
28
- entities: Object.freeze({}),
29
- queries: Object.freeze(
30
- queryKeys.reduce((result, x) => {
31
- result[x] = Object.freeze({})
32
- return result
33
- }, {})
34
- ),
35
- mutations: Object.freeze({}),
36
- })
20
+ const mutable = cacheOptions.mutableCollections
37
21
  cacheOptions.logsEnabled &&
38
22
  (0, utilsAndConstants_1.logDebug)('createCacheReducer', {
39
23
  queryKeys,
40
- initialState,
24
+ mutable,
41
25
  })
26
+ const getMutableInitialState = mutable
27
+ ? () => {
28
+ return {
29
+ entities: {},
30
+ queries: queryKeys.reduce((result, x) => {
31
+ result[x] = {}
32
+ return result
33
+ }, {}),
34
+ mutations: {},
35
+ }
36
+ }
37
+ : undefined
38
+ const immutableInitialState = mutable
39
+ ? undefined
40
+ : Object.freeze({
41
+ entities: Object.freeze({}),
42
+ queries: Object.freeze(
43
+ queryKeys.reduce((result, x) => {
44
+ result[x] = Object.freeze({})
45
+ return result
46
+ }, {})
47
+ ),
48
+ mutations: Object.freeze({}),
49
+ })
50
+ const {
51
+ clearCache,
52
+ clearMutationState,
53
+ clearQueryState,
54
+ invalidateQuery,
55
+ mergeEntityChanges,
56
+ updateMutationStateAndEntities,
57
+ updateQueryStateAndEntities,
58
+ } = actions
42
59
  const deepEqual = cacheOptions.deepComparisonEnabled
43
60
  ? utilsAndConstants_1.optionalUtils.deepEqual
44
61
  : undefined
45
- return (state = initialState, action) => {
62
+ return (state = mutable ? getMutableInitialState() : immutableInitialState, action) => {
46
63
  switch (action.type) {
47
- case actions.updateQueryStateAndEntities.type: {
64
+ case updateQueryStateAndEntities.type: {
48
65
  const {queryKey, queryCacheKey, state: queryState, entityChanges} = action
49
66
  const oldQueryState = state.queries[queryKey][queryCacheKey]
50
67
  let newQueryState = queryState && Object.assign(Object.assign({}, oldQueryState), queryState)
@@ -92,23 +109,36 @@ const createReducer = (actions, queryKeys, cacheOptions) => {
92
109
  if (newQueryState) {
93
110
  if (!(0, utilsAndConstants_1.isEmptyObject)(newQueryState)) {
94
111
  newState !== null && newState !== void 0 ? newState : (newState = Object.assign({}, state))
95
- newState.queries = Object.assign(Object.assign({}, state.queries), {
96
- [queryKey]: Object.assign(Object.assign({}, state.queries[queryKey]), {
97
- [queryCacheKey]: newQueryState,
98
- }),
99
- })
100
- } else if (oldQueryState !== undefined) {
101
- const _a = state.queries[queryKey],
102
- _b = queryCacheKey,
103
- _ = _a[_b],
104
- withoutCacheKey = __rest(_a, [typeof _b === 'symbol' ? _b : _b + ''])
112
+ if (mutable) {
113
+ newState.queries[queryKey][queryCacheKey] = newQueryState
114
+ ;(0, utilsAndConstants_1.incrementChangeKey)(newState.queries)
115
+ ;(0, utilsAndConstants_1.incrementChangeKey)(newState.queries[queryKey])
116
+ } else {
117
+ newState.queries = Object.assign(Object.assign({}, state.queries), {
118
+ [queryKey]: Object.assign(Object.assign({}, state.queries[queryKey]), {
119
+ [queryCacheKey]: newQueryState,
120
+ }),
121
+ })
122
+ } else if (oldQueryState !== undefined) {
105
123
  newState !== null && newState !== void 0 ? newState : (newState = Object.assign({}, state))
106
- newState.queries = Object.assign(Object.assign({}, state.queries), {[queryKey]: withoutCacheKey})
124
+ if (mutable) {
125
+ delete newState.queries[queryKey][queryCacheKey]
126
+ ;(0, utilsAndConstants_1.incrementChangeKey)(newState.queries)
127
+ ;(0, utilsAndConstants_1.incrementChangeKey)(newState.queries[queryKey])
128
+ } else {
129
+ const _a = state.queries[queryKey],
130
+ _b = queryCacheKey,
131
+ _ = _a[_b],
132
+ withoutCacheKey = __rest(_a, [typeof _b === 'symbol' ? _b : _b + ''])
133
+ newState.queries = Object.assign(Object.assign({}, state.queries), {
134
+ [queryKey]: withoutCacheKey,
135
+ })
136
+ }
107
137
  }
108
138
  }
109
139
  return newState !== null && newState !== void 0 ? newState : state
110
140
  }
111
- case actions.updateMutationStateAndEntities.type: {
141
+ case updateMutationStateAndEntities.type: {
112
142
  const {mutationKey, state: mutationState, entityChanges} = action
113
143
  const oldMutationState = state.mutations[mutationKey]
114
144
  let newMutationState =
@@ -151,112 +181,150 @@ const createReducer = (actions, queryKeys, cacheOptions) => {
151
181
  (0, utilsAndConstants_1.applyEntityChanges)(state.entities, entityChanges, cacheOptions)
152
182
  let newState
153
183
  if (newEntities) {
154
- newState !== null && newState !== void 0 ? newState : (newState = Object.assign({}, state))
155
- newState.entities = newEntities
184
+ newState = Object.assign(Object.assign({}, state), {entities: newEntities})
156
185
  }
157
186
  if (newMutationState) {
158
187
  if (!(0, utilsAndConstants_1.isEmptyObject)(newMutationState)) {
159
188
  newState !== null && newState !== void 0 ? newState : (newState = Object.assign({}, state))
160
- newState.mutations = Object.assign(Object.assign({}, state.mutations), {
161
- [mutationKey]: newMutationState,
162
- })
163
- } else if (oldMutationState !== undefined) {
164
- const _c = state.mutations,
165
- _d = mutationKey,
166
- _ = _c[_d],
167
- withoutMutationKey = __rest(_c, [typeof _d === 'symbol' ? _d : _d + ''])
189
+ if (mutable) {
190
+ state.mutations[mutationKey] = newMutationState
191
+ ;(0, utilsAndConstants_1.incrementChangeKey)(state.mutations)
192
+ } else {
193
+ newState.mutations = Object.assign(Object.assign({}, state.mutations), {
194
+ [mutationKey]: newMutationState,
195
+ })
196
+ } else if (oldMutationState !== undefined) {
168
197
  newState !== null && newState !== void 0 ? newState : (newState = Object.assign({}, state))
169
- newState.mutations = withoutMutationKey
198
+ if (mutable) {
199
+ delete state.mutations[mutationKey]
200
+ ;(0, utilsAndConstants_1.incrementChangeKey)(state.mutations)
201
+ } else {
202
+ const _c = state.mutations,
203
+ _d = mutationKey,
204
+ _ = _c[_d],
205
+ withoutMutationKey = __rest(_c, [typeof _d === 'symbol' ? _d : _d + ''])
206
+ newState.mutations = withoutMutationKey
207
+ }
170
208
  }
171
209
  }
172
210
  return newState !== null && newState !== void 0 ? newState : state
173
211
  }
174
- case actions.mergeEntityChanges.type: {
212
+ case mergeEntityChanges.type: {
175
213
  const {changes} = action
176
214
  const newEntities = (0, utilsAndConstants_1.applyEntityChanges)(state.entities, changes, cacheOptions)
177
215
  return newEntities ? Object.assign(Object.assign({}, state), {entities: newEntities}) : state
178
216
  }
179
- case actions.invalidateQuery.type: {
217
+ case invalidateQuery.type: {
180
218
  const {queries: queriesToInvalidate} = action
181
219
  if (queriesToInvalidate.length === 0) {
182
220
  return state
183
221
  }
184
222
  const now = Date.now()
185
- let newQueries = undefined
223
+ let newStatesByQueryKey
224
+ const copiedQueryKeys = mutable ? undefined : new Set()
186
225
  for (const {query: queryKey, cacheKey, expiresAt = now} of queriesToInvalidate) {
187
- const queryStates = (newQueries !== null && newQueries !== void 0 ? newQueries : state.queries)[
188
- queryKey
189
- ]
190
- if (cacheKey != null) {
191
- if (queryStates[cacheKey]) {
192
- const queryState = queryStates[cacheKey]
193
- if (queryState && queryState.expiresAt !== expiresAt) {
194
- newQueries !== null && newQueries !== void 0
195
- ? newQueries
196
- : (newQueries = Object.assign({}, state.queries))
197
- if (state.queries[queryKey] === newQueries[queryKey]) {
198
- newQueries[queryKey] = Object.assign({}, newQueries[queryKey])
199
- }
200
- newQueries[queryKey][cacheKey] = Object.assign(Object.assign({}, queryState), {expiresAt})
201
- if (expiresAt === undefined) {
202
- delete newQueries[queryKey][cacheKey].expiresAt
203
- }
226
+ const statesByCacheKey = (
227
+ newStatesByQueryKey !== null && newStatesByQueryKey !== void 0
228
+ ? newStatesByQueryKey
229
+ : state.queries
230
+ )[queryKey]
231
+ const cacheKeysToInvalidate = cacheKey != null ? [cacheKey] : Object.keys(statesByCacheKey)
232
+ for (const cacheKey of cacheKeysToInvalidate) {
233
+ const queryState = statesByCacheKey[cacheKey]
234
+ if (!queryState || queryState.expiresAt === expiresAt) {
235
+ continue
236
+ }
237
+ if (mutable) {
238
+ newStatesByQueryKey !== null && newStatesByQueryKey !== void 0
239
+ ? newStatesByQueryKey
240
+ : (newStatesByQueryKey = state.queries)
241
+ ;(0, utilsAndConstants_1.incrementChangeKey)(newStatesByQueryKey[queryKey])
242
+ } else {
243
+ newStatesByQueryKey !== null && newStatesByQueryKey !== void 0
244
+ ? newStatesByQueryKey
245
+ : (newStatesByQueryKey = Object.assign({}, state.queries))
246
+ if (!copiedQueryKeys.has(queryKey)) {
247
+ newStatesByQueryKey[queryKey] = Object.assign({}, newStatesByQueryKey[queryKey])
248
+ copiedQueryKeys.add(queryKey)
204
249
  }
205
250
  }
206
- } else {
207
- for (const cacheKey in queryStates) {
208
- const queryState = queryStates[cacheKey]
209
- if (queryState && queryState.expiresAt !== expiresAt) {
210
- newQueries !== null && newQueries !== void 0
211
- ? newQueries
212
- : (newQueries = Object.assign({}, state.queries))
213
- if (state.queries[queryKey] === newQueries[queryKey]) {
214
- newQueries[queryKey] = Object.assign({}, newQueries[queryKey])
215
- }
216
- newQueries[queryKey][cacheKey] = Object.assign(Object.assign({}, queryState), {expiresAt})
217
- if (expiresAt === undefined) {
218
- delete newQueries[queryKey][cacheKey].expiresAt
219
- }
251
+ if (expiresAt !== undefined) {
252
+ newStatesByQueryKey[queryKey][cacheKey] = Object.assign(Object.assign({}, queryState), {
253
+ expiresAt,
254
+ })
255
+ } else {
256
+ const {expiresAt: _} = queryState,
257
+ newQueryState = __rest(queryState, ['expiresAt'])
258
+ if ((0, utilsAndConstants_1.isEmptyObject)(newQueryState)) {
259
+ delete newStatesByQueryKey[queryKey][cacheKey]
260
+ } else {
261
+ newStatesByQueryKey[queryKey][cacheKey] = newQueryState
220
262
  }
221
263
  }
222
264
  }
223
265
  }
224
- return newQueries === undefined
225
- ? state
226
- : Object.assign(Object.assign({}, state), {queries: newQueries})
266
+ if (!newStatesByQueryKey) {
267
+ return state
268
+ }
269
+ if (mutable) {
270
+ ;(0, utilsAndConstants_1.incrementChangeKey)(newStatesByQueryKey)
271
+ }
272
+ return Object.assign(Object.assign({}, state), {queries: newStatesByQueryKey})
227
273
  }
228
- case actions.clearQueryState.type: {
274
+ case clearQueryState.type: {
229
275
  const {queries: queriesToClear} = action
230
276
  if (queriesToClear.length === 0) {
231
277
  return state
232
278
  }
233
- let newQueries = undefined
279
+ let newStatesByQueryKey
280
+ const copiedQueryKeys = mutable ? undefined : new Set()
234
281
  for (const {query: queryKey, cacheKey} of queriesToClear) {
235
- const queryStates = (newQueries !== null && newQueries !== void 0 ? newQueries : state.queries)[
236
- queryKey
237
- ]
282
+ const statesByCacheKey = (
283
+ newStatesByQueryKey !== null && newStatesByQueryKey !== void 0
284
+ ? newStatesByQueryKey
285
+ : state.queries
286
+ )[queryKey]
238
287
  if (cacheKey != null) {
239
- if (queryStates[cacheKey]) {
240
- newQueries !== null && newQueries !== void 0
241
- ? newQueries
242
- : (newQueries = Object.assign({}, state.queries))
243
- if (state.queries[queryKey] === newQueries[queryKey]) {
244
- newQueries[queryKey] = Object.assign({}, newQueries[queryKey])
288
+ if (!statesByCacheKey[cacheKey]) {
289
+ continue
290
+ }
291
+ if (mutable) {
292
+ newStatesByQueryKey !== null && newStatesByQueryKey !== void 0
293
+ ? newStatesByQueryKey
294
+ : (newStatesByQueryKey = state.queries)
295
+ ;(0, utilsAndConstants_1.incrementChangeKey)(newStatesByQueryKey[queryKey])
296
+ } else {
297
+ newStatesByQueryKey !== null && newStatesByQueryKey !== void 0
298
+ ? newStatesByQueryKey
299
+ : (newStatesByQueryKey = Object.assign({}, state.queries))
300
+ if (!copiedQueryKeys.has(queryKey)) {
301
+ newStatesByQueryKey[queryKey] = Object.assign({}, newStatesByQueryKey[queryKey])
302
+ copiedQueryKeys.add(queryKey)
245
303
  }
246
- delete newQueries[queryKey][cacheKey]
247
304
  }
248
- } else if (queryStates !== utilsAndConstants_1.EMPTY_OBJECT) {
249
- newQueries !== null && newQueries !== void 0
250
- ? newQueries
251
- : (newQueries = Object.assign({}, state.queries))
252
- newQueries[queryKey] = utilsAndConstants_1.EMPTY_OBJECT
305
+ delete newStatesByQueryKey[queryKey][cacheKey]
306
+ } else if (mutable) {
307
+ newStatesByQueryKey !== null && newStatesByQueryKey !== void 0
308
+ ? newStatesByQueryKey
309
+ : (newStatesByQueryKey = state.queries)
310
+ newStatesByQueryKey[queryKey] = {}
311
+ } else if (statesByCacheKey !== utilsAndConstants_1.EMPTY_OBJECT) {
312
+ newStatesByQueryKey !== null && newStatesByQueryKey !== void 0
313
+ ? newStatesByQueryKey
314
+ : (newStatesByQueryKey = Object.assign({}, state.queries))
315
+ newStatesByQueryKey[queryKey] = utilsAndConstants_1.EMPTY_OBJECT
316
+ copiedQueryKeys.add(queryKey)
253
317
  }
254
318
  }
255
- return newQueries === undefined
256
- ? state
257
- : Object.assign(Object.assign({}, state), {queries: newQueries})
319
+ if (newStatesByQueryKey === undefined) {
320
+ return state
321
+ }
322
+ if (mutable) {
323
+ ;(0, utilsAndConstants_1.incrementChangeKey)(newStatesByQueryKey)
324
+ }
325
+ return Object.assign(Object.assign({}, state), {queries: newStatesByQueryKey})
258
326
  }
259
- case actions.clearMutationState.type: {
327
+ case clearMutationState.type: {
260
328
  const {mutationKeys} = action
261
329
  if (mutationKeys.length === 0) {
262
330
  return state
@@ -266,16 +334,21 @@ const createReducer = (actions, queryKeys, cacheOptions) => {
266
334
  if (state.mutations[mutation]) {
267
335
  newMutations !== null && newMutations !== void 0
268
336
  ? newMutations
269
- : (newMutations = Object.assign({}, state.mutations))
337
+ : (newMutations = mutable ? state.mutations : Object.assign({}, state.mutations))
270
338
  delete newMutations[mutation]
271
339
  }
272
340
  }
273
- return newMutations === undefined
274
- ? state
275
- : Object.assign(Object.assign({}, state), {mutations: newMutations})
341
+ if (newMutations === undefined) {
342
+ return state
343
+ }
344
+ if (mutable) {
345
+ ;(0, utilsAndConstants_1.incrementChangeKey)(newMutations)
346
+ }
347
+ return Object.assign(Object.assign({}, state), {mutations: newMutations})
276
348
  }
277
- case actions.clearCache.type: {
349
+ case clearCache.type: {
278
350
  const {stateToKeep} = action
351
+ const initialState = mutable ? getMutableInitialState() : immutableInitialState
279
352
  return stateToKeep ? Object.assign(Object.assign({}, initialState), stateToKeep) : initialState
280
353
  }
281
354
  }
@@ -25,6 +25,7 @@ const createSelectors = (cache) => {
25
25
  : utilsAndConstants_1.EMPTY_OBJECT
26
26
  }
27
27
  return {
28
+ selectEntityById,
28
29
  selectQueryState,
29
30
  selectQueryResult: (state, query, cacheKey) => {
30
31
  return selectQueryState(state, query, cacheKey).result
@@ -56,7 +57,6 @@ const createSelectors = (cache) => {
56
57
  selectMutationParams: (state, mutation) => {
57
58
  return selectMutationState(state, mutation).params
58
59
  },
59
- selectEntityById,
60
60
  selectEntities: (state) => {
61
61
  return cache.cacheStateSelector(state).entities
62
62
  },