From c80688b75c723c6810053b50202a657c98e62798 Mon Sep 17 00:00:00 2001 From: Pamela Selle Date: Thu, 13 Aug 2015 15:37:10 -0400 Subject: [PATCH] feat(operator): add defaultIfEmpty --- spec/operators/defaultIfEmpty-spec.js | 50 +++++++++++++++++++++++++++ src/Observable.ts | 3 +- src/Rx.ts | 2 ++ src/operators/defaultIfEmpty.ts | 44 +++++++++++++++++++++++ 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 spec/operators/defaultIfEmpty-spec.js create mode 100644 src/operators/defaultIfEmpty.ts diff --git a/spec/operators/defaultIfEmpty-spec.js b/spec/operators/defaultIfEmpty-spec.js new file mode 100644 index 0000000000..111d5ac9fd --- /dev/null +++ b/spec/operators/defaultIfEmpty-spec.js @@ -0,0 +1,50 @@ +/* globals describe, it, expect */ +var Rx = require('../../dist/cjs/Rx'); +var Observable = Rx.Observable; + +describe('Observable.prototype.defaultIfEmpty()', function () { + it('should return the argument if Observable is empty', function (done) { + var emptyObservable = Observable.empty(); + emptyObservable.defaultIfEmpty(2) + .subscribe(function(x) { + expect(x).toBe(2); + }, null, done); + }); + + it('should return null if the Observable is empty and no arguments', function(done) { + var emptyObservable = Observable.empty(); + emptyObservable.defaultIfEmpty() + .subscribe(function(x) { + expect(x).toBe(null); + }, null, done); + }); + + it('should return the Observable if not empty with a default value', function(done) { + var expected = [1,2,3]; + var observable = Observable.of(1,2,3); + observable.defaultIfEmpty(2) + .subscribe(function(x) { + expect(x).toBe(expected.shift()); + }, null, done); + }); + + it('should return the Observable if not empty with no default value', function(done) { + var expected = [1,2,3]; + var observable = Observable.of(1,2,3); + observable.defaultIfEmpty() + .subscribe(function(x) { + expect(x).toBe(expected.shift()); + }, null, done); + }); + + it('should error if the Observable errors', function(done) { + var observable = Observable.throw("candy"); + observable.defaultIfEmpty(2) + .subscribe(function(x) { + throw "this should not be called"; + }, function(err) { + expect(err).toBe("candy"); + done(); + }); + }); +}); diff --git a/src/Observable.ts b/src/Observable.ts index 2c9813a1bf..38d256de52 100644 --- a/src/Observable.ts +++ b/src/Observable.ts @@ -130,7 +130,8 @@ export default class Observable { takeUntil: (observable: Observable) => Observable; partition: (predicate: (x: T) => boolean) => Observable[]; toPromise: (PromiseCtor: PromiseConstructor) => Promise; - + defaultIfEmpty: (defaultValue: R) => Observable|Observable; + observeOn: (scheduler: Scheduler, delay?: number) => Observable; subscribeOn: (scheduler: Scheduler, delay?: number) => Observable; diff --git a/src/Rx.ts b/src/Rx.ts index 3d82fdaed2..6b12698a40 100644 --- a/src/Rx.ts +++ b/src/Rx.ts @@ -123,9 +123,11 @@ observableProto.subscribeOn = subscribeOn; import partition from './operators/partition'; import toPromise from './operators/toPromise'; +import defaultIfEmpty from './operators/defaultIfEmpty'; observableProto.partition = partition; observableProto.toPromise = toPromise; +observableProto.defaultIfEmpty = defaultIfEmpty; import _catch from './operators/catch'; import retryWhen from './operators/retryWhen'; diff --git a/src/operators/defaultIfEmpty.ts b/src/operators/defaultIfEmpty.ts new file mode 100644 index 0000000000..46c03c4408 --- /dev/null +++ b/src/operators/defaultIfEmpty.ts @@ -0,0 +1,44 @@ +import Operator from '../Operator'; +import Observer from '../Observer'; +import Observable from '../Observable'; +import Subscriber from '../Subscriber'; + +import tryCatch from '../util/tryCatch'; +import {errorObject} from '../util/errorObject'; +import bindCallback from '../util/bindCallback'; + +export default function defaultIfEmpty(defaultValue: R = null) : Observable|Observable { + return this.lift(new DefaultIfEmptyOperator(defaultValue)); +} + +export class DefaultIfEmptyOperator extends Operator { + + constructor(private defaultValue: R) { + super(); + } + + call(observer: Observer): Observer { + return new DefaultIfEmptySubscriber(observer, this.defaultValue); + } +} + +export class DefaultIfEmptySubscriber extends Subscriber { + + isEmpty: boolean = true; + + constructor(destination: Observer, private defaultValue: R) { + super(destination); + } + + _next(x) { + this.isEmpty = false; + this.destination.next(x); + } + + _complete() { + if(this.isEmpty) { + this.destination.next(this.defaultValue); + } + this.destination.complete(); + } +}