Skip to content

Commit

Permalink
Add RecordArray#filterBy which contains a live, filtered subset
Browse files Browse the repository at this point in the history
This method takes the parameters `key` and an optional `value` and
returns an updating list of records of the `RecordArray`, which'
property value of `key` matches `value`.
  • Loading branch information
pangratz committed Jul 5, 2015
1 parent f548244 commit 1aeaa91
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 0 deletions.
53 changes: 53 additions & 0 deletions packages/ember-data/lib/system/record-arrays/record-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ import SnapshotRecordArray from "ember-data/system/snapshot-record-array";
var get = Ember.get;
var set = Ember.set;

var FilteredSubset = Ember.ArrayProxy.extend({
init: function() {
this._super(...arguments);

var { filterByArgs, recordArray } = this.getProperties('filterByArgs', 'recordArray');
var [key] = filterByArgs;

var path = `recordArray.@each.${key}`;
Ember.defineProperty(this, 'content', Ember.computed(path, function() {
return this.filterBy.apply(recordArray, filterByArgs);
}));
}
});


/**
A record array is an array that contains records of a certain type. The record
array materializes records as needed when they are retrieved for the first
Expand Down Expand Up @@ -96,6 +111,44 @@ export default Ember.ArrayProxy.extend(Ember.Evented, {
return internalModel && internalModel.getRecord();
},

/**
Get a filtered subset of the underlying `RecordArray`.
The subset updates when a record would match or mismatch the
specified filter parameters.
Example
```javascript
var allToms = store.all('person').filterBy('name', 'Tom');
allToms.get('length'); // 0, since no toms yet in store
var tom = store.push('person', { id: 1, name: 'Tom' });
allToms.get('length'); // Tom is added
tom.set('name', 'Thomas');
allToms.get('length'); // 0, since no more records with name === 'Tom'
```
@method filterBy
@param {String} key property path
@param {*} value optional
*/
filterBy: function(key, value) {
// only pass value to the arguments if it is present; this mimics the same
// behavior for `filterBy`: http://git.io/vIurH
var filterByArgs = [key];
if (arguments.length === 2) {
filterByArgs.push(value);
}

return FilteredSubset.create({
filterByArgs,
recordArray: this
});
},

/**
Used to get the latest version of all of the records in this array
from the adapter.
Expand Down
88 changes: 88 additions & 0 deletions packages/ember-data/tests/unit/record-array-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,91 @@ test("a record array should return a promise when updating", function() {
});
ok(promise.then && typeof promise.then === "function", "#update returns a promise");
});

test('filterBy - returns a filtered subset', function() {
var store = createStore({
person: Person
});

run(function() {
store.pushMany('person', [{ id: '1', name: "Tom" }, { id: '2', name: "Yehuda" }, { id: '3', name: "Alex" }]);
});

var all = store.all('person');
var toms = all.filterBy('name', 'Tom');
equal(toms.get('length'), 1);
deepEqual(toms.getEach('id'), ['1']);

// a new record is added if filter matches
run(function() {
store.push('person', { id: '4', name: "Tom" });
});
equal(toms.get('length'), 2);
deepEqual(toms.getEach('id'), ['1', '4']);

// a new record is not added if filter doesn't match
run(function() {
store.push('person', { id: '5', name: "Igor" });
});
equal(toms.get('length'), 2);
deepEqual(toms.getEach('id'), ['1', '4']);

// changing the filtered value remvoves the record from the list
run(function() {
// we are using a private method here to get the record immediatly
store.recordForId('person', '1').set('name', "Thomas");
});
equal(toms.get('length'), 1);
deepEqual(toms.getEach('id'), ['4']);

// change value back to original
run(function() {
store.recordForId('person', '1').set('name', "Tom");
});
equal(toms.get('length'), 2);
deepEqual(toms.getEach('id'), ['1', '4']);
});

test('filterBy - value is optional', function() {
var store = createStore({
person: Person
});

run(function() {
store.pushMany('person', [{ id: '1', name: "Tom" }, { id: '2' }]);
});

var all = store.all('person');
var allWithNames = all.filterBy('name');
equal(allWithNames.get('length'), 1);
deepEqual(allWithNames.getEach('id'), ['1']);

// a new record is added if filter matches
run(function() {
store.push('person', { id: '3', name: "Igor" });
});
equal(allWithNames.get('length'), 2);
deepEqual(allWithNames.getEach('id'), ['1', '3']);

// a new record is not added if filter doesn't match
run(function() {
store.push('person', { id: '4' });
});
equal(allWithNames.get('length'), 2);
deepEqual(allWithNames.getEach('id'), ['1', '3']);

// changing the filtered value remvoves the record from the list
run(function() {
// we are using a private method here to get the record immediatly
store.recordForId('person', '1').set('name', null);
});
equal(allWithNames.get('length'), 1);
deepEqual(allWithNames.getEach('id'), ['3']);

// change value back to original
run(function() {
store.recordForId('person', '1').set('name', "Tom");
});
equal(allWithNames.get('length'), 2);
deepEqual(allWithNames.getEach('id'), ['1', '3']);
});

0 comments on commit 1aeaa91

Please sign in to comment.