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

Implement deepPluck, a pluck operator for nested properties #526

Merged
merged 1 commit into from
Feb 5, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 32 additions & 3 deletions doc/api/core/operators/pluck.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
### `Rx.Observable.prototype.pluck(property)`
[Ⓢ](https://github.com/Reactive-Extensions/RxJS/blob/master/src/core/linq/observable/pluck.js "View in source")
[Ⓢ](https://github.com/Reactive-Extensions/RxJS/blob/master/src/core/linq/observable/pluck.js#L10 "View in source")

Projects each element of an observable sequence into a new form by incorporating the element's index.
Returns an Observable containing the value of a specified nested property from
all elements in the Observable sequence. If a property can't be resolved, it
will return `undefined` for that value.

#### Arguments
1. `property` *(`String`)*: The property to pluck.
1. `property` *(`String`)*: The property or properties to pluck. `pluck`
accepts an unlimited number of nested property parameters.

#### Returns
*(`Observable`)*: Returns a new Observable sequence of property values.
Expand Down Expand Up @@ -34,6 +37,32 @@ var subscription = source.subscribe(
// => Next: 1
// => Next: 2
// => Completed

// Using nested properties:

var source = Rx.Observable
.from([
{ valueA: { valueB: { valueC: 0 }}},
{ valueA: { valueB: { valueC: 1 }}},
{ valueA: { valueB: 2 }},
])
.pluck('valueA', 'valueB', 'valueC');

var subscription = source.subscribe(
function (x) {
console.log('Next: ' + x);
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
});

// => Next: 0
// => Next: 1
// => Next: undefined
// => Completed
```

### Location
Expand Down
26 changes: 22 additions & 4 deletions src/core/linq/observable/pluck.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
/**
* Retrieves the value of a specified property from all elements in the Observable sequence.
* @param {String} prop The property to pluck.
* Retrieves the value of a specified nested property from all elements in
* the Observable sequence.
* @param {String} nestedProps The nested property to pluck.
* @returns {Observable} Returns a new Observable sequence of property values.
*/
observableProto.pluck = function (prop) {
return this.map(function (x) { return x[prop]; });
observableProto.pluck = function () {
var args = [].slice.call(arguments);
var len = args.length;
return this.map(function (x) {
if (len === 0) {
return undefined;
}

var currentProp = x;
for (var i = 0; i < len; i++) {
var p = currentProp[args[i]];
if (typeof p !== 'undefined') {
currentProp = p;
} else {
return undefined;
}
}
return currentProp;
});
};
60 changes: 60 additions & 0 deletions tests/observable/pluck.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,63 @@ test('Pluck_Completed', function () {

xs.subscriptions.assertEqual(subscribe(200, 400));
});

test('Deep_Pluck_Nested_Completed', function () {
var scheduler = new TestScheduler();

var xs = scheduler.createHotObservable(
onNext(180, {a: {b: {c: 1}}}),
onNext(210, {a: {b: {c: 2}}}),
onNext(240, {a: {b: {c: 3}}}),
onNext(290, {a: {b: {c: 4}}}),
onNext(350, {a: {b: {c: 5}}}),
onCompleted(400),
onNext(410, {a: {b: {c: -1}}}),
onCompleted(420),
onError(430, new Error('ex'))
);

var results = scheduler.startWithCreate(function () {
return xs.pluck('a', 'b', 'c');
});

results.messages.assertEqual(
onNext(210, 2),
onNext(240, 3),
onNext(290, 4),
onNext(350, 5),
onCompleted(400)
);

xs.subscriptions.assertEqual(subscribe(200, 400));
});

test('Deep_Pluck_Nested_Edgecases', function () {
var scheduler = new TestScheduler();

var xs = scheduler.createHotObservable(
onNext(180, {a: {b: {c: 1}}}),
onNext(210, {a: {b: 2}}),
onNext(240, {a: {c: {c: 3}}}),
onNext(290, {}),
onNext(350, {a: {b: {c: 5}}}),
onCompleted(400),
onNext(410, {a: {b: {c: -1}}}),
onCompleted(420),
onError(430, new Error('ex'))
);

var results = scheduler.startWithCreate(function () {
return xs.pluck('a', 'b', 'c');
});

results.messages.assertEqual(
onNext(210, undefined),
onNext(240, undefined),
onNext(290, undefined),
onNext(350, 5),
onCompleted(400)
);

xs.subscriptions.assertEqual(subscribe(200, 400));
});