8000 feat: reintroduce smosh, add docs to selections by BioPhoton · Pull Request #1192 · rx-angular/rx-angular · GitHub
[go: up one dir, main page]

Skip to content

feat: reintroduce smosh, add docs to selections #1192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d8f3ae2
feat: reintroduce smosh, add docs to selections
BioPhoton Feb 3, 2022
a5a0e49
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 3, 2022
78becbd
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 3, 2022
caed2fa
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 3, 2022
70652ab
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 3, 2022
d622605
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 3, 2022
ef3131f
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 3, 2022
d2d52ff
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 3, 2022
0352d14
perf: reduce smosh, organize typings
BioPhoton Feb 7, 2022
f0401df
Merge branch 'main' into reintro-accumulate-observable
BioPhoton Feb 12, 2022
f4bdba7
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 27, 2022
e09314d
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 27, 2022
6da1e2e
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 27, 2022
ca28c9e
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 27, 2022
406cece
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 27, 2022
4b2d18e
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 27, 2022
ba7cb50
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 27, 2022
041f90d
Merge branch 'main' into reintro-accumulate-observable
BioPhoton Feb 27, 2022
b7a02bd
Update libs/state/selections/docs/Readme.md
BioPhoton Feb 27, 2022
163e81b
Update Readme.md
BioPhoton Feb 27, 2022
119328b
Update Readme.md
BioPhoton Mar 7, 2022
3893bb5
Update Readme.md
BioPhoton Mar 7, 2022
910331e
refactor(state): wip selections add spreads to smosh
BioPhoton Mar 7, 2022
7406ec6
refactor(state): wip selections add spreads to smosh
BioPhoton Mar 8, 2022
94d8b02
Merge branch 'main' into reintro-accumulate-observable
BioPhoton Mar 9, 2022
7d474c5
docs(state): selection
BioPhoton Mar 23, 2022
d8f4e5f
Update libs/state/selections/docs/Readme.md
BioPhoton Mar 24, 2022
d8f2ae1
Update libs/state/selections/docs/Readme.md
BioPhoton Mar 24, 2022
0b1bda8
chore(state): make eslint happy
edbzn Mar 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
perf: reduce smosh, organize typings
  • Loading branch information
BioPhoton committed Feb 7, 2022
commit 0352d14d68bb18fd32cfe35dbd3f5048b9ac777a
49 changes: 49 additions & 0 deletions libs/state/selections/spec/smosh.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,42 @@ describe('createSmoshObservable', () => {
});
});

it('should return observable that emits if only static values are used', () => {
testScheduler.run(({ cold, expectObservable }) => {
const vm$: Observable<ViewModelTest> = smosh({
prop1: i,
prop2: b,
prop3: t,
}, cold('s'))
const expected = '(x|)';
expectObservable(vm$).toBe(expected, { x });
});
});

it('should return observable that emits when all static and observable sources emitted at least once', () => {
testScheduler.run(({ cold, expectObservable }) => {
const vm$: Observable<ViewModelTest> = smosh({
prop1: cold('h-h-i-', { h, i }),
prop2: cold('--a-b-', { a, b }),
prop3: t,
}, cold( 's'))
const expected = '----x-';
expectObservable(vm$).toBe(expected, { x });
});
});

it('should return observable that not emit when all static and observable sources emitted not at least once', () => {
testScheduler.run(({ cold, expectObservable }) => {
const vm$: Observable<ViewModelTest> = smosh({
prop1: cold('h-h-i-', { h, i }),
prop2: cold('--a-b-', { a, b }),
prop3: undefined,
}, cold( 's'))
const expected = '----x-';
expectObservable(vm$).toBe(expected, { x });
});
});

it('should return observable that emits when all sources emitted at least once', () => {
testScheduler.run(({ cold, expectObservable }) => {
const vm$: Observable<ViewModelTest> = smosh({
Expand All @@ -116,6 +152,19 @@ describe('createSmoshObservable', () => {
});
});

it('should return observable that not emit when all sources emitted not at least once', () => {
testScheduler.run(({ cold, expectObservable }) => {
const vm$: Observable<ViewModelTest> = smosh({
prop1: cold('h-h-i-', { h, i }),
prop2: cold('--a-b-', { a, b }),
prop3: cold('------', { t }),
}, cold( 's'))
const expected = '------';
expectObservable(vm$).toBe(expected);
});
});


it('should emit last for sync values when durationSelector is a Promise', () => {
testScheduler.run(({ cold, expectObservable }) => {
const durationSelector = from(Promise.resolve(1));
Expand Down
43 changes: 13 additions & 30 deletions libs/state/selections/src/lib/smosh.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,15 @@
import { combineLatest, from, Observable } from 'rxjs';
import { distinctUntilChanged, filter, map, shareReplay } from 'rxjs/operators';


import { Promise } from '@rx-angular/cdk/zone-less/browser';
import { coalesceWith } from '@rx-angular/cdk/coalescing';
import { ExtractObservableValue } from '../../../../cdk/internals/core/src/lib/model';
import { ArrayReducerFn, NotEmpty, ObservableMap, PropName, PropType } from './interfaces';
import { NotEmpty, ObservableMap } from './interfaces';
import { coerceObservable } from '@rx-angular/cdk/coercing';

const resolvedPromise = Promise.resolve();
const resolvedPromise$ = from(resolvedPromise);

/**
* @internal
*
* Used for typing
*/
function getEntriesToObjectReducerFn<T extends Record<string, any>>(
keys: PropName<T>[]
): ArrayReducerFn<T> {
return (
accumulator: T,
currentValue?: PropType<T>,
currentIndex?: number
): T => {
return {
...accumulator,
[keys[currentIndex]]: currentValue,
};
};
}

/**
* This Observable creation function helps to accumulate an object of key & Observable of values to
* an Observable of objects of key & value.
Expand Down Expand Up @@ -66,15 +46,14 @@ function getEntriesToObjectReducerFn<T extends Record<string, any>>(
* @param obj - An object of key & Observable values pairs
* @param durationSelector - An Observable determining the duration for the internal coalescing method
*/
export function smosh<T extends ObservableMap & NotEmpty<T>>(
// @TODO type static or Observable to enable mixing of imperative and reatctive values
export function smosh<T extends ObservableMap | (Partial<T> & NotEmpty<T>)>(
obj: T,
durationSelector: Observable<any> = resolvedPromise$
): Observable<{ [K in keyof T]: ExtractObservableValue<T[K]> | T[K] }> {
): Observable<{ [K in keyof T]: ExtractObservableValue<T[K]> }> {
const keys = Object.keys(obj) as (keyof T)[];
// @TODO better typing to enable static values => coerceObservable(obj[key])
const observables = keys.map((key) =>
obj[key].pipe(
// turn values, if they are static, into Observables
coerceObservable(obj[key]).pipe(
// we avoid using the nullish operator later ;)
filter((v) => v !== undefined),
// state "changes" differ from each other, this operator ensures distinct values
Expand All @@ -85,9 +64,13 @@ export function smosh<T extends ObservableMap & NotEmpty<T>>(
// As combineLatest will emit multiple times for a change in multiple properties we coalesce those emissions together
coalesceWith(durationSelector),
// mapping array of values to object
map((values) =>
values.reduce(getEntriesToObjectReducerFn(keys), {} as any)
),
map((values) => {
let obj = {} as any;
for (let i = 0; i < values.length; i++) {
obj[keys[i]] = values[i];
}
return obj;
}),
// by using shareReplay we share the last composition work done to create the accumulated object
shareReplay(1)
);
Expand Down
0