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

[BUGFIX release] Refactor Model.reopen to use mixins #4091

Merged
merged 1 commit into from
Jan 18, 2016
Merged
Show file tree
Hide file tree
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
1 change: 0 additions & 1 deletion addon/-private/system/debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
@module ember-data
*/

import "ember-data/-private/system/debug/debug-info";
import DebugAdapter from "ember-data/-private/system/debug/debug-adapter";

export default DebugAdapter;
6 changes: 2 additions & 4 deletions addon/-private/system/debug/debug-info.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Model from "ember-data/model";
import Ember from "ember";

Model.reopen({
export default Ember.Mixin.create({

/**
Provides info about the model for debugging purposes
Expand Down Expand Up @@ -63,5 +63,3 @@ Model.reopen({
};
}
});

export default Model;
226 changes: 226 additions & 0 deletions addon/-private/system/model/attr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
import Ember from 'ember';
import { assert } from "ember-data/-private/debug";


var get = Ember.get;
var Map = Ember.Map;

/**
@module ember-data
*/

/**
@class Model
@namespace DS
*/

export const AttrClassMethodsMixin = Ember.Mixin.create({
/**
A map whose keys are the attributes of the model (properties
described by DS.attr) and whose values are the meta object for the
property.

Example

```app/models/person.js
import DS from 'ember-data';

export default DS.Model.extend({
firstName: attr('string'),
lastName: attr('string'),
birthday: attr('date')
});
```

```javascript
import Ember from 'ember';
import Person from 'app/models/person';

var attributes = Ember.get(Person, 'attributes')

attributes.forEach(function(meta, name) {
console.log(name, meta);
});

// prints:
// firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"}
// lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"}
// birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"}
```

@property attributes
@static
@type {Ember.Map}
@readOnly
*/
attributes: Ember.computed(function() {
var map = Map.create();

this.eachComputedProperty((name, meta) => {
if (meta.isAttribute) {
assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('<type>')` from " + this.toString(), name !== 'id');

meta.name = name;
map.set(name, meta);
}
});

return map;
}).readOnly(),

/**
A map whose keys are the attributes of the model (properties
described by DS.attr) and whose values are type of transformation
applied to each attribute. This map does not include any
attributes that do not have an transformation type.

Example

```app/models/person.js
import DS from 'ember-data';

export default DS.Model.extend({
firstName: attr(),
lastName: attr('string'),
birthday: attr('date')
});
```

```javascript
import Ember from 'ember';
import Person from 'app/models/person';

var transformedAttributes = Ember.get(Person, 'transformedAttributes')

transformedAttributes.forEach(function(field, type) {
console.log(field, type);
});

// prints:
// lastName string
// birthday date
```

@property transformedAttributes
@static
@type {Ember.Map}
@readOnly
*/
transformedAttributes: Ember.computed(function() {
var map = Map.create();

this.eachAttribute((key, meta) => {
if (meta.type) {
map.set(key, meta.type);
}
});

return map;
}).readOnly(),

/**
Iterates through the attributes of the model, calling the passed function on each
attribute.

The callback method you provide should have the following signature (all
parameters are optional):

```javascript
function(name, meta);
```

- `name` the name of the current property in the iteration
- `meta` the meta object for the attribute property in the iteration

Note that in addition to a callback, you can also pass an optional target
object that will be set as `this` on the context.

Example

```javascript
import DS from 'ember-data';

var Person = DS.Model.extend({
firstName: attr('string'),
lastName: attr('string'),
birthday: attr('date')
});

Person.eachAttribute(function(name, meta) {
console.log(name, meta);
});

// prints:
// firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"}
// lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"}
// birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"}
```

@method eachAttribute
@param {Function} callback The callback to execute
@param {Object} [binding] the value to which the callback's `this` should be bound
@static
*/
eachAttribute(callback, binding) {
get(this, 'attributes').forEach((meta, name) => {
callback.call(binding, name, meta);
});
},

/**
Iterates through the transformedAttributes of the model, calling
the passed function on each attribute. Note the callback will not be
called for any attributes that do not have an transformation type.

The callback method you provide should have the following signature (all
parameters are optional):

```javascript
function(name, type);
```

- `name` the name of the current property in the iteration
- `type` a string containing the name of the type of transformed
applied to the attribute

Note that in addition to a callback, you can also pass an optional target
object that will be set as `this` on the context.

Example

```javascript
import DS from 'ember-data';

var Person = DS.Model.extend({
firstName: attr(),
lastName: attr('string'),
birthday: attr('date')
});

Person.eachTransformedAttribute(function(name, type) {
console.log(name, type);
});

// prints:
// lastName string
// birthday date
```

@method eachTransformedAttribute
@param {Function} callback The callback to execute
@param {Object} [binding] the value to which the callback's `this` should be bound
@static
*/
eachTransformedAttribute(callback, binding) {
get(this, 'transformedAttributes').forEach((type, name) => {
callback.call(binding, name, type);
});
}
});


export const AttrInstanceMethodsMixin = Ember.Mixin.create({
eachAttribute(callback, binding) {
this.constructor.eachAttribute(callback, binding);
}
});
16 changes: 15 additions & 1 deletion addon/-private/system/model/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { assert, deprecate } from "ember-data/-private/debug";
import { PromiseObject } from "ember-data/-private/system/promise-proxies";
import Errors from "ember-data/-private/system/model/errors";
import isEnabled from 'ember-data/-private/features';
import DebuggerInfoMixin from 'ember-data/-private/system/debug/debug-info';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess with that, this line in addon/-private/system/debug.js can be removed then: the Model is imported in addon/-private/system/debug/debug-adapter.js...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the linked line from system/debug.js.

import { BelongsToMixin } from 'ember-data/-private/system/relationships/belongs-to';
import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many';
import { DidDefinePropertyMixin, RelationshipsClassMethodsMixin, RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext';
import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr';

/**
@module ember-data
Expand Down Expand Up @@ -972,4 +977,13 @@ if (isEnabled("ds-references")) {

}

export default Model;
Model.reopenClass(RelationshipsClassMethodsMixin);
Model.reopenClass(AttrClassMethodsMixin);

export default Model.extend(
DebuggerInfoMixin,
BelongsToMixin,
DidDefinePropertyMixin,
RelationshipsInstanceMethodsMixin,
HasManyMixin,
AttrInstanceMethodsMixin);
3 changes: 1 addition & 2 deletions addon/-private/system/relationships/belongs-to.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Ember from 'ember';
import { assert, warn } from "ember-data/-private/debug";
import Model from 'ember-data/model';
import normalizeModelName from "ember-data/-private/system/normalize-model-name";

/**
Expand Down Expand Up @@ -138,7 +137,7 @@ export default function belongsTo(modelName, options) {
These observers observe all `belongsTo` relationships on the record. See
`relationships/ext` to see how these observers get their dependencies.
*/
Model.reopen({
export const BelongsToMixin = Ember.Mixin.create({
notifyBelongsToChanged(key) {
this.notifyPropertyChange(key);
}
Expand Down
7 changes: 3 additions & 4 deletions addon/-private/system/relationships/ext.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
typeForRelationshipMeta,
relationshipFromMeta
} from "ember-data/-private/system/relationship-meta";
import Model from "ember-data/model";
import EmptyObject from "ember-data/-private/system/empty-object";

var get = Ember.get;
Expand Down Expand Up @@ -98,7 +97,7 @@ var relationshipsByNameDescriptor = Ember.computed(function() {
@class Model
@namespace DS
*/
Model.reopen({
export const DidDefinePropertyMixin = Ember.Mixin.create({

/**
This Ember.js hook allows an object to be notified when a property
Expand Down Expand Up @@ -157,7 +156,7 @@ Model.reopen({
extensively.
*/

Model.reopenClass({
export const RelationshipsClassMethodsMixin = Ember.Mixin.create({

/**
For a given relationship name, returns the model type of the relationship.
Expand Down Expand Up @@ -599,7 +598,7 @@ Model.reopenClass({

});

Model.reopen({
export const RelationshipsInstanceMethodsMixin = Ember.Mixin.create({
/**
Given a callback, iterates over each of the relationships in the model,
invoking the callback with the name of each relationship and its relationship
Expand Down
2 changes: 1 addition & 1 deletion addon/-private/system/relationships/has-many.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export default function hasMany(type, options) {
}).meta(meta);
}

Model.reopen({
export const HasManyMixin = Ember.Mixin.create({
notifyHasManyAdded(key) {
//We need to notifyPropertyChange in the adding case because we need to make sure
//we fetch the newly added record in case it is unloaded
Expand Down
Loading