@depup/reduxjs__toolkit 2.12.0-depup.28

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.
Files changed (173) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -0
  3. package/changes.json +18 -0
  4. package/dist/cjs/index.js +6 -0
  5. package/dist/cjs/redux-toolkit.development.cjs +2406 -0
  6. package/dist/cjs/redux-toolkit.development.cjs.map +1 -0
  7. package/dist/cjs/redux-toolkit.production.min.cjs +3 -0
  8. package/dist/cjs/redux-toolkit.production.min.cjs.map +1 -0
  9. package/dist/index.d.mts +2665 -0
  10. package/dist/index.d.ts +2665 -0
  11. package/dist/query/cjs/index.js +6 -0
  12. package/dist/query/cjs/rtk-query.development.cjs +3092 -0
  13. package/dist/query/cjs/rtk-query.development.cjs.map +1 -0
  14. package/dist/query/cjs/rtk-query.production.min.cjs +2 -0
  15. package/dist/query/cjs/rtk-query.production.min.cjs.map +1 -0
  16. package/dist/query/index.d.mts +3066 -0
  17. package/dist/query/index.d.ts +3066 -0
  18. package/dist/query/react/cjs/index.js +6 -0
  19. package/dist/query/react/cjs/rtk-query-react.development.cjs +748 -0
  20. package/dist/query/react/cjs/rtk-query-react.development.cjs.map +1 -0
  21. package/dist/query/react/cjs/rtk-query-react.production.min.cjs +2 -0
  22. package/dist/query/react/cjs/rtk-query-react.production.min.cjs.map +1 -0
  23. package/dist/query/react/index.d.mts +1009 -0
  24. package/dist/query/react/index.d.ts +1009 -0
  25. package/dist/query/react/rtk-query-react.browser.mjs +2 -0
  26. package/dist/query/react/rtk-query-react.browser.mjs.map +1 -0
  27. package/dist/query/react/rtk-query-react.legacy-esm.js +740 -0
  28. package/dist/query/react/rtk-query-react.legacy-esm.js.map +1 -0
  29. package/dist/query/react/rtk-query-react.modern.mjs +705 -0
  30. package/dist/query/react/rtk-query-react.modern.mjs.map +1 -0
  31. package/dist/query/rtk-query.browser.mjs +2 -0
  32. package/dist/query/rtk-query.browser.mjs.map +1 -0
  33. package/dist/query/rtk-query.legacy-esm.js +3117 -0
  34. package/dist/query/rtk-query.legacy-esm.js.map +1 -0
  35. package/dist/query/rtk-query.modern.mjs +3052 -0
  36. package/dist/query/rtk-query.modern.mjs.map +1 -0
  37. package/dist/react/cjs/index.js +6 -0
  38. package/dist/react/cjs/redux-toolkit-react.development.cjs +55 -0
  39. package/dist/react/cjs/redux-toolkit-react.development.cjs.map +1 -0
  40. package/dist/react/cjs/redux-toolkit-react.production.min.cjs +2 -0
  41. package/dist/react/cjs/redux-toolkit-react.production.min.cjs.map +1 -0
  42. package/dist/react/index.d.mts +22 -0
  43. package/dist/react/index.d.ts +22 -0
  44. package/dist/react/redux-toolkit-react.browser.mjs +2 -0
  45. package/dist/react/redux-toolkit-react.browser.mjs.map +1 -0
  46. package/dist/react/redux-toolkit-react.legacy-esm.js +47 -0
  47. package/dist/react/redux-toolkit-react.legacy-esm.js.map +1 -0
  48. package/dist/react/redux-toolkit-react.modern.mjs +28 -0
  49. package/dist/react/redux-toolkit-react.modern.mjs.map +1 -0
  50. package/dist/redux-toolkit.browser.mjs +3 -0
  51. package/dist/redux-toolkit.browser.mjs.map +1 -0
  52. package/dist/redux-toolkit.legacy-esm.js +2351 -0
  53. package/dist/redux-toolkit.legacy-esm.js.map +1 -0
  54. package/dist/redux-toolkit.modern.mjs +2330 -0
  55. package/dist/redux-toolkit.modern.mjs.map +1 -0
  56. package/dist/uncheckedindexed.ts +16 -0
  57. package/package.json +310 -0
  58. package/query/package.json +13 -0
  59. package/query/react/package.json +13 -0
  60. package/react/package.json +13 -0
  61. package/skills/build-modern-redux-apps/modern-redux/SKILL.md +304 -0
  62. package/skills/build-modern-redux-apps/modern-redux/references/store-lifetime.md +53 -0
  63. package/skills/build-modern-redux-apps/redux-dataflow/SKILL.md +264 -0
  64. package/skills/evolve-and-diagnose-redux-apps/debug-redux-toolkit-apps/SKILL.md +269 -0
  65. package/skills/evolve-and-diagnose-redux-apps/migrate-to-modern-redux/SKILL.md +226 -0
  66. package/skills/manage-server-data/adopt-rtk-query/SKILL.md +385 -0
  67. package/skills/manage-server-data/adopt-rtk-query/references/endpoint-lifecycle.md +36 -0
  68. package/skills/model-redux-state/build-slices-and-selectors/SKILL.md +364 -0
  69. package/skills/model-redux-state/build-slices-and-selectors/references/slice-patterns.md +59 -0
  70. package/skills/model-redux-state/design-state-ownership/SKILL.md +322 -0
  71. package/skills/model-redux-state/design-state-ownership/references/state-ownership.md +28 -0
  72. package/skills/orchestrate-side-effects/handle-side-effects/SKILL.md +271 -0
  73. package/skills/orchestrate-side-effects/handle-side-effects/references/listener-workflows.md +34 -0
  74. package/src/actionCreatorInvariantMiddleware.ts +34 -0
  75. package/src/autoBatchEnhancer.ts +146 -0
  76. package/src/combineSlices.ts +487 -0
  77. package/src/configureStore.ts +248 -0
  78. package/src/createAction.ts +324 -0
  79. package/src/createAsyncThunk.ts +791 -0
  80. package/src/createDraftSafeSelector.ts +30 -0
  81. package/src/createReducer.ts +217 -0
  82. package/src/createSlice.ts +1079 -0
  83. package/src/devtoolsExtension.ts +241 -0
  84. package/src/dynamicMiddleware/index.ts +93 -0
  85. package/src/dynamicMiddleware/react/index.ts +101 -0
  86. package/src/dynamicMiddleware/types.ts +82 -0
  87. package/src/entities/create_adapter.ts +47 -0
  88. package/src/entities/entity_state.ts +38 -0
  89. package/src/entities/index.ts +8 -0
  90. package/src/entities/models.ts +198 -0
  91. package/src/entities/sorted_state_adapter.ts +266 -0
  92. package/src/entities/state_adapter.ts +58 -0
  93. package/src/entities/state_selectors.ts +73 -0
  94. package/src/entities/unsorted_state_adapter.ts +204 -0
  95. package/src/entities/utils.ts +68 -0
  96. package/src/formatProdErrorMessage.ts +13 -0
  97. package/src/getDefaultEnhancers.ts +31 -0
  98. package/src/getDefaultMiddleware.ts +113 -0
  99. package/src/immerImports.ts +7 -0
  100. package/src/immutableStateInvariantMiddleware.ts +274 -0
  101. package/src/index.ts +213 -0
  102. package/src/listenerMiddleware/exceptions.ts +20 -0
  103. package/src/listenerMiddleware/index.ts +562 -0
  104. package/src/listenerMiddleware/task.ts +100 -0
  105. package/src/listenerMiddleware/types.ts +886 -0
  106. package/src/listenerMiddleware/utils.ts +30 -0
  107. package/src/mapBuilders.ts +298 -0
  108. package/src/matchers.ts +365 -0
  109. package/src/nanoid.ts +20 -0
  110. package/src/query/HandledError.ts +6 -0
  111. package/src/query/apiTypes.ts +120 -0
  112. package/src/query/baseQueryTypes.ts +101 -0
  113. package/src/query/core/apiState.ts +377 -0
  114. package/src/query/core/buildInitiate.ts +596 -0
  115. package/src/query/core/buildMiddleware/batchActions.ts +207 -0
  116. package/src/query/core/buildMiddleware/cacheCollection.ts +204 -0
  117. package/src/query/core/buildMiddleware/cacheLifecycle.ts +379 -0
  118. package/src/query/core/buildMiddleware/devMiddleware.ts +34 -0
  119. package/src/query/core/buildMiddleware/index.ts +162 -0
  120. package/src/query/core/buildMiddleware/invalidationByTags.ts +139 -0
  121. package/src/query/core/buildMiddleware/polling.ts +187 -0
  122. package/src/query/core/buildMiddleware/queryLifecycle.ts +508 -0
  123. package/src/query/core/buildMiddleware/types.ts +173 -0
  124. package/src/query/core/buildMiddleware/windowEventHandling.ts +64 -0
  125. package/src/query/core/buildSelectors.ts +413 -0
  126. package/src/query/core/buildSlice.ts +735 -0
  127. package/src/query/core/buildThunks.ts +1124 -0
  128. package/src/query/core/index.ts +58 -0
  129. package/src/query/core/module.ts +727 -0
  130. package/src/query/core/rtkImports.ts +24 -0
  131. package/src/query/core/setupListeners.ts +118 -0
  132. package/src/query/createApi.ts +506 -0
  133. package/src/query/defaultSerializeQueryArgs.ts +52 -0
  134. package/src/query/endpointDefinitions.ts +1717 -0
  135. package/src/query/fakeBaseQuery.ts +21 -0
  136. package/src/query/fetchBaseQuery.ts +385 -0
  137. package/src/query/index.ts +105 -0
  138. package/src/query/react/ApiProvider.tsx +69 -0
  139. package/src/query/react/buildHooks.ts +2297 -0
  140. package/src/query/react/constants.ts +2 -0
  141. package/src/query/react/index.ts +45 -0
  142. package/src/query/react/module.ts +275 -0
  143. package/src/query/react/namedHooks.ts +59 -0
  144. package/src/query/react/reactImports.ts +10 -0
  145. package/src/query/react/reactReduxImports.ts +1 -0
  146. package/src/query/react/rtkqImports.ts +8 -0
  147. package/src/query/react/useSerializedStableValue.ts +17 -0
  148. package/src/query/react/useShallowStableValue.ts +13 -0
  149. package/src/query/retry.ts +233 -0
  150. package/src/query/standardSchema.ts +35 -0
  151. package/src/query/tsHelpers.ts +48 -0
  152. package/src/query/utils/capitalize.ts +3 -0
  153. package/src/query/utils/copyWithStructuralSharing.ts +27 -0
  154. package/src/query/utils/countObjectKeys.ts +14 -0
  155. package/src/query/utils/filterMap.ts +27 -0
  156. package/src/query/utils/getCurrent.ts +6 -0
  157. package/src/query/utils/getOrInsert.ts +41 -0
  158. package/src/query/utils/immerImports.ts +9 -0
  159. package/src/query/utils/index.ts +11 -0
  160. package/src/query/utils/isAbsoluteUrl.ts +9 -0
  161. package/src/query/utils/isDocumentVisible.ts +12 -0
  162. package/src/query/utils/isNotNullish.ts +7 -0
  163. package/src/query/utils/isOnline.ts +12 -0
  164. package/src/query/utils/isValidUrl.ts +9 -0
  165. package/src/query/utils/joinUrls.ts +26 -0
  166. package/src/query/utils/signals.ts +33 -0
  167. package/src/react/index.ts +7 -0
  168. package/src/reduxImports.ts +8 -0
  169. package/src/reselectImports.ts +1 -0
  170. package/src/serializableStateInvariantMiddleware.ts +285 -0
  171. package/src/tsHelpers.ts +214 -0
  172. package/src/uncheckedindexed.ts +16 -0
  173. package/src/utils.ts +125 -0
@@ -0,0 +1,198 @@
1
+ import type { Draft } from 'immer'
2
+ import type { PayloadAction } from '../createAction'
3
+ import type { CastAny, Id } from '../tsHelpers'
4
+ import type { UncheckedIndexedAccess } from '../uncheckedindexed.js'
5
+ import type { GetSelectorsOptions } from './state_selectors'
6
+
7
+ /**
8
+ * @public
9
+ */
10
+ export type EntityId = number | string
11
+
12
+ /**
13
+ * @public
14
+ */
15
+ export type Comparer<T> = (a: T, b: T) => number
16
+
17
+ /**
18
+ * @public
19
+ */
20
+ export type IdSelector<T, Id extends EntityId> = (model: T) => Id
21
+
22
+ /**
23
+ * @public
24
+ */
25
+ export type Update<T, Id extends EntityId> = { id: Id; changes: Partial<T> }
26
+
27
+ /**
28
+ * @public
29
+ */
30
+ export interface EntityState<T, Id extends EntityId> {
31
+ ids: Id[]
32
+ entities: Record<Id, T>
33
+ }
34
+
35
+ /**
36
+ * @public
37
+ */
38
+ export interface EntityAdapterOptions<T, Id extends EntityId> {
39
+ selectId?: IdSelector<T, Id>
40
+ sortComparer?: false | Comparer<T>
41
+ }
42
+
43
+ export type PreventAny<S, T, Id extends EntityId> = CastAny<
44
+ S,
45
+ EntityState<T, Id>
46
+ >
47
+
48
+ export type DraftableEntityState<T, Id extends EntityId> =
49
+ | EntityState<T, Id>
50
+ | Draft<EntityState<T, Id>>
51
+
52
+ /**
53
+ * @public
54
+ */
55
+ export interface EntityStateAdapter<T, Id extends EntityId> {
56
+ addOne<S extends DraftableEntityState<T, Id>>(
57
+ state: PreventAny<S, T, Id>,
58
+ entity: T,
59
+ ): S
60
+ addOne<S extends DraftableEntityState<T, Id>>(
61
+ state: PreventAny<S, T, Id>,
62
+ action: PayloadAction<T>,
63
+ ): S
64
+
65
+ addMany<S extends DraftableEntityState<T, Id>>(
66
+ state: PreventAny<S, T, Id>,
67
+ entities: readonly T[] | Record<Id, T>,
68
+ ): S
69
+ addMany<S extends DraftableEntityState<T, Id>>(
70
+ state: PreventAny<S, T, Id>,
71
+ entities: PayloadAction<readonly T[] | Record<Id, T>>,
72
+ ): S
73
+
74
+ setOne<S extends DraftableEntityState<T, Id>>(
75
+ state: PreventAny<S, T, Id>,
76
+ entity: T,
77
+ ): S
78
+ setOne<S extends DraftableEntityState<T, Id>>(
79
+ state: PreventAny<S, T, Id>,
80
+ action: PayloadAction<T>,
81
+ ): S
82
+ setMany<S extends DraftableEntityState<T, Id>>(
83
+ state: PreventAny<S, T, Id>,
84
+ entities: readonly T[] | Record<Id, T>,
85
+ ): S
86
+ setMany<S extends DraftableEntityState<T, Id>>(
87
+ state: PreventAny<S, T, Id>,
88
+ entities: PayloadAction<readonly T[] | Record<Id, T>>,
89
+ ): S
90
+ setAll<S extends DraftableEntityState<T, Id>>(
91
+ state: PreventAny<S, T, Id>,
92
+ entities: readonly T[] | Record<Id, T>,
93
+ ): S
94
+ setAll<S extends DraftableEntityState<T, Id>>(
95
+ state: PreventAny<S, T, Id>,
96
+ entities: PayloadAction<readonly T[] | Record<Id, T>>,
97
+ ): S
98
+
99
+ removeOne<S extends DraftableEntityState<T, Id>>(
100
+ state: PreventAny<S, T, Id>,
101
+ key: Id,
102
+ ): S
103
+ removeOne<S extends DraftableEntityState<T, Id>>(
104
+ state: PreventAny<S, T, Id>,
105
+ key: PayloadAction<Id>,
106
+ ): S
107
+
108
+ removeMany<S extends DraftableEntityState<T, Id>>(
109
+ state: PreventAny<S, T, Id>,
110
+ keys: readonly Id[],
111
+ ): S
112
+ removeMany<S extends DraftableEntityState<T, Id>>(
113
+ state: PreventAny<S, T, Id>,
114
+ keys: PayloadAction<readonly Id[]>,
115
+ ): S
116
+
117
+ removeAll<S extends DraftableEntityState<T, Id>>(
118
+ state: PreventAny<S, T, Id>,
119
+ ): S
120
+
121
+ updateOne<S extends DraftableEntityState<T, Id>>(
122
+ state: PreventAny<S, T, Id>,
123
+ update: Update<T, Id>,
124
+ ): S
125
+ updateOne<S extends DraftableEntityState<T, Id>>(
126
+ state: PreventAny<S, T, Id>,
127
+ update: PayloadAction<Update<T, Id>>,
128
+ ): S
129
+
130
+ updateMany<S extends DraftableEntityState<T, Id>>(
131
+ state: PreventAny<S, T, Id>,
132
+ updates: ReadonlyArray<Update<T, Id>>,
133
+ ): S
134
+ updateMany<S extends DraftableEntityState<T, Id>>(
135
+ state: PreventAny<S, T, Id>,
136
+ updates: PayloadAction<ReadonlyArray<Update<T, Id>>>,
137
+ ): S
138
+
139
+ upsertOne<S extends DraftableEntityState<T, Id>>(
140
+ state: PreventAny<S, T, Id>,
141
+ entity: T,
142
+ ): S
143
+ upsertOne<S extends DraftableEntityState<T, Id>>(
144
+ state: PreventAny<S, T, Id>,
145
+ entity: PayloadAction<T>,
146
+ ): S
147
+
148
+ upsertMany<S extends DraftableEntityState<T, Id>>(
149
+ state: PreventAny<S, T, Id>,
150
+ entities: readonly T[] | Record<Id, T>,
151
+ ): S
152
+ upsertMany<S extends DraftableEntityState<T, Id>>(
153
+ state: PreventAny<S, T, Id>,
154
+ entities: PayloadAction<readonly T[] | Record<Id, T>>,
155
+ ): S
156
+ }
157
+
158
+ /**
159
+ * @public
160
+ */
161
+ export interface EntitySelectors<T, V, IdType extends EntityId> {
162
+ selectIds: (state: V) => IdType[]
163
+ selectEntities: (state: V) => Record<IdType, T>
164
+ selectAll: (state: V) => T[]
165
+ selectTotal: (state: V) => number
166
+ selectById: (state: V, id: IdType) => Id<UncheckedIndexedAccess<T>>
167
+ }
168
+
169
+ /**
170
+ * @public
171
+ */
172
+ export interface EntityStateFactory<T, Id extends EntityId> {
173
+ getInitialState(
174
+ state?: undefined,
175
+ entities?: Record<Id, T> | readonly T[],
176
+ ): EntityState<T, Id>
177
+ getInitialState<S extends object>(
178
+ state: S,
179
+ entities?: Record<Id, T> | readonly T[],
180
+ ): EntityState<T, Id> & S
181
+ }
182
+
183
+ /**
184
+ * @public
185
+ */
186
+ export interface EntityAdapter<T, Id extends EntityId>
187
+ extends EntityStateAdapter<T, Id>,
188
+ EntityStateFactory<T, Id>,
189
+ Required<EntityAdapterOptions<T, Id>> {
190
+ getSelectors(
191
+ selectState?: undefined,
192
+ options?: GetSelectorsOptions,
193
+ ): EntitySelectors<T, EntityState<T, Id>, Id>
194
+ getSelectors<V>(
195
+ selectState: (state: V) => EntityState<T, Id>,
196
+ options?: GetSelectorsOptions,
197
+ ): EntitySelectors<T, V, Id>
198
+ }
@@ -0,0 +1,266 @@
1
+ import type {
2
+ IdSelector,
3
+ Comparer,
4
+ EntityStateAdapter,
5
+ Update,
6
+ EntityId,
7
+ DraftableEntityState,
8
+ } from './models'
9
+ import { createStateOperator } from './state_adapter'
10
+ import { createUnsortedStateAdapter } from './unsorted_state_adapter'
11
+ import {
12
+ selectIdValue,
13
+ ensureEntitiesArray,
14
+ splitAddedUpdatedEntities,
15
+ getCurrent,
16
+ } from './utils'
17
+
18
+ // Borrowed from Replay
19
+ export function findInsertIndex<T>(
20
+ sortedItems: T[],
21
+ item: T,
22
+ comparisonFunction: Comparer<T>,
23
+ ): number {
24
+ let lowIndex = 0
25
+ let highIndex = sortedItems.length
26
+ while (lowIndex < highIndex) {
27
+ let middleIndex = (lowIndex + highIndex) >>> 1
28
+ const currentItem = sortedItems[middleIndex]
29
+ const res = comparisonFunction(item, currentItem)
30
+ if (res >= 0) {
31
+ lowIndex = middleIndex + 1
32
+ } else {
33
+ highIndex = middleIndex
34
+ }
35
+ }
36
+
37
+ return lowIndex
38
+ }
39
+
40
+ export function insert<T>(
41
+ sortedItems: T[],
42
+ item: T,
43
+ comparisonFunction: Comparer<T>,
44
+ ): T[] {
45
+ const insertAtIndex = findInsertIndex(sortedItems, item, comparisonFunction)
46
+
47
+ sortedItems.splice(insertAtIndex, 0, item)
48
+
49
+ return sortedItems
50
+ }
51
+
52
+ export function createSortedStateAdapter<T, Id extends EntityId>(
53
+ selectId: IdSelector<T, Id>,
54
+ comparer: Comparer<T>,
55
+ ): EntityStateAdapter<T, Id> {
56
+ type R = DraftableEntityState<T, Id>
57
+
58
+ const { removeOne, removeMany, removeAll } =
59
+ createUnsortedStateAdapter(selectId)
60
+
61
+ function addOneMutably(entity: T, state: R): void {
62
+ return addManyMutably([entity], state)
63
+ }
64
+
65
+ function addManyMutably(
66
+ newEntities: readonly T[] | Record<Id, T>,
67
+ state: R,
68
+ existingIds?: Id[],
69
+ ): void {
70
+ newEntities = ensureEntitiesArray(newEntities)
71
+
72
+ const existingKeys = new Set<Id>(existingIds ?? getCurrent(state.ids))
73
+ const addedKeys = new Set<Id>();
74
+ const models = newEntities.filter(
75
+ (model) => {
76
+ const modelId = selectIdValue(model, selectId);
77
+ const notAdded = !addedKeys.has(modelId);
78
+ if (notAdded) addedKeys.add(modelId);
79
+ return !existingKeys.has(modelId) && notAdded;
80
+ }
81
+ )
82
+
83
+ if (models.length !== 0) {
84
+ mergeFunction(state, models)
85
+ }
86
+ }
87
+
88
+ function setOneMutably(entity: T, state: R): void {
89
+ return setManyMutably([entity], state)
90
+ }
91
+
92
+ function setManyMutably(
93
+ newEntities: readonly T[] | Record<Id, T>,
94
+ state: R,
95
+ ): void {
96
+ let deduplicatedEntities = {} as Record<Id, T>;
97
+ newEntities = ensureEntitiesArray(newEntities)
98
+ if (newEntities.length !== 0) {
99
+ for (const item of newEntities) {
100
+ const entityId = selectId(item);
101
+ // For multiple items with the same ID, we should keep the last one.
102
+ deduplicatedEntities[entityId] = item;
103
+ delete (state.entities as Record<Id, T>)[entityId]
104
+ }
105
+ newEntities = ensureEntitiesArray(deduplicatedEntities);
106
+ mergeFunction(state, newEntities)
107
+ }
108
+ }
109
+
110
+ function setAllMutably(
111
+ newEntities: readonly T[] | Record<Id, T>,
112
+ state: R,
113
+ ): void {
114
+ newEntities = ensureEntitiesArray(newEntities)
115
+ state.entities = {} as Record<Id, T>
116
+ state.ids = []
117
+
118
+ addManyMutably(newEntities, state, [])
119
+ }
120
+
121
+ function updateOneMutably(update: Update<T, Id>, state: R): void {
122
+ return updateManyMutably([update], state)
123
+ }
124
+
125
+ function updateManyMutably(
126
+ updates: ReadonlyArray<Update<T, Id>>,
127
+ state: R,
128
+ ): void {
129
+ let appliedUpdates = false
130
+ let replacedIds = false
131
+
132
+ for (let update of updates) {
133
+ const entity: T | undefined = (state.entities as Record<Id, T>)[update.id]
134
+ if (!entity) {
135
+ continue
136
+ }
137
+
138
+ appliedUpdates = true
139
+
140
+ Object.assign(entity, update.changes)
141
+ const newId = selectId(entity)
142
+
143
+ if (update.id !== newId) {
144
+ // We do support the case where updates can change an item's ID.
145
+ // This makes things trickier - go ahead and swap the IDs in state now.
146
+ replacedIds = true
147
+ delete (state.entities as Record<Id, T>)[update.id]
148
+ const oldIndex = (state.ids as Id[]).indexOf(update.id)
149
+ state.ids[oldIndex] = newId
150
+ ;(state.entities as Record<Id, T>)[newId] = entity
151
+ }
152
+ }
153
+
154
+ if (appliedUpdates) {
155
+ mergeFunction(state, [], appliedUpdates, replacedIds)
156
+ }
157
+ }
158
+
159
+ function upsertOneMutably(entity: T, state: R): void {
160
+ return upsertManyMutably([entity], state)
161
+ }
162
+
163
+ function upsertManyMutably(
164
+ newEntities: readonly T[] | Record<Id, T>,
165
+ state: R,
166
+ ): void {
167
+ const [added, updated, existingIdsArray] = splitAddedUpdatedEntities<T, Id>(
168
+ newEntities,
169
+ selectId,
170
+ state,
171
+ )
172
+
173
+ if (added.length) {
174
+ addManyMutably(added, state, existingIdsArray)
175
+ }
176
+ if (updated.length) {
177
+ updateManyMutably(updated, state)
178
+ }
179
+ }
180
+
181
+ function areArraysEqual(a: readonly unknown[], b: readonly unknown[]) {
182
+ if (a.length !== b.length) {
183
+ return false
184
+ }
185
+
186
+ for (let i = 0; i < a.length; i++) {
187
+ if (a[i] === b[i]) {
188
+ continue
189
+ }
190
+ return false
191
+ }
192
+ return true
193
+ }
194
+
195
+ type MergeFunction = (
196
+ state: R,
197
+ addedItems: readonly T[],
198
+ appliedUpdates?: boolean,
199
+ replacedIds?: boolean,
200
+ ) => void
201
+
202
+ const mergeFunction: MergeFunction = (
203
+ state,
204
+ addedItems,
205
+ appliedUpdates,
206
+ replacedIds,
207
+ ) => {
208
+ const currentEntities = getCurrent(state.entities)
209
+ const currentIds = getCurrent(state.ids)
210
+
211
+ const stateEntities = state.entities as Record<Id, T>
212
+
213
+ let ids: Iterable<Id> = currentIds
214
+ if (replacedIds) {
215
+ ids = new Set(currentIds)
216
+ }
217
+
218
+ let sortedEntities: T[] = []
219
+ for (const id of ids) {
220
+ const entity = currentEntities[id]
221
+ if (entity) {
222
+ sortedEntities.push(entity)
223
+ }
224
+ }
225
+ const wasPreviouslyEmpty = sortedEntities.length === 0
226
+
227
+ // Insert/overwrite all new/updated
228
+ for (const item of addedItems) {
229
+ stateEntities[selectId(item)] = item
230
+
231
+ if (!wasPreviouslyEmpty) {
232
+ // Binary search insertion generally requires fewer comparisons
233
+ insert(sortedEntities, item, comparer)
234
+ }
235
+ }
236
+
237
+ if (wasPreviouslyEmpty) {
238
+ // All we have is the incoming values, sort them
239
+ sortedEntities = addedItems.slice().sort(comparer)
240
+ } else if (appliedUpdates) {
241
+ // We should have a _mostly_-sorted array already
242
+ sortedEntities.sort(comparer)
243
+ }
244
+
245
+ const newSortedIds = sortedEntities.map(selectId)
246
+
247
+ if (!areArraysEqual(currentIds, newSortedIds)) {
248
+ state.ids = newSortedIds
249
+ }
250
+ }
251
+
252
+ return {
253
+ removeOne,
254
+ removeMany,
255
+ removeAll,
256
+ addOne: createStateOperator(addOneMutably),
257
+ updateOne: createStateOperator(updateOneMutably),
258
+ upsertOne: createStateOperator(upsertOneMutably),
259
+ setOne: createStateOperator(setOneMutably),
260
+ setMany: createStateOperator(setManyMutably),
261
+ setAll: createStateOperator(setAllMutably),
262
+ addMany: createStateOperator(addManyMutably),
263
+ updateMany: createStateOperator(updateManyMutably),
264
+ upsertMany: createStateOperator(upsertManyMutably),
265
+ }
266
+ }
@@ -0,0 +1,58 @@
1
+ import { createNextState, isDraft } from '../immerImports'
2
+ import type { Draft } from 'immer'
3
+ import type { EntityId, DraftableEntityState, PreventAny } from './models'
4
+ import type { PayloadAction } from '../createAction'
5
+ import { isFSA } from '../createAction'
6
+
7
+ export const isDraftTyped = isDraft as <T>(
8
+ value: T | Draft<T>,
9
+ ) => value is Draft<T>
10
+
11
+ export function createSingleArgumentStateOperator<T, Id extends EntityId>(
12
+ mutator: (state: DraftableEntityState<T, Id>) => void,
13
+ ) {
14
+ const operator = createStateOperator(
15
+ (_: undefined, state: DraftableEntityState<T, Id>) => mutator(state),
16
+ )
17
+
18
+ return function operation<S extends DraftableEntityState<T, Id>>(
19
+ state: PreventAny<S, T, Id>,
20
+ ): S {
21
+ return operator(state as S, undefined)
22
+ }
23
+ }
24
+
25
+ export function createStateOperator<T, Id extends EntityId, R>(
26
+ mutator: (arg: R, state: DraftableEntityState<T, Id>) => void,
27
+ ) {
28
+ return function operation<S extends DraftableEntityState<T, Id>>(
29
+ state: S,
30
+ arg: R | PayloadAction<R>,
31
+ ): S {
32
+ function isPayloadActionArgument(
33
+ arg: R | PayloadAction<R>,
34
+ ): arg is PayloadAction<R> {
35
+ return isFSA(arg)
36
+ }
37
+
38
+ const runMutator = (draft: DraftableEntityState<T, Id>) => {
39
+ if (isPayloadActionArgument(arg)) {
40
+ mutator(arg.payload, draft)
41
+ } else {
42
+ mutator(arg, draft)
43
+ }
44
+ }
45
+
46
+ if (isDraftTyped<DraftableEntityState<T, Id>>(state)) {
47
+ // we must already be inside a `createNextState` call, likely because
48
+ // this is being wrapped in `createReducer` or `createSlice`.
49
+ // It's safe to just pass the draft to the mutator.
50
+ runMutator(state)
51
+
52
+ // since it's a draft, we'll just return it
53
+ return state
54
+ }
55
+
56
+ return createNextState(state, runMutator)
57
+ }
58
+ }
@@ -0,0 +1,73 @@
1
+ import type { CreateSelectorFunction, Selector } from 'reselect'
2
+ import { createDraftSafeSelector } from '../createDraftSafeSelector'
3
+ import type { EntityId, EntitySelectors, EntityState } from './models'
4
+
5
+ type AnyCreateSelectorFunction = CreateSelectorFunction<any, any, any>
6
+
7
+ export type GetSelectorsOptions = {
8
+ createSelector?: AnyCreateSelectorFunction
9
+ }
10
+
11
+ export function createSelectorsFactory<T, Id extends EntityId>() {
12
+ function getSelectors(
13
+ selectState?: undefined,
14
+ options?: GetSelectorsOptions,
15
+ ): EntitySelectors<T, EntityState<T, Id>, Id>
16
+ function getSelectors<V>(
17
+ selectState: (state: V) => EntityState<T, Id>,
18
+ options?: GetSelectorsOptions,
19
+ ): EntitySelectors<T, V, Id>
20
+ function getSelectors<V>(
21
+ selectState?: (state: V) => EntityState<T, Id>,
22
+ options: GetSelectorsOptions = {},
23
+ ): EntitySelectors<T, any, Id> {
24
+ const {
25
+ createSelector = createDraftSafeSelector as AnyCreateSelectorFunction,
26
+ } = options
27
+
28
+ const selectIds = (state: EntityState<T, Id>) => state.ids
29
+
30
+ const selectEntities = (state: EntityState<T, Id>) => state.entities
31
+
32
+ const selectAll = createSelector(
33
+ selectIds,
34
+ selectEntities,
35
+ (ids, entities): T[] => ids.map((id) => entities[id]!),
36
+ )
37
+
38
+ const selectId = (_: unknown, id: Id) => id
39
+
40
+ const selectById = (entities: Record<Id, T>, id: Id) => entities[id]
41
+
42
+ const selectTotal = createSelector(selectIds, (ids) => ids.length)
43
+
44
+ if (!selectState) {
45
+ return {
46
+ selectIds,
47
+ selectEntities,
48
+ selectAll,
49
+ selectTotal,
50
+ selectById: createSelector(selectEntities, selectId, selectById),
51
+ }
52
+ }
53
+
54
+ const selectGlobalizedEntities = createSelector(
55
+ selectState as Selector<V, EntityState<T, Id>>,
56
+ selectEntities,
57
+ )
58
+
59
+ return {
60
+ selectIds: createSelector(selectState, selectIds),
61
+ selectEntities: selectGlobalizedEntities,
62
+ selectAll: createSelector(selectState, selectAll),
63
+ selectTotal: createSelector(selectState, selectTotal),
64
+ selectById: createSelector(
65
+ selectGlobalizedEntities,
66
+ selectId,
67
+ selectById,
68
+ ),
69
+ }
70
+ }
71
+
72
+ return { getSelectors }
73
+ }