Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cleanup system/many-array #4645

Merged
merged 1 commit into from
Nov 11, 2016
Merged
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
165 changes: 79 additions & 86 deletions addon/-private/system/many-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { assert } from "ember-data/-private/debug";
import { PromiseArray } from "ember-data/-private/system/promise-proxies";
import { _objectIsAlive } from "ember-data/-private/system/store/common";

var get = Ember.get;
var set = Ember.set;
const { get, set } = Ember;

/**
A `ManyArray` is a `MutableArray` that represents the contents of a has-many
Expand Down Expand Up @@ -55,74 +54,25 @@ var set = Ember.set;
export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, {
init() {
this._super(...arguments);
this.currentState = Ember.A([]);
this.flushCanonical();
},

record: null,

canonicalState: null,
currentState: null,

length: 0,

objectAt(index) {
//Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses
if (!this.currentState[index]) {
return undefined;
}

return this.currentState[index].getRecord();
},

flushCanonical() {
let toSet = this.canonicalState;

//a hack for not removing new records
//TODO remove once we have proper diffing
let newRecords = this.currentState.filter(
// only add new records which are not yet in the canonical state of this
// relationship (a new record can be in the canonical state if it has
// been 'acknowleged' to be in the relationship via a store.push)
(internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1
);
toSet = toSet.concat(newRecords);
let oldLength = this.length;
this.arrayContentWillChange(0, this.length, toSet.length);
// It’s possible the parent side of the relationship may have been unloaded by this point
if (_objectIsAlive(this)) {
this.set('length', toSet.length);
}
this.currentState = toSet;
this.arrayContentDidChange(0, oldLength, this.length);
//TODO Figure out to notify only on additions and maybe only if unloaded
this.relationship.notifyHasManyChanged();
this.record.updateRecordArrays();
},
/**
`true` if the relationship is polymorphic, `false` otherwise.

@property {Boolean} isPolymorphic
@private
*/
isPolymorphic: false,

/**
/**
The loading state of this array

@property {Boolean} isLoaded
*/
isLoaded: false,
*/
this.isLoaded = false;
this.length = 0;

/**
The relationship which manages this array.
/**
Used for async `hasMany` arrays
to keep track of when they will resolve.

@property {ManyRelationship} relationship
@property {Ember.RSVP.Promise} promise
@private
*/
relationship: null,
*/
this.promise = null;

/**
/**
Metadata associated with the request for async hasMany relationships.

Example
Expand All @@ -136,7 +86,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, {
"id": 1,
"comment": "This is the first comment",
}, {
// ...
// ...
}],

"meta": {
Expand All @@ -152,15 +102,68 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, {
post.get('comments').then(function(comments) {
var meta = comments.get('meta');

// meta.page => 1
// meta.total => 5
// meta.page => 1
// meta.total => 5
});
```

@property {Object} meta
@public
*/
meta: null,
*/
this.meta = this.meta || null;

/**
`true` if the relationship is polymorphic, `false` otherwise.

@property {Boolean} isPolymorphic
@private
*/
this.isPolymorphic = this.isPolymorphic || false;

/**
The relationship which manages this array.

@property {ManyRelationship} relationship
@private
*/
this.relationship = this.relationship || null;

this.currentState = Ember.A([]);
this.flushCanonical();
},

objectAt(index) {
//Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses
if (!this.currentState[index]) {
return undefined;
}

return this.currentState[index].getRecord();
},

flushCanonical() {
let toSet = this.canonicalState;

//a hack for not removing new records
//TODO remove once we have proper diffing
let newRecords = this.currentState.filter(
// only add new records which are not yet in the canonical state of this
// relationship (a new record can be in the canonical state if it has
// been 'acknowleged' to be in the relationship via a store.push)
(internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1
);
toSet = toSet.concat(newRecords);
let oldLength = this.length;
this.arrayContentWillChange(0, this.length, toSet.length);
// It’s possible the parent side of the relationship may have been unloaded by this point
if (_objectIsAlive(this)) {
this.set('length', toSet.length);
}
this.currentState = toSet;
this.arrayContentDidChange(0, oldLength, this.length);
//TODO Figure out to notify only on additions and maybe only if unloaded
this.relationship.notifyHasManyChanged();
},

internalReplace(idx, amt, objects) {
if (!objects) {
Expand All @@ -179,9 +182,8 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, {

//TODO(Igor) optimize
internalRemoveRecords(records) {
var index;
for (var i=0; i < records.length; i++) {
index = this.currentState.indexOf(records[i]);
for (let i=0; i < records.length; i++) {
let index = this.currentState.indexOf(records[i]);
this.internalReplace(index, 1);
}
},
Expand All @@ -195,23 +197,15 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, {
},

replace(idx, amt, objects) {
var records;
let records;
if (amt > 0) {
records = this.currentState.slice(idx, idx+amt);
this.get('relationship').removeRecords(records);
}
if (objects) {
this.get('relationship').addRecords(objects.map((obj) => obj._internalModel), idx);
this.get('relationship').addRecords(objects.map(obj => obj._internalModel), idx);
}
},
/**
Used for async `hasMany` arrays
to keep track of when they will resolve.

@property {Ember.RSVP.Promise} promise
@private
*/
promise: null,

/**
@method loadingRecordsCount
Expand Down Expand Up @@ -262,11 +256,10 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, {
@return {DS.PromiseArray} promise
*/
save() {
var manyArray = this;
var promiseLabel = "DS: ManyArray#save " + get(this, 'type');
var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) {
return manyArray;
}, null, "DS: ManyArray#save return ManyArray");
let manyArray = this;
let promiseLabel = 'DS: ManyArray#save ' + get(this, 'type');
let promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).
then(() => manyArray, null, 'DS: ManyArray#save return ManyArray');

return PromiseArray.create({ promise });
},
Expand All @@ -284,7 +277,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, {
var type = get(this, 'type');
var record;

assert("You cannot add '" + type.modelName + "' records to this polymorphic relationship.", !get(this, 'isPolymorphic'));
assert(`You cannot add '${type.modelName}' records to this polymorphic relationship.`, !get(this, 'isPolymorphic'));
record = store.createRecord(type.modelName, hash);
this.pushObject(record);

Expand Down