-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(operators): higher-order lettables of reduce, min, max and defau…
…ltIfEmpty added
- Loading branch information
Showing
9 changed files
with
249 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { Operator } from '../Operator'; | ||
import { Observable } from '../Observable'; | ||
import { Subscriber } from '../Subscriber'; | ||
import { OperatorFunction } from '../interfaces'; | ||
|
||
/* tslint:disable:max-line-length */ | ||
export function defaultIfEmpty<T>(defaultValue?: T): OperatorFunction<T, T>; | ||
export function defaultIfEmpty<T, R>(defaultValue?: R): OperatorFunction<T, T | R>; | ||
/* tslint:enable:max-line-length */ | ||
|
||
/** | ||
* Emits a given value if the source Observable completes without emitting any | ||
* `next` value, otherwise mirrors the source Observable. | ||
* | ||
* <span class="informal">If the source Observable turns out to be empty, then | ||
* this operator will emit a default value.</span> | ||
* | ||
* <img src="./img/defaultIfEmpty.png" width="100%"> | ||
* | ||
* `defaultIfEmpty` emits the values emitted by the source Observable or a | ||
* specified default value if the source Observable is empty (completes without | ||
* having emitted any `next` value). | ||
* | ||
* @example <caption>If no clicks happen in 5 seconds, then emit "no clicks"</caption> | ||
* var clicks = Rx.Observable.fromEvent(document, 'click'); | ||
* var clicksBeforeFive = clicks.takeUntil(Rx.Observable.interval(5000)); | ||
* var result = clicksBeforeFive.defaultIfEmpty('no clicks'); | ||
* result.subscribe(x => console.log(x)); | ||
* | ||
* @see {@link empty} | ||
* @see {@link last} | ||
* | ||
* @param {any} [defaultValue=null] The default value used if the source | ||
* Observable is empty. | ||
* @return {Observable} An Observable that emits either the specified | ||
* `defaultValue` if the source Observable emits no items, or the values emitted | ||
* by the source Observable. | ||
* @method defaultIfEmpty | ||
* @owner Observable | ||
*/ | ||
export function defaultIfEmpty<T, R>(defaultValue: R = null): OperatorFunction<T, T | R> { | ||
return function defaultIfEmptyOperatorFunction(source: Observable<T>) { | ||
return source.lift(new DefaultIfEmptyOperator(defaultValue)); | ||
}; | ||
} | ||
|
||
class DefaultIfEmptyOperator<T, R> implements Operator<T, T | R> { | ||
|
||
constructor(private defaultValue: R) { | ||
} | ||
|
||
call(subscriber: Subscriber<T | R>, source: any): any { | ||
return source.subscribe(new DefaultIfEmptySubscriber(subscriber, this.defaultValue)); | ||
} | ||
} | ||
|
||
/** | ||
* We need this JSDoc comment for affecting ESDoc. | ||
* @ignore | ||
* @extends {Ignored} | ||
*/ | ||
class DefaultIfEmptySubscriber<T, R> extends Subscriber<T> { | ||
private isEmpty: boolean = true; | ||
|
||
constructor(destination: Subscriber<T | R>, private defaultValue: R) { | ||
super(destination); | ||
} | ||
|
||
protected _next(value: T): void { | ||
this.isEmpty = false; | ||
this.destination.next(value); | ||
} | ||
|
||
protected _complete(): void { | ||
if (this.isEmpty) { | ||
this.destination.next(this.defaultValue); | ||
} | ||
this.destination.complete(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,11 @@ | ||
export { concatMap } from './concatMap'; | ||
export { defaultIfEmpty } from './defaultIfEmpty'; | ||
export { filter } from './filter'; | ||
export { map } from './map'; | ||
export { max } from './max'; | ||
export { mergeMap } from './mergeMap'; | ||
export { min } from './min'; | ||
export { reduce } from './reduce'; | ||
export { scan } from './scan'; | ||
export { switchMap } from './switchMap'; | ||
export { takeLast } from './takeLast'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { reduce } from './reduce'; | ||
import { OperatorFunction } from '../interfaces'; | ||
|
||
/** | ||
* The Max operator operates on an Observable that emits numbers (or items that can be compared with a provided function), | ||
* and when source Observable completes it emits a single item: the item with the largest value. | ||
* | ||
* <img src="./img/max.png" width="100%"> | ||
* | ||
* @example <caption>Get the maximal value of a series of numbers</caption> | ||
* Rx.Observable.of(5, 4, 7, 2, 8) | ||
* .max() | ||
* .subscribe(x => console.log(x)); // -> 8 | ||
* | ||
* @example <caption>Use a comparer function to get the maximal item</caption> | ||
* interface Person { | ||
* age: number, | ||
* name: string | ||
* } | ||
* Observable.of<Person>({age: 7, name: 'Foo'}, | ||
* {age: 5, name: 'Bar'}, | ||
* {age: 9, name: 'Beer'}) | ||
* .max<Person>((a: Person, b: Person) => a.age < b.age ? -1 : 1) | ||
* .subscribe((x: Person) => console.log(x.name)); // -> 'Beer' | ||
* } | ||
* | ||
* @see {@link min} | ||
* | ||
* @param {Function} [comparer] - Optional comparer function that it will use instead of its default to compare the | ||
* value of two items. | ||
* @return {Observable} An Observable that emits item with the largest value. | ||
* @method max | ||
* @owner Observable | ||
*/ | ||
export function max<T>(comparer?: (x: T, y: T) => number): OperatorFunction<T, T> { | ||
const max: (x: T, y: T) => T = (typeof comparer === 'function') | ||
? (x, y) => comparer(x, y) > 0 ? x : y | ||
: (x, y) => x > y ? x : y; | ||
|
||
return reduce(max); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { reduce } from './reduce'; | ||
import { OperatorFunction } from '../interfaces'; | ||
|
||
/** | ||
* The Min operator operates on an Observable that emits numbers (or items that can be compared with a provided function), | ||
* and when source Observable completes it emits a single item: the item with the smallest value. | ||
* | ||
* <img src="./img/min.png" width="100%"> | ||
* | ||
* @example <caption>Get the minimal value of a series of numbers</caption> | ||
* Rx.Observable.of(5, 4, 7, 2, 8) | ||
* .min() | ||
* .subscribe(x => console.log(x)); // -> 2 | ||
* | ||
* @example <caption>Use a comparer function to get the minimal item</caption> | ||
* interface Person { | ||
* age: number, | ||
* name: string | ||
* } | ||
* Observable.of<Person>({age: 7, name: 'Foo'}, | ||
* {age: 5, name: 'Bar'}, | ||
* {age: 9, name: 'Beer'}) | ||
* .min<Person>( (a: Person, b: Person) => a.age < b.age ? -1 : 1) | ||
* .subscribe((x: Person) => console.log(x.name)); // -> 'Bar' | ||
* } | ||
* | ||
* @see {@link max} | ||
* | ||
* @param {Function} [comparer] - Optional comparer function that it will use instead of its default to compare the | ||
* value of two items. | ||
* @return {Observable<R>} An Observable that emits item with the smallest value. | ||
* @method min | ||
* @owner Observable | ||
*/ | ||
export function min<T>(comparer?: (x: T, y: T) => number): OperatorFunction<T, T> { | ||
const min: (x: T, y: T) => T = (typeof comparer === 'function') | ||
? (x, y) => comparer(x, y) < 0 ? x : y | ||
: (x, y) => x < y ? x : y; | ||
return reduce(min); | ||
} |
Oops, something went wrong.