Skip to content

Commit 0a6672e

Browse files
committed
feat(concatMapTo): add higher-order lettable version of concatMapTo
1 parent 73d30cd commit 0a6672e

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

Diff for: src/operator/concatMapTo.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Observable, ObservableInput } from '../Observable';
2-
import { MergeMapToOperator } from './mergeMapTo';
2+
import { concatMapTo as higherOrder } from '../operators';
33

44
/* tslint:disable:max-line-length */
55
export function concatMapTo<T, R>(this: Observable<T>, observable: ObservableInput<R>): Observable<R>;
@@ -64,5 +64,5 @@ export function concatMapTo<T, I, R>(this: Observable<T>, observable: Observable
6464
*/
6565
export function concatMapTo<T, I, R>(this: Observable<T>, innerObservable: Observable<I>,
6666
resultSelector?: (outerValue: T, innerValue: I, outerIndex: number, innerIndex: number) => R): Observable<R> {
67-
return this.lift(new MergeMapToOperator(innerObservable, resultSelector, 1));
67+
return higherOrder(innerObservable, resultSelector)(this);
6868
}

Diff for: src/operators/concatMapTo.ts

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Observable, ObservableInput } from '../Observable';
2+
import { concatMap } from './concatMap';
3+
import { OperatorFunction } from '../interfaces';
4+
5+
/* tslint:disable:max-line-length */
6+
export function concatMapTo<T, R>(observable: ObservableInput<R>): OperatorFunction<T, R>;
7+
export function concatMapTo<T, I, R>(observable: ObservableInput<I>, resultSelector: (outerValue: T, innerValue: I, outerIndex: number, innerIndex: number) => R): OperatorFunction<T, R>;
8+
/* tslint:enable:max-line-length */
9+
10+
/**
11+
* Projects each source value to the same Observable which is merged multiple
12+
* times in a serialized fashion on the output Observable.
13+
*
14+
* <span class="informal">It's like {@link concatMap}, but maps each value
15+
* always to the same inner Observable.</span>
16+
*
17+
* <img src="./img/concatMapTo.png" width="100%">
18+
*
19+
* Maps each source value to the given Observable `innerObservable` regardless
20+
* of the source value, and then flattens those resulting Observables into one
21+
* single Observable, which is the output Observable. Each new `innerObservable`
22+
* instance emitted on the output Observable is concatenated with the previous
23+
* `innerObservable` instance.
24+
*
25+
* __Warning:__ if source values arrive endlessly and faster than their
26+
* corresponding inner Observables can complete, it will result in memory issues
27+
* as inner Observables amass in an unbounded buffer waiting for their turn to
28+
* be subscribed to.
29+
*
30+
* Note: `concatMapTo` is equivalent to `mergeMapTo` with concurrency parameter
31+
* set to `1`.
32+
*
33+
* @example <caption>For each click event, tick every second from 0 to 3, with no concurrency</caption>
34+
* var clicks = Rx.Observable.fromEvent(document, 'click');
35+
* var result = clicks.concatMapTo(Rx.Observable.interval(1000).take(4));
36+
* result.subscribe(x => console.log(x));
37+
*
38+
* // Results in the following:
39+
* // (results are not concurrent)
40+
* // For every click on the "document" it will emit values 0 to 3 spaced
41+
* // on a 1000ms interval
42+
* // one click = 1000ms-> 0 -1000ms-> 1 -1000ms-> 2 -1000ms-> 3
43+
*
44+
* @see {@link concat}
45+
* @see {@link concatAll}
46+
* @see {@link concatMap}
47+
* @see {@link mergeMapTo}
48+
* @see {@link switchMapTo}
49+
*
50+
* @param {ObservableInput} innerObservable An Observable to replace each value from
51+
* the source Observable.
52+
* @param {function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any} [resultSelector]
53+
* A function to produce the value on the output Observable based on the values
54+
* and the indices of the source (outer) emission and the inner Observable
55+
* emission. The arguments passed to this function are:
56+
* - `outerValue`: the value that came from the source
57+
* - `innerValue`: the value that came from the projected Observable
58+
* - `outerIndex`: the "index" of the value that came from the source
59+
* - `innerIndex`: the "index" of the value from the projected Observable
60+
* @return {Observable} An observable of values merged together by joining the
61+
* passed observable with itself, one after the other, for each value emitted
62+
* from the source.
63+
* @method concatMapTo
64+
* @owner Observable
65+
*/
66+
export function concatMapTo<T, I, R>(
67+
innerObservable: Observable<I>,
68+
resultSelector?: (outerValue: T, innerValue: I, outerIndex: number, innerIndex: number) => R
69+
): OperatorFunction<T, R> {
70+
return concatMap(() => innerObservable, resultSelector);
71+
}

Diff for: src/operators/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export { catchError } from './catchError';
99
export { concat } from './concat';
1010
export { concatAll } from './concatAll';
1111
export { concatMap } from './concatMap';
12+
export { concatMapTo } from './concatMapTo';
1213
export { defaultIfEmpty } from './defaultIfEmpty';
1314
export { dematerialize } from './dematerialize';
1415
export { filter } from './filter';

0 commit comments

Comments
 (0)