Skip to content

Commit

Permalink
Users can deserialize data.
Browse files Browse the repository at this point in the history
  • Loading branch information
SeyZ committed Jan 31, 2016
1 parent 0564cb3 commit df0aadc
Show file tree
Hide file tree
Showing 8 changed files with 696 additions and 32 deletions.
5 changes: 4 additions & 1 deletion index.js
@@ -1 +1,4 @@
module.exports = require('./lib/serializer');
module.exports = {
Serializer: require('./lib/serializer'),
Deserializer: require('./lib/deserializer'),
};
126 changes: 126 additions & 0 deletions lib/deserializer-utils.js
@@ -0,0 +1,126 @@
'use strict';
var P = require('bluebird');
var _ = require('lodash');
var Inflector = require('./inflector');

module.exports = function (jsonapi, data, opts) {
function isComplexType(obj) {
return _.isArray(obj) || _.isPlainObject(obj);
}

function getValueForRelationship(relationshipData, included) {
if (opts && opts[relationshipData.type]) {
var valueForRelationshipFct = opts[relationshipData.type]
.valueForRelationship;

return valueForRelationshipFct(relationshipData, included);
} else {
return included;
}
}

function findIncluded(relationshipData) {
return new P(function (resolve) {
if (!jsonapi.included) { resolve(null); }

var included = _.findWhere(jsonapi.included, {
id: relationshipData.id,
type: relationshipData.type
});

if (included) {
return P
.all([extractAttributes(included), extractRelationships(included)])
.spread(function (attributes, relationships) {
resolve(_.extend(attributes, relationships));
});
} else {
return resolve(null);
}
});
}

function keyForAttribute(attribute) {
if (_.isPlainObject(attribute)) {
return _.transform(attribute, function (result, value, key) {
if (isComplexType(value)) {
result[keyForAttribute(key)] = keyForAttribute(value);
} else {
result[keyForAttribute(key)] = value;
}
});
} else if (_.isArray(attribute)) {
return attribute.map(function (attr) {
if (isComplexType(attr)) {
return keyForAttribute(attr);
} else {
return attr;
}
});
} else {
if (_.isFunction(opts.keyForAttribute)) {
return opts.keyForAttribute(attribute);
} else {
return Inflector.caserize(attribute, opts);
}
}
}

function extractAttributes(from) {
var dest = keyForAttribute(from.attributes);
dest.id = from.id;

return dest;
}

function extractRelationships(from) {
if (!from.relationships) { return; }

var dest = {};

return P
.each(Object.keys(from.relationships), function (key) {
var relationship = from.relationships[key];

if (_.isArray(relationship.data)) {
return P
.map(relationship.data, function (relationshipData) {
return extractIncludes(relationshipData);
})
.then(function (includes) {
if (includes) { dest[key] = includes; }
});
} else {
return extractIncludes(relationship.data)
.then(function (include) {
if (include) { dest[key] = include; }
});
}
})
.thenReturn(dest);
}

function extractIncludes(relationshipData) {
return findIncluded(relationshipData)
.then(function (included) {
var valueForRelationship = getValueForRelationship(relationshipData,
included);

if (valueForRelationship && _.isFunction(valueForRelationship.then)) {
return valueForRelationship.then(function (value) {
return value;
});
} else {
return valueForRelationship;
}
});
}

this.perform = function () {
return P
.all([extractAttributes(data), extractRelationships(data)])
.spread(function (attributes, relationships) {
return _.extend(attributes, relationships);
});
};
};
34 changes: 34 additions & 0 deletions lib/deserializer.js
@@ -0,0 +1,34 @@
'use strict';
var _ = require('lodash');
var P = require('bluebird');
var DeserializerUtils = require('./deserializer-utils');

module.exports = function (opts) {
if (!opts) { opts = {}; }

this.deserialize = function (jsonapi, callback) {
function collection() {
return P
.map(jsonapi.data, function (d) {
return new DeserializerUtils(jsonapi, d, opts).perform();
})
.then(function (result) {
callback(null, result);
});
}

function resource() {
return new DeserializerUtils(jsonapi, jsonapi.data, opts)
.perform()
.then(function (result) {
callback(null, result);
});
}

if (_.isArray(jsonapi.data)) {
return collection();
} else {
return resource();
}
};
};
28 changes: 28 additions & 0 deletions lib/inflector.js
@@ -0,0 +1,28 @@
'use strict';
var Inflector = require('inflected');

module.exports = {
caserize: function (attribute, opts) {
attribute = Inflector.underscore(attribute);

switch (opts.keyForAttribute) {
case 'dash-case':
case 'lisp-case':
case 'spinal-case':
case 'kebab-case':
return Inflector.dasherize(attribute);
case 'underscore_case':
case 'snake_case':
return attribute;
case 'CamelCase':
return Inflector.camelize(attribute);
case 'camelCase':
return Inflector.camelize(attribute, false);
default:
return Inflector.dasherize(attribute);
}
},
pluralize: function (type) {
return Inflector.pluralize(type);
}
};
28 changes: 3 additions & 25 deletions lib/serializer-utils.js
@@ -1,30 +1,8 @@
'use strict';
var _ = require('lodash');
var inflection = require('inflection');
var Inflector = require('./inflector');

module.exports = function (collectionName, record, payload, opts) {

function caserize(attribute) {
var caseMapping = {
'dash-case': inflection.dasherize,
'lisp-case': inflection.dasherize,
'spinal-case': inflection.dasherize,
'kebab-case': inflection.dasherize,
'underscore_case': inflection.underscore,
'snake_case': inflection.underscore,
'CamelCase': inflection.camelize,
'camelCase': _.partialRight( inflection.camelize, true)
};

var attributeCase = opts.keyForAttribute || 'dash-case';

if (_.keys(caseMapping).indexOf(attributeCase) < 0) {
attributeCase = 'dash-case';
}

return caseMapping[attributeCase](inflection.underscore(attribute));
}

function keyForAttribute(attribute) {
if (_.isPlainObject(attribute)) {
return _.transform(attribute, function (result, value, key) {
Expand All @@ -46,7 +24,7 @@ module.exports = function (collectionName, record, payload, opts) {
if (_.isFunction(opts.keyForAttribute)) {
return opts.keyForAttribute(attribute);
} else {
return caserize(attribute);
return Inflector.caserize(attribute, opts);
}
}
}
Expand All @@ -70,7 +48,7 @@ module.exports = function (collectionName, record, payload, opts) {
if (_.isFunction(opts.typeForAttribute)) {
type = opts.typeForAttribute(str, attrVal);
} else if (_.isUndefined(opts.pluralizeType) || opts.pluralizeType) {
type = inflection.pluralize(type);
type = Inflector.pluralize(type);
}

return type;
Expand Down
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -10,7 +10,8 @@
"license": "MIT",
"repository": "SeyZ/jsonapi-serializer",
"dependencies": {
"inflection": "^1.7.1",
"bluebird": "^2.10.2",
"inflected": "^1.1.6",
"lodash": "^3.9.3"
},
"devDependencies": {
Expand Down

0 comments on commit df0aadc

Please sign in to comment.