Added support for include relationship alias (as) and nested includes, fixed wrong joi json validation implementation inside parseInclude() function, fixed some associated routes resulted 404 because of prefix option
This commit is contained in:
parent
6fa9e90ec5
commit
e632f79e2b
@ -19,14 +19,14 @@ export default (server, a, b, names, options) => {
|
|||||||
update(server, a, b, names);
|
update(server, a, b, names);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const get = (server, a, b, names) => {
|
export const get = async (server, a, b, names) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: `${prefix}/${names.a.singular}/{aid}/${names.b.singular}/{bid}`,
|
path: `${prefix}${names.a.singular}/{aid}/${names.b.singular}/{bid}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
|
|
||||||
const base = await a.findOne({
|
const base = await a.findOne({
|
||||||
where: {
|
where: {
|
||||||
@ -51,14 +51,14 @@ export const get = (server, a, b, names) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const list = (server, a, b, names) => {
|
export const list = async (server, a, b, names) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: `${prefix}/${names.a.singular}/{aid}/${names.b.plural}`,
|
path: `${prefix}${names.a.singular}/{aid}/${names.b.plural}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
|
|
||||||
const base = await a.findOne({
|
const base = await a.findOne({
|
||||||
@ -77,16 +77,16 @@ export const list = (server, a, b, names) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const scope = (server, a, b, names) => {
|
export const scope = async (server, a, b, names) => {
|
||||||
const scopes = Object.keys(b.options.scopes);
|
const scopes = Object.keys(b.options.scopes);
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: `${prefix}/${names.a.singular}/{aid}/${names.b.plural}/{scope}`,
|
path: `${prefix}${names.a.singular}/{aid}/${names.b.plural}/{scope}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
|
|
||||||
const base = await a.findOne({
|
const base = await a.findOne({
|
||||||
@ -116,7 +116,7 @@ export const scope = (server, a, b, names) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const scopeScope = (server, a, b, names) => {
|
export const scopeScope = async (server, a, b, names) => {
|
||||||
const scopes = {
|
const scopes = {
|
||||||
a: Object.keys(a.options.scopes),
|
a: Object.keys(a.options.scopes),
|
||||||
b: Object.keys(b.options.scopes),
|
b: Object.keys(b.options.scopes),
|
||||||
@ -124,11 +124,11 @@ export const scopeScope = (server, a, b, names) => {
|
|||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: `${prefix}/${names.a.plural}/{scopea}/${names.b.plural}/{scopeb}`,
|
path: `${prefix}${names.a.plural}/{scopea}/${names.b.plural}/{scopeb}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
|
|
||||||
const list = await b.scope(request.params.scopeb).findAll({
|
const list = await b.scope(request.params.scopeb).findAll({
|
||||||
@ -152,14 +152,14 @@ export const scopeScope = (server, a, b, names) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const destroy = (server, a, b, names) => {
|
export const destroy = async (server, a, b, names) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
path: `${prefix}/${names.a.singular}/{aid}/${names.b.plural}`,
|
path: `${prefix}${names.a.singular}/{aid}/${names.b.plural}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
|
|
||||||
const base = await a.findOne({
|
const base = await a.findOne({
|
||||||
@ -179,16 +179,16 @@ export const destroy = (server, a, b, names) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const destroyScope = (server, a, b, names) => {
|
export const destroyScope = async (server, a, b, names) => {
|
||||||
const scopes = Object.keys(b.options.scopes);
|
const scopes = Object.keys(b.options.scopes);
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
path: `${prefix}/${names.a.singular}/{aid}/${names.b.plural}/{scope}`,
|
path: `${prefix}${names.a.singular}/{aid}/${names.b.plural}/{scope}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
|
|
||||||
const base = await a.findOne({
|
const base = await a.findOne({
|
||||||
@ -221,14 +221,14 @@ export const destroyScope = (server, a, b, names) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const update = (server, a, b, names) => {
|
export const update = async (server, a, b, names) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
path: `${prefix}/${names.a.singular}/{aid}/${names.b.plural}`,
|
path: `${prefix}${names.a.singular}/{aid}/${names.b.plural}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
|
|
||||||
const base = await a.findOne({
|
const base = await a.findOne({
|
||||||
|
@ -14,14 +14,14 @@ export default (server, a, b, names, options) => {
|
|||||||
update(server, a, b, names);
|
update(server, a, b, names);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const get = (server, a, b, names) => {
|
export const get = async (server, a, b, names) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: `${prefix}/${names.a.singular}/{aid}/${names.b.singular}`,
|
path: `${prefix}${names.a.singular}/{aid}/${names.b.singular}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
|
|
||||||
const base = await a.findOne({
|
const base = await a.findOne({
|
||||||
@ -47,7 +47,7 @@ export const get = (server, a, b, names) => {
|
|||||||
export const create = (server, a, b, names) => {
|
export const create = (server, a, b, names) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
path: `${prefix}/${names.a.singular}/{id}/${names.b.singular}`,
|
path: `${prefix}${names.a.singular}/{id}/${names.b.singular}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
@ -67,14 +67,14 @@ export const create = (server, a, b, names) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const destroy = (server, a, b, names) => {
|
export const destroy = async (server, a, b, names) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
path: `${prefix}/${names.a.singular}/{aid}/${names.b.singular}/{bid}`,
|
path: `${prefix}${names.a.singular}/{aid}/${names.b.singular}/{bid}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
|
|
||||||
const base = await a.findOne({
|
const base = await a.findOne({
|
||||||
@ -99,11 +99,11 @@ export const destroy = (server, a, b, names) => {
|
|||||||
export const update = (server, a, b, names) => {
|
export const update = (server, a, b, names) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
path: `${prefix}/${names.a.singular}/{aid}/${names.b.singular}/{bid}`,
|
path: `${prefix}${names.a.singular}/{aid}/${names.b.singular}/{bid}`,
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
|
|
||||||
const base = await a.findOne({
|
const base = await a.findOne({
|
||||||
|
@ -56,6 +56,17 @@ test('hasMany /team?include=players', async (t) => {
|
|||||||
t.truthy(playerIds.includes(player2.id));
|
t.truthy(playerIds.includes(player2.id));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('belongsTo with alias /player?include={"model": "Master", "as": "Coach"}', async(t) => {
|
||||||
|
const { server, instances } = t.context;
|
||||||
|
const { team1, master1 } = instances;
|
||||||
|
const path = `/player/${team1.id}?include={"model": "Master", "as": "Coach"}`;
|
||||||
|
|
||||||
|
const { result, statusCode } = await server.inject(path);
|
||||||
|
t.is(statusCode, STATUS_OK);
|
||||||
|
t.is(result.id, team1.id);
|
||||||
|
t.is(result.Coach.id, master1.id);
|
||||||
|
});
|
||||||
|
|
||||||
test('multiple includes /team?include=players&include=city', async(t) => {
|
test('multiple includes /team?include=players&include=city', async(t) => {
|
||||||
const { server, instances } = t.context;
|
const { server, instances } = t.context;
|
||||||
const { team1, player1, player2, city1 } = instances;
|
const { team1, player1, player2, city1 } = instances;
|
||||||
@ -86,6 +97,21 @@ test('multiple includes /team?include[]=players&include[]=city', async (t) => {
|
|||||||
t.is(result.City.id, city1.id);
|
t.is(result.City.id, city1.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('multiple includes /team?include[]=players&include[]={"model": "City"}', async(t) => {
|
||||||
|
const { server, instances } = t.context;
|
||||||
|
const { team1, player1, player2, city1 } = instances;
|
||||||
|
const path = `/team/${team1.id}?include[]=players&include[]={"model": "City"}`;
|
||||||
|
|
||||||
|
const { result, statusCode } = await server.inject(path);
|
||||||
|
t.is(statusCode, STATUS_OK);
|
||||||
|
t.is(result.id, team1.id);
|
||||||
|
|
||||||
|
const playerIds = result.Players.map(({ id }) => id);
|
||||||
|
t.truthy(playerIds.includes(player1.id));
|
||||||
|
t.truthy(playerIds.includes(player2.id));
|
||||||
|
t.is(result.City.id, city1.id);
|
||||||
|
});
|
||||||
|
|
||||||
test('inlcude filter /teams?include[]={"model": "City", "where": {"name": "Healdsburg"}}'
|
test('inlcude filter /teams?include[]={"model": "City", "where": {"name": "Healdsburg"}}'
|
||||||
, async(t) => {
|
, async(t) => {
|
||||||
const { server } = t.context;
|
const { server } = t.context;
|
||||||
@ -95,3 +121,37 @@ test('inlcude filter /teams?include[]={"model": "City", "where": {"name": "Heald
|
|||||||
const { statusCode } = await server.inject({ url, method });
|
const { statusCode } = await server.inject({ url, method });
|
||||||
t.is(statusCode, STATUS_OK);
|
t.is(statusCode, STATUS_OK);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('nested inlcude filter ' +
|
||||||
|
'/city?include[]={"model": "Team", "include": {"model": "Player", "where": {"name": "Pinot"}}}'
|
||||||
|
, async(t) => {
|
||||||
|
const { instances, server } = t.context;
|
||||||
|
const { city1, team1, player2 } = instances;
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
const url = '/city?include[]={"model": "Team", "include": {"model": "Player", "where": {"name": "Pinot"}}}';
|
||||||
|
const method = 'GET';
|
||||||
|
|
||||||
|
const { result, statusCode } = await server.inject({ url, method });
|
||||||
|
t.is(statusCode, STATUS_OK);
|
||||||
|
t.is(result.id, city1.id);
|
||||||
|
t.is(result.Teams[0].id, team1.id);
|
||||||
|
t.is(result.Teams[0].Players[0].id, player2.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('nested inlcude filter ' +
|
||||||
|
'/city?include[]={"model": "Team", "include": {"model": "City", "where": {"name": "Healdsburg"}}}'
|
||||||
|
, async(t) => {
|
||||||
|
const { instances, server } = t.context;
|
||||||
|
const { city1, team1, team2 } = instances;
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
const url = '/city?include[]={"model": "Team", "include": {"model": "City", "where": {"name": "Healdsburg"}}}';
|
||||||
|
const method = 'GET';
|
||||||
|
|
||||||
|
const { result, statusCode } = await server.inject({ url, method });
|
||||||
|
t.is(statusCode, STATUS_OK);
|
||||||
|
t.is(result.id, city1.id);
|
||||||
|
|
||||||
|
const teamIds = result.Teams.map(({ id }) => id);
|
||||||
|
t.truthy(teamIds.includes(team1.id));
|
||||||
|
t.truthy(teamIds.includes(team2.id));
|
||||||
|
});
|
||||||
|
22
src/crud.js
22
src/crud.js
@ -56,6 +56,7 @@ export default (server, model, { prefix, defaultConfig: config, models: permissi
|
|||||||
const modelName = model._singular;
|
const modelName = model._singular;
|
||||||
const modelAttributes = Object.keys(model.attributes);
|
const modelAttributes = Object.keys(model.attributes);
|
||||||
const associatedModelNames = Object.keys(model.associations);
|
const associatedModelNames = Object.keys(model.associations);
|
||||||
|
const associatedModelAliases = _.map(model.associations, (assoc => assoc.as));
|
||||||
const modelAssociations = [
|
const modelAssociations = [
|
||||||
...associatedModelNames,
|
...associatedModelNames,
|
||||||
..._.flatMap(associatedModelNames, (associationName) => {
|
..._.flatMap(associatedModelNames, (associationName) => {
|
||||||
@ -82,12 +83,13 @@ export default (server, model, { prefix, defaultConfig: config, models: permissi
|
|||||||
...attributeValidation,
|
...attributeValidation,
|
||||||
...sequelizeOperators,
|
...sequelizeOperators,
|
||||||
}),
|
}),
|
||||||
|
as: joi.string().valid(...associatedModelAliases),
|
||||||
|
include: joi.any(), // @Todo: should validate the same as associationValidation var below
|
||||||
})
|
})
|
||||||
: joi.valid(null);
|
: joi.valid(null);
|
||||||
const associationValidation = {
|
const associationValidation = {
|
||||||
include: [
|
include: [
|
||||||
joi.array().items(validAssociationsString),
|
joi.array().items(validAssociationsString, validAssociationsObject),
|
||||||
joi.array().items(validAssociationsObject),
|
|
||||||
validAssociationsString,
|
validAssociationsString,
|
||||||
validAssociationsObject,
|
validAssociationsObject,
|
||||||
],
|
],
|
||||||
@ -161,14 +163,14 @@ export default (server, model, { prefix, defaultConfig: config, models: permissi
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const list = ({ server, model, prefix = '/', config }) => {
|
export const list = async ({ server, model, prefix = '/', config }) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: path.join(prefix, model._plural),
|
path: path.join(prefix, model._plural),
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
const { limit, offset } = parseLimitAndOffset(request);
|
const { limit, offset } = parseLimitAndOffset(request);
|
||||||
const order = parseOrder(request);
|
const order = parseOrder(request);
|
||||||
@ -188,14 +190,14 @@ export const list = ({ server, model, prefix = '/', config }) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const get = ({ server, model, prefix = '/', config }) => {
|
export const get = async ({ server, model, prefix = '/', config }) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: path.join(prefix, model._singular, '{id?}'),
|
path: path.join(prefix, model._singular, '{id?}'),
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
const { id } = request.params;
|
const { id } = request.params;
|
||||||
if (id) where[model.primaryKeyField] = id;
|
if (id) where[model.primaryKeyField] = id;
|
||||||
@ -212,14 +214,14 @@ export const get = ({ server, model, prefix = '/', config }) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const scope = ({ server, model, prefix = '/', config }) => {
|
export const scope = async ({ server, model, prefix = '/', config }) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: path.join(prefix, model._plural, '{scope}'),
|
path: path.join(prefix, model._plural, '{scope}'),
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
const { limit, offset } = parseLimitAndOffset(request);
|
const { limit, offset } = parseLimitAndOffset(request);
|
||||||
const order = parseOrder(request);
|
const order = parseOrder(request);
|
||||||
@ -313,14 +315,14 @@ export const destroyAll = ({ server, model, prefix = '/', config }) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const destroyScope = ({ server, model, prefix = '/', config }) => {
|
export const destroyScope = async ({ server, model, prefix = '/', config }) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
path: path.join(prefix, model._plural, '{scope}'),
|
path: path.join(prefix, model._plural, '{scope}'),
|
||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
const include = parseInclude(request);
|
const include = await parseInclude(request);
|
||||||
const where = parseWhere(request);
|
const where = parseWhere(request);
|
||||||
|
|
||||||
if (include instanceof Error) return void reply(include);
|
if (include instanceof Error) return void reply(include);
|
||||||
|
65
src/utils.js
65
src/utils.js
@ -1,6 +1,7 @@
|
|||||||
import { omit, identity, toNumber, isString, isUndefined } from 'lodash';
|
import { omit, identity, toNumber, isString, isUndefined } from 'lodash';
|
||||||
import { notImplemented } from 'boom';
|
import { notImplemented } from 'boom';
|
||||||
import joi from 'joi';
|
import joi from 'joi';
|
||||||
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
const sequelizeKeys = ['include', 'order', 'limit', 'offset'];
|
const sequelizeKeys = ['include', 'order', 'limit', 'offset'];
|
||||||
|
|
||||||
@ -17,7 +18,9 @@ const getModels = (request) => {
|
|||||||
return models;
|
return models;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseInclude = request => {
|
export const parseInclude = async(request) => {
|
||||||
|
if (typeof request.query.include === 'undefined') return [];
|
||||||
|
|
||||||
const include = Array.isArray(request.query.include)
|
const include = Array.isArray(request.query.include)
|
||||||
? request.query.include
|
? request.query.include
|
||||||
: [request.query.include]
|
: [request.query.include]
|
||||||
@ -26,32 +29,58 @@ export const parseInclude = request => {
|
|||||||
const models = getModels(request);
|
const models = getModels(request);
|
||||||
if (models.isBoom) return models;
|
if (models.isBoom) return models;
|
||||||
|
|
||||||
return include.map(b => {
|
const getModelInstance = includeItem => {
|
||||||
|
return new Promise(async(resolve) => {
|
||||||
|
if (includeItem) {
|
||||||
|
if (typeof includeItem !== 'object') {
|
||||||
|
const singluarOrPluralMatch = Object.keys(models).find((modelName) => {
|
||||||
|
const { _singular, _plural } = models[modelName];
|
||||||
|
return _singular === includeItem || _plural === includeItem;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (singluarOrPluralMatch) {
|
||||||
|
return resolve(models[singluarOrPluralMatch]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof includeItem === 'string' && models.hasOwnProperty(includeItem)) {
|
||||||
|
return resolve(models[includeItem]);
|
||||||
|
} else if (typeof includeItem === 'object') {
|
||||||
|
if (
|
||||||
|
typeof includeItem.model === 'string' &&
|
||||||
|
includeItem.model.length &&
|
||||||
|
models.hasOwnProperty(includeItem.model)
|
||||||
|
) {
|
||||||
|
includeItem.model = models[includeItem.model];
|
||||||
|
}
|
||||||
|
if (includeItem.hasOwnProperty('include')) {
|
||||||
|
includeItem.include = await getModelInstance(includeItem.include);
|
||||||
|
return resolve(includeItem);
|
||||||
|
} else {
|
||||||
|
return resolve(includeItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return resolve(includeItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const jsonValidation = joi.string().regex(/^\{.*?"model":.*?\}$/);
|
||||||
|
const includes = include.map(async(b) => {
|
||||||
let a = b;
|
let a = b;
|
||||||
try {
|
try {
|
||||||
if (joi.string().regex(/^\{.*?"model":.*?\}$/)) {
|
if (!jsonValidation.validate(a).error) {
|
||||||
a = JSON.parse(b);
|
a = JSON.parse(b);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
if (typeof a !== 'object') {
|
|
||||||
const singluarOrPluralMatch = Object.keys(models).find((modelName) => {
|
|
||||||
const { _singular, _plural } = models[modelName];
|
|
||||||
return _singular === a || _plural === a;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (singluarOrPluralMatch) return models[singluarOrPluralMatch];
|
return getModelInstance(a);
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof a === 'string') return models[a];
|
|
||||||
|
|
||||||
if (a && typeof a.model === 'string' && a.model.length) {
|
|
||||||
a.model = models[a.model];
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
}).filter(identity);
|
}).filter(identity);
|
||||||
|
|
||||||
|
return await Promise.all(includes);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseWhere = request => {
|
export const parseWhere = request => {
|
||||||
|
18
test/fixtures/models/master.js
vendored
Normal file
18
test/fixtures/models/master.js
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export default (sequelize, DataTypes) => {
|
||||||
|
return sequelize.define('Master', {
|
||||||
|
id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
primaryKey: true,
|
||||||
|
autoIncrement: true,
|
||||||
|
},
|
||||||
|
name: DataTypes.STRING,
|
||||||
|
}, {
|
||||||
|
classMethods: {
|
||||||
|
associate: (models) => {
|
||||||
|
models.Master.hasMany(models.Player, {
|
||||||
|
foreignKey: 'coachId'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
4
test/fixtures/models/player.js
vendored
4
test/fixtures/models/player.js
vendored
@ -14,6 +14,10 @@ export default (sequelize, DataTypes) => {
|
|||||||
models.Player.belongsTo(models.Team, {
|
models.Player.belongsTo(models.Team, {
|
||||||
foreignKey: { name: 'teamId' },
|
foreignKey: { name: 'teamId' },
|
||||||
});
|
});
|
||||||
|
models.Player.belongsTo(models.Master, {
|
||||||
|
foreignKey: 'coachId',
|
||||||
|
as: 'Coach',
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
scopes: {
|
scopes: {
|
||||||
|
@ -14,6 +14,7 @@ const modelNames = [
|
|||||||
{ Singluar: 'City', singular: 'city', Plural: 'Cities', plural: 'cities' },
|
{ Singluar: 'City', singular: 'city', Plural: 'Cities', plural: 'cities' },
|
||||||
{ Singluar: 'Team', singular: 'team', Plural: 'Teams', plural: 'teams' },
|
{ Singluar: 'Team', singular: 'team', Plural: 'Teams', plural: 'teams' },
|
||||||
{ Singluar: 'Player', singular: 'player', Plural: 'Players', plural: 'players' },
|
{ Singluar: 'Player', singular: 'player', Plural: 'Players', plural: 'players' },
|
||||||
|
{ Singluar: 'Master', singular: 'master', Plural: 'Masters', plural: 'masters' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
@ -55,16 +56,24 @@ export default (test) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.beforeEach('create data', async(t) => {
|
test.beforeEach('create data', async(t) => {
|
||||||
const { Player, Team, City } = t.context.sequelize.models;
|
const { Player, Master, Team, City } = t.context.sequelize.models;
|
||||||
const city1 = await City.create({ name: 'Healdsburg' });
|
const city1 = await City.create({ name: 'Healdsburg' });
|
||||||
const team1 = await Team.create({ name: 'Baseballs', cityId: city1.id });
|
const team1 = await Team.create({ name: 'Baseballs', cityId: city1.id });
|
||||||
const team2 = await Team.create({ name: 'Footballs', cityId: city1.id });
|
const team2 = await Team.create({ name: 'Footballs', cityId: city1.id });
|
||||||
|
const master1 = await Master.create({ name: 'Shifu' });
|
||||||
|
const master2 = await Master.create({ name: 'Oogway' });
|
||||||
const player1 = await Player.create({
|
const player1 = await Player.create({
|
||||||
name: 'Cat', teamId: team1.id, active: true,
|
name: 'Cat', teamId: team1.id, active: true, coachId: master1.id
|
||||||
});
|
});
|
||||||
const player2 = await Player.create({ name: 'Pinot', teamId: team1.id });
|
const player2 = await Player.create({
|
||||||
const player3 = await Player.create({ name: 'Syrah', teamId: team2.id });
|
name: 'Pinot', teamId: team1.id, coachId: master1.id
|
||||||
t.context.instances = { city1, team1, team2, player1, player2, player3 };
|
});
|
||||||
|
const player3 = await Player.create({
|
||||||
|
name: 'Syrah', teamId: team2.id, coachId: master2.id
|
||||||
|
});
|
||||||
|
t.context.instances = {
|
||||||
|
city1, team1, team2, player1, player2, player3, master1, master2
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// kill the server so that we can exit and don't leak memory
|
// kill the server so that we can exit and don't leak memory
|
||||||
|
Loading…
Reference in New Issue
Block a user