define('ember-data/serializers/embedded-records-mixin', ['exports'], function (exports) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = Ember.Mixin.create({ /** Normalize the record and recursively normalize/extract all the embedded records while pushing them into the store as they are encountered A payload with an attr configured for embedded records needs to be extracted: ```js { "post": { "id": "1" "title": "Rails is omakase", "comments": [{ "id": "1", "body": "Rails is unagi" }, { "id": "2", "body": "Omakase O_o" }] } } ``` @method normalize @param {DS.Model} typeClass @param {Object} hash to be normalized @param {String} prop the hash has been referenced by @return {Object} the normalized hash **/ normalize: function normalize(typeClass, hash, prop) { var normalizedHash = this._super(typeClass, hash, prop); return this._extractEmbeddedRecords(this, this.store, typeClass, normalizedHash); }, keyForRelationship: function keyForRelationship(key, typeClass, method) { if (method === 'serialize' && this.hasSerializeRecordsOption(key) || method === 'deserialize' && this.hasDeserializeRecordsOption(key)) { return this.keyForAttribute(key, method); } else { return this._super(key, typeClass, method) || key; } }, /** Serialize `belongsTo` relationship when it is configured as an embedded object. This example of an author model belongs to a post model: ```js Post = DS.Model.extend({ title: DS.attr('string'), body: DS.attr('string'), author: DS.belongsTo('author') }); Author = DS.Model.extend({ name: DS.attr('string'), post: DS.belongsTo('post') }); ``` Use a custom (type) serializer for the post model to configure embedded author ```app/serializers/post.js import DS from 'ember-data'; export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { author: { embedded: 'always' } } }) ``` A payload with an attribute configured for embedded records can serialize the records together under the root attribute's payload: ```js { "post": { "id": "1" "title": "Rails is omakase", "author": { "id": "2" "name": "dhh" } } } ``` @method serializeBelongsTo @param {DS.Snapshot} snapshot @param {Object} json @param {Object} relationship */ serializeBelongsTo: function serializeBelongsTo(snapshot, json, relationship) { var attr = relationship.key; if (this.noSerializeOptionSpecified(attr)) { this._super(snapshot, json, relationship); return; } var includeIds = this.hasSerializeIdsOption(attr); var includeRecords = this.hasSerializeRecordsOption(attr); var embeddedSnapshot = snapshot.belongsTo(attr); if (includeIds) { var serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); } if (!embeddedSnapshot) { json[serializedKey] = null; } else { json[serializedKey] = embeddedSnapshot.id; if (relationship.options.polymorphic) { this.serializePolymorphicType(snapshot, json, relationship); } } } else if (includeRecords) { this._serializeEmbeddedBelongsTo(snapshot, json, relationship); } }, _serializeEmbeddedBelongsTo: function _serializeEmbeddedBelongsTo(snapshot, json, relationship) { var embeddedSnapshot = snapshot.belongsTo(relationship.key); var serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); } if (!embeddedSnapshot) { json[serializedKey] = null; } else { json[serializedKey] = embeddedSnapshot.serialize({ includeId: true }); this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, json[serializedKey]); if (relationship.options.polymorphic) { this.serializePolymorphicType(snapshot, json, relationship); } } }, /** Serializes `hasMany` relationships when it is configured as embedded objects. This example of a post model has many comments: ```js Post = DS.Model.extend({ title: DS.attr('string'), body: DS.attr('string'), comments: DS.hasMany('comment') }); Comment = DS.Model.extend({ body: DS.attr('string'), post: DS.belongsTo('post') }); ``` Use a custom (type) serializer for the post model to configure embedded comments ```app/serializers/post.js import DS from 'ember-data; export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { comments: { embedded: 'always' } } }) ``` A payload with an attribute configured for embedded records can serialize the records together under the root attribute's payload: ```js { "post": { "id": "1" "title": "Rails is omakase", "body": "I want this for my ORM, I want that for my template language..." "comments": [{ "id": "1", "body": "Rails is unagi" }, { "id": "2", "body": "Omakase O_o" }] } } ``` The attrs options object can use more specific instruction for extracting and serializing. When serializing, an option to embed `ids`, `ids-and-types` or `records` can be set. When extracting the only option is `records`. So `{ embedded: 'always' }` is shorthand for: `{ serialize: 'records', deserialize: 'records' }` To embed the `ids` for a related object (using a hasMany relationship): ```app/serializers/post.js import DS from 'ember-data; export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { comments: { serialize: 'ids', deserialize: 'records' } } }) ``` ```js { "post": { "id": "1" "title": "Rails is omakase", "body": "I want this for my ORM, I want that for my template language..." "comments": ["1", "2"] } } ``` To embed the relationship as a collection of objects with `id` and `type` keys, set `ids-and-types` for the related object. This is particularly useful for polymorphic relationships where records don't share the same table and the `id` is not enough information. By example having a user that has many pets: ```js User = DS.Model.extend({ name: DS.attr('string'), pets: DS.hasMany('pet', { polymorphic: true }) }); Pet = DS.Model.extend({ name: DS.attr('string'), }); Cat = Pet.extend({ // ... }); Parrot = Pet.extend({ // ... }); ``` ```app/serializers/user.js import DS from 'ember-data; export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { pets: { serialize: 'ids-and-types', deserialize: 'records' } } }); ``` ```js { "user": { "id": "1" "name": "Bertin Osborne", "pets": [ { "id": "1", "type": "Cat" }, { "id": "1", "type": "Parrot"} ] } } ``` @method serializeHasMany @param {DS.Snapshot} snapshot @param {Object} json @param {Object} relationship */ serializeHasMany: function serializeHasMany(snapshot, json, relationship) { var attr = relationship.key; if (this.noSerializeOptionSpecified(attr)) { this._super(snapshot, json, relationship); return; } if (this.hasSerializeIdsOption(attr)) { var serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); } json[serializedKey] = snapshot.hasMany(attr, { ids: true }); } else if (this.hasSerializeRecordsOption(attr)) { this._serializeEmbeddedHasMany(snapshot, json, relationship); } else { if (this.hasSerializeIdsAndTypesOption(attr)) { this._serializeHasManyAsIdsAndTypes(snapshot, json, relationship); } } }, /* Serializes a hasMany relationship as an array of objects containing only `id` and `type` keys. This has its use case on polymorphic hasMany relationships where the server is not storing all records in the same table using STI, and therefore the `id` is not enough information TODO: Make the default in Ember-data 3.0?? */ _serializeHasManyAsIdsAndTypes: function _serializeHasManyAsIdsAndTypes(snapshot, json, relationship) { var serializedKey = this.keyForAttribute(relationship.key, 'serialize'); var hasMany = snapshot.hasMany(relationship.key); json[serializedKey] = Ember.A(hasMany).map(function (recordSnapshot) { // // I'm sure I'm being utterly naive here. Propably id is a configurate property and // type too, and the modelName has to be normalized somehow. // return { id: recordSnapshot.id, type: recordSnapshot.modelName }; }); }, _serializeEmbeddedHasMany: function _serializeEmbeddedHasMany(snapshot, json, relationship) { var serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); } (true && Ember.warn('The embedded relationship \'' + serializedKey + '\' is undefined for \'' + snapshot.modelName + '\' with id \'' + snapshot.id + '\'. Please include it in your original payload.', Ember.typeOf(snapshot.hasMany(relationship.key)) !== 'undefined', { id: 'ds.serializer.embedded-relationship-undefined' })); json[serializedKey] = this._generateSerializedHasMany(snapshot, relationship); }, /* Returns an array of embedded records serialized to JSON */ _generateSerializedHasMany: function _generateSerializedHasMany(snapshot, relationship) { var hasMany = snapshot.hasMany(relationship.key); var manyArray = Ember.A(hasMany); var ret = new Array(manyArray.length); for (var i = 0; i < manyArray.length; i++) { var embeddedSnapshot = manyArray[i]; var embeddedJson = embeddedSnapshot.serialize({ includeId: true }); this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, embeddedJson); ret[i] = embeddedJson; } return ret; }, /** When serializing an embedded record, modify the property (in the json payload) that refers to the parent record (foreign key for relationship). Serializing a `belongsTo` relationship removes the property that refers to the parent record Serializing a `hasMany` relationship does not remove the property that refers to the parent record. @method removeEmbeddedForeignKey @param {DS.Snapshot} snapshot @param {DS.Snapshot} embeddedSnapshot @param {Object} relationship @param {Object} json */ removeEmbeddedForeignKey: function removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, json) { if (relationship.kind === 'belongsTo') { var parentRecord = snapshot.type.inverseFor(relationship.key, this.store); if (parentRecord) { var name = parentRecord.name; var embeddedSerializer = this.store.serializerFor(embeddedSnapshot.modelName); var parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind, 'deserialize'); if (parentKey) { delete json[parentKey]; } } } /*else if (relationship.kind === 'hasMany') { return; }*/ }, // checks config for attrs option to embedded (always) - serialize and deserialize hasEmbeddedAlwaysOption: function hasEmbeddedAlwaysOption(attr) { var option = this.attrsOption(attr); return option && option.embedded === 'always'; }, // checks config for attrs option to serialize ids hasSerializeRecordsOption: function hasSerializeRecordsOption(attr) { var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); var option = this.attrsOption(attr); return alwaysEmbed || option && option.serialize === 'records'; }, // checks config for attrs option to serialize records hasSerializeIdsOption: function hasSerializeIdsOption(attr) { var option = this.attrsOption(attr); return option && (option.serialize === 'ids' || option.serialize === 'id'); }, // checks config for attrs option to serialize records as objects containing id and types hasSerializeIdsAndTypesOption: function hasSerializeIdsAndTypesOption(attr) { var option = this.attrsOption(attr); return option && (option.serialize === 'ids-and-types' || option.serialize === 'id-and-type'); }, // checks config for attrs option to serialize records noSerializeOptionSpecified: function noSerializeOptionSpecified(attr) { var option = this.attrsOption(attr); return !(option && (option.serialize || option.embedded)); }, // checks config for attrs option to deserialize records // a defined option object for a resource is treated the same as // `deserialize: 'records'` hasDeserializeRecordsOption: function hasDeserializeRecordsOption(attr) { var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); var option = this.attrsOption(attr); return alwaysEmbed || option && option.deserialize === 'records'; }, attrsOption: function attrsOption(attr) { var attrs = this.get('attrs'); return attrs && (attrs[Ember.String.camelize(attr)] || attrs[attr]); }, /** @method _extractEmbeddedRecords @private */ _extractEmbeddedRecords: function _extractEmbeddedRecords(serializer, store, typeClass, partial) { var _this = this; typeClass.eachRelationship(function (key, relationship) { if (serializer.hasDeserializeRecordsOption(key)) { if (relationship.kind === "hasMany") { _this._extractEmbeddedHasMany(store, key, partial, relationship); } if (relationship.kind === "belongsTo") { _this._extractEmbeddedBelongsTo(store, key, partial, relationship); } } }); return partial; }, /** @method _extractEmbeddedHasMany @private */ _extractEmbeddedHasMany: function _extractEmbeddedHasMany(store, key, hash, relationshipMeta) { var relationshipHash = Ember.get(hash, 'data.relationships.' + key + '.data'); if (!relationshipHash) { return; } var hasMany = new Array(relationshipHash.length); for (var i = 0; i < relationshipHash.length; i++) { var item = relationshipHash[i]; var _normalizeEmbeddedRel = this._normalizeEmbeddedRelationship(store, relationshipMeta, item), data = _normalizeEmbeddedRel.data, included = _normalizeEmbeddedRel.included; hash.included = hash.included || []; hash.included.push(data); if (included) { var _hash$included; (_hash$included = hash.included).push.apply(_hash$included, included); } hasMany[i] = { id: data.id, type: data.type }; } var relationship = { data: hasMany }; Ember.set(hash, 'data.relationships.' + key, relationship); }, /** @method _extractEmbeddedBelongsTo @private */ _extractEmbeddedBelongsTo: function _extractEmbeddedBelongsTo(store, key, hash, relationshipMeta) { var relationshipHash = Ember.get(hash, 'data.relationships.' + key + '.data'); if (!relationshipHash) { return; } var _normalizeEmbeddedRel2 = this._normalizeEmbeddedRelationship(store, relationshipMeta, relationshipHash), data = _normalizeEmbeddedRel2.data, included = _normalizeEmbeddedRel2.included; hash.included = hash.included || []; hash.included.push(data); if (included) { var _hash$included2; (_hash$included2 = hash.included).push.apply(_hash$included2, included); } var belongsTo = { id: data.id, type: data.type }; var relationship = { data: belongsTo }; Ember.set(hash, 'data.relationships.' + key, relationship); }, /** @method _normalizeEmbeddedRelationship @private */ _normalizeEmbeddedRelationship: function _normalizeEmbeddedRelationship(store, relationshipMeta, relationshipHash) { var modelName = relationshipMeta.type; if (relationshipMeta.options.polymorphic) { modelName = relationshipHash.type; } var modelClass = store.modelFor(modelName); var serializer = store.serializerFor(modelName); return serializer.normalize(modelClass, relationshipHash, null); }, isEmbeddedRecordsMixin: true }); });