Skip to content

Commit

Permalink
Added support for dot-paths to JsonApiSerializer include feature
Browse files Browse the repository at this point in the history
  • Loading branch information
lolmaus committed Dec 15, 2015
1 parent 9cde7c5 commit 1d4295e
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 60 deletions.
2 changes: 2 additions & 0 deletions addon/orm/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ class Model {
.forEach(function(attr) {
_this[attr] = attrs[attr];
});

return this;
}


Expand Down
40 changes: 31 additions & 9 deletions addon/serializers/json-api-serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import Model from 'ember-cli-mirage/orm/model';
import Collection from 'ember-cli-mirage/orm/collection';
import _assign from 'lodash/object/assign';
import _get from 'lodash/object/get';
import _compose from 'lodash/function/compose';
import _trim from 'lodash/string/trim';
import _isString from 'lodash/lang/isString';
import _ from 'lodash';




class JsonApiSerializer {

Expand Down Expand Up @@ -58,7 +62,7 @@ class JsonApiSerializer {
_serializeRelationshipsFor(model, request) {
let serializer = this._serializerFor(model);

const relationships = this._combineRelationships(serializer, request);
const relationships = this._getRelationships(serializer, request);

relationships.forEach(type => {
let relationship = model[camelize(type)];
Expand Down Expand Up @@ -125,7 +129,7 @@ class JsonApiSerializer {
}

typeKeyForModel(model) {
return _compose(pluralize, dasherize)(model.type);
return dasherize(pluralize(model.type));
}

normalize(json) {
Expand Down Expand Up @@ -200,17 +204,35 @@ class JsonApiSerializer {
this.alreadySerialized[modelKey].push(model.id);
}

_combineRelationships(serializer = {}, request = {}) {
const serializerRelationships = _get(serializer, 'include', []);
let requestRelationships = _get(request, 'queryParams.include', []);
_getRelationships(serializer = {}, request = {}) {
const requestRelationships = _get(request, 'queryParams.include');

if (requestRelationships.length) {
requestRelationships = requestRelationships.split(',').map(_trim);
if (_isString(requestRelationships)) {
if(requestRelationships.length) {
return requestRelationships.split(',').map(_trim);
}
return [];
}

return [...serializerRelationships, ...requestRelationships];
return _get(serializer, 'include', []);
}

_getRelatedWithPath(parentModel, path) {
const relationships = path.split('.');
let currentModels = [parentModel];

relationships.forEach(relationship => {
currentModels =
_(currentModels)
.map(r => r.reload()[relationship])
.map(r => r instanceof Array ? [...r] : r) // Turning Collections into Arrays for lodash to recognize
.flatten()
.filter(r => r)
.value();
});

return currentModels;
}
}

// Defaults
Expand Down
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"ember-qunit-notifications": "0.0.7",
"qunit": "~1.18.0",
"pretender": "~0.9.0",
"Faker": "~3.0.0"
"Faker": "~3.0.0",
"sinonjs": "~1.17.1"
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"ember-disable-prototype-extensions": "^1.0.0",
"ember-disable-proxy-controllers": "^1.0.0",
"ember-export-application-global": "^1.0.3",
"ember-sinon": "0.3.0",
"ember-try": "0.0.6",
"mocha": "^2.1.0"
},
Expand Down
85 changes: 85 additions & 0 deletions tests/dummy/app/initializers/es2015-polyfills.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
export function initialize(/* container, application */) {
// Production steps of ECMA-262, Edition 6, 22.1.2.1
// Reference: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from
if (!Array.from) {
Array.from = (function () {
var toStr = Object.prototype.toString;
var isCallable = function (fn) {
return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
};
var toInteger = function (value) {
var number = Number(value);
if (isNaN(number)) { return 0; }
if (number === 0 || !isFinite(number)) { return number; }
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
};
var maxSafeInteger = Math.pow(2, 53) - 1;
var toLength = function (value) {
var len = toInteger(value);
return Math.min(Math.max(len, 0), maxSafeInteger);
};

// The length property of the from method is 1.
return function from(arrayLike/*, mapFn, thisArg */) {
// 1. Let C be the this value.
var C = this;

// 2. Let items be ToObject(arrayLike).
var items = Object(arrayLike);

// 3. ReturnIfAbrupt(items).
if (arrayLike == null) {
throw new TypeError("Array.from requires an array-like object - not null or undefined");
}

// 4. If mapfn is undefined, then let mapping be false.
var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
var T;
if (typeof mapFn !== 'undefined') {
// 5. else
// 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
if (!isCallable(mapFn)) {
throw new TypeError('Array.from: when provided, the second argument must be a function');
}

// 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 2) {
T = arguments[2];
}
}

// 10. Let lenValue be Get(items, "length").
// 11. Let len be ToLength(lenValue).
var len = toLength(items.length);

// 13. If IsConstructor(C) is true, then
// 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
// 14. a. Else, Let A be ArrayCreate(len).
var A = isCallable(C) ? Object(new C(len)) : new Array(len);

// 16. Let k be 0.
var k = 0;
// 17. Repeat, while k < len… (also steps a - h)
var kValue;
while (k < len) {
kValue = items[k];
if (mapFn) {
A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
} else {
A[k] = kValue;
}
k += 1;
}
// 18. Let putStatus be Put(A, "length", len, true).
A.length = len;
// 20. Return A.
return A;
};
}());
}
}

export default {
name: 'es2015-polyfills',
initialize: initialize
};
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ test(`model: it can include relationships specified by the include query param`,
});
});

test(`model: it can include relationships specified by a combination of the include query param (hasMany) and serializer.relationships (belongsTo)`, function(assert) {
test(`model: it can include relationships specified by a combination of the include query param (hasMany) and serializer.relationships (belongsTo, ignored)`, function(assert) {
const registry = new SerializerRegistry(this.schema, {
application: JsonApiSerializer,
blogPost: JsonApiSerializer.extend({
Expand Down Expand Up @@ -119,18 +119,6 @@ test(`model: it can include relationships specified by a combination of the incl
}
},
included: [
{
type: 'word-smiths',
id: 1,
attributes: {},
relationships: {
'blog-posts': {
data: [
{type: 'blog-posts', id: 1}
]
}
}
},
{
type: 'fine-comments',
id: 1,
Expand All @@ -156,7 +144,7 @@ test(`model: it can include relationships specified by a combination of the incl
});


test(`model: it can include relationships specified by a combination of the include query param (belongsTo) and serializer.relationships (hasMany)`, function(assert) {
test(`model: it can include relationships specified by a combination of the include query param (belongsTo) and serializer.relationships (hasMany, ignored)`, function(assert) {
const registry = new SerializerRegistry(this.schema, {
application: JsonApiSerializer,
blogPost: JsonApiSerializer.extend({
Expand Down Expand Up @@ -190,26 +178,6 @@ test(`model: it can include relationships specified by a combination of the incl
}
},
included: [
{
type: 'fine-comments',
id: 1,
attributes: {},
relationships: {
'blog-post': {
data: {type: 'blog-posts', id: 1}
}
}
},
{
type: 'fine-comments',
id: 2,
attributes: {},
relationships: {
'blog-post': {
data: {type: 'blog-posts', id: 1}
}
}
},
{
type: 'word-smiths',
id: 1,
Expand Down
19 changes: 18 additions & 1 deletion tests/integration/serializers/schema-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,24 @@ export default {
fineComment: Model.extend({
blogPost: Mirage.belongsTo()
}),
greatPhoto: Model
greatPhoto: Model,

foo: Model.extend({
bar: Mirage.belongsTo()
}),
bar: Model.extend({
baz: Mirage.belongsTo()
}),
baz: Model.extend({
quuxes: Mirage.hasMany()
}),
quux: Model.extend({
zomgs: Mirage.hasMany()
}),
zomg: Model.extend({
lol: Mirage.belongsTo()
}),
lol: Model
});

return this.schema;
Expand Down
Loading

0 comments on commit 1d4295e

Please sign in to comment.