Skip to content
This repository was archived by the owner on Apr 20, 2018. It is now read-only.

Commit aa71470

Browse files
Fixing single behavior
1 parent fd30167 commit aa71470

31 files changed

+917
-1078
lines changed

dist/rx.aggregates.js

Lines changed: 113 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -622,30 +622,76 @@
622622
}, source);
623623
};
624624

625-
/**
626-
* Returns the only element of an observable sequence that satisfies the condition in the optional predicate, and reports an exception if there is not exactly one element in the observable sequence.
627-
* @param {Function} [predicate] A predicate function to evaluate for elements in the source sequence.
628-
* @param {Any} [thisArg] Object to use as `this` when executing the predicate.
629-
* @returns {Observable} Sequence containing the single element in the observable sequence that satisfies the condition in the predicate.
630-
*/
631-
observableProto.single = function (predicate, thisArg) {
632-
if (isFunction(predicate)) { return this.filter(predicate, thisArg).single(); }
633-
var source = this;
634-
return new AnonymousObservable(function (o) {
635-
var value, seenValue = false;
636-
return source.subscribe(function (x) {
637-
if (seenValue) {
638-
o.onError(new Error('Sequence contains more than one element'));
639-
} else {
640-
value = x;
641-
seenValue = true;
625+
var SingleObserver = (function(__super__) {
626+
inherits(SingleObserver, __super__);
627+
function SingleObserver(o, obj, s) {
628+
this._o = o;
629+
this._obj = obj;
630+
this._s = s;
631+
this._i = 0;
632+
this._hv = false;
633+
this._v = null;
634+
__super__.call(this);
635+
}
636+
637+
SingleObserver.prototype.next = function (x) {
638+
var shouldYield = false;
639+
if (this._obj.predicate) {
640+
var res = tryCatch(this._obj.predicate)(x, this._i++, this._s);
641+
if (res === errorObj) { return this._o.onError(res.e); }
642+
Boolean(res) && (shouldYield = true);
643+
} else if (!this._obj.predicate) {
644+
shouldYield = true;
645+
}
646+
if (shouldYield) {
647+
if (this._hv) {
648+
return this._o.onError(new Error('Sequence contains more than one matching element'));
642649
}
643-
}, function (e) { o.onError(e); }, function () {
644-
o.onNext(value);
645-
o.onCompleted();
646-
});
647-
}, source);
648-
};
650+
this._hv = true;
651+
this._v = x;
652+
}
653+
};
654+
SingleObserver.prototype.error = function (e) { this._o.onError(e); };
655+
SingleObserver.prototype.completed = function () {
656+
if (this._hv) {
657+
this._o.onNext(this._v);
658+
this._o.onCompleted();
659+
}
660+
else if (this._obj.defaultValue === undefined) {
661+
this._o.onError(new EmptyError());
662+
} else {
663+
this._o.onNext(this._obj.defaultValue);
664+
this._o.onCompleted();
665+
}
666+
};
667+
668+
return SingleObserver;
669+
}(AbstractObserver));
670+
671+
672+
/**
673+
* Returns the only element of an observable sequence that satisfies the condition in the optional predicate, and reports an exception if there is not exactly one element in the observable sequence.
674+
* @returns {Observable} Sequence containing the single element in the observable sequence that satisfies the condition in the predicate.
675+
*/
676+
observableProto.single = function (predicate, thisArg) {
677+
var obj = {}, source = this;
678+
if (typeof arguments[0] === 'object') {
679+
obj = arguments[0];
680+
} else {
681+
obj = {
682+
predicate: arguments[0],
683+
thisArg: arguments[1],
684+
defaultValue: arguments[2]
685+
};
686+
}
687+
if (isFunction (obj.predicate)) {
688+
var fn = obj.predicate;
689+
obj.predicate = bindCallback(fn, obj.thisArg, 3);
690+
}
691+
return new AnonymousObservable(function (o) {
692+
return source.subscribe(new SingleObserver(o, obj, source));
693+
}, source);
694+
};
649695

650696
var FirstObserver = (function(__super__) {
651697
inherits(FirstObserver, __super__);
@@ -707,6 +753,49 @@
707753
}, source);
708754
};
709755

756+
var LastObserver = (function(__super__) {
757+
inherits(LastObserver, __super__);
758+
function LastObserver(o, obj, s) {
759+
this._o = o;
760+
this._obj = obj;
761+
this._s = s;
762+
this._i = 0;
763+
this._hv = false;
764+
this._v = null;
765+
__super__.call(this);
766+
}
767+
768+
LastObserver.prototype.next = function (x) {
769+
var shouldYield = false;
770+
if (this._obj.predicate) {
771+
var res = tryCatch(this._obj.predicate)(x, this._i++, this._s);
772+
if (res === errorObj) { return this._o.onError(res.e); }
773+
Boolean(res) && (shouldYield = true);
774+
} else if (!this._obj.predicate) {
775+
shouldYield = true;
776+
}
777+
if (shouldYield) {
778+
this._hv = true;
779+
this._v = x;
780+
}
781+
};
782+
LastObserver.prototype.error = function (e) { this._o.onError(e); };
783+
LastObserver.prototype.completed = function () {
784+
if (this._hv) {
785+
this._o.onNext(this._v);
786+
this._o.onCompleted();
787+
}
788+
else if (this._obj.defaultValue === undefined) {
789+
this._o.onError(new EmptyError());
790+
} else {
791+
this._o.onNext(this._obj.defaultValue);
792+
this._o.onCompleted();
793+
}
794+
};
795+
796+
return LastObserver;
797+
}(AbstractObserver));
798+
710799
/**
711800
* Returns the last element of an observable sequence that satisfies the condition in the predicate if specified, else the last element.
712801
* @returns {Observable} Sequence containing the last element in the observable sequence that satisfies the condition in the predicate.
@@ -727,34 +816,7 @@
727816
obj.predicate = bindCallback(fn, obj.thisArg, 3);
728817
}
729818
return new AnonymousObservable(function (o) {
730-
var value, seenValue = false, i = 0;
731-
return source.subscribe(
732-
function (x) {
733-
if (obj.predicate) {
734-
var res = tryCatch(obj.predicate)(x, i++, source);
735-
if (res === errorObj) { return o.onError(res.e); }
736-
if (res) {
737-
seenValue = true;
738-
value = x;
739-
}
740-
} else if (!obj.predicate) {
741-
seenValue = true;
742-
value = x;
743-
}
744-
},
745-
function (e) { o.onError(e); },
746-
function () {
747-
if (seenValue) {
748-
o.onNext(value);
749-
o.onCompleted();
750-
}
751-
else if (obj.defaultValue === undefined) {
752-
o.onError(new EmptyError());
753-
} else {
754-
o.onNext(obj.defaultValue);
755-
o.onCompleted();
756-
}
757-
});
819+
return source.subscribe(new LastObserver(o, obj, source));
758820
}, source);
759821
};
760822

0 commit comments

Comments
 (0)