Skip to content

Commit

Permalink
Make EmbeddedRecordsMixin work with the new Serializer API
Browse files Browse the repository at this point in the history
  • Loading branch information
wecc committed Jun 5, 2015
1 parent 009fbda commit a02a530
Show file tree
Hide file tree
Showing 2 changed files with 1,397 additions and 69 deletions.
266 changes: 197 additions & 69 deletions packages/ember-data/lib/serializers/embedded-records-mixin.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
var get = Ember.get;
var set = Ember.set;
var forEach = Ember.EnumerableUtils.forEach;
var camelize = Ember.String.camelize;

Expand Down Expand Up @@ -121,8 +123,13 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({
@return {Object} the normalized hash
**/
normalize: function(typeClass, hash, prop) {
if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) {
let normalizedHash = this._super(...arguments);
return _newNormalize.call(this, typeClass, normalizedHash, prop);
}

var normalizedHash = this._super(typeClass, hash, prop);
return extractEmbeddedRecords(this, this.store, typeClass, normalizedHash);
return this._extractEmbeddedRecords(this, this.store, typeClass, normalizedHash);
},

keyForRelationship: function(key, typeClass, method) {
Expand Down Expand Up @@ -393,107 +400,228 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({
attrsOption: function(attr) {
var attrs = this.get('attrs');
return attrs && (attrs[camelize(attr)] || attrs[attr]);
}
});
},

// chooses a relationship kind to branch which function is used to update payload
// does not change payload if attr is not embedded
function extractEmbeddedRecords(serializer, store, typeClass, partial) {
/**
@method _extractEmbeddedRecords
@private
*/
_extractEmbeddedRecords: function(serializer, store, typeClass, partial) {
if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) {
return _newExtractEmbeddedRecords.apply(this, arguments);
}

typeClass.eachRelationship(function(key, relationship) {
if (serializer.hasDeserializeRecordsOption(key)) {
var embeddedTypeClass = store.modelFor(relationship.type);
if (relationship.kind === "hasMany") {
if (relationship.options.polymorphic) {
extractEmbeddedHasManyPolymorphic(store, key, partial);
} else {
extractEmbeddedHasMany(store, key, embeddedTypeClass, partial);
typeClass.eachRelationship(function(key, relationship) {
if (serializer.hasDeserializeRecordsOption(key)) {
var embeddedTypeClass = store.modelFor(relationship.type);
if (relationship.kind === "hasMany") {
if (relationship.options.polymorphic) {
this._extractEmbeddedHasManyPolymorphic(store, key, partial);
} else {
this._extractEmbeddedHasMany(store, key, embeddedTypeClass, partial);
}
}
}
if (relationship.kind === "belongsTo") {
if (relationship.options.polymorphic) {
extractEmbeddedBelongsToPolymorphic(store, key, partial);
} else {
extractEmbeddedBelongsTo(store, key, embeddedTypeClass, partial);
if (relationship.kind === "belongsTo") {
if (relationship.options.polymorphic) {
this._extractEmbeddedBelongsToPolymorphic(store, key, partial);
} else {
this._extractEmbeddedBelongsTo(store, key, embeddedTypeClass, partial);
}
}
}
}, this);

return partial;
},

/**
@method _extractEmbeddedHasMany
@private
*/
_extractEmbeddedHasMany: function(store, key, embeddedTypeClass, hash) {
if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) {
return _newExtractEmbeddedHasMany.apply(this, arguments);
}
});

return partial;
}
if (!hash[key]) {
return hash;
}

var ids = [];

// handles embedding for `hasMany` relationship
function extractEmbeddedHasMany(store, key, embeddedTypeClass, hash) {
if (!hash[key]) {
var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName);
forEach(hash[key], function(data) {
var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null);
store.push(embeddedTypeClass.modelName, embeddedRecord);
ids.push(embeddedRecord.id);
});

hash[key] = ids;
return hash;
}
},

var ids = [];
/**
@method _extractEmbeddedHasManyPolymorphic
@private
*/
_extractEmbeddedHasManyPolymorphic: function(store, key, hash) {
if (!hash[key]) {
return hash;
}

var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName);
forEach(hash[key], function(data) {
var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null);
store.push(embeddedTypeClass.modelName, embeddedRecord);
ids.push(embeddedRecord.id);
});
var ids = [];

hash[key] = ids;
return hash;
}
forEach(hash[key], function(data) {
var modelName = data.type;
var embeddedSerializer = store.serializerFor(modelName);
var embeddedTypeClass = store.modelFor(modelName);
// var primaryKey = embeddedSerializer.get('primaryKey');

function extractEmbeddedHasManyPolymorphic(store, key, hash) {
if (!hash[key]) {
var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null);
store.push(embeddedTypeClass.modelName, embeddedRecord);
ids.push({ id: embeddedRecord.id, type: modelName });
});

hash[key] = ids;
return hash;
}
},

/**
@method _extractEmbeddedBelongsTo
@private
*/
_extractEmbeddedBelongsTo: function(store, key, embeddedTypeClass, hash) {
if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) {
return _newExtractEmbeddedBelongsTo.apply(this, arguments);
}

if (!hash[key]) {
return hash;
}

var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName);
var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, hash[key], null);
store.push(embeddedTypeClass.modelName, embeddedRecord);

var ids = [];
hash[key] = embeddedRecord.id;
//TODO Need to add a reference to the parent later so relationship works between both `belongsTo` records
return hash;
},

forEach(hash[key], function(data) {
/**
@method _extractEmbeddedBelongsToPolymorphic
@private
*/
_extractEmbeddedBelongsToPolymorphic: function(store, key, hash) {
if (!hash[key]) {
return hash;
}

var data = hash[key];
var modelName = data.type;
var embeddedSerializer = store.serializerFor(modelName);
var embeddedTypeClass = store.modelFor(modelName);
// var primaryKey = embeddedSerializer.get('primaryKey');

var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null);
store.push(embeddedTypeClass.modelName, embeddedRecord);
ids.push({ id: embeddedRecord.id, type: modelName });
});

hash[key] = ids;
return hash;
}

function extractEmbeddedBelongsTo(store, key, embeddedTypeClass, hash) {
if (!hash[key]) {
hash[key] = embeddedRecord.id;
hash[key + 'Type'] = modelName;
return hash;
},

/**
@method _normalizeEmbeddedRelationship
@private
*/
_normalizeEmbeddedRelationship: function(store, relationshipMeta, relationshipHash) {
let modelName = relationshipMeta.type;
if (relationshipMeta.options.polymorphic) {
modelName = relationshipHash.type;
}
let modelClass = store.modelFor(modelName);
let serializer = store.serializerFor(modelName);

return serializer.normalize(modelClass, relationshipHash, null);
}

var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName);
var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, hash[key], null);
store.push(embeddedTypeClass.modelName, embeddedRecord);
});

hash[key] = embeddedRecord.id;
//TODO Need to add a reference to the parent later so relationship works between both `belongsTo` records
return hash;
export default EmbeddedRecordsMixin;

/**
This is only to be used temporarily during the transition from the old
serializer API to the new one.
@method _newNormalize
@param {DS.Model} modelClass
@param {Object} hash
@return {Object}
@private
*/
function _newNormalize(typeClass, hash, prop) {
return this._extractEmbeddedRecords(this, this.store, typeClass, hash);
}

function extractEmbeddedBelongsToPolymorphic(store, key, hash) {
if (!hash[key]) {
return hash;
/**
@method _newExtractEmbeddedRecords
@private
*/
function _newExtractEmbeddedRecords(serializer, store, typeClass, partial) {
typeClass.eachRelationship((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);
}
}
}, this);
return partial;
}

/**
@method _newExtractEmbeddedHasMany
@private
*/
function _newExtractEmbeddedHasMany(store, key, hash, relationshipMeta) {
let relationshipHash = get(hash, `data.relationships.${key}.data`);
if (!relationshipHash) {
return;
}

var data = hash[key];
var modelName = data.type;
var embeddedSerializer = store.serializerFor(modelName);
var embeddedTypeClass = store.modelFor(modelName);
let hasMany = relationshipHash.map(item => {
let { data, included } = this._normalizeEmbeddedRelationship(store, relationshipMeta, item);
hash.included = hash.included || [];
hash.included.push(data);
hash.included.push(...included);

var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null);
store.push(embeddedTypeClass.modelName, embeddedRecord);
return { id: data.id, type: data.type };
});

hash[key] = embeddedRecord.id;
hash[key + 'Type'] = modelName;
return hash;
let relationship = { data: hasMany };
set(hash, `data.relationships.${key}`, relationship);
}

export default EmbeddedRecordsMixin;
/**
@method _newExtractEmbeddedBelongsTo
@private
*/
function _newExtractEmbeddedBelongsTo(store, key, hash, relationshipMeta) {
let relationshipHash = get(hash, `data.relationships.${key}.data`);
if (!relationshipHash) {
return;
}

let { data, included } = this._normalizeEmbeddedRelationship(store, relationshipMeta, relationshipHash);
hash.included = hash.included || [];
hash.included.push(data);
hash.included.push(...included);

let belongsTo = { id: data.id, type: data.type };
let relationship = { data: belongsTo };

set(hash, `data.relationships.${key}`, relationship);
}
Loading

0 comments on commit a02a530

Please sign in to comment.