Skip to content

Commit

Permalink
Merge pull request #4820 from emberjs/release-factory-for-backport
Browse files Browse the repository at this point in the history
[Backport of #4810 to release]
  • Loading branch information
bmac authored Feb 24, 2017
2 parents 9133cff + 71b2016 commit 0c7ebb8
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 29 deletions.
2 changes: 1 addition & 1 deletion addon/-private/system/model/internal-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ export default class InternalModel {
createOptions.container = this.store.container;
}

this._record = this.modelClass._create(createOptions);
this._record = this.store.modelFactoryFor(this.modelName).create(createOptions);

this._triggerDeferredTriggers();
}
Expand Down
28 changes: 14 additions & 14 deletions addon/-private/system/model/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { DidDefinePropertyMixin, RelationshipsClassMethodsMixin, RelationshipsIn
import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr';
import isEnabled from 'ember-data/-private/features';
import RootState from 'ember-data/-private/system/model/states';
import { runInDebug } from 'ember-data/-private/debug';

const {
get,
Expand Down Expand Up @@ -962,17 +963,20 @@ Object.defineProperty(Model.prototype, 'data', {
}
});

Model.reopenClass({
/**
Alias DS.Model's `create` method to `_create`. This allows us to create DS.Model
instances from within the store, but if end users accidentally call `create()`
(instead of `createRecord()`), we can raise an error.
runInDebug(function() {
Model.reopen({
init() {
this._super(...arguments);

@method _create
@private
@static
*/
_create: Model.create,
if (!this._internalModel) {
throw new Ember.Error('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.');
}
}
});
});

Model.reopenClass({
isModel: true,

/**
Override the class' `create()` method to raise an error. This
Expand All @@ -985,10 +989,6 @@ Model.reopenClass({
@private
@static
*/
create() {
throw new Ember.Error("You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.");
},

/**
Represents the model's class name as a string. This can be used to look up the model through
DS.Store's modelFor method.
Expand Down
62 changes: 49 additions & 13 deletions addon/-private/system/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ Store = Service.extend({
store: this
});
this._pendingSave = [];
this._modelClassCache = new EmptyObject();
this._instanceCache = new ContainerInstanceCache(getOwner(this), this);

//Used to keep track of all the find requests that need to be coalesced
Expand Down Expand Up @@ -2072,13 +2073,52 @@ Store = Service.extend({
assert("You need to pass a model name to the store's modelFor method", isPresent(modelName));
assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string');

let factory = this.modelFactoryFor(modelName);
let normalizedModelName = normalizeModelName(modelName);
let factory = this.modelFactoryFor(normalizedModelName);
if (!factory) {
//Support looking up mixins as base types for polymorphic relationships
factory = this._modelForMixin(modelName);
factory = this._modelForMixin(normalizedModelName);
}
if (!factory) {
throw new EmberError("No model was found for '" + modelName + "'");
throw new EmberError("No model was found for '" + normalizedModelName + "'");
}

return this._modelFor(normalizedModelName);
},

/*
@private
*/
_modelFor(modelName) {
let maybeFactory = this._modelFactoryFor(modelName);
// for factorFor factory/class split
return maybeFactory.class ? maybeFactory.class : maybeFactory;
},

_modelFactoryFor(modelName) {
heimdall.increment(modelFor);
let factory = this._modelClassCache[modelName];

if (!factory) {
factory = this.modelFactoryFor(modelName);

if (!factory) {
//Support looking up mixins as base types for polymorphic relationships
factory = this._modelForMixin(modelName);
}
if (!factory) {
throw new EmberError(`No model was found for '${modelName}'`);
}

// interopt with the future
let klass = getOwner(this).factoryFor ? factory.class : factory;

assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel);

// TODO: deprecate this
klass.modelName = klass.modelName || modelName;

this._modelClassCache[modelName] = factory;
}
factory.modelName = factory.modelName || normalizeModelName(modelName);

Expand All @@ -2087,19 +2127,15 @@ Store = Service.extend({

modelFactoryFor(modelName) {
heimdall.increment(modelFactoryFor);
assert("You need to pass a model name to the store's modelFactoryFor method", isPresent(modelName));
assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string');
let normalizedKey = normalizeModelName(modelName);

assert(`You need to pass a model name to the store's modelFactoryFor method`, isPresent(modelName));
assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string');
let trueModelName = normalizeModelName(modelName);
let owner = getOwner(this);

if (owner.factoryFor) {
let MaybeModel = owner.factoryFor(`model:${normalizedKey}`);
let MaybeModelFactory = MaybeModel && MaybeModel.class;

return MaybeModelFactory;
return owner.factoryFor(`model:${trueModelName}`);
} else {
return owner._lookupFactory(`model:${normalizedKey}`);
return owner._lookupFactory(`model:${trueModelName}`);
}
},

Expand Down Expand Up @@ -2494,7 +2530,7 @@ Store = Service.extend({
let idToRecord = typeMap.idToRecord;

assert(`The id ${id} has already been used with another record for modelClass ${modelClass}.`, !id || !idToRecord[id]);
assert(`'${inspect(modelClass)}' does not appear to be an ember-data model`, (typeof modelClass._create === 'function') );
assert(`'${inspect(modelClass)}' does not appear to be an ember-data model`, typeof modelClass.isModel);

// lookupFactory should really return an object that creates
// instances with the injections applied
Expand Down
35 changes: 35 additions & 0 deletions tests/integration/injection-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import setupStore from 'dummy/tests/helpers/store';
import Ember from 'ember';
import DS from 'ember-data';
import { module, test } from 'qunit';

let env, originalMODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS;
const { run } = Ember;

module('integration/injection eager injections', {
setup() {
Ember.MODEL_FACTORY_INJECTIONS = true;
env = setupStore();

env.registry.injection('model:foo', 'apple', 'service:apple');
env.registry.register('model:foo', DS.Model);
env.registry.register('service:apple', Ember.Object.extend({ isService: true }));
// container injection
},

teardown() {
// can be removed once we no longer support ember versions without lookupFactory
Ember.MODEL_FACTORY_INJECTIONS = originalMODEL_FACTORY_INJECTIONS;

run(env.store, 'destroy');
}
});

test('did inject', function(assert) {
let foo = run(() => env.store.createRecord('foo'));
let apple = foo.get('apple');
let Apple = env.registry.registrations['service:apple'];

assert.ok(apple, `'model:foo' instance should have an 'apple' property`);
assert.ok(apple instanceof Apple, `'model:foo'.apple should be an instance of 'service:apple'`);
});
2 changes: 1 addition & 1 deletion tests/unit/model-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var run = Ember.run;

var Person, store, env;

module("unit/model - DS.Model", {
module('unit/model - DS.Model', {
beforeEach() {
Person = DS.Model.extend({
name: DS.attr('string'),
Expand Down

0 comments on commit 0c7ebb8

Please sign in to comment.