Skip to content

Commit 93ba371

Browse files
author
Jon Rista
committed
feat: add selectors for tracking if loads were attempted
+ Add selectHasBeenLoaded to track if the data has ever been loaded before + Add selectLoadWasAttempted to track if an attempt to load the data has ever been made ^ Bumped version to 0.8.1 * Updated changelog to reflect latest changes Issue #218
1 parent 919dd94 commit 93ba371

File tree

10 files changed

+132
-2
lines changed

10 files changed

+132
-2
lines changed

CHANGELOG.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
1+
<a name="0.8.1"></a>
2+
3+
# [0.8.1](https://github.com/briebug/ngrx-auto-entity/compare/0.8.1-beta.1...0.8.1) Beta (2022-05-05)
4+
5+
Added two new loading related selectors: hasBeenLoaded and loadWasAttempted. These selectors allow
6+
end developers to determine if a load has ever been attempted before, which is sometimes necessary
7+
to display the correct information in a UI component. Until a load has at least been attempted, it
8+
would generally be inappropriate to display to the user that there are no Entities X, however as
9+
the current state of each entity currently stands, there is no way to determine that particular
10+
state of an entity. You can determine if an entity is loading or not, which is useful for displaying
11+
a spinner, but other messaging requires more information.
12+
13+
### Features
14+
15+
- **selectors:** Added selectHasBeenLoaded to selector map
16+
- **selectors:** Added selectLoadWasAttempted to selector map
17+
18+
119
<a name="0.8.0-beta.1"></a>
220

3-
# [0.7.2](https://github.com/briebug/ngrx-auto-entity/compare/0.7.2...0.8.1-beta.1) Beta (2022-04-05)
21+
# [0.8.0-beta.1](https://github.com/briebug/ngrx-auto-entity/compare/0.7.2...0.8.1-beta.1) Beta (2022-04-05)
422

523
Updated state builders to build all state functionality "on-demand" to limit memory footprint when
624
lots of entities are used. This aligns selectors, facades, etc. with the way actions were implemented

projects/ngrx-auto-entity/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "0.8.0-beta.1",
2+
"version": "0.8.1",
33
"name": "@briebug/ngrx-auto-entity",
44
"description": "Automatic Entity State and Facades for NgRx. Simplifying reactive state!",
55
"license": "SEE LICENSE IN LICENSE.md",

projects/ngrx-auto-entity/src/lib/selectors/tracking.selectors.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
import { IEntityTracking } from '../util/entity-state';
22

3+
// prettier-ignore
4+
export const mapToHasBeenLoaded =
5+
(tracking: IEntityTracking): boolean =>
6+
tracking?.loadedAt != null;
7+
8+
// prettier-ignore
9+
export const mapToLoadWasAttempted =
10+
(tracking: IEntityTracking): boolean =>
11+
tracking?.isLoading != null;
12+
313
// prettier-ignore
414
export const mapToIsLoading =
515
(tracking: IEntityTracking): boolean =>

projects/ngrx-auto-entity/src/lib/util/facade-builder.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export const buildFacade = <TModel, TParentState>(selectors: ISelectorMap<TParen
5252
this.currentPage$ = this.store.select(selectors.selectCurrentPage);
5353
this.currentRange$ = this.store.select(selectors.selectCurrentRange);
5454
this.totalPageable$ = this.store.select(selectors.selectTotalPageable);
55+
this.hasBeenLoaded$ = this.store.select(selectors.selectHasBeenLoaded);
56+
this.loadWasAttempted$ = this.store.select(selectors.selectLoadWasAttempted);
5557
this.isLoading$ = this.store.select(selectors.selectIsLoading);
5658
this.isSaving$ = this.store.select(selectors.selectIsSaving);
5759
this.isDeleting$ = this.store.select(selectors.selectIsDeleting);
@@ -80,6 +82,8 @@ export const buildFacade = <TModel, TParentState>(selectors: ISelectorMap<TParen
8082
currentPage$: Observable<Page>;
8183
currentRange$: Observable<Range>;
8284
totalPageable$: Observable<number>;
85+
hasBeenLoaded$: Observable<boolean>;
86+
loadWasAttempted$: Observable<boolean>;
8387
isLoading$: Observable<boolean>;
8488
isSaving$: Observable<boolean>;
8589
isDeleting$: Observable<boolean>;

projects/ngrx-auto-entity/src/lib/util/facade.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export interface IEntityFacade<TModel> {
2424
currentPage$: Observable<Page>;
2525
currentRange$: Observable<Range>;
2626
totalPageable$: Observable<number>;
27+
hasBeenLoaded$: Observable<boolean>;
28+
loadWasAttempted$: Observable<boolean>;
2729
isLoading$: Observable<boolean>;
2830
isSaving$: Observable<boolean>;
2931
isDeleting$: Observable<boolean>;

projects/ngrx-auto-entity/src/lib/util/selector-map-builder.spec.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ const selectorProperties = [
5454
'selectCurrentPage',
5555
'selectCurrentRange',
5656
'selectTotalPageable',
57+
'selectHasBeenLoaded',
58+
'selectLoadWasAttempted',
5759
'selectIsLoading',
5860
'selectIsSaving',
5961
'selectIsDeleting',
@@ -424,4 +426,76 @@ describe('buildSelectorMap()', () => {
424426
expect(entities).toBeObservable(hot('a', { a: false }));
425427
});
426428
});
429+
430+
describe('selectHasBeenLoaded', () => {
431+
it('should return true if the loadedAt date is non-nullish', () => {
432+
const store: MockStore<{}> = TestBed.inject(MockStore);
433+
434+
store.resetSelectors();
435+
store.setState({
436+
test: {
437+
tracking: {
438+
loadedAt: Date.now()
439+
}
440+
}
441+
});
442+
443+
const getState = state => state.test;
444+
445+
const { selectHasBeenLoaded } = buildSelectorMap<ITestState, IEntityState<Test>, Test, unknown>(getState);
446+
const hasBeen = store.select(selectHasBeenLoaded);
447+
expect(hasBeen).toBeObservable(hot('a', { a: true }));
448+
});
449+
450+
it('should return false if the loadedAt date is nullish', () => {
451+
const store: MockStore<{}> = TestBed.inject(MockStore);
452+
453+
store.resetSelectors();
454+
store.setState({
455+
test: {}
456+
});
457+
458+
const getState = state => state.test;
459+
460+
const { selectHasBeenLoaded } = buildSelectorMap<ITestState, IEntityState<Test>, Test, unknown>(getState);
461+
const hasBeen = store.select(selectHasBeenLoaded);
462+
expect(hasBeen).toBeObservable(hot('a', { a: false }));
463+
});
464+
});
465+
466+
describe('selectLoadWasAttempted', () => {
467+
it('should return true if the isLoading tracking flag is non-nullish', () => {
468+
const store: MockStore<{}> = TestBed.inject(MockStore);
469+
470+
store.resetSelectors();
471+
store.setState({
472+
test: {
473+
tracking: {
474+
isLoading: false
475+
}
476+
}
477+
});
478+
479+
const getState = state => state.test;
480+
481+
const { selectLoadWasAttempted } = buildSelectorMap<ITestState, IEntityState<Test>, Test, unknown>(getState);
482+
const hasBeen = store.select(selectLoadWasAttempted);
483+
expect(hasBeen).toBeObservable(hot('a', { a: true }));
484+
});
485+
486+
it('should return false if the isLoading tracking flag is nullish', () => {
487+
const store: MockStore<{}> = TestBed.inject(MockStore);
488+
489+
store.resetSelectors();
490+
store.setState({
491+
test: {}
492+
});
493+
494+
const getState = state => state.test;
495+
496+
const { selectLoadWasAttempted } = buildSelectorMap<ITestState, IEntityState<Test>, Test, unknown>(getState);
497+
const hasBeen = store.select(selectLoadWasAttempted);
498+
expect(hasBeen).toBeObservable(hot('a', { a: false }));
499+
});
500+
});
427501
});

projects/ngrx-auto-entity/src/lib/util/selector-map-builder.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ import {
1919
import {
2020
mapToCreatedAt,
2121
mapToDeletedAt,
22+
mapToHasBeenLoaded,
2223
mapToIsDeleting,
2324
mapToIsLoading,
2425
mapToIsSaving,
2526
mapToLoadedAt,
27+
mapToLoadWasAttempted,
2628
mapToReplacedAt,
2729
mapToSavedAt,
2830
mapToUpdatedAt
@@ -133,6 +135,14 @@ export const buildSelectorMap = <TParentState, TState extends IEntityState<TMode
133135
}
134136

135137
// Tracking:
138+
get selectHasBeenLoaded() {
139+
return createSelector(this.selectTracking, mapToHasBeenLoaded);
140+
}
141+
142+
get selectLoadWasAttempted() {
143+
return createSelector(this.selectTracking, mapToLoadWasAttempted);
144+
}
145+
136146
get selectIsLoading() {
137147
return createSelector(this.selectTracking, mapToIsLoading);
138148
}

projects/ngrx-auto-entity/src/lib/util/selector-map.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export interface ISelectorMap<TParentState, TModel> {
2929
selectCurrentPage: MemoizedSelector<object | TParentState, Page | undefined>;
3030
selectCurrentRange: MemoizedSelector<object | TParentState, Range | undefined>;
3131
selectTotalPageable: MemoizedSelector<object | TParentState, number>;
32+
selectHasBeenLoaded: MemoizedSelector<object | TParentState, boolean>;
33+
selectLoadWasAttempted: MemoizedSelector<object | TParentState, boolean>;
3234
selectIsLoading: MemoizedSelector<object | TParentState, boolean>;
3335
selectIsSaving: MemoizedSelector<object | TParentState, boolean>;
3436
selectIsDeleting: MemoizedSelector<object | TParentState, boolean>;

projects/ngrx-auto-entity/src/lib/util/state-builder.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ describe('buildState()', () => {
6060
expect(built.selectors).toSatisfy(selectors => selectors.__proto__.hasOwnProperty('selectCurrentPage'));
6161
expect(built.selectors).toSatisfy(selectors => selectors.__proto__.hasOwnProperty('selectCurrentRange'));
6262
expect(built.selectors).toSatisfy(selectors => selectors.__proto__.hasOwnProperty('selectTotalPageable'));
63+
expect(built.selectors).toSatisfy(selectors => selectors.__proto__.hasOwnProperty('selectHasBeenLoaded'));
64+
expect(built.selectors).toSatisfy(selectors => selectors.__proto__.hasOwnProperty('selectLoadWasAttempted'));
6365
expect(built.selectors).toSatisfy(selectors => selectors.__proto__.hasOwnProperty('selectIsLoading'));
6466
expect(built.selectors).toSatisfy(selectors => selectors.__proto__.hasOwnProperty('selectIsSaving'));
6567
expect(built.selectors).toSatisfy(selectors => selectors.__proto__.hasOwnProperty('selectIsDeleting'));
@@ -142,6 +144,8 @@ describe('buildState()', () => {
142144
selectHasNoEntities: hasNoTestEntities,
143145
selectIsDeleting: testIsDeleting,
144146
selectIsDirty: testIsDirty,
147+
selectHasBeenLoaded: testHasBeenLoaded,
148+
selectLoadWasAttempted: testLoadWasAttempted,
145149
selectIsLoading: testIsLoading,
146150
selectIsSaving: testIsSaving,
147151
selectLoadedAt: testLoadedAt,
@@ -176,6 +180,8 @@ describe('buildState()', () => {
176180
selectHasNoEntities: hasNoTest2Entities,
177181
selectIsDeleting: test2IsDeleting,
178182
selectIsDirty: test2IsDirty,
183+
selectHasBeenLoaded: test2HasBeenLoaded,
184+
selectLoadWasAttempted: test2LoadWasAttempted,
179185
selectIsLoading: test2IsLoading,
180186
selectIsSaving: test2IsSaving,
181187
selectLoadedAt: test2LoadedAt,
@@ -214,6 +220,8 @@ describe('buildState()', () => {
214220
expect(hasNoTestEntities).not.toEqual(hasNoTest2Entities);
215221
expect(testIsDeleting).not.toEqual(test2IsDeleting);
216222
expect(testIsDirty).not.toEqual(test2IsDirty);
223+
expect(testHasBeenLoaded).not.toEqual(test2HasBeenLoaded);
224+
expect(testLoadWasAttempted).not.toEqual(test2LoadWasAttempted);
217225
expect(testIsLoading).not.toEqual(test2IsLoading);
218226
expect(testIsSaving).not.toEqual(test2IsSaving);
219227
expect(testLoadedAt).not.toEqual(test2LoadedAt);

projects/ngrx-auto-entity/src/lib/util/util.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ const selectorProperties = [
4444
'selectCurrentPage',
4545
'selectCurrentRange',
4646
'selectTotalPageable',
47+
'selectHasBeenLoaded',
48+
'selectLoadWasAttempted',
4749
'selectIsLoading',
4850
'selectIsSaving',
4951
'selectIsDeleting',

0 commit comments

Comments
 (0)