Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3ee6fda

Browse files
eneajahoedbzn
authored andcommitted
feat(state): add provideRxStateConfig function
1 parent eaa3b4b commit 3ee6fda

File tree

3 files changed

+80
-15
lines changed

3 files changed

+80
-15
lines changed

libs/state/selections/spec/accumulation-observable.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import { TestBed } from '@angular/core/testing';
22
import {
3-
RX_ACCUMULATOR_FN,
4-
createAccumulationObservable,
5-
select,
6-
} from '@rx-angular/state/selections';
7-
import {
8-
PrimitiveState,
93
initialPrimitiveState,
104
jestMatcher,
5+
PrimitiveState,
116
} from '@test-helpers/rx-angular';
127
import { of, throwError } from 'rxjs';
138
import { map } from 'rxjs/operators';
149
import { TestScheduler } from 'rxjs/testing';
10+
import {
11+
createAccumulationObservable,
12+
RX_ACCUMULATOR_FN,
13+
} from '../src/lib/accumulation-observable';
14+
import { select } from '../src/lib/operators';
1515

1616
function setupAccumulationObservable<T extends object>(cfg: {
1717
initialState?: T;

libs/state/selections/src/lib/accumulation-observable.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { inject, InjectionToken } from '@angular/core';
12
import {
23
BehaviorSubject,
34
ConnectableObservable,
@@ -20,7 +21,6 @@ import {
2021
withLatestFrom,
2122
} from 'rxjs/operators';
2223
import { AccumulationFn, Accumulator } from './model';
23-
import { inject, InjectionToken } from '@angular/core';
2424

2525
const defaultAccumulator: AccumulationFn = <T>(st: T, sl: Partial<T>): T => {
2626
return { ...st, ...sl };
@@ -40,36 +40,37 @@ const defaultAccumulator: AccumulationFn = <T>(st: T, sl: Partial<T>): T => {
4040
export const RX_ACCUMULATOR_FN = new InjectionToken<AccumulationFn>(
4141
'RX_ACCUMULATOR_FN',
4242
{
43+
providedIn: 'root',
4344
factory: () => defaultAccumulator,
44-
}
45+
},
4546
);
4647

4748
export function createAccumulationObservable<T extends object>(
4849
stateObservables = new Subject<Observable<Partial<T>>>(),
49-
stateSlices = new Subject<Partial<T>>()
50+
stateSlices = new Subject<Partial<T>>(),
5051
): Accumulator<T> {
5152
const accumulatorFn = inject(RX_ACCUMULATOR_FN);
5253
const accumulatorObservable = new BehaviorSubject(accumulatorFn);
5354
const signal$ = merge(
5455
stateObservables.pipe(
5556
distinctUntilChanged(),
5657
mergeAll(),
57-
observeOn(queueScheduler)
58+
observeOn(queueScheduler),
5859
),
59-
stateSlices.pipe(observeOn(queueScheduler))
60+
stateSlices.pipe(observeOn(queueScheduler)),
6061
).pipe(
6162
withLatestFrom(accumulatorObservable.pipe(observeOn(queueScheduler))),
6263
scan(
6364
(state, [slice, stateAccumulator]) => stateAccumulator(state, slice),
64-
{} as T
65+
{} as T,
6566
),
6667
tap(
6768
(newState) => (compositionObservable.state = newState),
68-
(error) => console.error(error)
69+
(error) => console.error(error),
6970
),
7071
// @Notice We catch the error here as it get lost in between `publish` and `publishReplay`. We return empty to
7172
catchError((e) => EMPTY),
72-
publish()
73+
publish(),
7374
);
7475
const state$: Observable<T> = signal$.pipe(publishReplay(1));
7576
const compositionObservable: Accumulator<T> = {
@@ -105,7 +106,7 @@ export function createAccumulationObservable<T extends object>(
105106
compositionObservable.signal$ as ConnectableObservable<T>
106107
).connect();
107108
sub.add(
108-
(compositionObservable.state$ as ConnectableObservable<T>).connect()
109+
(compositionObservable.state$ as ConnectableObservable<T>).connect(),
109110
);
110111
sub.add(() => {
111112
accumulatorObservable.complete();
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { InjectionToken, Provider } from '@angular/core';
2+
import { AccumulationFn, RX_ACCUMULATOR_FN } from '../../selections/src';
3+
4+
export const enum RX_STATE_CONFIGS {
5+
Scheduler,
6+
Accumulator,
7+
}
8+
9+
interface RxStateConfigFn {
10+
kind: RX_STATE_CONFIGS;
11+
providers: Provider[];
12+
}
13+
14+
/**
15+
* Injection token for the default accumulator function.
16+
* @param fn
17+
*/
18+
export function withAccumulatorFn(fn: AccumulationFn): RxStateConfigFn {
19+
return {
20+
kind: RX_STATE_CONFIGS.Accumulator,
21+
providers: [{ provide: RX_ACCUMULATOR_FN, useValue: fn }],
22+
};
23+
}
24+
25+
export const RX_STATE_SCHEDULER = new InjectionToken<any>(
26+
'RX_STATE_SCHEDULER',
27+
{
28+
providedIn: 'root',
29+
factory: () => undefined,
30+
},
31+
);
32+
33+
/**
34+
* Injection token for the default scheduler for rxState.
35+
* @param fn
36+
*/
37+
export function withScheduler(
38+
scheduler: any /* TODO: add type here*/,
39+
): RxStateConfigFn {
40+
return {
41+
kind: RX_STATE_CONFIGS.Scheduler,
42+
providers: [{ provide: RX_STATE_SCHEDULER, useValue: scheduler }],
43+
};
44+
}
45+
46+
/**
47+
* This function is used to provide the configuration for the rxState function.
48+
*
49+
* You can provide multiple configurations at once.
50+
*
51+
* You can use these functions to provide the configuration:
52+
* - withAccumulatorFn - to provide a custom accumulator function
53+
* - withScheduler - to provide a custom scheduler
54+
*
55+
*/
56+
export function provideRxStateConfig(
57+
...configs: RxStateConfigFn[]
58+
): Provider[] {
59+
return flatten(configs.map((c) => c.providers));
60+
}
61+
62+
function flatten<T>(arr: T[][]): T[] {
63+
return arr.reduce((acc, val) => acc.concat(val), []);
64+
}

0 commit comments

Comments
 (0)