Skip to content

Commit

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

return this;
}


Expand Down
45 changes: 36 additions & 9 deletions addon/serializers/json-api-serializer.js
@@ -1,11 +1,21 @@
import extend from '../utils/extend';
import { dasherize, pluralize, camelize } from '../utils/inflector';
import pipe from '../utils/pipe';
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 _curryRight from 'lodash/function/curryRight';
import _trim from 'lodash/string/trim';
import _flatten from 'lodash/array/flatten';
import _map from 'lodash/collection/map';
import _filter from 'lodash/collection/filter';
import _isString from 'lodash/lang/isString';


const _mapCR = _curryRight(_map)(null);
const _filterCR = _curryRight(_filter)(null);


class JsonApiSerializer {

Expand Down Expand Up @@ -58,7 +68,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 +135,7 @@ class JsonApiSerializer {
}

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

normalize(json) {
Expand Down Expand Up @@ -200,17 +210,34 @@ 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 =
pipe(currentModels)(
_mapCR(r => r.reload()[relationship]),
_mapCR(r => r instanceof Array ? Array.from(r) : r), // Turning Collections into Arrays for lodash to recognize
_flatten,
_filterCR(r => r)
);
});

return currentModels;
}
}

// Defaults
Expand Down
7 changes: 7 additions & 0 deletions addon/utils/pipe.js
@@ -0,0 +1,7 @@
import _flow from 'lodash/function/flow';

export default function pipe (...args) {
return (...methods) => {
return _flow(...methods)(...args);
};
}
3 changes: 2 additions & 1 deletion bower.json
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
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
19 changes: 18 additions & 1 deletion tests/integration/serializers/schema-helper.js
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
70 changes: 55 additions & 15 deletions tests/unit/serializers/json-api-serializer-test.js
@@ -1,4 +1,7 @@
import JsonApiSerializer from 'ember-cli-mirage/serializers/json-api-serializer';
import schemaHelper from '../../integration/serializers/schema-helper';
import _map from 'lodash/collection/map';
import _includes from 'lodash/collection/includes';

import {module, test} from 'qunit';

Expand All @@ -8,7 +11,7 @@ module('Unit | Serializers | JsonApiSerializer', {
}
});

test('_combineRelationships should combine relationships from serializer and request', function(assert) {
test('_getRelationships should prefer relationships from request', function(assert) {

const otherSerializer = {
include: ['foo', 'bar']
Expand All @@ -20,79 +23,116 @@ test('_combineRelationships should combine relationships from serializer and req
}
};

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

assert.deepEqual(result, ['foo', 'bar', 'baz', 'quux']);
assert.deepEqual(result, ['baz', 'quux']);
});


test('_combineRelationships should not choke on missing request', function(assert) {
test('_getRelationships should not choke on missing request', function(assert) {

const otherSerializer = {
include: ['foo', 'bar']
};

const result = this.serializer._combineRelationships(otherSerializer);
const result = this.serializer._getRelationships(otherSerializer);

assert.deepEqual(result, ['foo', 'bar']);
});


test('_combineRelationships should not choke on empty request', function(assert) {
test('_getRelationships should not choke on empty request', function(assert) {

const otherSerializer = {
include: ['foo', 'bar']
};

const request = {};

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

assert.deepEqual(result, ['foo', 'bar']);
});


test('_combineRelationships should not choke on empty queryParams', function(assert) {
test('_getRelationships should not choke on empty queryParams', function(assert) {

const otherSerializer = {
include: ['foo', 'bar']
};

const request = {queryParams: {}};

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

assert.deepEqual(result, ['foo', 'bar']);
});


test('_combineRelationships should not choke on empty included', function(assert) {
test('_getRelationships should not choke on empty included', function(assert) {

const otherSerializer = {
include: ['foo', 'bar']
};

const request = {
queryParams: {
included: ''
include: ''
}
};

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

assert.deepEqual(result, ['foo', 'bar']);
assert.deepEqual(result, []);
});


test('_combineRelationships should not choke on missing serializer.relationships', function(assert) {
test('_getRelationships should not choke on missing serializer.relationships', function(assert) {

const request = {
queryParams: {
include: 'baz,quux'
}
};

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

assert.deepEqual(result, ['baz', 'quux']);
});


test('_getRelatedModelWithPath belongsTo', function(assert) {
const schema = schemaHelper.setup();

const foo = schema.foo.create();
const bar = foo.createBar();
foo.save();
const baz = bar.createBaz();
bar.save();
const quux1 = baz.createQuux();
const quux2 = baz.createQuux();
baz.save();
const zomg1 = quux1.createZomg();
const zomg2 = quux1.createZomg();
quux1.save();
const zomg3 = quux2.createZomg();
const zomg4 = quux2.createZomg();
quux2.save();
const lol1 = zomg1.createLol();
const lol2 = zomg2.createLol();
const lol3 = zomg3.createLol();
const lol4 = zomg4.createLol();
zomg1.save();
zomg2.save();
zomg3.save();
zomg4.save();

const result = this.serializer._getRelatedWithPath(foo, 'bar.baz.quuxes.zomgs.lol');
const ids = _map(result, 'id');

assert.equal(result.length, 4);
assert.ok(_includes(ids, lol1.id));
assert.ok(_includes(ids, lol2.id));
assert.ok(_includes(ids, lol3.id));
assert.ok(_includes(ids, lol4.id));
});

0 comments on commit 3e2a347

Please sign in to comment.