@ngrx-traits/core 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.
- package/README.md +24 -0
- package/bundles/ngrx-traits-core-testing.umd.js +52 -0
- package/bundles/ngrx-traits-core-testing.umd.js.map +1 -0
- package/bundles/ngrx-traits-core.umd.js +1212 -0
- package/bundles/ngrx-traits-core.umd.js.map +1 -0
- package/cache/cache.actions.d.ts +29 -0
- package/cache/cache.models.d.ts +20 -0
- package/cache/cache.module.d.ts +7 -0
- package/cache/cache.reducer.d.ts +3 -0
- package/cache/cache.selectors.d.ts +3 -0
- package/cache/cache.service.d.ts +65 -0
- package/cache/index.d.ts +17 -0
- package/create-entity-feature.d.ts +59 -0
- package/esm2015/cache/cache.actions.js +6 -0
- package/esm2015/cache/cache.actions.js.map +1 -0
- package/esm2015/cache/cache.models.js +31 -0
- package/esm2015/cache/cache.models.js.map +1 -0
- package/esm2015/cache/cache.module.js +18 -0
- package/esm2015/cache/cache.module.js.map +1 -0
- package/esm2015/cache/cache.reducer.js +141 -0
- package/esm2015/cache/cache.reducer.js.map +1 -0
- package/esm2015/cache/cache.selectors.js +5 -0
- package/esm2015/cache/cache.selectors.js.map +1 -0
- package/esm2015/cache/cache.service.js +72 -0
- package/esm2015/cache/cache.service.js.map +1 -0
- package/esm2015/cache/index.js +7 -0
- package/esm2015/cache/index.js.map +1 -0
- package/esm2015/create-entity-feature.js +283 -0
- package/esm2015/create-entity-feature.js.map +1 -0
- package/esm2015/index.js +7 -0
- package/esm2015/index.js.map +1 -0
- package/esm2015/local-store/disable-local-trait-effects.token.js +6 -0
- package/esm2015/local-store/disable-local-trait-effects.token.js.map +1 -0
- package/esm2015/local-store/index.js +3 -0
- package/esm2015/local-store/index.js.map +1 -0
- package/esm2015/local-store/traits-local-store.js +75 -0
- package/esm2015/local-store/traits-local-store.js.map +1 -0
- package/esm2015/model.js +28 -0
- package/esm2015/model.js.map +1 -0
- package/esm2015/ngrx-traits-core.js +5 -0
- package/esm2015/ngrx-traits-core.js.map +1 -0
- package/esm2015/public_api.js +2 -0
- package/esm2015/public_api.js.map +1 -0
- package/esm2015/testing/index.js +2 -0
- package/esm2015/testing/index.js.map +1 -0
- package/esm2015/testing/ngrx-traits-core-testing.js +5 -0
- package/esm2015/testing/ngrx-traits-core-testing.js.map +1 -0
- package/esm2015/testing/provide-mock-local-traits.js +39 -0
- package/esm2015/testing/provide-mock-local-traits.js.map +1 -0
- package/esm2015/testing/public_api.js +2 -0
- package/esm2015/testing/public_api.js.map +1 -0
- package/esm2015/trait-effect.js +32 -0
- package/esm2015/trait-effect.js.map +1 -0
- package/esm2015/util.js +17 -0
- package/esm2015/util.js.map +1 -0
- package/fesm2015/ngrx-traits-core-testing.js +46 -0
- package/fesm2015/ngrx-traits-core-testing.js.map +1 -0
- package/fesm2015/ngrx-traits-core.js +699 -0
- package/fesm2015/ngrx-traits-core.js.map +1 -0
- package/index.d.ts +6 -0
- package/local-store/disable-local-trait-effects.token.d.ts +5 -0
- package/local-store/index.d.ts +2 -0
- package/local-store/traits-local-store.d.ts +33 -0
- package/model.d.ts +103 -0
- package/ngrx-traits-core.d.ts +5 -0
- package/package.json +29 -0
- package/public_api.d.ts +1 -0
- package/testing/index.d.ts +1 -0
- package/testing/ngrx-traits-core-testing.d.ts +5 -0
- package/testing/package.json +10 -0
- package/testing/provide-mock-local-traits.d.ts +8 -0
- package/testing/public_api.d.ts +1 -0
- package/trait-effect.d.ts +16 -0
- package/util.d.ts +8 -0
|
@@ -0,0 +1,699 @@
|
|
|
1
|
+
import * as i2 from '@ngrx/store';
|
|
2
|
+
import { createFeatureSelector, createReducer, createSelector, combineReducers, ReducerManager, Store, createAction, props, on, StoreModule } from '@ngrx/store';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { Injectable, InjectionToken, Injector, NgModule } from '@angular/core';
|
|
5
|
+
import * as i1 from '@ngrx/effects';
|
|
6
|
+
import { ofType, EffectSources, Actions } from '@ngrx/effects';
|
|
7
|
+
import { takeUntil, first, concatMap, tap } from 'rxjs/operators';
|
|
8
|
+
import { of } from 'rxjs';
|
|
9
|
+
|
|
10
|
+
function insertIf(condition, getElement) {
|
|
11
|
+
return condition ? [getElement()] : [];
|
|
12
|
+
}
|
|
13
|
+
function toMap(a) {
|
|
14
|
+
return a.reduce((acum, value) => {
|
|
15
|
+
acum[value] = true;
|
|
16
|
+
return acum;
|
|
17
|
+
}, {});
|
|
18
|
+
}
|
|
19
|
+
function capitalize(name) {
|
|
20
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
21
|
+
}
|
|
22
|
+
function camelCaseToSentence(text) {
|
|
23
|
+
const result = text.replace(/([A-Z])/g, ' $1');
|
|
24
|
+
return result.charAt(0).toUpperCase() + result.slice(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function createTraitFactory(f) {
|
|
28
|
+
return f;
|
|
29
|
+
}
|
|
30
|
+
function createEntityFeatureFactory(namesOrFactory, ...traits) {
|
|
31
|
+
return ((config) => {
|
|
32
|
+
const { entityName, entitiesName } = 'entityName' in namesOrFactory
|
|
33
|
+
? namesOrFactory
|
|
34
|
+
: { entityName: 'Entity', entitiesName: 'Entities' };
|
|
35
|
+
const singular = capitalize(entityName);
|
|
36
|
+
const plural = entitiesName
|
|
37
|
+
? capitalize(entitiesName)
|
|
38
|
+
: capitalize(entityName + 's');
|
|
39
|
+
const sortedTraits = sortTraits('entityName' in namesOrFactory ? [...traits] : [namesOrFactory, ...traits]);
|
|
40
|
+
const allConfigs = buildAllConfigs(sortedTraits);
|
|
41
|
+
const allActions = buildAllActions(sortedTraits, config.actionsGroupKey, singular, plural, allConfigs);
|
|
42
|
+
const allSelectors = buildAllSelectors(sortedTraits, allConfigs);
|
|
43
|
+
const allMutators = buildAllMutators(sortedTraits, allSelectors, allConfigs);
|
|
44
|
+
const initialState = buildInitialState(sortedTraits, allConfigs);
|
|
45
|
+
const reducer = buildReducer(sortedTraits, initialState, allActions, allSelectors, allMutators, allConfigs);
|
|
46
|
+
const featureSelector = typeof config.featureSelector === 'string'
|
|
47
|
+
? createFeatureSelector(config.featureSelector)
|
|
48
|
+
: config.featureSelector;
|
|
49
|
+
const allFeatureSelectors = allSelectors && getSelectorsForFeature(featureSelector, allSelectors);
|
|
50
|
+
const allEffects = buildAllEffects(sortedTraits, allActions, allFeatureSelectors, allConfigs);
|
|
51
|
+
return {
|
|
52
|
+
actions: entityName
|
|
53
|
+
? renameProps(allActions, singular, plural)
|
|
54
|
+
: allActions,
|
|
55
|
+
selectors: entityName
|
|
56
|
+
? renameProps(allFeatureSelectors, singular, plural)
|
|
57
|
+
: allSelectors,
|
|
58
|
+
initialState,
|
|
59
|
+
reducer: reducer !== null && reducer !== void 0 ? reducer : createReducer(initialState),
|
|
60
|
+
effects: allEffects,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function renameProps(target, entityName, entitiesName) {
|
|
65
|
+
const result = {};
|
|
66
|
+
for (const [key, value] of Object.entries(target)) {
|
|
67
|
+
const newKey = key
|
|
68
|
+
.replace('Entities', entitiesName)
|
|
69
|
+
.replace('Entity', entityName);
|
|
70
|
+
result[newKey] = value;
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
function sortTraits(traits) {
|
|
75
|
+
var _a;
|
|
76
|
+
const sortedTraits = [];
|
|
77
|
+
for (let i = 0; i < traits.length; i++) {
|
|
78
|
+
const trait = traits[i];
|
|
79
|
+
if (!((_a = trait.depends) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
80
|
+
sortedTraits.push(trait);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (trait.depends.length > 1)
|
|
84
|
+
for (const d of trait.depends) {
|
|
85
|
+
const isTraitPresent = traits.some((tr) => tr.key === d);
|
|
86
|
+
if (isTraitPresent) {
|
|
87
|
+
trait.depends = [d];
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (trait.depends.length > 1)
|
|
92
|
+
throw Error('could not find dependencies ' + trait.depends.join(' '));
|
|
93
|
+
const isDependencyAlreadyAdded = sortedTraits.some((tr) => { var _a; return tr.key === ((_a = trait === null || trait === void 0 ? void 0 : trait.depends) === null || _a === void 0 ? void 0 : _a[0]); });
|
|
94
|
+
if (isDependencyAlreadyAdded)
|
|
95
|
+
sortedTraits.push(trait);
|
|
96
|
+
else {
|
|
97
|
+
// move trait to the end
|
|
98
|
+
delete traits[i];
|
|
99
|
+
traits.push(trait);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return sortedTraits;
|
|
103
|
+
}
|
|
104
|
+
function buildAllConfigs(sortedTraits) {
|
|
105
|
+
return sortedTraits.reduce((acc, factory) => {
|
|
106
|
+
acc[factory.key] = factory.config;
|
|
107
|
+
return acc;
|
|
108
|
+
}, {});
|
|
109
|
+
}
|
|
110
|
+
function buildAllActions(sortedTraits, actionsGroupKey, entityName, entitiesName, allConfigs) {
|
|
111
|
+
return sortedTraits.reduce((previousResult, factory) => {
|
|
112
|
+
var _a, _b;
|
|
113
|
+
let result = (_b = (_a = factory === null || factory === void 0 ? void 0 : factory.actions) === null || _a === void 0 ? void 0 : _a.call(factory, {
|
|
114
|
+
actionsGroupKey: actionsGroupKey,
|
|
115
|
+
entityName,
|
|
116
|
+
entitiesName,
|
|
117
|
+
allConfigs,
|
|
118
|
+
})) !== null && _b !== void 0 ? _b : {};
|
|
119
|
+
result = previousResult ? Object.assign(Object.assign({}, previousResult), result) : result;
|
|
120
|
+
return result;
|
|
121
|
+
}, {});
|
|
122
|
+
}
|
|
123
|
+
function buildAllSelectors(sortedTraits, allConfigs) {
|
|
124
|
+
return sortedTraits.reduce((previousResult, factory) => {
|
|
125
|
+
var _a, _b;
|
|
126
|
+
let result = (_b = (_a = factory === null || factory === void 0 ? void 0 : factory.selectors) === null || _a === void 0 ? void 0 : _a.call(factory, {
|
|
127
|
+
previousSelectors: previousResult,
|
|
128
|
+
allConfigs,
|
|
129
|
+
})) !== null && _b !== void 0 ? _b : {};
|
|
130
|
+
result = previousResult ? Object.assign(Object.assign({}, previousResult), result) : result;
|
|
131
|
+
return result;
|
|
132
|
+
}, {});
|
|
133
|
+
}
|
|
134
|
+
function buildAllMutators(sortedTraits, allSelectors, allConfigs) {
|
|
135
|
+
return (sortedTraits.reduce((previousResult, factory) => {
|
|
136
|
+
var _a, _b;
|
|
137
|
+
let result = (_b = (_a = factory === null || factory === void 0 ? void 0 : factory.mutators) === null || _a === void 0 ? void 0 : _a.call(factory, {
|
|
138
|
+
allSelectors: allSelectors,
|
|
139
|
+
previousMutators: previousResult,
|
|
140
|
+
allConfigs,
|
|
141
|
+
})) !== null && _b !== void 0 ? _b : {};
|
|
142
|
+
result = previousResult ? Object.assign(Object.assign({}, previousResult), result) : result;
|
|
143
|
+
return result;
|
|
144
|
+
}, {}) || {});
|
|
145
|
+
}
|
|
146
|
+
function buildInitialState(sortedTraits, allConfigs) {
|
|
147
|
+
return sortedTraits.reduce((previousResult, factory) => {
|
|
148
|
+
var _a, _b, _c;
|
|
149
|
+
const result = (_c = (_b = (_a = factory === null || factory === void 0 ? void 0 : factory.initialState) === null || _a === void 0 ? void 0 : _a.call(factory, {
|
|
150
|
+
previousInitialState: previousResult,
|
|
151
|
+
allConfigs,
|
|
152
|
+
})) !== null && _b !== void 0 ? _b : previousResult) !== null && _c !== void 0 ? _c : {};
|
|
153
|
+
return result;
|
|
154
|
+
}, {});
|
|
155
|
+
}
|
|
156
|
+
function buildReducer(sortedTraits, initialState, allActions, allSelectors, allMutators, allConfigs) {
|
|
157
|
+
return sortedTraits.reduce((previousResult, factory) => {
|
|
158
|
+
var _a;
|
|
159
|
+
const result = (_a = factory === null || factory === void 0 ? void 0 : factory.reducer) === null || _a === void 0 ? void 0 : _a.call(factory, {
|
|
160
|
+
initialState,
|
|
161
|
+
allActions,
|
|
162
|
+
allSelectors,
|
|
163
|
+
allMutators,
|
|
164
|
+
allConfigs,
|
|
165
|
+
});
|
|
166
|
+
return result && previousResult
|
|
167
|
+
? (state = initialState, action) => {
|
|
168
|
+
const aState = previousResult(state, action);
|
|
169
|
+
return result(aState, action);
|
|
170
|
+
}
|
|
171
|
+
: result !== null && result !== void 0 ? result : previousResult;
|
|
172
|
+
}, undefined);
|
|
173
|
+
}
|
|
174
|
+
function buildAllEffects(sortedTraits, allActions, allFeatureSelectors, allConfigs) {
|
|
175
|
+
return sortedTraits.reduce((previousResult, factory) => {
|
|
176
|
+
var _a, _b;
|
|
177
|
+
let result = (_b = (_a = factory === null || factory === void 0 ? void 0 : factory.effects) === null || _a === void 0 ? void 0 : _a.call(factory, {
|
|
178
|
+
allActions,
|
|
179
|
+
allSelectors: allFeatureSelectors,
|
|
180
|
+
allConfigs,
|
|
181
|
+
})) !== null && _b !== void 0 ? _b : [];
|
|
182
|
+
result = previousResult ? [...previousResult, ...result] : result;
|
|
183
|
+
return result;
|
|
184
|
+
}, []);
|
|
185
|
+
}
|
|
186
|
+
function getSelectorsForFeature(featureSelect, selectors) {
|
|
187
|
+
const ss = {};
|
|
188
|
+
for (const prop in selectors) {
|
|
189
|
+
ss[prop] = createSelector(featureSelect, selectors[prop]);
|
|
190
|
+
}
|
|
191
|
+
return ss;
|
|
192
|
+
}
|
|
193
|
+
function setPropertyReducer(sourceReducer, property, propertyReducer) {
|
|
194
|
+
return function reducer(state, action) {
|
|
195
|
+
const sourceState = sourceReducer(state, action);
|
|
196
|
+
return Object.assign(Object.assign({}, sourceState), { [property]: propertyReducer(sourceState[property], action) });
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function setPropertiesReducer(sourceReducer, propertiesReducers) {
|
|
200
|
+
return function reducer(state, action) {
|
|
201
|
+
const newState = Object.assign({}, sourceReducer(state, action));
|
|
202
|
+
for (const property in propertiesReducers) {
|
|
203
|
+
newState[property] = propertiesReducers[property](newState[property], action);
|
|
204
|
+
}
|
|
205
|
+
return newState;
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function joinReducers(firstReducer, secondReducer) {
|
|
209
|
+
return function reducer(state, action) {
|
|
210
|
+
const sourceState = firstReducer(state, action);
|
|
211
|
+
return secondReducer(sourceState, action);
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function combineEntityFeatures(traitFactoriesMap) {
|
|
215
|
+
return ((config) => {
|
|
216
|
+
const featureSelector = typeof config.featureSelector === 'string'
|
|
217
|
+
? createFeatureSelector(config.featureSelector)
|
|
218
|
+
: config.featureSelector;
|
|
219
|
+
const actions = {};
|
|
220
|
+
const selectors = {};
|
|
221
|
+
const reducers = {};
|
|
222
|
+
let effects = [];
|
|
223
|
+
for (const [key, entityFeatureFactory] of Object.entries(traitFactoriesMap)) {
|
|
224
|
+
const selector = createSelector(featureSelector, (state) => state[key]);
|
|
225
|
+
const featureTraits = entityFeatureFactory({
|
|
226
|
+
actionsGroupKey: config.actionsGroupKey,
|
|
227
|
+
featureSelector: selector,
|
|
228
|
+
});
|
|
229
|
+
actions[key] = featureTraits.actions;
|
|
230
|
+
selectors[key] = featureTraits.selectors;
|
|
231
|
+
reducers[key] = featureTraits.reducer;
|
|
232
|
+
effects = [...effects, ...featureTraits.effects];
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
actions,
|
|
236
|
+
selectors,
|
|
237
|
+
reducer: combineReducers(reducers),
|
|
238
|
+
effects,
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function mixEntityFeatures(traitFactoriesMap) {
|
|
243
|
+
return ((config) => {
|
|
244
|
+
const featureSelector = typeof config.featureSelector === 'string'
|
|
245
|
+
? createFeatureSelector(config.featureSelector)
|
|
246
|
+
: config.featureSelector;
|
|
247
|
+
let actions = {};
|
|
248
|
+
let selectors = {};
|
|
249
|
+
const reducers = {};
|
|
250
|
+
let effects = [];
|
|
251
|
+
for (const [key, entityFeatureFactory] of Object.entries(traitFactoriesMap)) {
|
|
252
|
+
const selector = createSelector(featureSelector, (state) => state[key]);
|
|
253
|
+
const featureTraits = entityFeatureFactory({
|
|
254
|
+
actionsGroupKey: config.actionsGroupKey,
|
|
255
|
+
featureSelector: selector,
|
|
256
|
+
});
|
|
257
|
+
actions = Object.assign(Object.assign({}, actions), featureTraits.actions);
|
|
258
|
+
selectors = Object.assign(Object.assign({}, selectors), featureTraits.selectors);
|
|
259
|
+
reducers[key] = featureTraits.reducer;
|
|
260
|
+
effects = [...effects, ...featureTraits.effects];
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
actions,
|
|
264
|
+
selectors,
|
|
265
|
+
reducer: combineReducers(reducers),
|
|
266
|
+
effects,
|
|
267
|
+
};
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function addEntityFeaturesProperties(targetTraitFactory, traitFactoriesMap) {
|
|
271
|
+
return ((config) => {
|
|
272
|
+
const featureSelector = typeof config.featureSelector === 'string'
|
|
273
|
+
? createFeatureSelector(config.featureSelector)
|
|
274
|
+
: config.featureSelector;
|
|
275
|
+
const targetFeatureTraits = targetTraitFactory({
|
|
276
|
+
actionsGroupKey: config.actionsGroupKey,
|
|
277
|
+
featureSelector: featureSelector,
|
|
278
|
+
});
|
|
279
|
+
const actions = Object.assign({}, targetFeatureTraits.actions);
|
|
280
|
+
const selectors = Object.assign({}, targetFeatureTraits.selectors);
|
|
281
|
+
const reducers = {};
|
|
282
|
+
let effects = [...targetFeatureTraits.effects];
|
|
283
|
+
for (const [key, entityFeatureFactory] of Object.entries(traitFactoriesMap)) {
|
|
284
|
+
const selector = createSelector(featureSelector, (state) => state[key]);
|
|
285
|
+
const featureTraits = entityFeatureFactory({
|
|
286
|
+
actionsGroupKey: config.actionsGroupKey,
|
|
287
|
+
featureSelector: selector,
|
|
288
|
+
});
|
|
289
|
+
actions[key] = featureTraits.actions;
|
|
290
|
+
selectors[key] = featureTraits.selectors;
|
|
291
|
+
reducers[key] = featureTraits.reducer;
|
|
292
|
+
effects = [...effects, ...featureTraits.effects];
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
actions,
|
|
296
|
+
selectors,
|
|
297
|
+
reducer: setPropertiesReducer(targetFeatureTraits.reducer, reducers),
|
|
298
|
+
effects,
|
|
299
|
+
};
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
// export
|
|
303
|
+
/// products:{actions, selectors, }, orders: {actions,slectors}
|
|
304
|
+
/// { actions: {ProductActions, OrderActions}, selectors: {ProductSelectors, OrderSelectors}
|
|
305
|
+
// TODO finish implementing combineTrais and addPropertiesTraits
|
|
306
|
+
// TODO finish renaming traits
|
|
307
|
+
|
|
308
|
+
// type G = ReplaceProps<
|
|
309
|
+
// ReplaceProps<
|
|
310
|
+
// {
|
|
311
|
+
// loadEntities: 1;
|
|
312
|
+
// loadEntitiesSuccess: 2;
|
|
313
|
+
// selectEntities: 3;
|
|
314
|
+
// selectEntity: 4;
|
|
315
|
+
// },
|
|
316
|
+
// 'Entities',
|
|
317
|
+
// 'products'
|
|
318
|
+
// >,
|
|
319
|
+
// 'Entity',
|
|
320
|
+
// 'product'
|
|
321
|
+
// >;
|
|
322
|
+
//
|
|
323
|
+
// const g: G = {};
|
|
324
|
+
// // g.
|
|
325
|
+
// type F= ReplaceEntityNames<{
|
|
326
|
+
// loadEntities: 1;
|
|
327
|
+
// loadEntitiesSuccess: 2;
|
|
328
|
+
// selectEntities: 3;
|
|
329
|
+
// selectEntity: 4;
|
|
330
|
+
// }, 'product','products'>;
|
|
331
|
+
// const f: F = {};
|
|
332
|
+
// f.
|
|
333
|
+
// TODO clean up file
|
|
334
|
+
|
|
335
|
+
class TraitEffect {
|
|
336
|
+
constructor(actions$, store) {
|
|
337
|
+
this.actions$ = actions$;
|
|
338
|
+
this.store = store;
|
|
339
|
+
this.name = this.constructor.name;
|
|
340
|
+
this.componentId = '';
|
|
341
|
+
}
|
|
342
|
+
ngrxOnIdentifyEffects() {
|
|
343
|
+
return this.componentId ? this.name + this.componentId : '';
|
|
344
|
+
}
|
|
345
|
+
ngrxOnRunEffects(resolvedEffects$) {
|
|
346
|
+
return this.componentId
|
|
347
|
+
? resolvedEffects$.pipe(takeUntil(this.actions$.pipe(ofType(getDestroyActionName(this.componentId)))))
|
|
348
|
+
: resolvedEffects$;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
TraitEffect.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: TraitEffect, deps: [{ token: i1.Actions }, { token: i2.Store }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
352
|
+
TraitEffect.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: TraitEffect });
|
|
353
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: TraitEffect, decorators: [{
|
|
354
|
+
type: Injectable
|
|
355
|
+
}], ctorParameters: function () { return [{ type: i1.Actions }, { type: i2.Store }]; } });
|
|
356
|
+
function getDestroyActionName(id) {
|
|
357
|
+
return `[${id}] Destroyed`;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* @internal
|
|
362
|
+
*/
|
|
363
|
+
const DISABLE_LOCAL_TRAIT_EFFECTS = new InjectionToken('disableLocalTraitEffects');
|
|
364
|
+
|
|
365
|
+
let id = 0;
|
|
366
|
+
function uniqueComponentId() {
|
|
367
|
+
return id++;
|
|
368
|
+
}
|
|
369
|
+
function buildLocalTraits(injector, componentName, traitFactory) {
|
|
370
|
+
var _a;
|
|
371
|
+
const reducers = injector.get(ReducerManager);
|
|
372
|
+
const effects = injector.get(EffectSources);
|
|
373
|
+
const store = injector.get(Store);
|
|
374
|
+
const componentId = `${componentName}_${uniqueComponentId()}`;
|
|
375
|
+
const traits = traitFactory({
|
|
376
|
+
featureSelector: createFeatureSelector(componentId),
|
|
377
|
+
actionsGroupKey: `[${componentId}]`,
|
|
378
|
+
});
|
|
379
|
+
traits.reducer && reducers.addReducer(componentId, traits.reducer);
|
|
380
|
+
const providers = (traits.effects && [...traits.effects.map((e) => ({ provide: e }))]) || [];
|
|
381
|
+
const disableLocalTraitsEffects = injector.get(DISABLE_LOCAL_TRAIT_EFFECTS, false);
|
|
382
|
+
if (!disableLocalTraitsEffects) {
|
|
383
|
+
const i = Injector.create({
|
|
384
|
+
providers: providers,
|
|
385
|
+
parent: injector,
|
|
386
|
+
});
|
|
387
|
+
(_a = traits.effects) === null || _a === void 0 ? void 0 : _a.forEach((e) => {
|
|
388
|
+
const effect = i.get(e);
|
|
389
|
+
effect.componentId = componentId;
|
|
390
|
+
effects.addEffects(effect);
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
function destroy() {
|
|
394
|
+
store.dispatch({ type: getDestroyActionName(componentId) });
|
|
395
|
+
/**
|
|
396
|
+
* A service that extends TraitsLocalStore and other component service are destroyed
|
|
397
|
+
* before the component that depends on them, this causes that any subscriptions
|
|
398
|
+
* to selectors of the TraitsLocalStore could fail because the store state is removed before
|
|
399
|
+
* they are unsubscribe by the onDestroy of the component. Executing reducers.removeReducer
|
|
400
|
+
* inside setTimeout ensures the state is remove after the component onDestroy was called,
|
|
401
|
+
* avoiding the before mentioned possible issues.
|
|
402
|
+
*/
|
|
403
|
+
setTimeout(() => reducers.removeReducer(componentId));
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
destroy,
|
|
407
|
+
actions: traits.actions,
|
|
408
|
+
selectors: traits.selectors,
|
|
409
|
+
addEffects(localEffect) {
|
|
410
|
+
localEffect.componentId = componentId;
|
|
411
|
+
effects.addEffects(localEffect);
|
|
412
|
+
},
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
class TraitsLocalStore extends TraitEffect {
|
|
416
|
+
constructor(injector) {
|
|
417
|
+
super(injector.get(Actions), injector.get(Store));
|
|
418
|
+
this.injector = injector;
|
|
419
|
+
const config = this.setup();
|
|
420
|
+
this.traits = buildLocalTraits(this.injector, config.componentName, config.traitsFactory);
|
|
421
|
+
this.localActions = this.traits.actions;
|
|
422
|
+
this.localSelectors = this.traits.selectors;
|
|
423
|
+
}
|
|
424
|
+
ngOnDestroy() {
|
|
425
|
+
this.traits.destroy();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
TraitsLocalStore.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: TraitsLocalStore, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
429
|
+
TraitsLocalStore.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: TraitsLocalStore });
|
|
430
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: TraitsLocalStore, decorators: [{
|
|
431
|
+
type: Injectable
|
|
432
|
+
}], ctorParameters: function () { return [{ type: i0.Injector }]; } });
|
|
433
|
+
|
|
434
|
+
function hash(key) {
|
|
435
|
+
return JSON.stringify(key, (_, val) => typeof val == 'object'
|
|
436
|
+
? Object.keys(val)
|
|
437
|
+
.sort()
|
|
438
|
+
.reduce((result, k) => {
|
|
439
|
+
result[k] = val[k];
|
|
440
|
+
return result;
|
|
441
|
+
}, {})
|
|
442
|
+
: val);
|
|
443
|
+
}
|
|
444
|
+
function hashKey(key) {
|
|
445
|
+
return typeof key === 'string'
|
|
446
|
+
? [key]
|
|
447
|
+
: key.map((k) => {
|
|
448
|
+
return typeof k === 'string' ? k : hash(k);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
function getCacheValue(keys, state) {
|
|
452
|
+
var _a;
|
|
453
|
+
let parent = state;
|
|
454
|
+
for (const key of keys) {
|
|
455
|
+
parent = (_a = parent === null || parent === void 0 ? void 0 : parent.keys) === null || _a === void 0 ? void 0 : _a[key];
|
|
456
|
+
if (!parent)
|
|
457
|
+
return undefined;
|
|
458
|
+
}
|
|
459
|
+
return parent === null || parent === void 0 ? void 0 : parent.data;
|
|
460
|
+
}
|
|
461
|
+
function isCacheValid(cache, exp) {
|
|
462
|
+
return !cache.invalid && Date.now() <= cache.date + exp;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const cacheStateSelector = createFeatureSelector('cache');
|
|
466
|
+
const selectCache = (key) => createSelector(cacheStateSelector, (state) => getCacheValue(hashKey(key), state));
|
|
467
|
+
|
|
468
|
+
const cache$1 = createAction('[Cache] Cache', props());
|
|
469
|
+
const hitCache = createAction('[Cache] Hit Cache', props());
|
|
470
|
+
const invalidateCache$1 = createAction('[Cache] Invalidate Cache', props());
|
|
471
|
+
const deleteCache = createAction('[Cache] Delete Cache', props());
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Cache the result of source parameter using the provided key, when call
|
|
475
|
+
* again if the cache is valid (exist and is not expired or invalidated)
|
|
476
|
+
* it will return the cache value without calling again source
|
|
477
|
+
* @example
|
|
478
|
+
* // cache for 3 min
|
|
479
|
+
* loadStores$ = createEffect(() => {
|
|
480
|
+
* return this.actions$.pipe(
|
|
481
|
+
* ofType(ProductStoreActions.loadStores),
|
|
482
|
+
* exhaustMap(() =>
|
|
483
|
+
* cache({
|
|
484
|
+
* key: ['stores'],
|
|
485
|
+
* store: this.store,
|
|
486
|
+
* source: this.storeService.getStores(),
|
|
487
|
+
* expire: 1000 * 60 * 3 // optional param , cache forever if not present
|
|
488
|
+
* }).pipe(
|
|
489
|
+
* map((res) => ProductStoreActions.loadStoresSuccess({ entities: res })),
|
|
490
|
+
* catchError(() => of(ProductStoreActions.loadStoresFail()))
|
|
491
|
+
* )
|
|
492
|
+
* )
|
|
493
|
+
* );
|
|
494
|
+
* });
|
|
495
|
+
* // cache top 10, for 3 mins
|
|
496
|
+
* loadDepartments$ = createEffect(() => {
|
|
497
|
+
* return this.actions$.pipe(
|
|
498
|
+
* ofType(this.localActions.loadDepartments),
|
|
499
|
+
* concatLatestFrom(() =>
|
|
500
|
+
* this.store.select(this.localSelectors.selectDepartmentsFilter)
|
|
501
|
+
* ),
|
|
502
|
+
* exhaustMap(([_, filters]) =>
|
|
503
|
+
* cache({
|
|
504
|
+
* key: ['stores','departments',{ storeId: filters!.storeId },
|
|
505
|
+
* store: this.store,
|
|
506
|
+
* source: this.storeService.getStoreDepartments(filters!.storeId),
|
|
507
|
+
* expires: 1000 * 60 * 3,
|
|
508
|
+
* maxCacheSize: 10,
|
|
509
|
+
* }).pipe(
|
|
510
|
+
* map((res) =>
|
|
511
|
+
* this.localActions.loadDepartmentsSuccess({
|
|
512
|
+
* entities: res,
|
|
513
|
+
* })
|
|
514
|
+
* ),
|
|
515
|
+
* catchError(() => of(this.localActions.loadDepartmentsFail()))
|
|
516
|
+
* )
|
|
517
|
+
* )
|
|
518
|
+
* );
|
|
519
|
+
* });
|
|
520
|
+
*
|
|
521
|
+
* @param options - configuration
|
|
522
|
+
* @param options.store - required ngrx store
|
|
523
|
+
* @param options.key - key can be string, array of string or array of string with plain objects
|
|
524
|
+
* @param options.source - called when cache is invalid
|
|
525
|
+
* @param options.expires - time to expire the cache valued, if not present is infinite
|
|
526
|
+
* @param options.maxCacheSize - max number of keys to store , only works if last key is variable
|
|
527
|
+
*/
|
|
528
|
+
function cache({ store, key, source, expires, maxCacheSize, }) {
|
|
529
|
+
const exp = expires !== null && expires !== void 0 ? expires : Infinity;
|
|
530
|
+
return store.select(selectCache(key)).pipe(first(), concatMap((cache) => cache && isCacheValid(cache, exp)
|
|
531
|
+
? of(cache.value).pipe(tap(() => store.dispatch(hitCache({ key }))))
|
|
532
|
+
: source.pipe(tap((value) => store.dispatch(cache$1({
|
|
533
|
+
key,
|
|
534
|
+
date: Date.now(),
|
|
535
|
+
value,
|
|
536
|
+
maxCacheSize,
|
|
537
|
+
}))))));
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const initialState = {
|
|
541
|
+
keys: {},
|
|
542
|
+
};
|
|
543
|
+
const cacheReducer = createReducer(initialState, on(cache$1, (state, { key, value, date, maxCacheSize }) => setCacheValue(hashKey(key), { value, date, invalid: false }, state, maxCacheSize)), on(invalidateCache$1, (state, { key }) => {
|
|
544
|
+
const k = hashKey(key);
|
|
545
|
+
return invalidateCache(k, state);
|
|
546
|
+
}), on(deleteCache, (state, { key }) => {
|
|
547
|
+
const k = hashKey(key);
|
|
548
|
+
return deleteCacheValue(k, state);
|
|
549
|
+
}), on(hitCache, (state, { key }) => {
|
|
550
|
+
const k = hashKey(key);
|
|
551
|
+
return increaseCacheHitCount(k, state);
|
|
552
|
+
}));
|
|
553
|
+
function setCacheValue(keys, value, state, maxCacheSize, expires) {
|
|
554
|
+
const newState = Object.assign({}, state);
|
|
555
|
+
let cache = newState;
|
|
556
|
+
let lastCache = undefined;
|
|
557
|
+
for (let i = 0; i < keys.length; i++) {
|
|
558
|
+
const key = keys[i];
|
|
559
|
+
cache.keys = (cache === null || cache === void 0 ? void 0 : cache.keys) ? Object.assign({}, cache === null || cache === void 0 ? void 0 : cache.keys) : {};
|
|
560
|
+
let v = cache.keys[key];
|
|
561
|
+
v = v ? Object.assign({}, v) : {};
|
|
562
|
+
cache.keys[key] = v;
|
|
563
|
+
lastCache = cache;
|
|
564
|
+
cache = v;
|
|
565
|
+
}
|
|
566
|
+
cache.data = cache.data
|
|
567
|
+
? Object.assign(Object.assign({}, value), { hitCount: cache.data.hitCount + 1 }) : Object.assign(Object.assign({}, value), { hitCount: 1 });
|
|
568
|
+
if (maxCacheSize &&
|
|
569
|
+
(lastCache === null || lastCache === void 0 ? void 0 : lastCache.keys) &&
|
|
570
|
+
Object.keys(lastCache.keys).length > maxCacheSize) {
|
|
571
|
+
const entries = findLessHitOrOldestCacheEntries(lastCache, expires !== null && expires !== void 0 ? expires : Infinity, maxCacheSize);
|
|
572
|
+
if (entries && entries.length) {
|
|
573
|
+
for (const [key] of entries) {
|
|
574
|
+
delete lastCache.keys[key];
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return newState;
|
|
579
|
+
}
|
|
580
|
+
function findLessHitOrOldestCacheEntries(state, expires, maxCacheSize) {
|
|
581
|
+
if (!state.keys)
|
|
582
|
+
return undefined;
|
|
583
|
+
const entries = Object.entries(state.keys);
|
|
584
|
+
// find the newest key;
|
|
585
|
+
const [newestKey] = entries.reduce((a, b) => {
|
|
586
|
+
var _a, _b, _c, _d;
|
|
587
|
+
const aDate = (_b = (_a = a[1].data) === null || _a === void 0 ? void 0 : _a.date) !== null && _b !== void 0 ? _b : 0;
|
|
588
|
+
const bDate = (_d = (_c = b[1].data) === null || _c === void 0 ? void 0 : _c.date) !== null && _d !== void 0 ? _d : 0;
|
|
589
|
+
return aDate > bDate ? a : b;
|
|
590
|
+
});
|
|
591
|
+
const sorted = entries.sort(([aKey, aValue], [bKey, bValue]) => {
|
|
592
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
593
|
+
// ensures the newest key always wins
|
|
594
|
+
if (aKey === newestKey)
|
|
595
|
+
return -1;
|
|
596
|
+
if (bKey === newestKey)
|
|
597
|
+
return 1;
|
|
598
|
+
const aValid = aValue.data && isCacheValid(aValue.data, expires) ? 1 : 0;
|
|
599
|
+
const bValid = bValue.data && isCacheValid(bValue.data, expires) ? 1 : 0;
|
|
600
|
+
const diffValid = aValid - bValid;
|
|
601
|
+
const diffHit = ((_b = (_a = aValue.data) === null || _a === void 0 ? void 0 : _a.hitCount) !== null && _b !== void 0 ? _b : 0) - ((_d = (_c = bValue.data) === null || _c === void 0 ? void 0 : _c.hitCount) !== null && _d !== void 0 ? _d : 0);
|
|
602
|
+
const diffDate = ((_f = (_e = aValue.data) === null || _e === void 0 ? void 0 : _e.date) !== null && _f !== void 0 ? _f : 0) - ((_h = (_g = bValue.data) === null || _g === void 0 ? void 0 : _g.date) !== null && _h !== void 0 ? _h : 0);
|
|
603
|
+
return (-1 * (diffValid === 0 ? (diffHit === 0 ? diffDate : diffHit) : diffValid));
|
|
604
|
+
});
|
|
605
|
+
return sorted.slice(maxCacheSize);
|
|
606
|
+
}
|
|
607
|
+
function deleteCacheValue(keys, state) {
|
|
608
|
+
const newState = Object.assign({}, state);
|
|
609
|
+
let cache = newState;
|
|
610
|
+
for (const key of keys) {
|
|
611
|
+
if (!cache.keys)
|
|
612
|
+
return state;
|
|
613
|
+
cache.keys = Object.assign({}, cache === null || cache === void 0 ? void 0 : cache.keys);
|
|
614
|
+
let v = cache.keys[key];
|
|
615
|
+
if (!v)
|
|
616
|
+
return state;
|
|
617
|
+
v = Object.assign({}, v);
|
|
618
|
+
cache.keys[key] = v;
|
|
619
|
+
cache = v;
|
|
620
|
+
}
|
|
621
|
+
if (cache.data)
|
|
622
|
+
delete cache.data;
|
|
623
|
+
else if (cache.keys)
|
|
624
|
+
delete cache.keys;
|
|
625
|
+
return newState;
|
|
626
|
+
}
|
|
627
|
+
function invalidateCache(keys, state) {
|
|
628
|
+
var _a;
|
|
629
|
+
const newState = Object.assign({}, state);
|
|
630
|
+
let cache = newState;
|
|
631
|
+
for (const key of keys) {
|
|
632
|
+
if (!(cache === null || cache === void 0 ? void 0 : cache.keys))
|
|
633
|
+
return state;
|
|
634
|
+
cache.keys = Object.assign({}, cache === null || cache === void 0 ? void 0 : cache.keys);
|
|
635
|
+
let v = (_a = cache === null || cache === void 0 ? void 0 : cache.keys) === null || _a === void 0 ? void 0 : _a[key];
|
|
636
|
+
if (!v)
|
|
637
|
+
return state;
|
|
638
|
+
v = Object.assign({}, v);
|
|
639
|
+
cache.keys[key] = v;
|
|
640
|
+
cache = v;
|
|
641
|
+
}
|
|
642
|
+
cache && invalidaSubKeys(cache);
|
|
643
|
+
return newState;
|
|
644
|
+
}
|
|
645
|
+
function increaseCacheHitCount(keys, state) {
|
|
646
|
+
var _a;
|
|
647
|
+
const newState = Object.assign({}, state);
|
|
648
|
+
let cache = newState;
|
|
649
|
+
for (const key of keys) {
|
|
650
|
+
if (!(cache === null || cache === void 0 ? void 0 : cache.keys))
|
|
651
|
+
return state;
|
|
652
|
+
cache.keys = Object.assign({}, cache === null || cache === void 0 ? void 0 : cache.keys);
|
|
653
|
+
let v = (_a = cache === null || cache === void 0 ? void 0 : cache.keys) === null || _a === void 0 ? void 0 : _a[key];
|
|
654
|
+
if (!v)
|
|
655
|
+
return state;
|
|
656
|
+
v = Object.assign({}, v);
|
|
657
|
+
cache.keys[key] = v;
|
|
658
|
+
cache = v;
|
|
659
|
+
}
|
|
660
|
+
if (!cache.data)
|
|
661
|
+
return state;
|
|
662
|
+
cache.data = Object.assign(Object.assign({}, cache.data), { hitCount: cache.data.hitCount + 1 });
|
|
663
|
+
return newState;
|
|
664
|
+
}
|
|
665
|
+
function invalidaSubKeys(state) {
|
|
666
|
+
if (state.data) {
|
|
667
|
+
state.data = Object.assign(Object.assign({}, state.data), { invalid: true });
|
|
668
|
+
}
|
|
669
|
+
if (state.keys) {
|
|
670
|
+
state.keys = Object.assign({}, state.keys);
|
|
671
|
+
for (const key in state.keys) {
|
|
672
|
+
state.keys[key] = invalidaSubKeys(Object.assign({}, state.keys[key]));
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return state;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
class CacheModule {
|
|
679
|
+
}
|
|
680
|
+
CacheModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: CacheModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
681
|
+
CacheModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: CacheModule, imports: [i2.StoreFeatureModule] });
|
|
682
|
+
CacheModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: CacheModule, providers: [], imports: [[StoreModule.forFeature('cache', cacheReducer)]] });
|
|
683
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.2", ngImport: i0, type: CacheModule, decorators: [{
|
|
684
|
+
type: NgModule,
|
|
685
|
+
args: [{
|
|
686
|
+
imports: [StoreModule.forFeature('cache', cacheReducer)],
|
|
687
|
+
providers: [],
|
|
688
|
+
}]
|
|
689
|
+
}] });
|
|
690
|
+
|
|
691
|
+
const CacheActions = { invalidateCache: invalidateCache$1, deleteCache };
|
|
692
|
+
const CacheSelectors = { getCache: selectCache };
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Generated bundle index. Do not edit.
|
|
696
|
+
*/
|
|
697
|
+
|
|
698
|
+
export { CacheActions, CacheModule, CacheSelectors, DISABLE_LOCAL_TRAIT_EFFECTS, TraitEffect, TraitsLocalStore, addEntityFeaturesProperties, buildLocalTraits, cache, camelCaseToSentence, capitalize, combineEntityFeatures, createEntityFeatureFactory, createTraitFactory, getDestroyActionName, insertIf, joinReducers, mixEntityFeatures, setPropertiesReducer, setPropertyReducer, toMap };
|
|
699
|
+
//# sourceMappingURL=ngrx-traits-core.js.map
|