Skip to content

Commit

Permalink
First pass on ad-hoc serializers
Browse files Browse the repository at this point in the history
  • Loading branch information
begedin authored and samselikoff committed Jun 18, 2016
1 parent 8162b96 commit 203aaee
Show file tree
Hide file tree
Showing 6 changed files with 345 additions and 156 deletions.
113 changes: 80 additions & 33 deletions addon/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import extend from './utils/extend';
import { singularize, pluralize, camelize } from './utils/inflector';

import _isFunction from 'lodash/lang/isFunction';
import _ from 'lodash';

class Serializer {

Expand Down Expand Up @@ -39,12 +40,7 @@ class Serializer {
if (this.isModel(response)) {
json = this._serializeModel(response, request);
} else {
json = response.models.reduce((allAttrs, model) => {
allAttrs.push(this._serializeModel(model));
this._resetAlreadySerialized();

return allAttrs;
}, []);
json = this._serializeCollection(response, request);
}

return this._formatResponse(response, json);
Expand Down Expand Up @@ -235,6 +231,21 @@ class Serializer {
return _assign(attrs, relatedAttrs);
}

/**
* @method _serializeCollection
* @param collection
* @param request
* @private
*/
_serializeCollection(collection, request, removeForeignKeys, serializeRelationships) {
return collection.models.reduce((allAttrs, model) => {
allAttrs.push(this._serializeModel(model, request, removeForeignKeys, serializeRelationships));
this._resetAlreadySerialized();

return allAttrs;
}, []);
}

/**
* @method _oldAttrsForModel
* @param model
Expand Down Expand Up @@ -288,11 +299,11 @@ class Serializer {
*/
_serializeSideloadedModelOrCollection(modelOrCollection, request) {
if (this.isModel(modelOrCollection)) {
return this._serializeSideloadedModelResponse(modelOrCollection, request);
return this._serializeIncludedModel(modelOrCollection, request);
} else if (modelOrCollection.models && modelOrCollection.models.length) {

return modelOrCollection.models.reduce((allAttrs, model) => {
return this._serializeSideloadedModelResponse(model, request, true, allAttrs);
return this._serializeIncludedModel(model, request, true, allAttrs);
}, {});

// We have an empty collection
Expand All @@ -302,15 +313,38 @@ class Serializer {
}

/**
* @method _serializeSideloadedModelResponse
* @method _serializeRelationshipsFor
* @param model
* @param request
* @private
*/
_serializeRelationshipsFor(model, request, topLevelIsArray = false, allAttrs = {}, root = null) {
let relationshipNames = this._getRelationshipNames(request);

relationshipNames
.map((relationshipName) => this._getRelated(model, relationshipName))
.filter(Boolean)
.forEach(relationship => {
let relatedModels = this.isModel(relationship) ? [relationship] : relationship;

relatedModels.forEach(relatedModel => {
let serializer = this.serializerFor(relatedModel.modelName);
let relationshipKey = serializer.keyForRelationship(relatedModel.modelName);
serializer._serializeIncludedModel(relatedModel, request, true, allAttrs, relationshipKey);
});
});
}

/**
* @method _serializeIncludedModel
* @param model
* @param request
* @param [topLevelIsArray=false]
* @param allAttrs
* @param [root=null]
* @private
*/
_serializeSideloadedModelResponse(model, request, topLevelIsArray = false, allAttrs = {}, root = null) {
_serializeIncludedModel(model, request, topLevelIsArray = false, allAttrs = {}, root = null) {
if (this._hasBeenSerialized(model)) {
return allAttrs;
}
Expand All @@ -328,18 +362,7 @@ class Serializer {
allAttrs[key] = modelAttrs;
}

// Traverse this model's relationships
this._valueForInclude(this, request)
.map(key => model[camelize(key)])
.filter(Boolean)
.forEach(relationship => {
let relatedModels = this.isModel(relationship) ? [relationship] : relationship.models;

relatedModels.forEach(relatedModel => {
let serializer = this.serializerFor(relatedModel.modelName);
serializer._serializeSideloadedModelResponse(relatedModel, request, true, allAttrs, serializer.keyForRelationship(relatedModel.modelName));
});
});
this._serializeRelationshipsFor(model, request, topLevelIsArray, allAttrs, root);

return allAttrs;
}
Expand Down Expand Up @@ -387,14 +410,14 @@ class Serializer {
let attrs = this.oldSerialize(model, request);

if (removeForeignKeys) {
model.fks.forEach(key => {
model.fks.map(this._serializeForeignKey).forEach(key => {
delete attrs[key];
});
}

if (embedRelatedIds) {
this._valueForInclude(this, request)
.map(key => model[camelize(key)])
this._getRelationshipNames(request)
.map((key) => this._getRelatedValue(model, key))
.filter(this.isCollection)
.forEach(relatedCollection => {
attrs[this.keyForRelationshipIds(relatedCollection.modelName)] = relatedCollection.models.map(model => model.id);
Expand All @@ -404,14 +427,18 @@ class Serializer {
return attrs;
}

_serializeForeignKey(key) {
return key;
}

/**
* @method _attrsForRelationships
* @param model
* @param request
* @private
*/
_attrsForRelationships(model, request) {
return this._valueForInclude(this, request)
return this._getRelationshipNames(request)
.reduce((attrs, key) => {
let modelOrCollection = model[camelize(key)];
let serializer = this.serializerFor(modelOrCollection.modelName);
Expand All @@ -435,9 +462,9 @@ class Serializer {
* @private
*/
_hasBeenSerialized(model) {
let relationshipKey = `${camelize(model.modelName)}Ids`;

return (this.alreadySerialized[relationshipKey] && this.alreadySerialized[relationshipKey].indexOf(model.id) > -1);
let relationshipKey = this.keyForRelationshipIds(model.modelName);
let obj = this.alreadySerialized[relationshipKey];
return obj && obj.indexOf(model.id) > -1;
}

/**
Expand All @@ -446,7 +473,7 @@ class Serializer {
* @private
*/
_augmentAlreadySerialized(model) {
let modelKey = `${camelize(model.modelName)}Ids`;
let modelKey = this.keyForRelationshipIds(model.modelName);

this.alreadySerialized[modelKey] = this.alreadySerialized[modelKey] || [];
this.alreadySerialized[modelKey].push(model.id);
Expand All @@ -468,20 +495,40 @@ class Serializer {
}

/**
* @method _valueForInclude
* @method _getRelationshipNames
* @param serializer
* @param request
* @private
*/
_valueForInclude(serializer, request) {
let { include } = serializer;
_getRelationshipNames(request) {
let { include } = this;

if (_isFunction(include)) {
return include(request);
} else {
return include;
}
}

_getRelated(parentModel, path) {
return path.split('.').reduce((related, relationshipName) => {
return _(related)
.map(r => this._getRelatedValue(r.reload(), relationshipName))
.map(r => this.isCollection(r) ? r.models : r) // Turning Collections into Arrays for lodash to recognize
.flatten()
.filter()
.value();
}, [parentModel]);
}

_getRelatedValue(model, key) {
let camelizedKey = camelize(key);
if (_isFunction(this[camelizedKey])) {
return this[camelizedKey](model);
} else {
return model[camelizedKey];
}
}
}

// Defaults
Expand Down
4 changes: 2 additions & 2 deletions addon/serializers/active-model-serializer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// jscs:disable requireArrayDestructuring, requireParenthesesAroundArrowParam
import Serializer from '../serializer';
import { underscore, pluralize, dasherize } from '../utils/inflector';
import { underscore, pluralize, dasherize, singularize } from '../utils/inflector';

export default Serializer.extend({

Expand All @@ -17,7 +17,7 @@ export default Serializer.extend({
},

keyForRelationshipIds(type) {
return `${underscore(type)}_ids`;
return `${underscore(singularize(type))}_ids`;
},

normalize(payload) {
Expand Down
Loading

0 comments on commit 203aaee

Please sign in to comment.