From c26f2b27dc8e3d99acaa230e62e211503517df77 Mon Sep 17 00:00:00 2001 From: Dmitriy Stolyar Date: Thu, 22 Apr 2021 11:29:55 +0300 Subject: [PATCH 1/5] added logging to the hold method --- libs/state/src/lib/rx-state.service.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/state/src/lib/rx-state.service.ts b/libs/state/src/lib/rx-state.service.ts index c664fb1904..b2394048c9 100644 --- a/libs/state/src/lib/rx-state.service.ts +++ b/libs/state/src/lib/rx-state.service.ts @@ -547,7 +547,10 @@ export class RxState implements OnDestroy, Subscribable { obsOrObsWithSideEffect: Observable, sideEffectFn?: (arg: S) => void ): void { - const sideEffect = obsOrObsWithSideEffect.pipe(catchError(e => EMPTY)) + const sideEffect = obsOrObsWithSideEffect.pipe(catchError(e => { + console.error(e) + return EMPTY + })) if (typeof sideEffectFn === 'function') { this.effectObservable.nextEffectObservable( sideEffect.pipe(tap(sideEffectFn)) From 056bfc0adce03e71d97a0198013e5e9bcc57c482 Mon Sep 17 00:00:00 2001 From: Dmitriy Stolyar Date: Tue, 11 May 2021 12:28:21 +0300 Subject: [PATCH 2/5] unit test was added --- libs/state/spec/rx-state.service.spec.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/state/spec/rx-state.service.spec.ts b/libs/state/spec/rx-state.service.spec.ts index 5346c72cc2..f5c730fc9e 100644 --- a/libs/state/spec/rx-state.service.spec.ts +++ b/libs/state/spec/rx-state.service.spec.ts @@ -10,7 +10,7 @@ import { TestScheduler } from 'rxjs/testing'; // tslint:disable-next-line:nx-enforce-module-boundaries import { RxState, select } from '@rx-angular/state'; import { map, pluck, switchMap, take, takeUntil } from 'rxjs/operators'; -import { from, interval, of, Subject } from 'rxjs'; +import { from, interval, of, Subject, throwError } from 'rxjs'; function setupState(cfg: { initialState?: T }) { const { initialState } = { ...cfg }; @@ -590,5 +590,12 @@ describe('RxStateService', () => { state.hold(of(1, 2, 3), effect); expect(calls).toBe(3); })); + + it('should logging error', fakeAsync(() => { + jest.spyOn(console, 'error').mockImplementation(); + const state = setupState({ initialState: initialPrimitiveState }); + state.hold(throwError(new Error('something went wrong'))); + expect(console.error).toHaveBeenCalledWith(new Error('something went wrong')); + })); }); }); From 5aab5ef61d4e668f754633f8cafcee14c926cd97 Mon Sep 17 00:00:00 2001 From: Dmitriy Stolyar Date: Fri, 14 May 2021 16:27:02 +0300 Subject: [PATCH 3/5] ErrorHandler was added --- libs/state/spec/rx-state.service.spec.ts | 16 +++- libs/state/src/lib/rx-state.service.ts | 97 +++++++++++++++++------- 2 files changed, 83 insertions(+), 30 deletions(-) diff --git a/libs/state/spec/rx-state.service.spec.ts b/libs/state/spec/rx-state.service.spec.ts index f5c730fc9e..e3891d3671 100644 --- a/libs/state/spec/rx-state.service.spec.ts +++ b/libs/state/spec/rx-state.service.spec.ts @@ -1,3 +1,4 @@ +import { ErrorHandler, Injector } from '@angular/core'; // tslint:disable-next-line:nx-enforce-module-boundaries import { jestMatcher } from '@test-helpers'; import { fakeAsync, TestBed } from '@angular/core/testing'; @@ -11,6 +12,9 @@ import { TestScheduler } from 'rxjs/testing'; import { RxState, select } from '@rx-angular/state'; import { map, pluck, switchMap, take, takeUntil } from 'rxjs/operators'; import { from, interval, of, Subject, throwError } from 'rxjs'; +import { + ɵsetCurrentInjector as setCurrentInjector +} from '@angular/core'; function setupState(cfg: { initialState?: T }) { const { initialState } = { ...cfg }; @@ -591,11 +595,17 @@ describe('RxStateService', () => { expect(calls).toBe(3); })); - it('should logging error', fakeAsync(() => { - jest.spyOn(console, 'error').mockImplementation(); + it('should invoke provided ErrorHandler', fakeAsync(() => { const state = setupState({ initialState: initialPrimitiveState }); + const customErrorHandler: ErrorHandler = { + handleError: jest.fn() + }; + TestBed.overrideProvider(ErrorHandler, { useValue: customErrorHandler }); + setCurrentInjector(TestBed.inject(Injector)); state.hold(throwError(new Error('something went wrong'))); - expect(console.error).toHaveBeenCalledWith(new Error('something went wrong')); + expect(customErrorHandler.handleError).toHaveBeenCalledWith( + new Error('something went wrong') + ); })); }); }); diff --git a/libs/state/src/lib/rx-state.service.ts b/libs/state/src/lib/rx-state.service.ts index b2394048c9..26e2e45f22 100644 --- a/libs/state/src/lib/rx-state.service.ts +++ b/libs/state/src/lib/rx-state.service.ts @@ -1,8 +1,32 @@ -import { Injectable, OnDestroy } from '@angular/core'; -import { EMPTY, isObservable, Observable, OperatorFunction, Subscribable, Subscription, Unsubscribable } from 'rxjs'; +import { + ErrorHandler, + inject, + Injectable, + InjectFlags, + OnDestroy, +} from '@angular/core'; +import { + EMPTY, + isObservable, + Observable, + OperatorFunction, + Subscribable, + Subscription, + Unsubscribable, +} from 'rxjs'; import { catchError, map, pluck, tap } from 'rxjs/operators'; -import { isKeyOf, isOperateFnArrayGuard, isStringArrayGuard, pipeFromArray, safePluck } from './core'; -import { AccumulationFn, createAccumulationObservable, createSideEffectObservable } from './cdk'; +import { + AccumulationFn, + createAccumulationObservable, + createSideEffectObservable, +} from './cdk'; +import { + isKeyOf, + isOperateFnArrayGuard, + isStringArrayGuard, + pipeFromArray, + safePluck, +} from './core'; import { stateful } from './rxjs/operators'; type ProjectStateFn = (oldState: T) => Partial; @@ -120,30 +144,38 @@ export class RxState implements OnDestroy, Subscribable { k3: K3 ): T[K1][K2][K3]; /** @internal **/ - get(k1: K1, k2: K2, k3: K3, k4: K4): T[K1][K2][K3][K4]; + K4 extends keyof T[K1][K2][K3] + >(k1: K1, k2: K2, k3: K3, k4: K4): T[K1][K2][K3][K4]; /** @internal **/ - get(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5): T[K1][K2][K3][K4][K5]; + K5 extends keyof T[K1][K2][K3][K4] + >(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5): T[K1][K2][K3][K4][K5]; /** @internal **/ - get(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5, k6: K6): T[K1][K2][K3][K4][K5][K6]; + K6 extends keyof T[K1][K2][K3][K4][K5] + >(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5, k6: K6): T[K1][K2][K3][K4][K5][K6]; /** @internal **/ - get( + K6 extends keyof T[K1][K2][K3][K4][K5] + >( ...keys: | [K1] | [K1, K2] @@ -163,9 +195,9 @@ export class RxState implements OnDestroy, Subscribable { if (!!keys && keys.length) { return safePluck(this.accumulator.state, keys); } else { - return hasStateAnyKeys ? - this.accumulator.state : - undefined as unknown as T; + return hasStateAnyKeys + ? this.accumulator.state + : ((undefined as unknown) as T); } } @@ -472,33 +504,41 @@ export class RxState implements OnDestroy, Subscribable { /** * @internal */ - select(k1: K1, k2: K2, k3: K3): Observable; + K3 extends keyof T[K1][K2] + >(k1: K1, k2: K2, k3: K3): Observable; /** * @internal */ - select(k1: K1, k2: K2, k3: K3, k4: K4): Observable; + K4 extends keyof T[K1][K2][K3] + >(k1: K1, k2: K2, k3: K3, k4: K4): Observable; /** * @internal */ - select(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5): Observable; + K5 extends keyof T[K1][K2][K3][K4] + >(k1: K1, k2: K2, k3: K3, k4: K4, k5: K5): Observable; /** * @internal */ - select( + K6 extends keyof T[K1][K2][K3][K4][K5] + >( k1: K1, k2: K2, k3: K3, @@ -547,10 +587,13 @@ export class RxState implements OnDestroy, Subscribable { obsOrObsWithSideEffect: Observable, sideEffectFn?: (arg: S) => void ): void { - const sideEffect = obsOrObsWithSideEffect.pipe(catchError(e => { - console.error(e) - return EMPTY - })) + const sideEffect = obsOrObsWithSideEffect.pipe( + catchError((e) => { + const errorHandler = inject(ErrorHandler, InjectFlags.Optional); + errorHandler?.handleError(e); + return EMPTY; + }) + ); if (typeof sideEffectFn === 'function') { this.effectObservable.nextEffectObservable( sideEffect.pipe(tap(sideEffectFn)) From 39404eb0f647d5ac56a606ece38a0a80fb0e078b Mon Sep 17 00:00:00 2001 From: Dmitriy Stolyar Date: Fri, 14 May 2021 16:30:20 +0300 Subject: [PATCH 4/5] fix code style --- libs/state/src/lib/rx-state.service.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/state/src/lib/rx-state.service.ts b/libs/state/src/lib/rx-state.service.ts index 26e2e45f22..4bcd45da6e 100644 --- a/libs/state/src/lib/rx-state.service.ts +++ b/libs/state/src/lib/rx-state.service.ts @@ -15,11 +15,6 @@ import { Unsubscribable, } from 'rxjs'; import { catchError, map, pluck, tap } from 'rxjs/operators'; -import { - AccumulationFn, - createAccumulationObservable, - createSideEffectObservable, -} from './cdk'; import { isKeyOf, isOperateFnArrayGuard, @@ -27,6 +22,11 @@ import { pipeFromArray, safePluck, } from './core'; +import { + AccumulationFn, + createAccumulationObservable, + createSideEffectObservable, +} from './cdk'; import { stateful } from './rxjs/operators'; type ProjectStateFn = (oldState: T) => Partial; From 8c3a9c16d8bd53de81cff0ce61bbf35e995beefa Mon Sep 17 00:00:00 2001 From: Dmitriy Stolyar Date: Wed, 7 Jul 2021 12:18:28 +0300 Subject: [PATCH 5/5] comment was added --- libs/state/src/lib/rx-state.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/state/src/lib/rx-state.service.ts b/libs/state/src/lib/rx-state.service.ts index 4bcd45da6e..e4eff86674 100644 --- a/libs/state/src/lib/rx-state.service.ts +++ b/libs/state/src/lib/rx-state.service.ts @@ -589,6 +589,7 @@ export class RxState implements OnDestroy, Subscribable { ): void { const sideEffect = obsOrObsWithSideEffect.pipe( catchError((e) => { + // used injector for compatibility with https://github.com/rx-angular/rx-angular/blob/master/libs/state/docs/usage.md#inherit const errorHandler = inject(ErrorHandler, InjectFlags.Optional); errorHandler?.handleError(e); return EMPTY;