@ngrx-traits/common 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/README.md +7 -0
  2. package/async-action/async-action.model.d.ts +19 -0
  3. package/async-action/async-action.trait.d.ts +59 -0
  4. package/async-action/index.d.ts +2 -0
  5. package/bundles/ngrx-traits-common.umd.js +2126 -0
  6. package/bundles/ngrx-traits-common.umd.js.map +1 -0
  7. package/crud-entities/crud-entities.model.d.ts +76 -0
  8. package/crud-entities/crud-entities.trait.actions.d.ts +2 -0
  9. package/crud-entities/crud-entities.trait.d.ts +35 -0
  10. package/crud-entities/crud-entities.trait.mutators.d.ts +3 -0
  11. package/crud-entities/crud-entities.trait.reducer.d.ts +7 -0
  12. package/crud-entities/crud-entities.trait.selectors.d.ts +3 -0
  13. package/crud-entities/index.d.ts +2 -0
  14. package/entities-pagination/entities-pagination.model.d.ts +82 -0
  15. package/entities-pagination/entities-pagination.model.internal.d.ts +12 -0
  16. package/entities-pagination/entities-pagination.trait.actions.d.ts +2 -0
  17. package/entities-pagination/entities-pagination.trait.d.ts +55 -0
  18. package/entities-pagination/entities-pagination.trait.effects.d.ts +8 -0
  19. package/entities-pagination/entities-pagination.trait.mutators.d.ts +3 -0
  20. package/entities-pagination/entities-pagination.trait.reducer.d.ts +7 -0
  21. package/entities-pagination/entities-pagination.trait.selectors.d.ts +4 -0
  22. package/entities-pagination/index.d.ts +2 -0
  23. package/esm2015/async-action/async-action.model.js +2 -0
  24. package/esm2015/async-action/async-action.model.js.map +1 -0
  25. package/esm2015/async-action/async-action.trait.js +96 -0
  26. package/esm2015/async-action/async-action.trait.js.map +1 -0
  27. package/esm2015/async-action/index.js +3 -0
  28. package/esm2015/async-action/index.js.map +1 -0
  29. package/esm2015/crud-entities/crud-entities.model.js +8 -0
  30. package/esm2015/crud-entities/crud-entities.model.js.map +1 -0
  31. package/esm2015/crud-entities/crud-entities.trait.actions.js +20 -0
  32. package/esm2015/crud-entities/crud-entities.trait.actions.js.map +1 -0
  33. package/esm2015/crud-entities/crud-entities.trait.js +53 -0
  34. package/esm2015/crud-entities/crud-entities.trait.js.map +1 -0
  35. package/esm2015/crud-entities/crud-entities.trait.mutators.js +101 -0
  36. package/esm2015/crud-entities/crud-entities.trait.mutators.js.map +1 -0
  37. package/esm2015/crud-entities/crud-entities.trait.reducer.js +15 -0
  38. package/esm2015/crud-entities/crud-entities.trait.reducer.js.map +1 -0
  39. package/esm2015/crud-entities/crud-entities.trait.selectors.js +70 -0
  40. package/esm2015/crud-entities/crud-entities.trait.selectors.js.map +1 -0
  41. package/esm2015/crud-entities/index.js +3 -0
  42. package/esm2015/crud-entities/index.js.map +1 -0
  43. package/esm2015/entities-pagination/entities-pagination.model.internal.js +2 -0
  44. package/esm2015/entities-pagination/entities-pagination.model.internal.js.map +1 -0
  45. package/esm2015/entities-pagination/entities-pagination.model.js +2 -0
  46. package/esm2015/entities-pagination/entities-pagination.model.js.map +1 -0
  47. package/esm2015/entities-pagination/entities-pagination.trait.actions.js +20 -0
  48. package/esm2015/entities-pagination/entities-pagination.trait.actions.js.map +1 -0
  49. package/esm2015/entities-pagination/entities-pagination.trait.effects.js +54 -0
  50. package/esm2015/entities-pagination/entities-pagination.trait.effects.js.map +1 -0
  51. package/esm2015/entities-pagination/entities-pagination.trait.js +80 -0
  52. package/esm2015/entities-pagination/entities-pagination.trait.js.map +1 -0
  53. package/esm2015/entities-pagination/entities-pagination.trait.mutators.js +23 -0
  54. package/esm2015/entities-pagination/entities-pagination.trait.mutators.js.map +1 -0
  55. package/esm2015/entities-pagination/entities-pagination.trait.reducer.js +33 -0
  56. package/esm2015/entities-pagination/entities-pagination.trait.reducer.js.map +1 -0
  57. package/esm2015/entities-pagination/entities-pagination.trait.selectors.js +65 -0
  58. package/esm2015/entities-pagination/entities-pagination.trait.selectors.js.map +1 -0
  59. package/esm2015/entities-pagination/index.js +3 -0
  60. package/esm2015/entities-pagination/index.js.map +1 -0
  61. package/esm2015/filter-entities/filter-entities.model.internal.js +2 -0
  62. package/esm2015/filter-entities/filter-entities.model.internal.js.map +1 -0
  63. package/esm2015/filter-entities/filter-entities.model.js +2 -0
  64. package/esm2015/filter-entities/filter-entities.model.js.map +1 -0
  65. package/esm2015/filter-entities/filter-entities.trait.actions.js +16 -0
  66. package/esm2015/filter-entities/filter-entities.trait.actions.js.map +1 -0
  67. package/esm2015/filter-entities/filter-entities.trait.effect.js +56 -0
  68. package/esm2015/filter-entities/filter-entities.trait.effect.js.map +1 -0
  69. package/esm2015/filter-entities/filter-entities.trait.js +68 -0
  70. package/esm2015/filter-entities/filter-entities.trait.js.map +1 -0
  71. package/esm2015/filter-entities/filter-entities.trait.mutators.js +7 -0
  72. package/esm2015/filter-entities/filter-entities.trait.mutators.js.map +1 -0
  73. package/esm2015/filter-entities/filter-entities.trait.reducer.js +9 -0
  74. package/esm2015/filter-entities/filter-entities.trait.reducer.js.map +1 -0
  75. package/esm2015/filter-entities/filter-entities.trait.selectors.js +9 -0
  76. package/esm2015/filter-entities/filter-entities.trait.selectors.js.map +1 -0
  77. package/esm2015/filter-entities/index.js +3 -0
  78. package/esm2015/filter-entities/index.js.map +1 -0
  79. package/esm2015/index.js +12 -0
  80. package/esm2015/index.js.map +1 -0
  81. package/esm2015/load-entities/index.js +3 -0
  82. package/esm2015/load-entities/index.js.map +1 -0
  83. package/esm2015/load-entities/load-entities.model.js +2 -0
  84. package/esm2015/load-entities/load-entities.model.js.map +1 -0
  85. package/esm2015/load-entities/load-entities.mutators.js +8 -0
  86. package/esm2015/load-entities/load-entities.mutators.js.map +1 -0
  87. package/esm2015/load-entities/load-entities.trait.actions.js +10 -0
  88. package/esm2015/load-entities/load-entities.trait.actions.js.map +1 -0
  89. package/esm2015/load-entities/load-entities.trait.js +57 -0
  90. package/esm2015/load-entities/load-entities.trait.js.map +1 -0
  91. package/esm2015/load-entities/load-entities.trait.reducer.js +12 -0
  92. package/esm2015/load-entities/load-entities.trait.reducer.js.map +1 -0
  93. package/esm2015/load-entities/load-entities.trait.selectors.js +33 -0
  94. package/esm2015/load-entities/load-entities.trait.selectors.js.map +1 -0
  95. package/esm2015/load-entities/load-entities.utils.js +10 -0
  96. package/esm2015/load-entities/load-entities.utils.js.map +1 -0
  97. package/esm2015/load-entity/index.js +3 -0
  98. package/esm2015/load-entity/index.js.map +1 -0
  99. package/esm2015/load-entity/load-entity.model.js +2 -0
  100. package/esm2015/load-entity/load-entity.model.js.map +1 -0
  101. package/esm2015/load-entity/load-entity.traits.js +65 -0
  102. package/esm2015/load-entity/load-entity.traits.js.map +1 -0
  103. package/esm2015/ngrx-traits-common.js +5 -0
  104. package/esm2015/ngrx-traits-common.js.map +1 -0
  105. package/esm2015/public_api.js +2 -0
  106. package/esm2015/public_api.js.map +1 -0
  107. package/esm2015/reset/index.js +2 -0
  108. package/esm2015/reset/index.js.map +1 -0
  109. package/esm2015/reset/reset.trait.js +66 -0
  110. package/esm2015/reset/reset.trait.js.map +1 -0
  111. package/esm2015/select-entities/index.js +4 -0
  112. package/esm2015/select-entities/index.js.map +1 -0
  113. package/esm2015/select-entities/select-entities.model.js +2 -0
  114. package/esm2015/select-entities/select-entities.model.js.map +1 -0
  115. package/esm2015/select-entities/select-entities.trait.actions.js +11 -0
  116. package/esm2015/select-entities/select-entities.trait.actions.js.map +1 -0
  117. package/esm2015/select-entities/select-entities.trait.js +50 -0
  118. package/esm2015/select-entities/select-entities.trait.js.map +1 -0
  119. package/esm2015/select-entities/select-entities.trait.mutators.js +21 -0
  120. package/esm2015/select-entities/select-entities.trait.mutators.js.map +1 -0
  121. package/esm2015/select-entities/select-entities.trait.reducer.js +40 -0
  122. package/esm2015/select-entities/select-entities.trait.reducer.js.map +1 -0
  123. package/esm2015/select-entities/select-entities.trait.selectors.js +28 -0
  124. package/esm2015/select-entities/select-entities.trait.selectors.js.map +1 -0
  125. package/esm2015/select-entities/select-entities.utils.js +25 -0
  126. package/esm2015/select-entities/select-entities.utils.js.map +1 -0
  127. package/esm2015/select-entity/index.js +3 -0
  128. package/esm2015/select-entity/index.js.map +1 -0
  129. package/esm2015/select-entity/select-entity.model.js +2 -0
  130. package/esm2015/select-entity/select-entity.model.js.map +1 -0
  131. package/esm2015/select-entity/select-entity.trait.actions.js +9 -0
  132. package/esm2015/select-entity/select-entity.trait.actions.js.map +1 -0
  133. package/esm2015/select-entity/select-entity.trait.js +47 -0
  134. package/esm2015/select-entity/select-entity.trait.js.map +1 -0
  135. package/esm2015/select-entity/select-entity.trait.mutators.js +17 -0
  136. package/esm2015/select-entity/select-entity.trait.mutators.js.map +1 -0
  137. package/esm2015/select-entity/select-entity.trait.reducer.js +26 -0
  138. package/esm2015/select-entity/select-entity.trait.reducer.js.map +1 -0
  139. package/esm2015/select-entity/select-entity.trait.selectors.js +13 -0
  140. package/esm2015/select-entity/select-entity.trait.selectors.js.map +1 -0
  141. package/esm2015/set-entity/index.js +3 -0
  142. package/esm2015/set-entity/index.js.map +1 -0
  143. package/esm2015/set-entity/set-entity.model.js +2 -0
  144. package/esm2015/set-entity/set-entity.model.js.map +1 -0
  145. package/esm2015/set-entity/set-entity.trait.js +52 -0
  146. package/esm2015/set-entity/set-entity.trait.js.map +1 -0
  147. package/esm2015/sort-entities/index.js +4 -0
  148. package/esm2015/sort-entities/index.js.map +1 -0
  149. package/esm2015/sort-entities/sort-entities.model.js +2 -0
  150. package/esm2015/sort-entities/sort-entities.model.js.map +1 -0
  151. package/esm2015/sort-entities/sort-entities.trait.actions.js +8 -0
  152. package/esm2015/sort-entities/sort-entities.trait.actions.js.map +1 -0
  153. package/esm2015/sort-entities/sort-entities.trait.effect.js +28 -0
  154. package/esm2015/sort-entities/sort-entities.trait.effect.js.map +1 -0
  155. package/esm2015/sort-entities/sort-entities.trait.js +53 -0
  156. package/esm2015/sort-entities/sort-entities.trait.js.map +1 -0
  157. package/esm2015/sort-entities/sort-entities.trait.mutators.js +13 -0
  158. package/esm2015/sort-entities/sort-entities.trait.mutators.js.map +1 -0
  159. package/esm2015/sort-entities/sort-entities.trait.reducer.js +22 -0
  160. package/esm2015/sort-entities/sort-entities.trait.reducer.js.map +1 -0
  161. package/esm2015/sort-entities/sort-entities.trait.selectors.js +10 -0
  162. package/esm2015/sort-entities/sort-entities.trait.selectors.js.map +1 -0
  163. package/esm2015/sort-entities/sort-entities.utils.js +61 -0
  164. package/esm2015/sort-entities/sort-entities.utils.js.map +1 -0
  165. package/fesm2015/ngrx-traits-common.js +1511 -0
  166. package/fesm2015/ngrx-traits-common.js.map +1 -0
  167. package/filter-entities/filter-entities.model.d.ts +57 -0
  168. package/filter-entities/filter-entities.model.internal.d.ts +14 -0
  169. package/filter-entities/filter-entities.trait.actions.d.ts +2 -0
  170. package/filter-entities/filter-entities.trait.d.ts +42 -0
  171. package/filter-entities/filter-entities.trait.effect.d.ts +6 -0
  172. package/filter-entities/filter-entities.trait.mutators.d.ts +2 -0
  173. package/filter-entities/filter-entities.trait.reducer.d.ts +5 -0
  174. package/filter-entities/filter-entities.trait.selectors.d.ts +4 -0
  175. package/filter-entities/index.d.ts +2 -0
  176. package/index.d.ts +11 -0
  177. package/load-entities/index.d.ts +2 -0
  178. package/load-entities/load-entities.model.d.ts +97 -0
  179. package/load-entities/load-entities.mutators.d.ts +3 -0
  180. package/load-entities/load-entities.trait.actions.d.ts +2 -0
  181. package/load-entities/load-entities.trait.d.ts +39 -0
  182. package/load-entities/load-entities.trait.reducer.d.ts +4 -0
  183. package/load-entities/load-entities.trait.selectors.d.ts +3 -0
  184. package/load-entities/load-entities.utils.d.ts +4 -0
  185. package/load-entity/index.d.ts +2 -0
  186. package/load-entity/load-entity.model.d.ts +9 -0
  187. package/load-entity/load-entity.traits.d.ts +64 -0
  188. package/ngrx-traits-common.d.ts +5 -0
  189. package/package.json +28 -0
  190. package/public_api.d.ts +1 -0
  191. package/reset/index.d.ts +1 -0
  192. package/reset/reset.trait.d.ts +32 -0
  193. package/select-entities/index.d.ts +3 -0
  194. package/select-entities/select-entities.model.d.ts +41 -0
  195. package/select-entities/select-entities.trait.actions.d.ts +2 -0
  196. package/select-entities/select-entities.trait.d.ts +34 -0
  197. package/select-entities/select-entities.trait.mutators.d.ts +2 -0
  198. package/select-entities/select-entities.trait.reducer.d.ts +8 -0
  199. package/select-entities/select-entities.trait.selectors.d.ts +3 -0
  200. package/select-entities/select-entities.utils.d.ts +7 -0
  201. package/select-entity/index.d.ts +2 -0
  202. package/select-entity/select-entity.model.d.ts +33 -0
  203. package/select-entity/select-entity.trait.actions.d.ts +2 -0
  204. package/select-entity/select-entity.trait.d.ts +30 -0
  205. package/select-entity/select-entity.trait.mutators.d.ts +2 -0
  206. package/select-entity/select-entity.trait.reducer.d.ts +8 -0
  207. package/select-entity/select-entity.trait.selectors.d.ts +2 -0
  208. package/set-entity/index.d.ts +2 -0
  209. package/set-entity/set-entity.model.d.ts +16 -0
  210. package/set-entity/set-entity.trait.d.ts +39 -0
  211. package/sort-entities/index.d.ts +3 -0
  212. package/sort-entities/sort-entities.model.d.ts +35 -0
  213. package/sort-entities/sort-entities.trait.actions.d.ts +2 -0
  214. package/sort-entities/sort-entities.trait.d.ts +33 -0
  215. package/sort-entities/sort-entities.trait.effect.d.ts +6 -0
  216. package/sort-entities/sort-entities.trait.mutators.d.ts +3 -0
  217. package/sort-entities/sort-entities.trait.reducer.d.ts +4 -0
  218. package/sort-entities/sort-entities.trait.selectors.d.ts +2 -0
  219. package/sort-entities/sort-entities.utils.d.ts +8 -0
@@ -0,0 +1,1511 @@
1
+ import * as i2 from '@ngrx/store';
2
+ import { createReducer, on, createAction, props, createSelector } from '@ngrx/store';
3
+ import { insertIf, createTraitFactory, TraitEffect, toMap, camelCaseToSentence, capitalize } from '@ngrx-traits/core';
4
+ import { createEntityAdapter } from '@ngrx/entity';
5
+ import * as i0 from '@angular/core';
6
+ import { Injectable } from '@angular/core';
7
+ import { asyncScheduler, EMPTY, timer, of, pipe } from 'rxjs';
8
+ import { debounce, concatMap, first, map, distinctUntilChanged, startWith, pairwise, concatMapTo, filter, mapTo } from 'rxjs/operators';
9
+ import * as i1 from '@ngrx/effects';
10
+ import { createEffect, ofType, concatLatestFrom } from '@ngrx/effects';
11
+ import { __rest } from 'tslib';
12
+
13
+ const loadEntitiesTraitKey = 'loadEntities';
14
+
15
+ function createLoadEntitiesInitialState(previousInitialState = {}, allConfigs) {
16
+ const traitConfig = allConfigs.loadEntities;
17
+ const adapter = traitConfig.adapter;
18
+ return Object.assign(Object.assign(Object.assign({}, previousInitialState), adapter.getInitialState()), { status: undefined });
19
+ }
20
+ function createLoadEntitiesTraitReducer(initialState, actions, allMutators, allConfigs) {
21
+ const handleEntitiesMerge = !(allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.pagination);
22
+ return createReducer(initialState, on(actions.loadEntities, (state) => (Object.assign(Object.assign({}, state), { status: 'loading' }))), on(actions.loadEntitiesFail, (state) => (Object.assign(Object.assign({}, state), { status: 'fail' }))), on(actions.loadEntitiesSuccess, (state) => (Object.assign(Object.assign({}, state), { status: 'success' }))), ...insertIf(handleEntitiesMerge, () => on(actions.loadEntitiesSuccess, (state, { entities }) => allMutators.setEntitiesList(entities, Object.assign({}, state)))));
23
+ }
24
+
25
+ function createLoadEntitiesTraitMutators(allConfigs) {
26
+ var _a;
27
+ const adapter = (_a = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.loadEntities) === null || _a === void 0 ? void 0 : _a.adapter;
28
+ return {
29
+ setEntitiesList: adapter === null || adapter === void 0 ? void 0 : adapter.setAll,
30
+ };
31
+ }
32
+
33
+ function createLoadEntitiesTraitActions(actionsGroupKey, entitiesName) {
34
+ const actions = {
35
+ loadEntities: createAction(`${actionsGroupKey} Load ${entitiesName}`),
36
+ loadEntitiesSuccess: createAction(`${actionsGroupKey} Load ${entitiesName} Success`, props()),
37
+ loadEntitiesFail: createAction(`${actionsGroupKey} Load ${entitiesName} Fail`, (props) => ({ error: props === null || props === void 0 ? void 0 : props.error })),
38
+ };
39
+ return actions;
40
+ }
41
+
42
+ function isLoading(state) {
43
+ return state.status === 'loading';
44
+ }
45
+ function isSuccess(state) {
46
+ return state.status === 'success';
47
+ }
48
+ function isFail(state) {
49
+ return state.status === 'fail';
50
+ }
51
+
52
+ function selectEntitiesFilter(state) {
53
+ return state.filters;
54
+ }
55
+ function createFilterTraitSelectors() {
56
+ return {
57
+ selectEntitiesFilter,
58
+ };
59
+ }
60
+
61
+ function createLoadEntitiesTraitSelectors(allConfigs) {
62
+ var _a, _b;
63
+ const adapter = (_a = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.loadEntities) === null || _a === void 0 ? void 0 : _a.adapter;
64
+ const entitySelectors = adapter.getSelectors();
65
+ const filterFunction = (_b = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.filter) === null || _b === void 0 ? void 0 : _b.filterFn;
66
+ let selectors = {
67
+ selectEntitiesList: entitySelectors.selectAll,
68
+ selectEntitiesMap: entitySelectors.selectEntities,
69
+ selectEntitiesIdsList: entitySelectors.selectIds,
70
+ selectEntitiesTotal: entitySelectors.selectTotal,
71
+ isEntitiesLoadingFail: isFail,
72
+ isEntitiesLoading: isLoading,
73
+ isEntitiesLoadingSuccess: isSuccess,
74
+ };
75
+ if (filterFunction && entitySelectors) {
76
+ const selectEntitiesList = createSelector(entitySelectors.selectAll, selectEntitiesFilter, (entities, filters) => filters ? entities.filter((e) => filterFunction(filters, e)) : entities);
77
+ selectors = Object.assign(Object.assign({}, selectors), { selectEntitiesList, selectEntitiesMap: createSelector(selectors.selectEntitiesMap, selectEntitiesFilter, (entities, filters) => {
78
+ const result = {};
79
+ for (const id in entities) {
80
+ const e = entities[id];
81
+ if (filterFunction(filters, e)) {
82
+ result[id] = e;
83
+ }
84
+ }
85
+ return result;
86
+ }), selectEntitiesTotal: createSelector(selectEntitiesList, (entities) => entities.length), selectEntitiesIdsList: createSelector(selectEntitiesList, (entities) => entities.map((e) => adapter === null || adapter === void 0 ? void 0 : adapter.selectId(e))) });
87
+ }
88
+ return selectors;
89
+ }
90
+
91
+ /**
92
+ * Generates the ngrx code needed to load a list of entities from the backend
93
+ * with a load[EntitiesName], load[EntitiesName]Success, load[EntitiesName]Fail actions, and selectors to query the
94
+ * entities like selectEntity[EntitiesName]List, selectEntity[EntitiesName]Ids, selectEntity[EntitiesName]Map, and its progress loading
95
+ * with isLoading[EntitiesName],isLoading[EntitiesName]Success, isLoading[EntitiesName]Fail. This trait is the base for all other traits related
96
+ * to a list of entities, the other will call loadEntities when needing data.
97
+ * @param traitConfig - Config object fot the trait factory
98
+ * @param traitConfig.selectId - Function that returns the id of an entity
99
+ * @param traitConfig.sortComparer - Default sort function for to @ngrx/entity EntityAdapter
100
+ *
101
+ * @example
102
+ * // The following trait config
103
+ *
104
+ * export interface TestState
105
+ * extends LoadEntitiesState<Todo>{}
106
+ *
107
+ * const traits = createEntityFeatureFactory(
108
+ * {entityName: 'Todo'},
109
+ * addLoadEntitiesTrait<Todo>(),
110
+ * )({
111
+ * actionsGroupKey: '[Todos]',
112
+ * featureSelector: createFeatureSelector<TestState>>(
113
+ * 'todos',
114
+ * ),
115
+ * });
116
+ * // will generate the actions and selectors
117
+ * traits.actions.loadTodos()
118
+ * traits.actions.loadTodosSuccess({entities: todos})
119
+ * traits.actions.loadTodosFail();
120
+ * traits.selectors.selectTodosList
121
+ * traits.selectors.selectTodosMap
122
+ * traits.selectors.selectTodosIds
123
+ * traits.selectors.selectTodosTotal
124
+ * traits.selectors.isLoadingTodos
125
+ * traits.selectors.isSuccessTodosSuccess
126
+ * traits.selectors.isFailTodosFail
127
+ */
128
+ function addLoadEntitiesTrait(traitConfig) {
129
+ const adapter = createEntityAdapter(traitConfig);
130
+ return createTraitFactory({
131
+ key: loadEntitiesTraitKey,
132
+ config: Object.assign(Object.assign({}, traitConfig), { adapter }),
133
+ actions: ({ actionsGroupKey, entitiesName }) => createLoadEntitiesTraitActions(actionsGroupKey, entitiesName),
134
+ selectors: ({ allConfigs }) => createLoadEntitiesTraitSelectors(allConfigs),
135
+ mutators: ({ allConfigs }) => createLoadEntitiesTraitMutators(allConfigs),
136
+ initialState: ({ previousInitialState, allConfigs, }) => createLoadEntitiesInitialState(previousInitialState, allConfigs),
137
+ reducer: ({ initialState, allActions, allMutators, allConfigs }) => createLoadEntitiesTraitReducer(initialState, allActions, allMutators, allConfigs),
138
+ });
139
+ }
140
+
141
+ const entitiesPaginationTraitKey = 'pagination';
142
+
143
+ function createFilterTraitEffects(allActions, allSelectors, allConfigs) {
144
+ const traitConfig = allConfigs.filter;
145
+ class FilterEffect extends TraitEffect {
146
+ constructor() {
147
+ super(...arguments);
148
+ this.storeFilter$ = createEffect(() => ({ debounce: debounceTime = traitConfig.defaultDebounceTime, scheduler = asyncScheduler, } = {}) => this.actions$.pipe(ofType(allActions.filterEntities), debounce((value) => (value === null || value === void 0 ? void 0 : value.forceLoad) ? EMPTY : timer(debounceTime, scheduler)), concatMap((payload) => payload.patch
149
+ ? this.store.select(allSelectors.selectEntitiesFilter).pipe(first(), map((storedFilters) => (Object.assign(Object.assign({}, payload), { filters: Object.assign(Object.assign({}, storedFilters), payload === null || payload === void 0 ? void 0 : payload.filters) }))))
150
+ : of(payload)), distinctUntilChanged((previous, current) => !(current === null || current === void 0 ? void 0 : current.forceLoad) &&
151
+ JSON.stringify(previous === null || previous === void 0 ? void 0 : previous.filters) ===
152
+ JSON.stringify(current === null || current === void 0 ? void 0 : current.filters)), (traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.isRemoteFilter)
153
+ ? pipe(startWith({
154
+ filters: traitConfig.defaultFilter,
155
+ patch: false,
156
+ }), pairwise(), concatMap(([previous, current]) => (traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.isRemoteFilter(previous === null || previous === void 0 ? void 0 : previous.filters, current === null || current === void 0 ? void 0 : current.filters))
157
+ ? [
158
+ allActions.storeEntitiesFilter({
159
+ filters: current === null || current === void 0 ? void 0 : current.filters,
160
+ patch: current === null || current === void 0 ? void 0 : current.patch,
161
+ }),
162
+ allActions.loadEntities(),
163
+ ]
164
+ : [
165
+ allActions.storeEntitiesFilter({
166
+ filters: current === null || current === void 0 ? void 0 : current.filters,
167
+ patch: current === null || current === void 0 ? void 0 : current.patch,
168
+ }),
169
+ ]))
170
+ : map((action) => allActions.storeEntitiesFilter({
171
+ filters: action === null || action === void 0 ? void 0 : action.filters,
172
+ patch: action === null || action === void 0 ? void 0 : action.patch,
173
+ }))));
174
+ this.loadEntities$ = (!(traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.filterFn) || (traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.isRemoteFilter)) &&
175
+ createEffect(() => {
176
+ return this.actions$.pipe(ofType(allActions['storeEntitiesFilter']), concatMap(() => (allActions === null || allActions === void 0 ? void 0 : allActions.loadEntitiesFirstPage)
177
+ ? [
178
+ allActions.clearEntitiesPagesCache(),
179
+ allActions.loadEntitiesFirstPage(),
180
+ ]
181
+ : [allActions.loadEntities()]));
182
+ });
183
+ }
184
+ }
185
+ FilterEffect.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: FilterEffect, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
186
+ FilterEffect.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: FilterEffect });
187
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: FilterEffect, decorators: [{
188
+ type: Injectable
189
+ }] });
190
+ return [FilterEffect];
191
+ }
192
+
193
+ function createFilterInitialState(previousInitialState, allConfigs) {
194
+ var _a;
195
+ return Object.assign(Object.assign({}, previousInitialState), { filters: (_a = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.filter) === null || _a === void 0 ? void 0 : _a.defaultFilter });
196
+ }
197
+ function createFilterTraitReducer(initialState, allActions, allMutators) {
198
+ return createReducer(initialState, on(allActions.storeEntitiesFilter, (state, { filters }) => allMutators.setEntitiesFilters(filters, state)));
199
+ }
200
+
201
+ const filterEntitiesTraitKey = 'filter';
202
+
203
+ function createFilterTraitMutators() {
204
+ function setEntitiesFilters(filters, state) {
205
+ return Object.assign(Object.assign({}, state), { filters });
206
+ }
207
+ return { setEntitiesFilters };
208
+ }
209
+
210
+ function createFilterTraitActions(actionsGroupKey, entitiesName) {
211
+ const actions = {
212
+ filterEntities: createAction(`${actionsGroupKey} Filter ${entitiesName}`, (props) => ({
213
+ filters: props === null || props === void 0 ? void 0 : props.filters,
214
+ forceLoad: props === null || props === void 0 ? void 0 : props.forceLoad,
215
+ patch: props === null || props === void 0 ? void 0 : props.patch,
216
+ })),
217
+ storeEntitiesFilter: createAction(`${actionsGroupKey} Store ${entitiesName} Filter`, (props) => ({
218
+ filters: props === null || props === void 0 ? void 0 : props.filters,
219
+ patch: props === null || props === void 0 ? void 0 : props.patch,
220
+ })),
221
+ };
222
+ return actions;
223
+ }
224
+
225
+ /**
226
+ * Generates the ngrx code needed to filter a list of entities locally or remotely, adds a filter
227
+ * action and a selectFilter selector, the filter action is debounced and the filter will only
228
+ * call the loadEntities action if the params have changed, so there is no need to implement that in
229
+ * the components. The filter action has a `forceLoad` param which can
230
+ * be use to skip that restriction for one call or setting the `defaultDebounceTime` to 0 for all calls.
231
+ * Calling the filter action will also replace the `filters` param in the store, if the `patch` param is set
232
+ * the filters are merged with the previous value in the store.
233
+ * @param traitConfig - Config object fot the trait factory
234
+ * @param traitConfig.defaultFilter - Initial value for the filter
235
+ * @param traitConfig.filterFn - Function to filter entities in memory, if not present then its expected
236
+ * is filtered by the backend unless isRemoteFilter is defned
237
+ * @param traitConfig.defaultDebounceTime - Value in milliseconds. Default to 400ms
238
+ * @param traitConfig.isRemoteFilter - Function to when it returns true it fires loadEntities so a remote
239
+ * backend filtering can run, otherwise it uses filterFn to do a local filtering
240
+ *
241
+ * @example
242
+ * // The following trait config
243
+ *
244
+ * export interface TestState
245
+ * extends EntityAndStatusState<Todo>,FilterState<TodoFilter>{}
246
+ *
247
+ * const traits = createEntityFeatureFactory(
248
+ * addLoadEntitiesTrait<Todo>(),
249
+ * //addFilterEntitiesTrait<Todo,TodoFilter>() // no params uses remote filtering
250
+ * addFilterEntitiesTrait<Todo,TodoFilter>({filterFn: (filter, entity) => // local filtering
251
+ * filter?.content && entity.content?.includes(filter?.content) || false})
252
+ * // or use the following function to switch between remote search and local
253
+ * // depending on which properties have changed in the filter
254
+ * // isRemoteFilter: (previous, current) => previous?.someRemoteParam !== current?.someRemoteParam,
255
+ * )({
256
+ * actionsGroupKey: '[Todos]',
257
+ * featureSelector: createFeatureSelector<TestState>>(
258
+ * 'todos',
259
+ * ),
260
+ * });
261
+ * // will generate the following actions and selectors, plus the ones generated by other traits
262
+ * traits.actions.filterTodos()
263
+ * traits.selectors.selectTodosFilter()
264
+ */
265
+ function addFilterEntitiesTrait({ defaultDebounceTime = 400, defaultFilter, filterFn, isRemoteFilter, } = {}) {
266
+ return createTraitFactory({
267
+ key: filterEntitiesTraitKey,
268
+ depends: [entitiesPaginationTraitKey, loadEntitiesTraitKey],
269
+ config: {
270
+ defaultDebounceTime,
271
+ defaultFilter,
272
+ filterFn,
273
+ isRemoteFilter,
274
+ },
275
+ actions: ({ actionsGroupKey, entitiesName }) => createFilterTraitActions(actionsGroupKey, entitiesName),
276
+ selectors: () => createFilterTraitSelectors(),
277
+ mutators: () => createFilterTraitMutators(),
278
+ initialState: ({ previousInitialState, allConfigs, }) => createFilterInitialState(previousInitialState, allConfigs),
279
+ reducer: ({ initialState, allActions, allMutators }) => createFilterTraitReducer(initialState, allActions, allMutators),
280
+ effects: ({ allActions, allSelectors, allConfigs }) => createFilterTraitEffects(allActions, allSelectors, allConfigs),
281
+ });
282
+ }
283
+
284
+ function createPaginationTraitSelectors(previousSelectors, allConfigs) {
285
+ var _a;
286
+ const { selectEntitiesList, isEntitiesLoading } = previousSelectors;
287
+ const filterFunction = (_a = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.filter) === null || _a === void 0 ? void 0 : _a.filterFn;
288
+ function selectPagination(state) {
289
+ return state.pagination;
290
+ }
291
+ const selectPaginationFiltered = filterFunction
292
+ ? createSelector(selectEntitiesList, selectPagination, (entities, pagination) => {
293
+ return Object.assign(Object.assign({}, pagination), { total: entities.length, cache: Object.assign(Object.assign({}, pagination.cache), { start: 0, end: entities.length }) });
294
+ })
295
+ : selectPagination;
296
+ const selectPageEntitiesList = createSelector(selectEntitiesList, selectPaginationFiltered, (entities, pagination, { page } = { page: pagination.currentPage }) => {
297
+ const startIndex = page * pagination.pageSize - pagination.cache.start;
298
+ let endIndex = startIndex + pagination.pageSize;
299
+ endIndex =
300
+ endIndex < pagination.cache.end ? endIndex : pagination.cache.end;
301
+ return entities.slice(startIndex, endIndex);
302
+ });
303
+ const selectEntitiesPageInfo = createSelector(selectPaginationFiltered, (pagination) => {
304
+ const pagesCount = pagination.total && pagination.total > 0
305
+ ? Math.ceil(pagination.total / pagination.pageSize)
306
+ : undefined;
307
+ return {
308
+ pageIndex: pagination.currentPage,
309
+ total: pagination.total,
310
+ pageSize: pagination.pageSize,
311
+ pagesCount,
312
+ hasPrevious: pagination.currentPage - 1 >= 0,
313
+ hasNext: pagination.total && pagination.total > 0
314
+ ? pagination.currentPage + 1 < pagesCount
315
+ : true,
316
+ cacheType: pagination.cache.type,
317
+ };
318
+ });
319
+ const isEntitiesPageInCache = createSelector(selectPaginationFiltered, (pagination, { page } = { page: pagination.currentPage }) => {
320
+ const startIndex = page * pagination.pageSize;
321
+ let endIndex = startIndex + pagination.pageSize - 1;
322
+ endIndex =
323
+ pagination.total && endIndex > pagination.total
324
+ ? pagination.total - 1
325
+ : endIndex;
326
+ return (startIndex >= pagination.cache.start && endIndex <= pagination.cache.end);
327
+ });
328
+ const selectEntitiesPage = createSelector(selectPageEntitiesList, selectEntitiesPageInfo,
329
+ // props look unsued but they are pass to the selectPageEntities
330
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
331
+ (entities, pageInfo, props = { page: pageInfo.pageIndex }) => (Object.assign({ entities }, pageInfo)));
332
+ const selectEntitiesPagedRequest = createSelector(selectPagination, (pagination) => ({
333
+ startIndex: pagination.pageSize * pagination.requestPage,
334
+ size: pagination.pageSize * pagination.pagesToCache,
335
+ page: pagination.requestPage,
336
+ }));
337
+ const isLoadingEntitiesPage = createSelector(isEntitiesLoading, selectPagination, (isLoading, pagination) => isLoading && pagination.requestPage === pagination.currentPage);
338
+ return {
339
+ selectPageEntitiesList,
340
+ isEntitiesPageInCache,
341
+ selectEntitiesPage,
342
+ selectEntitiesPagedRequest,
343
+ selectEntitiesPageInfo,
344
+ isLoadingEntitiesPage,
345
+ };
346
+ }
347
+
348
+ function createPaginationTraitActions(actionsGroupKey, entitiesName) {
349
+ const actions = {
350
+ loadEntitiesPage: createAction(`${actionsGroupKey} Load ${entitiesName} Page`, ({ index, forceLoad }) => ({
351
+ index,
352
+ forceLoad,
353
+ })),
354
+ loadEntitiesPageSuccess: createAction(`${actionsGroupKey} Load ${entitiesName}
355
+ Page Success`),
356
+ loadEntitiesPageFail: createAction(`${actionsGroupKey} Load ${entitiesName} Page Fail`),
357
+ loadEntitiesPreviousPage: createAction(`${actionsGroupKey} Load Previous ${entitiesName} Page`),
358
+ loadEntitiesNextPage: createAction(`${actionsGroupKey} Load Next ${entitiesName} Page`),
359
+ loadEntitiesFirstPage: createAction(`${actionsGroupKey} Load First ${entitiesName} Page`, (forceLoad) => ({ forceLoad })),
360
+ loadEntitiesLastPage: createAction(`${actionsGroupKey} Load Last ${entitiesName} Page`),
361
+ clearEntitiesPagesCache: createAction(`${actionsGroupKey} Clear ${entitiesName} Cache`),
362
+ setEntitiesRequestPage: createAction(`${actionsGroupKey} Set ${entitiesName} Request Page`, props()),
363
+ };
364
+ return actions;
365
+ }
366
+
367
+ function createPaginationInitialState(previousInitialState, allConfigs) {
368
+ const { currentPage, pageSize, cacheType, pagesToCache } = allConfigs.pagination;
369
+ return Object.assign(Object.assign({}, previousInitialState), { pagination: {
370
+ pageSize,
371
+ currentPage,
372
+ requestPage: currentPage,
373
+ pagesToCache,
374
+ cache: {
375
+ type: cacheType,
376
+ start: 0,
377
+ end: 0,
378
+ },
379
+ } });
380
+ }
381
+ function createPaginationTraitReducer(initialState, allActions, allSelectors, allMutators, allConfigs) {
382
+ var _a;
383
+ function addToCacheTotal(state, add) {
384
+ var _a;
385
+ return Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { total: ((_a = state.pagination.total) !== null && _a !== void 0 ? _a : 0) + add }) });
386
+ }
387
+ function clearPagesCache(state) {
388
+ return Object.assign(Object.assign({}, state), { entities: {}, ids: [], pagination: Object.assign(Object.assign({}, state.pagination), { currentPage: 0, total: 0, cache: Object.assign(Object.assign({}, state.pagination.cache), { start: 0, end: 0 }) }) });
389
+ }
390
+ function recalculateTotal(state) {
391
+ const total = allSelectors.selectEntitiesTotal(state);
392
+ return Object.assign(Object.assign({}, state), { status: 'success', pagination: Object.assign(Object.assign({}, state.pagination), { currentPage: 0, total, cache: Object.assign(Object.assign({}, state.pagination.cache), { start: 0, end: total }) }) });
393
+ }
394
+ const filterRemote = !((_a = allConfigs === null || allConfigs === void 0 ? void 0 : allConfigs.filter) === null || _a === void 0 ? void 0 : _a.filterFn);
395
+ return createReducer(initialState, on(allActions.loadEntitiesPage, (state, { index }) => (Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { currentPage: index, requestPage: index }), status: 'loading' }))), on(allActions.setEntitiesRequestPage, (state, { index }) => (Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { requestPage: index }), status: 'loading' }))), on(allActions.loadEntitiesPageSuccess, (state) => (Object.assign(Object.assign({}, state), { status: 'success' }))), on(allActions.loadEntitiesPageFail, (state) => (Object.assign(Object.assign({}, state), { status: 'fail' }))), on(allActions.clearEntitiesPagesCache, (state) => clearPagesCache(state)), on(allActions.loadEntitiesSuccess, (state, { entities, total }) => allMutators.mergePaginatedEntities(entities, total, Object.assign(Object.assign({}, state), { status: 'success' }))), ...insertIf(allActions.addEntities, () => on(allActions.addEntities, (state, { entities }) => addToCacheTotal(state, entities.length))), ...insertIf(allActions.removeEntities, () => on(allActions.removeEntities, (state, { keys }) => addToCacheTotal(state, -keys.length))), ...insertIf(filterRemote && allActions.filterEntities, () => on(allActions.filterEntities, (state) => recalculateTotal(state))), ...insertIf(allActions.removeAllEntities, () => on(allActions.removeAllEntities, (state) => clearPagesCache(state))));
396
+ }
397
+
398
+ function createPaginationTraitEffects(allActions, allSelectors) {
399
+ class PaginationEffect extends TraitEffect {
400
+ constructor() {
401
+ super(...arguments);
402
+ this.loadPage$ = createEffect(() => {
403
+ return this.actions$.pipe(ofType(allActions.loadEntitiesPage), concatLatestFrom(() => this.store.select(allSelectors.isEntitiesPageInCache)), map(([{ forceLoad }, isInCache]) => !forceLoad && isInCache
404
+ ? allActions.loadEntitiesPageSuccess()
405
+ : allActions.loadEntities()));
406
+ });
407
+ this.preloadNextPage$ = createEffect(() => {
408
+ return this.actions$.pipe(ofType(allActions.loadEntitiesPageSuccess), concatMapTo(this.store.select(allSelectors.selectEntitiesPageInfo).pipe(first())), filter((pageInfo) => !!pageInfo.total &&
409
+ pageInfo.hasNext &&
410
+ pageInfo.cacheType !== 'full'), concatMap((pageInfo) => this.store
411
+ .select(allSelectors.isEntitiesPageInCache, {
412
+ page: pageInfo.pageIndex + 1,
413
+ })
414
+ .pipe(first(), map((isInCache) => (!isInCache && pageInfo) || undefined))), filter((pageInfo) => !!pageInfo), concatMap((pageInfo) => [
415
+ allActions.setEntitiesRequestPage({ index: pageInfo.pageIndex + 1 }),
416
+ allActions.loadEntities(),
417
+ ]));
418
+ });
419
+ this.loadFirstPage$ = createEffect(() => {
420
+ return this.actions$.pipe(ofType(allActions.loadEntitiesFirstPage), map(() => allActions.loadEntitiesPage({ index: 0 })));
421
+ });
422
+ this.loadPreviousPage$ = createEffect(() => {
423
+ return this.actions$.pipe(ofType(allActions.loadEntitiesPreviousPage), concatMapTo(this.store.select(allSelectors.selectEntitiesPageInfo).pipe(first())), map((page) => page.hasPrevious
424
+ ? allActions.loadEntitiesPage({ index: page.pageIndex - 1 })
425
+ : allActions.loadEntitiesPageFail()));
426
+ });
427
+ this.loadNextPage$ = createEffect(() => {
428
+ return this.actions$.pipe(ofType(allActions.loadEntitiesNextPage), concatMapTo(this.store.select(allSelectors.selectEntitiesPageInfo).pipe(first())), map((page) => page.hasNext
429
+ ? allActions.loadEntitiesPage({ index: page.pageIndex + 1 })
430
+ : allActions.loadEntitiesPageFail()));
431
+ });
432
+ this.loadLastPage$ = createEffect(() => {
433
+ return this.actions$.pipe(ofType(allActions.loadEntitiesLastPage), concatMapTo(this.store.select(allSelectors.selectEntitiesPageInfo).pipe(first())), map((page) => page.hasNext && page.pagesCount
434
+ ? allActions.loadEntitiesPage({ index: page.pagesCount - 1 })
435
+ : allActions.loadEntitiesPageFail()));
436
+ });
437
+ }
438
+ }
439
+ PaginationEffect.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: PaginationEffect, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
440
+ PaginationEffect.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: PaginationEffect });
441
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: PaginationEffect, decorators: [{
442
+ type: Injectable
443
+ }] });
444
+ return [PaginationEffect];
445
+ }
446
+
447
+ function createPaginationTraitMutators(allSelectors, allConfigs) {
448
+ const adapter = allConfigs.loadEntities.adapter;
449
+ function mergePaginatedEntities(entities, total = undefined, state) {
450
+ const cacheType = state.pagination.cache.type;
451
+ switch (cacheType) {
452
+ case 'full':
453
+ return adapter.setAll(entities, Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { total: entities.length, cache: Object.assign(Object.assign({}, state.pagination.cache), { start: 0, end: entities.length }) }) }));
454
+ case 'partial': {
455
+ const isPreloadNextPages = state.pagination.currentPage + 1 === state.pagination.requestPage;
456
+ const start = state.pagination.currentPage * state.pagination.pageSize;
457
+ const newEntities = isPreloadNextPages
458
+ ? [...allSelectors.selectPageEntitiesList(state), ...entities]
459
+ : entities;
460
+ return adapter.setAll(newEntities, Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { total, cache: Object.assign(Object.assign({}, state.pagination.cache), { start, end: start + entities.length }) }) }));
461
+ }
462
+ case 'grow':
463
+ return adapter.addMany(entities, Object.assign(Object.assign({}, state), { pagination: Object.assign(Object.assign({}, state.pagination), { total, cache: Object.assign(Object.assign({}, state.pagination.cache), { end: state.ids.length + entities.length }) }) }));
464
+ }
465
+ return state;
466
+ }
467
+ return { mergePaginatedEntities };
468
+ }
469
+
470
+ /**
471
+ * Generates ngrx code to paginate an list of entities, this has 3 cache `cacheType`
472
+ * - 'full': The full result is cache in memory and split in pages to render, useful
473
+ * for small result but not so small that requires been render in pages
474
+ * - 'partial': Backend returns partial results because is are to big, this has a cache a few pages forward
475
+ * to avoid calling the backend on each page, the cache is clean when a new loadEntities is required
476
+ * - 'grow': Similar to partial that the backend returns partial result, but in this case the cache grows,
477
+ * after each loadEntities the cache is appended to the previous cache, this mode is ideal for infinite scrolls,
478
+ * where you will only call loadNextPage.
479
+ * To make the pagination experience smoother the loadEntities to get new pages is done when the current page is change to
480
+ * the last cached page.
481
+ * @param config
482
+ * @param config.cacheType - Default to 'full', change the cache mode
483
+ * @param config.pageSize - Default to 20, number of entities on each page
484
+ * @param config.currentPage - Default to 0, starting page
485
+ * @param config.pagesToCache - Default to 3, used in partial and grow cache mode, is the number of
486
+ * extra pages kept in cache to avoid calling the backend on each page
487
+ *
488
+ * @example
489
+ * // The following trait config
490
+ *
491
+ * export interface TestState
492
+ * extends EntityAndStatusState<Todo>,SingleSelectionState{}
493
+ *
494
+ * const traits = createEntityFeatureFactory(
495
+ * addLoadEntitiesTrait<Todo>(),
496
+ * addEntitiesPaginationTrait<Todo>()
497
+ * )({
498
+ * actionsGroupKey: '[Todos]',
499
+ * featureSelector: createFeatureSelector<TestState>>(
500
+ * 'todos',
501
+ * ),
502
+ * });
503
+ * // will generate the following actions and selectors, plus the ones generated by other traits
504
+ * traits.actions.loadTodosPage({index})
505
+ * traits.actions.loadTodosPageSuccess()
506
+ * traits.actions.loadTodosPageFail()
507
+ * traits.actions.loadTodosNextPage()
508
+ * traits.actions.loadTodosPreviousPage()
509
+ * traits.actions.loadTodosFirstPage()
510
+ * traits.actions.loadTodosLastPage()
511
+ * traits.actions.clearTodosPagesCache()
512
+ *
513
+ * // page param is optional and defaults to current page
514
+ * traits.selectors.isTodosPageInCache({page})
515
+ * traits.selectors.selectPageTodosList({page})
516
+ * traits.selectors.isLoadingTodosPage({page})
517
+ * // prefer isLoadingTodosPage over isLoadingTodos which will return true even
518
+ * // if the page loading is not the current one
519
+ * traits.selectors.selectTodosPage({page})
520
+ * traits.selectors.selectTodosPagedRequest()// use in effects to get paging parameter
521
+ * traits.selectors.selectTodosPageInfo()
522
+ */
523
+ function addEntitiesPaginationTrait({ cacheType = 'full', pageSize = 20, currentPage = 0, pagesToCache = 3, } = {}) {
524
+ return createTraitFactory({
525
+ key: entitiesPaginationTraitKey,
526
+ depends: [loadEntitiesTraitKey],
527
+ config: {
528
+ cacheType,
529
+ pageSize,
530
+ currentPage,
531
+ pagesToCache,
532
+ },
533
+ actions: ({ actionsGroupKey, entitiesName }) => createPaginationTraitActions(actionsGroupKey, entitiesName),
534
+ selectors: ({ previousSelectors, allConfigs, }) => createPaginationTraitSelectors(previousSelectors, allConfigs),
535
+ mutators: ({ allSelectors, allConfigs }) => createPaginationTraitMutators(allSelectors, allConfigs),
536
+ initialState: ({ previousInitialState, allConfigs, }) => createPaginationInitialState(previousInitialState, allConfigs),
537
+ reducer: ({ initialState, allActions, allSelectors, allMutators, allConfigs, }) => createPaginationTraitReducer(initialState, allActions, allSelectors, allMutators, allConfigs),
538
+ effects: ({ allActions, allSelectors }) => createPaginationTraitEffects(allActions, allSelectors),
539
+ });
540
+ }
541
+
542
+ function createSelectEntitiesTraitActions(actionsGroupKey, entitiesName) {
543
+ return {
544
+ selectEntities: createAction(`${actionsGroupKey} Select ${entitiesName}`, props()),
545
+ deselectEntities: createAction(`${actionsGroupKey} Deselect ${entitiesName}`, props()),
546
+ toggleSelectEntities: createAction(`${actionsGroupKey} Toggle Select ${entitiesName}`, props()),
547
+ toggleSelectAllEntities: createAction(`${actionsGroupKey} Toggle Select All ${entitiesName}`),
548
+ clearEntitiesSelection: createAction(`${actionsGroupKey} Clear ${entitiesName} Selection`),
549
+ };
550
+ }
551
+
552
+ function deselectEntities(id, state) {
553
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
554
+ const _a = state.selectedIds, _b = id, _value = _a[_b], selectedIds = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
555
+ return Object.assign(Object.assign({}, state), { selectedIds: selectedIds });
556
+ }
557
+ function selectEntities(id, state) {
558
+ return Object.assign(Object.assign({}, state), { selectedIds: Object.assign(Object.assign({}, state.selectedIds), { [id]: true }) });
559
+ }
560
+ function toggleSelectEntities(id, state) {
561
+ const selected = state.selectedIds[id];
562
+ if (selected) {
563
+ return deselectEntities(id, state);
564
+ }
565
+ else {
566
+ return selectEntities(id, state);
567
+ }
568
+ }
569
+ function clearEntitiesSelection(state) {
570
+ return Object.assign(Object.assign({}, state), { selectedIds: {} });
571
+ }
572
+ function selectTotalSelectedEntities(state) {
573
+ return Object.keys(state.selectedIds).length;
574
+ }
575
+
576
+ function createSelectEntitiesTraitSelectors(previousSelectors) {
577
+ const { selectEntitiesMap, selectEntitiesTotal } = previousSelectors;
578
+ function selectEntitiesIdsSelectedMap(state) {
579
+ return state.selectedIds;
580
+ }
581
+ const selectEntitiesIdsSelectedList = createSelector(selectEntitiesIdsSelectedMap, (ids) => Object.keys(ids));
582
+ const selectEntitiesSelectedMap = createSelector(selectEntitiesIdsSelectedList, selectEntitiesMap, (selectedIds, entities) => selectedIds.reduce((acum, id) => {
583
+ acum[id] = entities[id];
584
+ return acum;
585
+ }, {}));
586
+ const selectEntitiesSelectedList = createSelector(selectEntitiesIdsSelectedList, selectEntitiesMap, (selectedIds, entities) => selectedIds.map((id) => entities[id]));
587
+ const isAllEntitiesSelected = createSelector((state) => selectEntitiesTotal(state), selectTotalSelectedEntities, (total, totalSelected) => totalSelected > 0 && totalSelected === total
588
+ ? 'all'
589
+ : totalSelected === 0
590
+ ? 'none'
591
+ : 'some');
592
+ return {
593
+ selectEntitiesIdsSelectedMap,
594
+ selectEntitiesIdsSelectedList,
595
+ selectEntitiesSelectedMap,
596
+ selectEntitiesSelectedList,
597
+ selectTotalSelectedEntities,
598
+ isAllEntitiesSelected,
599
+ };
600
+ }
601
+
602
+ function createSelectEntitiesInitialState(previousInitialState) {
603
+ return Object.assign(Object.assign({}, previousInitialState), { selectedIds: {} });
604
+ }
605
+ function createSelectEntitiesTraitReducer(initialState, allActions, allMutators, allConfigs) {
606
+ var _a, _b;
607
+ const { adapter } = allConfigs.loadEntities;
608
+ const sortRemote = (_a = allConfigs.sort) === null || _a === void 0 ? void 0 : _a.remote;
609
+ const paginationCacheType = (_b = allConfigs.pagination) === null || _b === void 0 ? void 0 : _b.cacheType;
610
+ function updateSelectedIdsChanged(state, updates) {
611
+ const changedIds = updates.reduce((acc, updated) => {
612
+ const id = adapter.selectId(updated.changes);
613
+ if (id && id !== updated.id && state.selectedIds[updated.id] != null) {
614
+ acc.push(updated);
615
+ return acc;
616
+ }
617
+ return acc;
618
+ }, []);
619
+ if (changedIds.length) {
620
+ const selectedIds = Object.assign({}, state.selectedIds);
621
+ changedIds.forEach((updated) => {
622
+ const id = adapter.selectId(updated.changes);
623
+ const value = selectedIds[updated.id];
624
+ delete selectedIds[updated.id];
625
+ selectedIds[id] = value;
626
+ });
627
+ return Object.assign(Object.assign({}, state), { selectedIds });
628
+ }
629
+ return state;
630
+ }
631
+ return createReducer(initialState, on(allActions.selectEntities, (state, { id }) => allMutators.selectEntities(id, state)), on(allActions.deselectEntities, (state, { id }) => allMutators.deselectEntities(id, state)), on(allActions.toggleSelectEntities, (state, { id }) => allMutators.toggleSelectEntities(id, state)), on(allActions.toggleSelectAllEntities, (state) => allMutators.toggleSelectAllEntities(state)), ...insertIf(allActions.removeEntities, () => on(allActions.removeEntities, (state, { keys }) => {
632
+ const selectedIds = Object.assign({}, state.selectedIds);
633
+ keys.forEach((v) => {
634
+ delete selectedIds[v];
635
+ });
636
+ return Object.assign(Object.assign({}, state), { selectedIds });
637
+ })), ...insertIf(allActions.updateEntities, () => on(allActions.updateEntities, (state, { updates }) => updateSelectedIdsChanged(state, updates))), on(allActions.clearEntitiesSelection, (state) => allMutators.clearEntitiesSelection(state)), ...insertIf(allActions.removeAllEntities, () => on(allActions.removeAllEntities, (state) => allMutators.clearEntitiesSelection(state))), ...insertIf(sortRemote, () => on(allActions.sortEntities, (state) => allMutators.clearEntitiesSelection(state))), ...insertIf(allActions.filterEntities, () => on(allActions.filterEntities, (state) => allMutators.clearEntitiesSelection(state))), ...insertIf(!allActions.loadEntitiesPageSuccess, () => on(allActions.loadEntitiesSuccess, (state) => allMutators.clearEntitiesSelection(state))), ...insertIf(!!allActions.loadEntitiesPageSuccess && paginationCacheType === 'partial', () => on(allActions.loadEntitiesPageSuccess, (state) => allMutators.clearEntitiesSelection(state))));
638
+ }
639
+
640
+ function createSelectEntitiesTraitMutators({ isAllEntitiesSelected, }) {
641
+ function toggleSelectAllEntities(state) {
642
+ const allSelected = isAllEntitiesSelected(state);
643
+ if (allSelected === 'all') {
644
+ return Object.assign(Object.assign({}, state), { selectedIds: {} });
645
+ }
646
+ else {
647
+ return Object.assign(Object.assign({}, state), { selectedIds: toMap(state.ids) });
648
+ }
649
+ }
650
+ return {
651
+ selectEntities,
652
+ deselectEntities,
653
+ toggleSelectEntities,
654
+ toggleSelectAllEntities,
655
+ clearEntitiesSelection,
656
+ };
657
+ }
658
+
659
+ /**
660
+ * Generates ngrx code to add multi selection to a list
661
+ *
662
+ * @example
663
+ * // The following trait config
664
+ *
665
+ * export interface TestState
666
+ * extends EntityAndStatusState<Todo>,MultipleSelectionState{}
667
+ *
668
+ * const traits = createEntityFeatureFactory(
669
+ * addLoadEntitiesTrait<Todo>(),
670
+ * addSelectEntitiesTrait<Todo>()
671
+ * )({
672
+ * actionsGroupKey: '[Todos]',
673
+ * featureSelector: createFeatureSelector<TestState>>(
674
+ * 'todos',
675
+ * ),
676
+ * });
677
+ * // will generate the following actions and selectors, plus the ones generated by other traits
678
+ * traits.actions.selectTodos({id})
679
+ * traits.actions.deselectTodos({id})
680
+ * traits.actions.toggleSectTodos({id})
681
+ * traits.actions.toggleSelectAllTodos()
682
+ * traits.actions.clearTodosSelection()
683
+ *
684
+ * traits.selectors.isAllTodosSelected()
685
+ * traits.selectors.selectTodosIdsSelectedMap()
686
+ * traits.selectors.selectTodosIdsSelectedList()
687
+ * traits.selectors.selectTodosSelectedMap()
688
+ * traits.selectors.selectTodosSelectedList()
689
+ * traits.selectors.selectTotalSelectedTodos()
690
+ */
691
+ function addSelectEntitiesTrait() {
692
+ return createTraitFactory({
693
+ key: 'SelectEntities',
694
+ depends: [loadEntitiesTraitKey],
695
+ actions: ({ actionsGroupKey, entitiesName }) => createSelectEntitiesTraitActions(actionsGroupKey, entitiesName),
696
+ selectors: ({ previousSelectors }) => createSelectEntitiesTraitSelectors(previousSelectors),
697
+ initialState: ({ previousInitialState }) => createSelectEntitiesInitialState(previousInitialState),
698
+ mutators: ({ allSelectors }) => createSelectEntitiesTraitMutators(allSelectors),
699
+ reducer: ({ initialState, allActions, allMutators, allConfigs }) => createSelectEntitiesTraitReducer(initialState, allActions, allMutators, allConfigs),
700
+ });
701
+ }
702
+
703
+ function createSelectEntityTraitActions(actionsGroupKey, entityName) {
704
+ return {
705
+ selectEntity: createAction(`${actionsGroupKey} Select ${entityName}`, props()),
706
+ deselectEntity: createAction(`${actionsGroupKey} Deselect ${entityName}`),
707
+ toggleSelectEntity: createAction(`${actionsGroupKey} Toggle Select ${entityName}`, props()),
708
+ };
709
+ }
710
+
711
+ function createSelectEntityTraitSelectors() {
712
+ function selectEntityIdSelected(state) {
713
+ return state.selectedId;
714
+ }
715
+ function selectEntitySelected(state) {
716
+ return (state.selectedId && state.entities[state.selectedId]) || undefined;
717
+ }
718
+ return {
719
+ selectEntityIdSelected,
720
+ selectEntitySelected,
721
+ };
722
+ }
723
+
724
+ function createSelectEntityInitialState(previousInitialState, allConfigs) {
725
+ var _a;
726
+ const selectedId = (_a = allConfigs.singleSelection) === null || _a === void 0 ? void 0 : _a.selectedId;
727
+ return Object.assign(Object.assign({}, previousInitialState), { selectedId });
728
+ }
729
+ function createSelectEntityTraitReducer(initialState, allActions, allMutators, allConfigs) {
730
+ var _a, _b;
731
+ const { adapter } = allConfigs.loadEntities;
732
+ const sortRemote = (_a = allConfigs.sort) === null || _a === void 0 ? void 0 : _a.remote;
733
+ const paginationCacheType = (_b = allConfigs.pagination) === null || _b === void 0 ? void 0 : _b.cacheType;
734
+ return createReducer(initialState, on(allActions.selectEntity, (state, { id }) => allMutators.selectEntity(id, state)), on(allActions.deselectEntity, (state) => allMutators.deselectEntity(state)), on(allActions.toggleSelectEntity, (state, { id }) => allMutators.toggleSelectEntity(id, state)), ...insertIf(allActions.removeAllEntities, () => on(allActions.removeAllEntities, (state) => allMutators.deselectEntity(state))), ...insertIf(sortRemote, () => on(allActions.sortEntities, (state) => allMutators.deselectEntity(state))), ...insertIf(allActions.filterEntities, () => on(allActions.filterEntities, (state) => allMutators.deselectEntity(state))), ...insertIf(!allActions.loadEntitiesPageSuccess, () => on(allActions.loadEntitiesSuccess, (state) => allMutators.deselectEntity(state))), ...insertIf(!!allActions.loadEntitiesPageSuccess && paginationCacheType === 'partial', () => on(allActions.loadEntitiesPageSuccess, (state) => allMutators.deselectEntity(state))), ...insertIf(allActions.removeEntities, () => on(allActions.removeEntities, (state, { keys }) => {
735
+ const shouldDeselect = keys.some((v) => v === state.selectedId);
736
+ return shouldDeselect
737
+ ? Object.assign(Object.assign({}, state), { selectedId: undefined }) : state;
738
+ })), ...insertIf(allActions.updateEntities, () => on(allActions.updateEntities, (state, { updates }) => {
739
+ const change = updates.find((updated) => {
740
+ const id = adapter.selectId(updated.changes);
741
+ return id && id !== updated.id && state.selectedId === updated.id;
742
+ });
743
+ return change
744
+ ? Object.assign(Object.assign({}, state), { selectedId: adapter.selectId(change.changes) }) : state;
745
+ })));
746
+ }
747
+
748
+ function createSelectEntityTraitMutators() {
749
+ function selectEntity(id, state) {
750
+ return Object.assign(Object.assign({}, state), { selectedId: id });
751
+ }
752
+ function deselectEntity(state) {
753
+ return Object.assign(Object.assign({}, state), { selectedId: undefined });
754
+ }
755
+ function toggleSelectEntity(id, state) {
756
+ return Object.assign(Object.assign({}, state), { selectedId: state.selectedId === id ? undefined : id });
757
+ }
758
+ return {
759
+ selectEntity,
760
+ deselectEntity,
761
+ toggleSelectEntity,
762
+ };
763
+ }
764
+
765
+ /**
766
+ * Generates ngrx code to add single selection to a list
767
+ * @param config
768
+ * @param config.selectedId - Default selected id
769
+ *
770
+ * @example
771
+ * // The following trait config
772
+ *
773
+ * export interface TestState
774
+ * extends EntityAndStatusState<Todo>,SelectEntityState{}
775
+ *
776
+ * const traits = createEntityFeatureFactory(
777
+ * addLoadEntitiesTrait<Todo>(),
778
+ * addSelectEntityTrait<Todo>()
779
+ * )({
780
+ * actionsGroupKey: '[Todos]',
781
+ * featureSelector: createFeatureSelector<TestState>>(
782
+ * 'todos',
783
+ * ),
784
+ * });
785
+ * // will generate the following actions and selectors, plus the ones generated by other traits
786
+ * traits.actions.selectTodo({id})
787
+ * traits.actions.deselectTodo()
788
+ * traits.actions.toggleSelectTodo({id})
789
+ *
790
+ * traits.selectors.selectTodoIdSelected()
791
+ * traits.selectors.selectTodoSelected()
792
+ */
793
+ function addSelectEntityTrait(config) {
794
+ return createTraitFactory({
795
+ key: 'singleSelection',
796
+ depends: [loadEntitiesTraitKey],
797
+ config,
798
+ actions: ({ actionsGroupKey, entityName }) => createSelectEntityTraitActions(actionsGroupKey, entityName),
799
+ selectors: () => createSelectEntityTraitSelectors(),
800
+ mutators: () => createSelectEntityTraitMutators(),
801
+ initialState: ({ previousInitialState, allConfigs, }) => createSelectEntityInitialState(previousInitialState, allConfigs),
802
+ reducer: ({ initialState, allActions, allMutators, allConfigs }) => createSelectEntityTraitReducer(initialState, allActions, allMutators, allConfigs),
803
+ });
804
+ }
805
+
806
+ const selectEntityTraitKey = 'singleSelection';
807
+
808
+ var ChangeType;
809
+ (function (ChangeType) {
810
+ ChangeType["CREATED"] = "c";
811
+ ChangeType["UPDATED"] = "u";
812
+ ChangeType["DELETED"] = "d";
813
+ })(ChangeType || (ChangeType = {}));
814
+ const crudEntitiesTraitKey = 'crud';
815
+
816
+ function createCrudTraitActions(actionsGroupKey, entitiesName) {
817
+ return {
818
+ addEntities: createAction(`${actionsGroupKey} Add ${entitiesName}`, (...entities) => ({
819
+ entities,
820
+ })),
821
+ removeEntities: createAction(`${actionsGroupKey} Remove ${entitiesName}`, (...keys) => ({
822
+ keys,
823
+ })),
824
+ updateEntities: createAction(`${actionsGroupKey} Update ${entitiesName}`, (...updates) => ({
825
+ updates,
826
+ })),
827
+ upsertEntities: createAction(`${actionsGroupKey} Upsert ${entitiesName}`, (...entities) => ({
828
+ entities,
829
+ })),
830
+ removeAllEntities: createAction(`${actionsGroupKey} Remove All ${entitiesName}`, (predicate) => ({ predicate })),
831
+ clearEntitiesChanges: createAction(`${actionsGroupKey} Clear ${entitiesName} Changes`),
832
+ };
833
+ }
834
+
835
+ function createCrudTraitSelectors(previousSelectors) {
836
+ function selectChanges(state) {
837
+ return state.changes;
838
+ }
839
+ function selectFilteredChanges(state) {
840
+ const cache = {};
841
+ return state.changes.reduce((acc, value) => {
842
+ const changes = cache[value.id];
843
+ if (!changes) {
844
+ cache[value.id] = [value.changeType];
845
+ acc.push(value);
846
+ return acc;
847
+ }
848
+ if (value.changeType === ChangeType.UPDATED) {
849
+ return acc;
850
+ }
851
+ if (value.changeType === ChangeType.DELETED &&
852
+ changes.includes(ChangeType.CREATED)) {
853
+ delete cache[value.id];
854
+ return acc.filter((v) => v.id !== value.id);
855
+ }
856
+ if (value.changeType === ChangeType.DELETED) {
857
+ delete cache[value.id];
858
+ const newAcc = acc.filter((v) => v.id !== value.id);
859
+ newAcc.push(value);
860
+ return newAcc;
861
+ }
862
+ return acc;
863
+ }, []);
864
+ }
865
+ const { selectEntitiesMap } = previousSelectors;
866
+ const selectEntitiesChangesList = createSelector((state) => selectEntitiesMap(state), selectChanges, (entities, changed, { type }) => {
867
+ if (type)
868
+ return changed
869
+ .filter((c) => c.changeType === type)
870
+ .map((change) => {
871
+ var _a;
872
+ return ({
873
+ changeType: change.changeType,
874
+ entity: (_a = entities[change.id]) !== null && _a !== void 0 ? _a : {
875
+ id: change.id,
876
+ },
877
+ });
878
+ });
879
+ const map = changed.map((change) => {
880
+ var _a;
881
+ return ({
882
+ changeType: change.changeType,
883
+ entity: (_a = entities[change.id]) !== null && _a !== void 0 ? _a : {
884
+ id: change.id,
885
+ },
886
+ });
887
+ });
888
+ return map;
889
+ });
890
+ const selectFilteredEntitiesChangesList = createSelector(selectFilteredChanges, (state) => selectEntitiesMap(state), (changes, entities) => changes.map((c) => {
891
+ var _a;
892
+ return {
893
+ entity: (_a = entities[c.id]) !== null && _a !== void 0 ? _a : { id: c.id },
894
+ changeType: c.changeType,
895
+ };
896
+ }));
897
+ return {
898
+ selectEntitiesChangesList,
899
+ selectFilteredEntitiesChangesList,
900
+ };
901
+ }
902
+
903
+ function createCrudInitialState(previousInitialState) {
904
+ return Object.assign(Object.assign({}, previousInitialState), { changes: [] });
905
+ }
906
+ function createCrudTraitReducer(initialState, allActions, allMutators, allConfigs) {
907
+ var _a, _b, _c;
908
+ const sortRemote = (_a = allConfigs.sort) === null || _a === void 0 ? void 0 : _a.remote;
909
+ const filterRemote = allConfigs.filter && !((_b = allConfigs.filter) === null || _b === void 0 ? void 0 : _b.filterFn);
910
+ const paginationCacheType = (_c = allConfigs.pagination) === null || _c === void 0 ? void 0 : _c.cacheType;
911
+ return createReducer(initialState, on(allActions.addEntities, (state, { entities }) => allMutators.addEntities(entities, state)), on(allActions.updateEntities, (state, { updates }) => allMutators.updateEntities(updates, state)), on(allActions.upsertEntities, (state, { entities }) => allMutators.upsertEntities(entities, state)), on(allActions.removeEntities, (state, { keys }) => allMutators.removeEntities(keys, state)), on(allActions.removeAllEntities, (state, { predicate }) => predicate
912
+ ? allMutators.removeEntities(predicate, state)
913
+ : allMutators.removeAllEntities(state)), on(allActions.clearEntitiesChanges, (state) => allMutators.clearEntitiesChanges(state)), ...insertIf(sortRemote, () => on(allActions.sortEntities, (state) => allMutators.clearEntitiesChanges(state))), ...insertIf(filterRemote, () => on(allActions.filterEntities, (state) => allMutators.clearEntitiesChanges(state))), ...insertIf(!allActions.loadEntitiesPageSuccess, () => on(allActions.loadEntitiesSuccess, (state) => allMutators.clearEntitiesChanges(state))), ...insertIf(!!allActions.loadEntitiesPageSuccess && paginationCacheType === 'partial', () => on(allActions.loadEntitiesPageSuccess, (state) => allMutators.clearEntitiesChanges(state))));
914
+ }
915
+
916
+ function createCrudTraitMutators(allConfigs) {
917
+ const { storeChanges } = allConfigs.crud || {};
918
+ const adapter = allConfigs.loadEntities.adapter;
919
+ function generateChangeEntry(entity, changeType, customId) {
920
+ return {
921
+ id: customId !== null && customId !== void 0 ? customId : adapter.selectId(entity),
922
+ changeType,
923
+ entityChanges: (storeChanges && entity) || undefined,
924
+ };
925
+ }
926
+ function addEntities(entities, state, addFirst = false) {
927
+ const changes = [
928
+ ...state.changes,
929
+ ...entities.map((entity) => generateChangeEntry(entity, ChangeType.CREATED)),
930
+ ];
931
+ if (!addFirst)
932
+ return adapter.addMany(entities, Object.assign(Object.assign({}, state), { changes }));
933
+ const newIds = entities.map((e) => adapter.selectId(e));
934
+ const newEntities = Object.assign({}, state.entities);
935
+ entities.forEach((e) => {
936
+ const id = adapter.selectId(e);
937
+ newEntities[id] = e;
938
+ });
939
+ return Object.assign(Object.assign({}, state), { ids: [...newIds, ...state.ids], entities: newEntities, changes });
940
+ }
941
+ function upsertEntities(entities, state) {
942
+ const oldChanges = [...state.changes];
943
+ const existingIds = adapter.getSelectors().selectIds(state);
944
+ const [additions, updates] = entities.reduce(([a, u], entity) => existingIds.indexOf(adapter.selectId(entity)) !== -1
945
+ ? [a, [...u, entity]]
946
+ : [[...a, entity], u], [new Array(), new Array()]);
947
+ return adapter.upsertMany(entities, Object.assign(Object.assign({}, state), { changes: [
948
+ ...oldChanges,
949
+ ...additions.map((entity) => generateChangeEntry(entity, ChangeType.CREATED)),
950
+ ...updates.map((entity) => generateChangeEntry(entity, ChangeType.UPDATED)),
951
+ ] }));
952
+ }
953
+ function removeEntities(keysOrPredicate, state) {
954
+ if (typeof keysOrPredicate === 'function') {
955
+ return adapter.removeMany(keysOrPredicate, Object.assign(Object.assign({}, state), { changes: [
956
+ ...state.changes,
957
+ ...state.ids.map((id) => ({
958
+ id,
959
+ changeType: ChangeType.DELETED,
960
+ })),
961
+ ] }));
962
+ }
963
+ return adapter.removeMany(keysOrPredicate, Object.assign(Object.assign({}, state), { changes: [
964
+ ...state.changes,
965
+ ...keysOrPredicate.map((key) => ({
966
+ id: key,
967
+ changeType: ChangeType.DELETED,
968
+ })),
969
+ ] }));
970
+ }
971
+ function removeAllEntities(state) {
972
+ return adapter.removeAll(Object.assign(Object.assign({}, state), { changes: [
973
+ ...state.changes,
974
+ ...state.ids.map((id) => ({
975
+ id,
976
+ changeType: ChangeType.DELETED,
977
+ })),
978
+ ] }));
979
+ }
980
+ function clearEntitiesChanges(state) {
981
+ return Object.assign(Object.assign({}, state), { changes: [] });
982
+ }
983
+ function updateEntities(updates, state) {
984
+ const oldChanges = [...state.changes];
985
+ updates.forEach((updated) => {
986
+ const id = adapter.selectId(updated.changes);
987
+ if (id && id !== updated.id) {
988
+ // if the id changes update the id of pold changes
989
+ const index = oldChanges.findIndex((v) => v.id === updated.id);
990
+ const oldChange = oldChanges[index];
991
+ oldChanges[index] = Object.assign(Object.assign({}, oldChange), { id });
992
+ }
993
+ });
994
+ return adapter.updateMany(updates, Object.assign(Object.assign({}, state), { changes: [
995
+ ...oldChanges,
996
+ ...updates.map((updated) => {
997
+ var _a;
998
+ return ({
999
+ id: (_a = adapter.selectId(updated.changes)) !== null && _a !== void 0 ? _a : updated.id,
1000
+ changeType: ChangeType.UPDATED,
1001
+ entityChanges: (storeChanges && updated.changes) || undefined,
1002
+ });
1003
+ }),
1004
+ ] }));
1005
+ }
1006
+ return {
1007
+ addEntities,
1008
+ removeEntities,
1009
+ updateEntities,
1010
+ removeAllEntities,
1011
+ clearEntitiesChanges,
1012
+ upsertEntities,
1013
+ };
1014
+ }
1015
+
1016
+ /**
1017
+ * Generates ngrx code to add, remove update, upsert entities on a list, it also
1018
+ * tracks the changes made, helpful for implementing batch updates. The `storeChanges` (false by default),
1019
+ * will store for add and update the changed entity props in the property `entityChanges` of the `Change` object.
1020
+ * @param config
1021
+ * @param config.storeChanges - Will store the changes made, default fals
1022
+ *
1023
+ * @example
1024
+ * // The following trait config
1025
+ *
1026
+ * export interface TestState
1027
+ * extends EntityAndStatusState<Todo>, CrudState<Todo>{}
1028
+ *
1029
+ * const traits = createEntityFeatureFactory(
1030
+ * addLoadEntitiesTrait<Todo>(),
1031
+ * addCrudEntitiesTrait<Todo>()
1032
+ * )({
1033
+ * actionsGroupKey: '[Todos]',
1034
+ * featureSelector: createFeatureSelector<TestState>>(
1035
+ * 'todos',
1036
+ * ),
1037
+ * });
1038
+ * // will generate the following actions and selectors, plus the ones generated by other traits
1039
+ * traits.actions.addTodos(entity1,entity2...)
1040
+ * traits.actions.updateTodos({id: id1, changes:{prop1}},{id: id2, changes:{prop2}} ...)
1041
+ * traits.actions.upsertTodos(entity1,entity2...)
1042
+ * traits.actions.removeAllTodos()
1043
+ * traits.actions.clearTodosChanges()
1044
+ *
1045
+ * traits.selectors.selectTodosChangesList()
1046
+ * traits.selectors.selectFilteredTodosChangesList()
1047
+ * traits.selectors.selectAllFilteredChanges()
1048
+ */
1049
+ function addCrudEntitiesTrait({ storeChanges = false, } = {}) {
1050
+ return createTraitFactory({
1051
+ key: crudEntitiesTraitKey,
1052
+ depends: [loadEntitiesTraitKey],
1053
+ config: { storeChanges },
1054
+ actions: ({ actionsGroupKey, entitiesName }) => createCrudTraitActions(actionsGroupKey, entitiesName),
1055
+ selectors: ({ previousSelectors }) => createCrudTraitSelectors(previousSelectors),
1056
+ mutators: ({ allConfigs }) => createCrudTraitMutators(allConfigs),
1057
+ initialState: ({ previousInitialState }) => createCrudInitialState(previousInitialState),
1058
+ reducer: ({ initialState, allActions, allMutators, allConfigs }) => createCrudTraitReducer(initialState, allActions, allMutators, allConfigs),
1059
+ });
1060
+ }
1061
+
1062
+ const sortTraitKey = 'sort';
1063
+
1064
+ const MAX_SAFE_INTEGER = 9007199254740991;
1065
+ function _isNumberValue(value) {
1066
+ // parseFloat(value) handles most of the cases we're interested in (it treats null, empty string,
1067
+ // and other non-number values as NaN, where Number just uses 0) but it considers the string
1068
+ // '123hello' to be a valid number. Therefore we also check if Number(value) is NaN.
1069
+ return !isNaN(parseFloat(value)) && !isNaN(Number(value));
1070
+ }
1071
+ function sortingDataAccessor(data, sortHeaderId) {
1072
+ const value = data[sortHeaderId];
1073
+ if (_isNumberValue(value)) {
1074
+ const numberValue = Number(value);
1075
+ // Numbers beyond `MAX_SAFE_INTEGER` can't be compared reliably so we
1076
+ // leave them as strings. For more info: https://goo.gl/y5vbSg
1077
+ return numberValue < MAX_SAFE_INTEGER ? numberValue : value;
1078
+ }
1079
+ return value;
1080
+ }
1081
+ /**
1082
+ * Gets a sorted copy of the data array based on the state of the Sort.
1083
+ * @param data The array of data that should be sorted.
1084
+ * @param sort The connected MatSort that holds the current sort state.
1085
+ */
1086
+ function sortData(data, sort) {
1087
+ const active = sort.active;
1088
+ const direction = sort.direction;
1089
+ if (!active || direction === '') {
1090
+ return data;
1091
+ }
1092
+ return data.sort((a, b) => {
1093
+ const valueA = sortingDataAccessor(a, active);
1094
+ const valueB = sortingDataAccessor(b, active);
1095
+ // If both valueA and valueB exist (truthy), then compare the two. Otherwise, check if
1096
+ // one value exists while the other doesn't. In this case, existing value should come last.
1097
+ // This avoids inconsistent results when comparing values to undefined/null.
1098
+ // If neither value exists, return 0 (equal).
1099
+ let comparatorResult = 0;
1100
+ if (valueA != null && valueB != null) {
1101
+ // Check if one value is greater than the other; if equal, comparatorResult should remain 0.
1102
+ if (typeof valueA === 'string' || typeof valueB === 'string') {
1103
+ // if either values are a string, then force both to be strings before localCompare
1104
+ comparatorResult = valueA.toString().localeCompare(valueB.toString());
1105
+ }
1106
+ else {
1107
+ if (valueA > valueB) {
1108
+ comparatorResult = 1;
1109
+ }
1110
+ else if (valueA < valueB) {
1111
+ comparatorResult = -1;
1112
+ }
1113
+ }
1114
+ }
1115
+ else if (valueA != null) {
1116
+ comparatorResult = 1;
1117
+ }
1118
+ else if (valueB != null) {
1119
+ comparatorResult = -1;
1120
+ }
1121
+ return comparatorResult * (direction === 'asc' ? 1 : -1);
1122
+ });
1123
+ }
1124
+
1125
+ function createSortTraitMutators({ selectEntitiesList }, allConfigs) {
1126
+ function sortEntities({ active, direction }, state) {
1127
+ const { adapter } = allConfigs.loadEntities;
1128
+ const entities = selectEntitiesList(state);
1129
+ const sortedIds = sortData(entities, { active, direction }).map((v) => adapter.selectId(v));
1130
+ return Object.assign(Object.assign({}, state), { ids: sortedIds, sort: Object.assign(Object.assign({}, state.sort), { current: { active, direction } }) });
1131
+ }
1132
+ return {
1133
+ sortEntities,
1134
+ };
1135
+ }
1136
+
1137
+ function createSortInitialState(previousInitialState, allConfigs) {
1138
+ const { defaultSort } = allConfigs.sort;
1139
+ return Object.assign(Object.assign({}, previousInitialState), { sort: {
1140
+ current: defaultSort,
1141
+ default: defaultSort,
1142
+ } });
1143
+ }
1144
+ function createSortTraitReducer(initialState, allActions, allMutators, allConfigs) {
1145
+ const { remote } = allConfigs.sort;
1146
+ return createReducer(initialState, on(allActions.sortEntities, (state, { active, direction }) => !remote
1147
+ ? allMutators.sortEntities({ active, direction }, state)
1148
+ : Object.assign(Object.assign({}, state), { sort: Object.assign(Object.assign({}, state.sort), { current: { active, direction } }) })), on(allActions.resetEntitiesSort, (state) => {
1149
+ var _a, _b, _c;
1150
+ return ((_a = state.sort) === null || _a === void 0 ? void 0 : _a.default)
1151
+ ? !remote
1152
+ ? allMutators.sortEntities((_b = state.sort) === null || _b === void 0 ? void 0 : _b.default, state)
1153
+ : Object.assign(Object.assign({}, state), { sort: Object.assign(Object.assign({}, state.sort), { current: (_c = state.sort) === null || _c === void 0 ? void 0 : _c.default }) })
1154
+ : state;
1155
+ }));
1156
+ }
1157
+
1158
+ function createSortTraitSelectors() {
1159
+ function selectEntitiesSort(state) {
1160
+ var _a;
1161
+ return (_a = state.sort) === null || _a === void 0 ? void 0 : _a.current;
1162
+ }
1163
+ return {
1164
+ selectEntitiesSort,
1165
+ };
1166
+ }
1167
+
1168
+ function createSortTraitEffect(allActions, allConfigs) {
1169
+ const { remote } = allConfigs.sort;
1170
+ class SortEffect extends TraitEffect {
1171
+ constructor() {
1172
+ super(...arguments);
1173
+ this.remoteSort$ = createEffect(() => {
1174
+ return this.actions$.pipe(ofType(allActions.sortEntities, allActions.resetEntitiesSort), concatMap(() => allActions.loadEntitiesFirstPage
1175
+ ? [
1176
+ allActions.clearEntitiesPagesCache(),
1177
+ allActions.loadEntitiesFirstPage(),
1178
+ ]
1179
+ : [allActions.loadEntities()]));
1180
+ });
1181
+ }
1182
+ }
1183
+ SortEffect.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: SortEffect, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
1184
+ SortEffect.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: SortEffect });
1185
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: SortEffect, decorators: [{
1186
+ type: Injectable
1187
+ }] });
1188
+ return remote ? [SortEffect] : [];
1189
+ }
1190
+
1191
+ function createSortTraitActions(actionsGroupKey, entitiesName) {
1192
+ return {
1193
+ sortEntities: createAction(`${actionsGroupKey} Sort ${entitiesName}`, props()),
1194
+ resetEntitiesSort: createAction(`${actionsGroupKey} Reset ${entitiesName} Sort`),
1195
+ };
1196
+ }
1197
+
1198
+ /**
1199
+ * Generates ngrx code to sort locally or remotely a list of entities
1200
+ * @param config
1201
+ * @param config.defaultSort - Required, Default entity prop for the sort
1202
+ * @param config.remote - Optional field, default to false, when true disables local
1203
+ * sorting and every sort action call will now trigger a loadEntities action and the backend
1204
+ * should sort the data, use selectSort in the effect that call backend to get the requested sort,
1205
+ * when false all sorting is done in memory when the sort action is fired
1206
+ *
1207
+ * @example
1208
+ * // The following trait config
1209
+ * export interface TestState
1210
+ * extends EntityAndStatusState<Todo>, SortState<Todo>{}
1211
+ *
1212
+ * const traits = createEntityFeatureFactory(
1213
+ * addLoadEntitiesTrait<Todo>(),
1214
+ * addSortEntitiesTrait<Todo>({
1215
+ * defaultSort: {active:'id', direction:'asc'}
1216
+ * })
1217
+ * )({
1218
+ * actionsGroupKey: '[Todos]',
1219
+ * featureSelector: createFeatureSelector<TestState>>(
1220
+ * 'todos',
1221
+ * ),
1222
+ * });
1223
+ * // will generate the following actions and selectors, plus the ones generated by other traits
1224
+ * traits.actions.sortTodos({active:'id', direction:'desc'})
1225
+ * traits.actions.resetTodosSort()
1226
+ *
1227
+ * traits.selectors.selectTodosSort()
1228
+ */
1229
+ function addSortEntitiesTrait({ remote = false, defaultSort, }) {
1230
+ return createTraitFactory({
1231
+ key: sortTraitKey,
1232
+ depends: [loadEntitiesTraitKey],
1233
+ config: { remote, defaultSort },
1234
+ actions: ({ actionsGroupKey, entitiesName }) => createSortTraitActions(actionsGroupKey, entitiesName),
1235
+ selectors: () => createSortTraitSelectors(),
1236
+ mutators: ({ allSelectors, allConfigs }) => createSortTraitMutators(allSelectors, allConfigs),
1237
+ initialState: ({ previousInitialState, allConfigs, }) => createSortInitialState(previousInitialState, allConfigs),
1238
+ reducer: ({ initialState, allActions, allMutators, allConfigs }) => createSortTraitReducer(initialState, allActions, allMutators, allConfigs),
1239
+ effects: ({ allActions, allConfigs }) => createSortTraitEffect(allActions, allConfigs),
1240
+ });
1241
+ }
1242
+
1243
+ /**
1244
+ * Generates the ngrx code needed to reset the current state to the initial state.
1245
+ * @param traitConfig - Config object fot the trait factory
1246
+ * @param traitConfig.resetOn - set an extra action which will also trigger a reset state,
1247
+ * useful if you want to create an action that reset several features states
1248
+ *
1249
+ * @example
1250
+ * // The following trait config
1251
+ *
1252
+ * export interface TestState
1253
+ * extends EntityAndStatusState<Todo>,FilterState<TodoFilter>{}
1254
+ *
1255
+ * const traits = createEntityFeatureFactory(
1256
+ * addLoadEntitiesTrait<Todo>(),
1257
+ * addResetEntitiesStateTrait()
1258
+ * )({
1259
+ * actionsGroupKey: '[Todos]',
1260
+ * featureSelector: createFeatureSelector<TestState>>(
1261
+ * 'todos',
1262
+ * ),
1263
+ * });
1264
+ * // will generate the following actions, plus the ones generated by other traits
1265
+ * traits.actions.resetTodosState()
1266
+ */
1267
+ function addResetEntitiesStateTrait(traitConfig = {}) {
1268
+ return createTraitFactory({
1269
+ key: 'reset',
1270
+ config: traitConfig,
1271
+ actions: ({ actionsGroupKey, entitiesName, }) => ({
1272
+ resetEntitiesState: createAction(`${actionsGroupKey} Reset ${entitiesName} State`),
1273
+ }),
1274
+ reducer: ({ allActions, initialState }) => createReducer(initialState, on(allActions.resetEntitiesState, () => initialState)),
1275
+ effects: ({ allActions }) => {
1276
+ var _a;
1277
+ class ResetEffect extends TraitEffect {
1278
+ //TODO: not sure why Im forced to override this constructor
1279
+ // or test wont pass, strangely doesnt happen in other files
1280
+ // with similar case like pagination.effects.ts
1281
+ constructor(actions$, store) {
1282
+ var _a;
1283
+ super(actions$, store);
1284
+ this.externalReset$ = ((_a = traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.resetOn) === null || _a === void 0 ? void 0 : _a.length) &&
1285
+ createEffect(() => {
1286
+ return this.actions$.pipe(ofType(...traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.resetOn), mapTo(allActions.resetEntitiesState()));
1287
+ });
1288
+ }
1289
+ }
1290
+ ResetEffect.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: ResetEffect, deps: [{ token: i1.Actions }, { token: i2.Store }], target: i0.ɵɵFactoryTarget.Injectable });
1291
+ ResetEffect.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: ResetEffect });
1292
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: ResetEffect, decorators: [{
1293
+ type: Injectable
1294
+ }], ctorParameters: function () { return [{ type: i1.Actions }, { type: i2.Store }]; } });
1295
+ return ((_a = traitConfig === null || traitConfig === void 0 ? void 0 : traitConfig.resetOn) === null || _a === void 0 ? void 0 : _a.length) ? [ResetEffect] : [];
1296
+ },
1297
+ });
1298
+ }
1299
+
1300
+ /**
1301
+ * Generates the typical ngrx code need to make a async action with
1302
+ * a request, success and failure actions, plus a status property to track its progress
1303
+ * and selectors to query the status.
1304
+ *
1305
+ * @param options - Config object for the trait factory
1306
+ * @param options.name - Name of the main request action, should be in camel case
1307
+ * @param options.actionProps - Optional param for the main request action, use the props()
1308
+ * function for its value, if not present action will have no params,
1309
+ * @param options.actionSuccessProps - Optional param for the request success action,
1310
+ * use the props() function for its value, if not present action success will have no params
1311
+ * @param options.actionFailProps - Optional param for the request fail action,
1312
+ * use the props() function for its value, if not present action fail will have no params
1313
+ * @returns the trait factory
1314
+ *
1315
+ * @example
1316
+ * // The following trait config
1317
+ * const traits = createEntityFeatureFactory(
1318
+ * {entityName: 'Todo'},
1319
+ * addAsyncActionTrait({
1320
+ * name: 'createClient',
1321
+ * actionProps: props<{ name: string }>(),
1322
+ * actionSuccessProps: props<{ id: string }>(),
1323
+ * }),
1324
+ * )({
1325
+ * actionsGroupKey: 'Client',
1326
+ * featureSelector: createFeatureSelector<AsyncActionState<'createClient'>>(
1327
+ * 'client',
1328
+ * ),
1329
+ * });
1330
+ * // will generate the actions and selectors
1331
+ * traits.actions.createClient({name:'Pedro'})
1332
+ * traits.actions.createClientSuccess({id:'123'})
1333
+ * traits.actions.createClientFail();
1334
+ * traits.selectors.isLoadingCreateClient
1335
+ * traits.selectors.isSuccessCreateClient
1336
+ * traits.selectors.isFailCreateClient
1337
+ */
1338
+ function addAsyncActionTrait({ name, actionProps, actionSuccessProps, actionFailProps, }) {
1339
+ const nameAsSentence = camelCaseToSentence(name);
1340
+ let internalActions;
1341
+ return createTraitFactory({
1342
+ key: name + '-call',
1343
+ config: {
1344
+ name,
1345
+ actionProps,
1346
+ actionSuccessProps,
1347
+ actionFailProps,
1348
+ },
1349
+ actions: ({ actionsGroupKey, }) => {
1350
+ internalActions = {
1351
+ request: (actionProps
1352
+ ? createAction(`${actionsGroupKey} ${nameAsSentence}`, actionProps)
1353
+ : createAction(`${actionsGroupKey} ${nameAsSentence}`)),
1354
+ requestSuccess: (actionSuccessProps
1355
+ ? createAction(`${actionsGroupKey} ${nameAsSentence} Success`, actionSuccessProps)
1356
+ : createAction(`${actionsGroupKey} ${nameAsSentence} Success`)),
1357
+ requestFail: (actionFailProps
1358
+ ? createAction(`${actionsGroupKey} ${nameAsSentence} Failure`, actionFailProps)
1359
+ : createAction(`${actionsGroupKey} ${nameAsSentence} Failure`)),
1360
+ };
1361
+ if (name) {
1362
+ return {
1363
+ [`${name}`]: internalActions.request,
1364
+ [`${name}Success`]: internalActions.requestSuccess,
1365
+ [`${name}Fail`]: internalActions.requestFail,
1366
+ };
1367
+ }
1368
+ return internalActions;
1369
+ },
1370
+ selectors: () => {
1371
+ function isLoadingEntity(state) {
1372
+ return state[`${name}Status`] === 'loading';
1373
+ }
1374
+ function isSuccessEntity(state) {
1375
+ return state[`${name}Status`] === 'success';
1376
+ }
1377
+ function isFailEntity(state) {
1378
+ return state[`${name}Status`] === 'fail';
1379
+ }
1380
+ const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
1381
+ return {
1382
+ [`isLoading${capitalizedName}`]: isLoadingEntity,
1383
+ [`isSuccess${capitalizedName}`]: isSuccessEntity,
1384
+ [`isFail${capitalizedName}`]: isFailEntity,
1385
+ };
1386
+ },
1387
+ initialState: ({ previousInitialState }) => previousInitialState,
1388
+ reducer: ({ initialState }) => {
1389
+ return createReducer(initialState, on(internalActions.request, (state) => (Object.assign(Object.assign({}, state), { [`${name}Status`]: 'loading' }))), on(internalActions.requestFail, (state) => (Object.assign(Object.assign({}, state), { [`${name}Status`]: 'fail' }))), on(internalActions.requestSuccess, (state) => (Object.assign(Object.assign({}, state), { [`${name}Status`]: 'success' }))));
1390
+ },
1391
+ });
1392
+ }
1393
+
1394
+ /**
1395
+ * Generates ngrx code needed to load and entity and store it in a state
1396
+ * @param entityName - Entity name, should be in camel case
1397
+ * @param options.actionProps - Optional param for the main request action,
1398
+ * use the props() function for its value, if not present action will have no params,
1399
+ * @param options.actionSuccessProps - Optional param for the request success
1400
+ * action, use the props() function for its value, if not present action success will have no params
1401
+ * @param options.actionFailProps - Optional param for the request fail action,
1402
+ * use the props() function for its value, if not present action fail will have no params
1403
+ * @returns the trait factory
1404
+ *
1405
+ * @example
1406
+ * const traits = createEntityFeatureFactory(
1407
+ * ...addLoadEntityTraits({
1408
+ * entityName: 'client',
1409
+ * requestProps: props<{ id: string }>(),
1410
+ * responseProps: props<{ client: Client }>(),
1411
+ * }),
1412
+ * )({
1413
+ * actionsGroupKey: 'Client',
1414
+ * featureSelector: createFeatureSelector<
1415
+ * LoadEntityState<Client, 'client'>
1416
+ * >('client'),
1417
+ * });
1418
+ *
1419
+ * // will generate
1420
+ * traits.actions.loadClient({id:123});
1421
+ * traits.actions.loadClientSuccess({client: {id: '123', name: 'gabs'}});
1422
+ * traits.actions.loadClientFail();
1423
+ * traits.selectors.selectClient
1424
+ * traits.selectors.isLoadingLoadClient
1425
+ * traits.selectors.isSuccessLoadClient
1426
+ * traits.selectors.isFailLoadClient
1427
+ */
1428
+ function addLoadEntityTraits({ entityName, actionProps, actionSuccessProps, actionFailProps, }) {
1429
+ const capitalizedName = capitalize(entityName);
1430
+ return [
1431
+ addAsyncActionTrait({
1432
+ name: ('load' + capitalizedName),
1433
+ actionProps,
1434
+ actionSuccessProps,
1435
+ actionFailProps,
1436
+ }),
1437
+ createTraitFactory({
1438
+ key: `load${capitalizedName}`,
1439
+ config: { entityName, actionProps, actionSuccessProps, actionFailProps },
1440
+ selectors: () => {
1441
+ function selectEntity(state) {
1442
+ return state[`${entityName}`];
1443
+ }
1444
+ return {
1445
+ [`select${capitalizedName}`]: selectEntity,
1446
+ };
1447
+ },
1448
+ initialState: ({ previousInitialState, }) => previousInitialState,
1449
+ reducer: ({ initialState, allActions }) => {
1450
+ return createReducer(initialState, on(allActions[`load${capitalizedName}Success`], (state, action) => (Object.assign(Object.assign({}, state), { [entityName]: action[entityName] }))));
1451
+ },
1452
+ }),
1453
+ ];
1454
+ }
1455
+
1456
+ /**
1457
+ * Generates ngrx code needed to set and entity in the store state
1458
+ * @param entityName - Entity name, should be in camel case
1459
+ * @param options.actionProps - param for the main request action,
1460
+ * use the props() function for its value
1461
+ * @returns the trait factory
1462
+ *
1463
+ * @example
1464
+ * const traits = createEntityFeatureFactory(
1465
+ * addSetEntityTraits({
1466
+ * entityName: 'client',
1467
+ * actionProps: props<{ client: { id: number; name: string } }
1468
+ * }),
1469
+ * )({
1470
+ * actionsGroupKey: 'Client',
1471
+ * featureSelector: createFeatureSelector<
1472
+ * SetEntityState<Client, 'client'>
1473
+ * >('client'),
1474
+ * });
1475
+ *
1476
+ * // will generate
1477
+ * traits.actions.setClient({client: {id:123, name: 'gabs'}});
1478
+ * traits.selectors.selectClient
1479
+ */
1480
+ function addSetEntityTrait({ entityName, actionProps, }) {
1481
+ const capitalizedName = capitalize(entityName);
1482
+ return createTraitFactory({
1483
+ key: `load${capitalizedName}`,
1484
+ config: { entityName, actionProps },
1485
+ actions: ({ actionsGroupKey }) => {
1486
+ const setEntity = createAction(`${actionsGroupKey} Set ${capitalizedName}`, actionProps);
1487
+ return {
1488
+ [`set${capitalizedName}`]: setEntity,
1489
+ };
1490
+ },
1491
+ selectors: () => {
1492
+ function selectEntity(state) {
1493
+ return state[`${entityName}`];
1494
+ }
1495
+ return {
1496
+ [`select${capitalizedName}`]: selectEntity,
1497
+ };
1498
+ },
1499
+ initialState: ({ previousInitialState }) => previousInitialState,
1500
+ reducer: ({ initialState, allActions }) => {
1501
+ return createReducer(initialState, on(allActions[`set${capitalizedName}`], (state, action) => (Object.assign(Object.assign({}, state), { [entityName]: action[entityName] }))));
1502
+ },
1503
+ });
1504
+ }
1505
+
1506
+ /**
1507
+ * Generated bundle index. Do not edit.
1508
+ */
1509
+
1510
+ export { ChangeType, _isNumberValue, addAsyncActionTrait, addCrudEntitiesTrait, addEntitiesPaginationTrait, addFilterEntitiesTrait, addLoadEntitiesTrait, addLoadEntityTraits, addResetEntitiesStateTrait, addSelectEntitiesTrait, addSelectEntityTrait, addSetEntityTrait, addSortEntitiesTrait, clearEntitiesSelection, crudEntitiesTraitKey, deselectEntities, entitiesPaginationTraitKey, filterEntitiesTraitKey, loadEntitiesTraitKey, selectEntities, selectEntityTraitKey, selectTotalSelectedEntities, sortData, sortTraitKey, toggleSelectEntities };
1511
+ //# sourceMappingURL=ngrx-traits-common.js.map