Skip to content

Commit

Permalink
Cache relationships meta in production
Browse files Browse the repository at this point in the history
  • Loading branch information
igorT authored and stefanpenner committed Dec 3, 2014
1 parent 8dcbe2c commit 7a608d4
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 59 deletions.
135 changes: 77 additions & 58 deletions packages/ember-data/lib/system/relationships/ext.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,80 @@ import {
var get = Ember.get;
var filter = Ember.ArrayPolyfills.filter;

var relationshipsDescriptor = Ember.computed(function() {
if (Ember.testing === true && relationshipsDescriptor._cacheable === true) {
relationshipsDescriptor._cacheable = false;
}

var map = new MapWithDefault({
defaultValue: function() { return []; }
});

// Loop through each computed property on the class
this.eachComputedProperty(function(name, meta) {
// If the computed property is a relationship, add
// it to the map.
if (meta.isRelationship) {
meta.key = name;
var relationshipsForType = map.get(typeForRelationshipMeta(this.store, meta));

relationshipsForType.push({
name: name,
kind: meta.kind
});
}
});

return map;
}).readOnly();

var relatedTypesDescriptor = Ember.computed(function() {
if (Ember.testing === true && relatedTypesDescriptor._cacheable === true) {
relatedTypesDescriptor._cacheable = false;
}

var type;
var types = Ember.A();

// Loop through each computed property on the class,
// and create an array of the unique types involved
// in relationships
this.eachComputedProperty(function(name, meta) {
if (meta.isRelationship) {
meta.key = name;
type = typeForRelationshipMeta(this.store, meta);

Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", type);

if (!types.contains(type)) {
Ember.assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!type);
types.push(type);
}
}
});

return types;
}).readOnly();

var relationshipsByNameDescriptor = Ember.computed(function() {
if (Ember.testing === true && relationshipsByNameDescriptor._cacheable === true) {
relationshipsByNameDescriptor._cacheable = false;
}

var map = Map.create();

this.eachComputedProperty(function(name, meta) {
if (meta.isRelationship) {
meta.key = name;
var relationship = relationshipFromMeta(this.store, meta);
relationship.type = typeForRelationshipMeta(this.store, meta);
map.set(name, relationship);
}
});

return map;
}).readOnly();

/**
@module ember-data
*/
Expand Down Expand Up @@ -266,28 +340,8 @@ Model.reopenClass({
@type Ember.Map
@readOnly
*/
relationships: Ember.computed(function() {
var map = new MapWithDefault({
defaultValue: function() { return []; }
});

// Loop through each computed property on the class
this.eachComputedProperty(function(name, meta) {
// If the computed property is a relationship, add
// it to the map.
if (meta.isRelationship) {
meta.key = name;
var relationshipsForType = map.get(typeForRelationshipMeta(this.store, meta));

relationshipsForType.push({
name: name,
kind: meta.kind
});
}
});

return map;
}).cacheable(false).readOnly(),
relationships: relationshipsDescriptor,

/**
A hash containing lists of the model's relationships, grouped
Expand Down Expand Up @@ -361,29 +415,7 @@ Model.reopenClass({
@type Ember.Array
@readOnly
*/
relatedTypes: Ember.computed(function() {
var type;
var types = Ember.A();

// Loop through each computed property on the class,
// and create an array of the unique types involved
// in relationships
this.eachComputedProperty(function(name, meta) {
if (meta.isRelationship) {
meta.key = name;
type = typeForRelationshipMeta(this.store, meta);

Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", type);

if (!types.contains(type)) {
Ember.assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!type);
types.push(type);
}
}
});

return types;
}).cacheable(false).readOnly(),
relatedTypes: relatedTypesDescriptor,

/**
A map whose keys are the relationships of a model and whose values are
Expand Down Expand Up @@ -416,20 +448,7 @@ Model.reopenClass({
@type Ember.Map
@readOnly
*/
relationshipsByName: Ember.computed(function() {
var map = Map.create();

this.eachComputedProperty(function(name, meta) {
if (meta.isRelationship) {
meta.key = name;
var relationship = relationshipFromMeta(this.store, meta);
relationship.type = typeForRelationshipMeta(this.store, meta);
map.set(name, relationship);
}
});

return map;
}).cacheable(false).readOnly(),
relationshipsByName: relationshipsByNameDescriptor,

/**
A map whose keys are the fields of the model and whose values are strings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,58 @@ test("relationshipsByName does not cache a factory", function() {
"model factory based on relationship type matches the model based on store.modelFor" );
});

test("asdf", function() {
test("relationshipsByName is cached in production", function() {
var model = store.modelFor('user');
var oldTesting = Ember.testing;
//We set the cacheable to true because that is the default state for any CP and then assert that it
//did not get dynamically changed when accessed
var oldCacheable = Ember.meta(model).descs.relationshipsByName._cacheable;
Ember.meta(model).descs.relationshipsByName._cacheable = true;
Ember.testing = false;
try {
equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached');
equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached');
} finally {
Ember.testing = oldTesting;
Ember.meta(model).descs.relationshipsByName._cacheable = oldCacheable;
}
});

test("relatedTypes is cached in production", function() {
var model = store.modelFor('user');
var oldTesting = Ember.testing;
//We set the cacheable to true because that is the default state for any CP and then assert that it
//did not get dynamically changed when accessed
var oldCacheable = Ember.meta(model).descs.relatedTypes._cacheable;
Ember.meta(model).descs.relatedTypes._cacheable = true;
Ember.testing = false;
try {
equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached');
equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached');
} finally {
Ember.testing = oldTesting;
Ember.meta(model).descs.relatedTypes._cacheable = oldCacheable;
}
});

test("relationships is cached in production", function() {
var model = store.modelFor('user');
var oldTesting = Ember.testing;
//We set the cacheable to true because that is the default state for any CP and then assert that it
//did not get dynamically changed when accessed
var oldCacheable = Ember.meta(model).descs.relatedTypes._cacheable;
Ember.meta(model).descs.relationships._cacheable = true;
Ember.testing = false;
try {
equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached');
equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached');
} finally {
Ember.testing = oldTesting;
Ember.meta(model).descs.relationships._cacheable = oldCacheable;
}
});

test("relationship changes shouldn’t cause async fetches", function() {
expect(2);

/* Scenario:
Expand Down

0 comments on commit 7a608d4

Please sign in to comment.