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:
Muhammad Labib Ramadhan 2016-11-10 01:46:42 +07:00
parent 6fa9e90ec5
commit e632f79e2b
8 changed files with 202 additions and 80 deletions

View File

@ -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({

View File

@ -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({

View File

@ -6,7 +6,7 @@ const STATUS_OK = 200;
setup(test); setup(test);
test('belongsTo /team?include=city', async (t) => { test('belongsTo /team?include=city', async(t) => {
const { server, instances } = t.context; const { server, instances } = t.context;
const { team1, city1 } = instances; const { team1, city1 } = instances;
const path = `/team/${team1.id}?include=city`; const path = `/team/${team1.id}?include=city`;
@ -17,7 +17,7 @@ test('belongsTo /team?include=city', async (t) => {
t.is(result.City.id, city1.id); t.is(result.City.id, city1.id);
}); });
test('belongsTo /team?include=cities', async (t) => { test('belongsTo /team?include=cities', async(t) => {
const { server, instances } = t.context; const { server, instances } = t.context;
const { team1, city1 } = instances; const { team1, city1 } = instances;
const path = `/team/${team1.id}?include=cities`; const path = `/team/${team1.id}?include=cities`;
@ -28,7 +28,7 @@ test('belongsTo /team?include=cities', async (t) => {
t.is(result.City.id, city1.id); t.is(result.City.id, city1.id);
}); });
test('hasMany /team?include=player', async (t) => { test('hasMany /team?include=player', async(t) => {
const { server, instances } = t.context; const { server, instances } = t.context;
const { team1, player1, player2 } = instances; const { team1, player1, player2 } = instances;
const path = `/team/${team1.id}?include=player`; const path = `/team/${team1.id}?include=player`;
@ -42,7 +42,7 @@ test('hasMany /team?include=player', async (t) => {
t.truthy(playerIds.includes(player2.id)); t.truthy(playerIds.includes(player2.id));
}); });
test('hasMany /team?include=players', async (t) => { test('hasMany /team?include=players', async(t) => {
const { server, instances } = t.context; const { server, instances } = t.context;
const { team1, player1, player2 } = instances; const { team1, player1, player2 } = instances;
const path = `/team/${team1.id}?include=players`; const path = `/team/${team1.id}?include=players`;
@ -56,7 +56,18 @@ test('hasMany /team?include=players', async (t) => {
t.truthy(playerIds.includes(player2.id)); t.truthy(playerIds.includes(player2.id));
}); });
test('multiple includes /team?include=players&include=city', async (t) => { 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) => {
const { server, instances } = t.context; const { server, instances } = t.context;
const { team1, player1, player2, city1 } = instances; const { team1, player1, player2, city1 } = instances;
const path = `/team/${team1.id}?include=players&include=city`; const path = `/team/${team1.id}?include=players&include=city`;
@ -71,7 +82,7 @@ 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[]=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;
const path = `/team/${team1.id}?include[]=players&include[]=city`; const path = `/team/${team1.id}?include[]=players&include[]=city`;
@ -86,8 +97,23 @@ 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;
const url = '/teams?include[]={"model": "City", "where": {"name": "Healdsburg"}}'; const url = '/teams?include[]={"model": "City", "where": {"name": "Healdsburg"}}';
const method = 'GET'; const method = 'GET';
@ -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));
});

View File

@ -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);

View File

@ -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'];
@ -9,7 +10,7 @@ const getModels = (request) => {
const noRequestModels = !request.models; const noRequestModels = !request.models;
if (noGetDb && noRequestModels) { if (noGetDb && noRequestModels) {
return notImplemented('`request.getDb` or `request.models` are not defined.' return notImplemented('`request.getDb` or `request.models` are not defined.'
+ 'Be sure to load hapi-sequelize before hapi-sequelize-crud.'); + 'Be sure to load hapi-sequelize before hapi-sequelize-crud.');
} }
const { models } = noGetDb ? request : request.getDb(); const { models } = noGetDb ? request : request.getDb();
@ -17,41 +18,69 @@ 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]
; ;
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
View 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'
});
},
},
});
};

View File

@ -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: {

View File

@ -14,15 +14,16 @@ 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' },
]; ];
export default (test) => { export default (test) => {
test.beforeEach('get an open port', async (t) => { test.beforeEach('get an open port', async(t) => {
t.context.port = await getPort(); t.context.port = await getPort();
}); });
test.beforeEach('setup server', async (t) => { test.beforeEach('setup server', async(t) => {
const sequelize = t.context.sequelize = new Sequelize({ const sequelize = t.context.sequelize = new Sequelize({
dialect: 'sqlite', dialect: 'sqlite',
logging: false, logging: false,
@ -46,25 +47,33 @@ export default (test) => {
}); });
await server.register({ await server.register({
register: require('../src/index.js'), register: require('../src/index.js'),
options: { options: {
name: dbName, name: dbName,
},
}, },
},
); );
}); });
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