Skip to content

Commit

Permalink
Merge pull request #3185 from whatthewhat/model-relationships-getter
Browse files Browse the repository at this point in the history
[REBASE] Model relationships getter
  • Loading branch information
igorT committed Jun 3, 2015
2 parents f40b1f9 + 69892b4 commit ae6355a
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 48 deletions.
21 changes: 8 additions & 13 deletions packages/ember-data/lib/system/model/internal-model.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import merge from "ember-data/system/merge";
import RootState from "ember-data/system/model/states";
import createRelationshipFor from "ember-data/system/relationships/state/create";
import Relationships from "ember-data/system/relationships/state/create";
import Snapshot from "ember-data/system/snapshot";
import Errors from "ember-data/system/model/errors";

Expand Down Expand Up @@ -60,7 +60,7 @@ var InternalModel = function InternalModel(type, id, store, container, data) {
this._deferredTriggers = [];
this._attributes = Ember.create(null);
this._inFlightAttributes = Ember.create(null);
this._relationships = Ember.create(null);
this._relationships = new Relationships(this);
this.currentState = RootState.empty;
this.isReloading = false;
/*
Expand All @@ -84,11 +84,6 @@ var InternalModel = function InternalModel(type, id, store, container, data) {
when we are deleted
*/
this._implicitRelationships = Ember.create(null);
var model = this;
//TODO Move into a getter for better perf
this.eachRelationship(function(key, descriptor) {
model._relationships[key] = createRelationshipFor(model, descriptor, model.store);
});
};

InternalModel.prototype = {
Expand Down Expand Up @@ -441,8 +436,8 @@ InternalModel.prototype = {
*/
clearRelationships: function() {
this.eachRelationship(function(name, relationship) {
var rel = this._relationships[name];
if (rel) {
if (this._relationships.has(name)) {
var rel = this._relationships.get(name);
//TODO(Igor) figure out whether we want to clear or disconnect
rel.clear();
rel.destroy();
Expand All @@ -457,7 +452,7 @@ InternalModel.prototype = {

disconnectRelationships: function() {
this.eachRelationship(function(name, relationship) {
this._relationships[name].disconnect();
this._relationships.get(name).disconnect();
}, this);
var model = this;
forEach.call(Ember.keys(this._implicitRelationships), function(key) {
Expand All @@ -467,7 +462,7 @@ InternalModel.prototype = {

reconnectRelationships: function() {
this.eachRelationship(function(name, relationship) {
this._relationships[name].reconnect();
this._relationships.get(name).reconnect();
}, this);
var model = this;
forEach.call(Ember.keys(this._implicitRelationships), function(key) {
Expand Down Expand Up @@ -524,15 +519,15 @@ InternalModel.prototype = {
});
//We use the pathway of setting the hasMany as if it came from the adapter
//because the user told us that they know this relationships exists already
this._relationships[key].updateRecordsFromAdapter(recordsToSet);
this._relationships.get(key).updateRecordsFromAdapter(recordsToSet);
},

_preloadBelongsTo: function(key, preloadValue, type) {
var recordToSet = this._convertStringOrNumberIntoInternalModel(preloadValue, type);

//We use the pathway of setting the hasMany as if it came from the adapter
//because the user told us that they know this relationships exists already
this._relationships[key].setRecord(recordToSet);
this._relationships.get(key).setRecord(recordToSet);
},

_convertStringOrNumberIntoInternalModel: function(value, type) {
Expand Down
10 changes: 5 additions & 5 deletions packages/ember-data/lib/system/relationships/belongs-to.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,21 @@ function belongsTo(modelName, options) {

return computedPolyfill({
get: function(key) {
return this._internalModel._relationships[key].getRecord();
return this._internalModel._relationships.get(key).getRecord();
},
set: function(key, value) {
if (value === undefined) {
value = null;
}
if (value && value.then) {
this._internalModel._relationships[key].setRecordPromise(value);
this._internalModel._relationships.get(key).setRecordPromise(value);
} else if (value) {
this._internalModel._relationships[key].setRecord(value._internalModel);
this._internalModel._relationships.get(key).setRecord(value._internalModel);
} else {
this._internalModel._relationships[key].setRecord(value);
this._internalModel._relationships.get(key).setRecord(value);
}

return this._internalModel._relationships[key].getRecord();
return this._internalModel._relationships.get(key).getRecord();
}
}).meta(meta);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-data/lib/system/relationships/has-many.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,11 @@ function hasMany(type, options) {

return computedPolyfill({
get: function(key) {
var relationship = this._internalModel._relationships[key];
var relationship = this._internalModel._relationships.get(key);
return relationship.getRecords();
},
set: function(key, records) {
var relationship = this._internalModel._relationships[key];
var relationship = this._internalModel._relationships.get(key);
relationship.clear();
Ember.assert("You must pass an array of records to set a hasMany relationship", Ember.isArray(records));
relationship.addRecords(Ember.A(records).mapBy('_internalModel'));
Expand Down
22 changes: 21 additions & 1 deletion packages/ember-data/lib/system/relationships/state/create.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import ManyRelationship from "ember-data/system/relationships/state/has-many";
import BelongsToRelationship from "ember-data/system/relationships/state/belongs-to";

var get = Ember.get;

var createRelationshipFor = function(record, relationshipMeta, store) {
var inverseKey;
var inverse = record.type.inverseFor(relationshipMeta.key, store);
Expand All @@ -16,4 +18,22 @@ var createRelationshipFor = function(record, relationshipMeta, store) {
}
};

export default createRelationshipFor;
var Relationships = function(record) {
this.record = record;
this.initializedRelationships = Ember.create(null);
};

Relationships.prototype.has = function(key) {
return !!this.initializedRelationships[key];
};

Relationships.prototype.get = function(key) {
var relationships = this.initializedRelationships;
var relationshipsByName = get(this.record.type, 'relationshipsByName');
if (!relationships[key] && relationshipsByName.get(key)) {
relationships[key] = createRelationshipFor(this.record, relationshipsByName.get(key), this.record.store);
}
return relationships[key];
};

export default Relationships;
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Relationship.prototype = {
if (!this.canonicalMembers.has(record)) {
this.canonicalMembers.add(record);
if (this.inverseKey) {
record._relationships[this.inverseKey].addCanonicalRecord(this.record);
record._relationships.get(this.inverseKey).addCanonicalRecord(this.record);
} else {
if (!record._implicitRelationships[this.inverseKeyForImplicit]) {
record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} });
Expand Down Expand Up @@ -117,7 +117,7 @@ Relationship.prototype = {
this.members.addWithIndex(record, idx);
this.notifyRecordRelationshipAdded(record, idx);
if (this.inverseKey) {
record._relationships[this.inverseKey].addRecord(this.record);
record._relationships.get(this.inverseKey).addRecord(this.record);
} else {
if (!record._implicitRelationships[this.inverseKeyForImplicit]) {
record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} });
Expand All @@ -144,12 +144,12 @@ Relationship.prototype = {

addRecordToInverse: function(record) {
if (this.inverseKey) {
record._relationships[this.inverseKey].addRecord(this.record);
record._relationships.get(this.inverseKey).addRecord(this.record);
}
},

removeRecordFromInverse: function(record) {
var inverseRelationship = record._relationships[this.inverseKey];
var inverseRelationship = record._relationships.get(this.inverseKey);
//Need to check for existence, as the record might unloading at the moment
if (inverseRelationship) {
inverseRelationship.removeRecordFromOwn(this.record);
Expand All @@ -163,7 +163,7 @@ Relationship.prototype = {
},

removeCanonicalRecordFromInverse: function(record) {
var inverseRelationship = record._relationships[this.inverseKey];
var inverseRelationship = record._relationships.get(this.inverseKey);
//Need to check for existence, as the record might unloading at the moment
if (inverseRelationship) {
inverseRelationship.removeCanonicalRecordFromOwn(this.record);
Expand Down
6 changes: 3 additions & 3 deletions packages/ember-data/lib/system/snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ Snapshot.prototype = {
return this._belongsToRelationships[keyName];
}

relationship = this._internalModel._relationships[keyName];
relationship = this._internalModel._relationships.get(keyName);
if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) {
throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined.");
}
Expand Down Expand Up @@ -294,7 +294,7 @@ Snapshot.prototype = {
return this._hasManyRelationships[keyName];
}

relationship = this._internalModel._relationships[keyName];
relationship = this._internalModel._relationships.get(keyName);
if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) {
throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined.");
}
Expand Down Expand Up @@ -381,7 +381,7 @@ Snapshot.prototype = {
return this.attr(keyName);
}

var relationship = this._internalModel._relationships[keyName];
var relationship = this._internalModel._relationships.get(keyName);

if (relationship && relationship.relationshipMeta.kind === 'belongsTo') {
return this.belongsTo(keyName);
Expand Down
7 changes: 5 additions & 2 deletions packages/ember-data/lib/system/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ Store = Service.extend({
record.setProperties(properties);

internalModel.eachRelationship(function(key, descriptor) {
internalModel._relationships[key].setHasData(true);
internalModel._relationships.get(key).setHasData(true);
});

return record;
Expand Down Expand Up @@ -2111,16 +2111,19 @@ function setupRelationships(store, record, data) {
typeClass.eachRelationship(function(key, descriptor) {
var kind = descriptor.kind;
var value = data[key];
var relationship = record._relationships[key];
var relationship;

if (data.links && data.links[key]) {
relationship = record._relationships.get(key);
relationship.updateLink(data.links[key]);
}

if (value !== undefined) {
if (kind === 'belongsTo') {
relationship = record._relationships.get(key);
relationship.setCanonicalRecord(value);
} else if (kind === 'hasMany') {
relationship = record._relationships.get(key);
relationship.updateRecordsFromAdapter(value);
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/ember-data/tests/integration/inverse-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ test("Errors out if you do not define an inverse for a reflexive relationship",
var reflexiveModel;
run(function() {
reflexiveModel = store.push('reflexive-model', { id: 1 });
reflexiveModel.get('reflexiveProp');
});
}, /Detected a reflexive relationship by the name of 'reflexiveProp'/);
});
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ test("belongsTo hasData async loaded", function () {

run(function() {
store.find('book', 1).then(function(book) {
var relationship = book._internalModel._relationships['author'];
var relationship = book._internalModel._relationships.get('author');
equal(relationship.hasData, true, 'relationship has data');
});
});
Expand All @@ -652,7 +652,7 @@ test("belongsTo hasData sync loaded", function () {

run(function() {
store.find('book', 1).then(function(book) {
var relationship = book._internalModel._relationships['author'];
var relationship = book._internalModel._relationships.get('author');
equal(relationship.hasData, true, 'relationship has data');
});
});
Expand All @@ -671,7 +671,7 @@ test("belongsTo hasData async not loaded", function () {

run(function() {
store.find('book', 1).then(function(book) {
var relationship = book._internalModel._relationships['author'];
var relationship = book._internalModel._relationships.get('author');
equal(relationship.hasData, false, 'relationship does not have data');
});
});
Expand All @@ -686,7 +686,7 @@ test("belongsTo hasData sync not loaded", function () {

run(function() {
store.find('book', 1).then(function(book) {
var relationship = book._internalModel._relationships['author'];
var relationship = book._internalModel._relationships.get('author');
equal(relationship.hasData, false, 'relationship does not have data');
});
});
Expand All @@ -701,7 +701,7 @@ test("belongsTo hasData async created", function () {

run(function() {
var book = store.createRecord('book', { name: 'The Greatest Book' });
var relationship = book._internalModel._relationships['author'];
var relationship = book._internalModel._relationships.get('author');
equal(relationship.hasData, true, 'relationship has data');
});
});
Expand All @@ -711,7 +711,46 @@ test("belongsTo hasData sync created", function () {

run(function() {
var book = store.createRecord('book', { name: 'The Greatest Book' });
var relationship = book._internalModel._relationships['author'];
var relationship = book._internalModel._relationships.get('author');
equal(relationship.hasData, true, 'relationship has data');
});
});

test("Model's belongsTo relationship should not be created during model creation", function () {
var user;
run(function () {
user = env.store.push('user', { id: 1 });
ok(!user._internalModel._relationships.has('favouriteMessage'), 'Newly created record should not have relationships');
});
});

test("Model's belongsTo relationship should be created during model creation if relationship passed in constructor", function () {
var user, message;
run(function () {
message = env.store.createRecord('message');
user = env.store.createRecord('user', {
name: 'John Doe',
favouriteMessage: message
});
ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships");
});
});

test("Model's belongsTo relationship should be created during 'set' method", function () {
var user, message;
run(function () {
message = env.store.createRecord('message');
user = env.store.createRecord('user');
user.set('favouriteMessage', message);
ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships");
});
});

test("Model's belongsTo relationship should be created during 'get' method", function () {
var user;
run(function () {
user = env.store.createRecord('user');
user.get('favouriteMessage');
ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships");
});
});
Loading

0 comments on commit ae6355a

Please sign in to comment.