diff --git a/src/packages/controller/test/find-related.test.js b/src/packages/controller/test/find-related.test.js new file mode 100644 index 00000000..9d3e9fac --- /dev/null +++ b/src/packages/controller/test/find-related.test.js @@ -0,0 +1,84 @@ +// @flow +import { expect } from 'chai'; +import { describe, it, before } from 'mocha'; + +import { Model } from '../../database'; +import setType from '../../../utils/set-type'; +import { getTestApp } from '../../../../test/utils/get-test-app'; +import findRelated from '../utils/find-related'; + +import type Controller from '../index'; + +describe('module "controller"', () => { + describe('util findRelated()', () => { + let controllers: Map; + + before(async () => { + const app = await getTestApp(); + + controllers = app.controllers; + }); + + it('resolves with the correct object', async () => { + const result = await findRelated(controllers, { + user: { + data: { + id: 1, + type: 'users' + } + }, + image: { + data: null + }, + comments: { + data: [ + { + id: 1, + type: 'comments' + }, + { + id: 2, + type: 'comments' + }, + { + id: 3, + type: 'comments' + }, + { + id: 4, + type: 'invalid-type' + } + ] + }, + reactions: { + data: 'invalid data...' + }, + invalidType: { + data: { + id: 1, + type: 'invalid-type' + } + } + }); + + expect(result).to.have.all.keys([ + 'user', + 'image', + 'comments' + ]); + + expect(result) + .to.have.property('user') + .and.be.an('object'); + + expect(result) + .to.have.property('image') + .and.be.null; + + expect(result) + .to.have.property('comments') + .and.be.an('array') + .with.lengthOf(3); + }); + }); +}); diff --git a/src/packages/controller/test/params-to-query.test.js b/src/packages/controller/test/params-to-query.test.js new file mode 100644 index 00000000..7daf9d56 --- /dev/null +++ b/src/packages/controller/test/params-to-query.test.js @@ -0,0 +1,189 @@ +// @flow +import { expect } from 'chai'; +import { describe, it, before } from 'mocha'; + +import type { Model } from '../../database'; +import type { Request$params } from '../../server'; +import merge from '../../../utils/merge'; +import setType from '../../../utils/set-type'; +import paramsToQuery from '../utils/params-to-query'; +import { getTestApp } from '../../../../test/utils/get-test-app'; + +describe('module "controller"', () => { + describe('util paramsToQuery()', () => { + let Post: Class; + const createParams = (obj: Object): Request$params => setType(() => { + return merge({ + sort: 'createdAt', + filter: {}, + fields: { + posts: [ + 'body', + 'title', + 'createdAt', + 'updatedAt' + ] + } + }, obj); + }); + + before(async () => { + const { models } = await getTestApp(); + + Post = setType(() => models.get('post')); + }); + + it('returns the correct params object', () => { + const subject = createParams({ + id: 1, + sort: 'title', + page: { + size: 10, + number: 5 + }, + filter: { + title: 'New Post' + }, + fields: { + posts: [ + 'body', + 'title' + ] + } + }); + + const result = paramsToQuery(Post, subject); + + expect(result).to.have.property('id', 1); + expect(result).to.have.property('page', 5); + expect(result).to.have.property('limit', 10); + + expect(result) + .to.have.property('sort') + .and.deep.equal([ + 'title', + 'ASC' + ]); + + expect(result) + .to.have.property('filter') + .and.deep.equal({ + title: 'New Post' + }); + + expect(result) + .to.have.property('select') + .and.deep.equal([ + 'id', + 'body', + 'title' + ]); + }); + + describe('- page', () => { + const subject = createParams({ + page: { + size: 10, + number: 2 + } + }); + + it('converts `number` and `size` to `page` and `limit`', () => { + const result = paramsToQuery(Post, subject); + + expect(result).to.have.property('page', 2); + expect(result).to.have.property('limit', 10); + }); + }); + + describe('- sort', () => { + it('converts asc parameters', () => { + const subject = createParams({ + sort: 'title' + }); + + const result = paramsToQuery(Post, subject); + + expect(result) + .to.have.property('sort') + .and.deep.equal(['title', 'ASC']); + }); + + it('converts desc parameters', () => { + const subject = createParams({ + sort: '-title' + }); + + const result = paramsToQuery(Post, subject); + + expect(result) + .to.have.property('sort') + .and.deep.equal(['title', 'DESC']); + }); + }); + + describe('- fields', () => { + it('can properly build included fields', () => { + const subject = createParams({ + fields: { + users: [ + 'name' + ] + }, + include: [ + 'user' + ] + }); + + const result = paramsToQuery(Post, subject); + + expect(result) + .to.have.property('include') + .and.deep.equal({ + user: [ + 'id', + 'name' + ] + }); + }); + + it('ignores invalid field sets', () => { + const subject = createParams({ + fields: { + authors: [ + 'name' + ] + }, + include: [ + 'author' + ] + }); + + const result = paramsToQuery(Post, subject); + + expect(result) + .to.have.property('include') + .and.deep.equal({}); + }); + + it('only adds `id` when the include array is `undefined`', () => { + const subject = createParams({ + fields: { + images: [ + 'id', + 'url' + ] + } + }); + + const result = paramsToQuery(Post, subject); + + expect(result) + .to.have.property('include') + .and.deep.equal({ + image: ['id'] + }); + }); + }); + }); +}); diff --git a/src/packages/controller/utils/find-related.js b/src/packages/controller/utils/find-related.js index 9d8029be..752a30ea 100644 --- a/src/packages/controller/utils/find-related.js +++ b/src/packages/controller/utils/find-related.js @@ -22,22 +22,29 @@ export default function findRelated( ...result, [key]: value }; - } else if (Array.isArray(value)) { + } + + if (Array.isArray(value)) { return { ...result, [key]: Promise.all( - value.map(({ id, type }) => { + value.reduce((arr, { id, type }) => { const controller = controllers.get(type); if (controller) { - return controller.model.find(id); + return [ + ...arr, + controller.model.find(id) + ]; } - return Promise.resolve(undefined); - }) + return arr; + }, []) ) }; - } else if (isObject(value)) { + } + + if (isObject(value)) { const { id, type } = value; const controller = controllers.get(type);