diff --git a/.env-sample b/.env-sample new file mode 100644 index 0000000..edeb2de --- /dev/null +++ b/.env-sample @@ -0,0 +1,5 @@ +DB_USERNAME='DB_USERNAME' +DB_PASSWORD='DB_PASSWORD' +DB_DATABASE='DB_DATABASE' +DB_HOST='DB_HOST' +DB_DIALECT='DB_DIALECT' \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index e69de29..ef46313 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -0,0 +1,62 @@ +module.exports = { + "env": { + "es6": true, + "node": true, + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "rules": { + "array-bracket-spacing": ["error", "never"], + "array-element-newline": ["error", "consistent"], + "arrow-spacing": ["error", { "before": true, "after": true }], + "block-spacing": "error", + "camelcase": 0, + "comma-spacing": ["error", { "before": false, "after": true }], + "computed-property-spacing": ["error", "never"], + "dot-location": ["error", "property"], + "eol-last": ["error", "always"], + "func-call-spacing": ["error", "never"], + "function-paren-newline": ["error", "never"], + "implicit-arrow-linebreak": ["error", "beside"], + "indent": ["error", 2, { "SwitchCase": 1 }], + "key-spacing": ["error", { "afterColon": true }], + "keyword-spacing": ["error", { "before": true, "after": true }], + "linebreak-style": ["error", "unix"], + "max-len": ["error", { "code": 120, "ignoreComments": true, "ignoreTrailingComments": true }], + "no-console": "error", + "no-case-declarations": 0, + "no-mixed-spaces-and-tabs": "error", + "no-multi-spaces": "error", + "no-spaced-func": "error", + "no-trailing-spaces": ["error", { "ignoreComments": true }], + "no-whitespace-before-property": "error", + "nonblock-statement-body-position": ["error", "beside"], + "object-curly-newline": ["error", { "multiline": true, "minProperties": 5, "consistent": true }], + "object-curly-spacing": ["error", "always", { "arraysInObjects": true, "objectsInObjects": true }], + "object-property-newline": ["error", { "allowAllPropertiesOnSameLine": true }], + "one-var": ["error", "never"], + "operator-linebreak": ["error", "after", { "overrides": { "?": "before", ":": "before" } }], + "padded-blocks": ["error", "never"], + "padding-line-between-statements": [ + "error", + { blankLine: "always", prev: "*", next: "return" }, + { blankLine: "always", prev: ["const", "let", "var"], next: "*" }, + { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"] }, + ], + "quotes": ["error", "single"], + "rest-spread-spacing": ["error", "never"], + "space-before-blocks": "error", + "space-before-function-paren": ["error", { "anonymous": "always", "named": "never", "asyncArrow": "always" }], + "space-in-parens": ["error", "never"], + "space-infix-ops": "error", + "space-unary-ops": "error", + "spaced-comment": ["error", "always"], + "semi": ["error", "never"], + "semi-spacing": ["error", { "before": false, "after": true }], + "switch-colon-spacing": "error", + "template-tag-spacing": ["error", "always"], + } +}; \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3c3629e..79cf6ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +setup.sql +.env diff --git a/.pug-lintrc.js b/.pug-lintrc.js new file mode 100644 index 0000000..5ae7099 --- /dev/null +++ b/.pug-lintrc.js @@ -0,0 +1,24 @@ +module.exports = { + disallowAttributeConcatenation: true, + disallowBlockExpansion: true, + disallowClassLiterals: true, + disallowDuplicateAttributes: true, + disallowHtmlText: true, + disallowIdLiterals: true, + disallowLegacyMixinCall: true, + disallowMultipleLineBreaks: true, + disallowSpacesInsideAttributeBrackets: true, + disallowStringConcatenation: 'aggressive', + disallowTagInterpolation: true, + disallowTrailingSpaces: true, + requireLineFeedAtFileEnd: true, + requireLowerCaseAttributes: true, + requireLowerCaseTags: true, + requireSpaceAfterCodeOperator: true, + requireStrictEqualityOperators: true, + validateAttributeQuoteMarks: '"', + validateExtensions: true, + validateIndentation: 2, + validateLineBreaks: 'LF', + validateTemplateString: true +} \ No newline at end of file diff --git a/Pokemon-API-ERD.png b/Pokemon-API-ERD.png new file mode 100644 index 0000000..9788939 Binary files /dev/null and b/Pokemon-API-ERD.png differ diff --git a/configs/sequelize.js b/configs/sequelize.js new file mode 100644 index 0000000..e3b2585 --- /dev/null +++ b/configs/sequelize.js @@ -0,0 +1,9 @@ +module.exports = { + development: { + username: process.env.DB_USERNAME, + password: process.env.DB_PASSWORD, + database: process.env.DB_DATABASE, + host: process.env.DB_HOST, + dialect: process.env.DB_DIALECT, + } +} diff --git a/controllers/Forms.js b/controllers/Forms.js new file mode 100644 index 0000000..5bc2775 --- /dev/null +++ b/controllers/Forms.js @@ -0,0 +1,29 @@ +const models = require('../models') + +const getAllForms = async (request, response) => { + try { + const allForms = await models.Forms.findAll() + + return response.send(allForms) + } catch (error) { + return response.status(500).send('Unable to retrieve all the forms, please try again.') + } +} + +const getFormById = async (request, response) => { + try { + const { id } = request.params + const Form = await models.Forms.findOne({ + where: { name: id }, + include: [{ model: models.Pokemons }] + }) + + return Form + ? response.status(200).send(Form) + : response.status(404).send(`It appears there is no form called '${id}' does not exist.`) + } catch (error) { + return response.status(500).send('Unable to retrieve the form, please try again.') + } +} + +module.exports = { getAllForms, getFormById } diff --git a/controllers/Pokemons.js b/controllers/Pokemons.js new file mode 100644 index 0000000..373a0a2 --- /dev/null +++ b/controllers/Pokemons.js @@ -0,0 +1,126 @@ +const models = require('../models') + +const getAllPokemon = async (request, response) => { + try { + const allPokemon = await models.Pokemons.findAll() + + return response.send(allPokemon) + } catch (error) { + return response.status(500).send('Could not retrieve all pokemon, please try again.') + } +} + +const getPokemonById = async (request, response) => { + try { + const { id } = request.params + const pokemon = await models.Pokemons.findOne({ + where: { name: id }, + include: [ + { model: models.Forms }, + { model: models.Types } + ] + }) + + return pokemon + ? response.status(200).send(pokemon) + : response.status(404).send(`Could not find the pokemon ${id}.`) + } catch (error) { + return response.status(500).send('Could not retrieve the pokemon, please try again.') + } +} + +const getPokemonByGenerationId = async (request, response) => { + try { + const { id } = request.params + const allPokemonInGeneration = await models.Pokemons.findAll({ where: { generationNumber: id } }) + + return allPokemonInGeneration.length + ? response.send(allPokemonInGeneration) + : response.status(404).send(`No generation ${id} pokemon currently exists.`) + } catch (error) { + return response.status(500).send('Could not retrieve the pokemon by the sepcified generation, please try again.') + } +} + +const saveNewPokemon = async (request, response) => { + try { + const { + name, + generationNumber, + types + } = request.body + const isProtected = request.body.isProtected || 0 + const fromId = request.body.fromId.toLowerCase() === 'null' + ? null + : request.body.fromId + + + if (!name || !generationNumber) { + return response + .status(400) + .send('At least one of the following attributes is missing: pokedexNumber, name, or generationNumber') + } + + const [savedPokemon, created] = await models.Pokemons.findOrCreate({ + where: { name }, + defaults: { generationNumber, fromId, isProtected } + }) + + Promise.resolve(savedPokemon) + + if (created) { + const promisedTypesId = types.map(async typeName => { + const [type] = await models.Types.findOrCreate({ where: { name: typeName } }) + + return type.id + }) + + + const typesId = await Promise.all(promisedTypesId) + const { pokedexNumber } = savedPokemon + + typesId.map(async (typeId) => { + const promisedPokemonType = await models.PokemonTypes.findOrCreate({ + where: { PokemonPokedexNumber: pokedexNumber }, + defaults: { TypeId: typeId } + }) + + const pokemonType = Promise.resolve(promisedPokemonType) + + return pokemonType + }) + } + + + return response.status(201).send(savedPokemon) + } catch (error) { + return response.status(500).send('Could not reach the database, please try again.') + } +} + +const deletePokemon = async (request, response) => { + try { + const { name } = request.params + + const pokemon = await models.Pokemons.findOne({ where: { name } }) + + if (!pokemon) return response.status(404).send(`No pokemon matching the name: ${name}`) + + if (pokemon.isProtected) return response.status(409).send('Cannot delete protected pokemon') + + await models.PokemonTypes.destroy({ where: { PokemonPokedexNumber: pokemon.pokedexNumber } }) + await models.Pokemons.destroy({ where: { name } }) + + return response.send(`Successfully deleted the pokemon: ${name}.`) + } catch (error) { + return response.status(500).send('Unknown error while deleting pokemon, please try again.') + } +} + +module.exports = { + getAllPokemon, + getPokemonById, + getPokemonByGenerationId, + saveNewPokemon, + deletePokemon +} diff --git a/controllers/Types.js b/controllers/Types.js new file mode 100644 index 0000000..5607d55 --- /dev/null +++ b/controllers/Types.js @@ -0,0 +1,26 @@ +const models = require('../models') + +const getAllTypes = async (request, response) => { + try { + const allTypes = await models.Types.findAll() + + return response.send(allTypes) + } catch (error) { + return response.status(500).send('Could not retrieve all the types, please try again.') + } +} + +const getTypeById = async (request, response) => { + try { + const { id } = request.params + const type = await models.Types.findOne({ where: { name: id }, include: [{ model: models.Pokemons }] }) + + return type + ? response.status(200).send(type) + : response.status(404).send(`Could not find the type: ${id}.`) + } catch (error) { + return response.status(500).send('Could not retrieve the specified type, please try again.') + } +} + +module.exports = { getAllTypes, getTypeById } diff --git a/index.js b/index.js new file mode 100644 index 0000000..0854244 --- /dev/null +++ b/index.js @@ -0,0 +1,41 @@ +const express = require('express') +const bodyParser = require('body-parser') +const { + getAllPokemon, + getPokemonById, + getPokemonByGenerationId, + saveNewPokemon, + deletePokemon +} = require('./controllers/Pokemons') +const { getAllTypes, getTypeById } = require('./controllers/Types') +const { getAllForms, getFormById } = require('./controllers/Forms') + +const app = express() + +app.set('view engine', 'pug') +app.use(express.static('public')) + +app.get('/', (request, response) => { + return response.status(200).render('index') +}) + +app.get('/pokemon', getAllPokemon) +app.post('/pokemon', bodyParser.json(), saveNewPokemon) +app.get('/pokemon/:id', getPokemonById) +app.delete('/pokemon/:name', deletePokemon) + +app.get('/generation/:id', getPokemonByGenerationId) + +app.get('/types', getAllTypes) +app.get('/types/:id', getTypeById) + +app.get('/forms', getAllForms) +app.get('/forms/:id', getFormById) + +app.all('*', (request, response) => { + return response.status(404).send('Looks like you found nothing in the pokedex.') +}) + +app.listen(1337, () => { + console.log('Listening on 1337...')// eslint-disable-line no-console +}) diff --git a/migrations/20200524223604-initial-table-creation.js b/migrations/20200524223604-initial-table-creation.js new file mode 100644 index 0000000..a1c4162 --- /dev/null +++ b/migrations/20200524223604-initial-table-creation.js @@ -0,0 +1,106 @@ +module.exports = { + up: async (queryInterface, Sequelize) => { + /* + Add altering commands here. + Return a promise to correctly handle asynchronicity. + + Example: + return queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + + await queryInterface.createTable('Pokemons', { + pokedexNumber: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, + name: { type: Sequelize.STRING, allowNull: false }, + generationNumber: { type: Sequelize.INTEGER, allowNull: false }, + fromId: { type: Sequelize.INTEGER, allowNull: true }, + isProtected: { type: Sequelize.TINYINT, default: 0 }, + createdAt: { type: Sequelize.DATE, defaultValue: Sequelize.literal('CURRENT_TIMESTAMP') }, + updatedAt: { + type: Sequelize.DATE, + defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP') + }, + deletedAt: { type: Sequelize.DATE }, + }) + + await queryInterface.createTable('Forms', { + id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, + name: { type: Sequelize.STRING, allowNull: false }, + createdAt: { type: Sequelize.DATE, defaultValue: Sequelize.literal('CURRENT_TIMESTAMP') }, + updatedAt: { + type: Sequelize.DATE, + defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP') + }, + deletedAt: { type: Sequelize.DATE }, + }) + + await queryInterface.createTable('Types', { + id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, + name: { type: Sequelize.STRING, allowNull: false }, + createdAt: { type: Sequelize.DATE, defaultValue: Sequelize.literal('CURRENT_TIMESTAMP') }, + updatedAt: { + type: Sequelize.DATE, + defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP') + }, + deletedAt: { type: Sequelize.DATE }, + }) + + await queryInterface.createTable('PokemonTypes', { + PokemonPokedexNumber: { + type: Sequelize.INTEGER, + autoIncrement: true, + primaryKey: true, + references: { model: 'Pokemons', key: 'pokedexNumber' } + }, + TypeId: { + type: Sequelize.INTEGER, + allowNull: false, + primaryKey: true, + references: { model: 'Types', key: 'id' } + }, + createdAt: { type: Sequelize.DATE, defaultValue: Sequelize.literal('CURRENT_TIMESTAMP') }, + updatedAt: { + type: Sequelize.DATE, + defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP') + }, + deletedAt: { type: Sequelize.DATE }, + }) + + return queryInterface.createTable('PokemonForms', { + id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, + PokemonPokedexNumber: { + type: Sequelize.INTEGER, + references: { model: 'Pokemons', key: 'pokedexNumber' } + }, + FormId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { model: 'Forms', key: 'id' } + }, + createdAt: { type: Sequelize.DATE, defaultValue: Sequelize.literal('CURRENT_TIMESTAMP') }, + updatedAt: { + type: Sequelize.DATE, + defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP') + }, + deletedAt: { type: Sequelize.DATE }, + }) + }, + + down: async (queryInterface) => { + /* + Add reverting commands here. + Return a promise to correctly handle asynchronicity. + Example: + return queryInterface.dropTable('users'); + */ + + await queryInterface.dropTable('PokemonForms') + + await queryInterface.dropTable('Forms') + + await queryInterface.dropTable('PokemonTypes') + + await queryInterface.dropTable('Types') + + return queryInterface.dropTable('Pokemons') + } +} diff --git a/migrations/20200524230810-initial-data-load-first-gen.js b/migrations/20200524230810-initial-data-load-first-gen.js new file mode 100644 index 0000000..b501aa6 --- /dev/null +++ b/migrations/20200524230810-initial-data-load-first-gen.js @@ -0,0 +1,994 @@ +module.exports = { + up: async (queryInterface, Sequelize) => { + /* + Add altering commands here. + Return a promise to correctly handle asynchronicity. + + Example: + return queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + + await queryInterface.bulkInsert('Pokemons', [ + { name: 'Bulbasaur', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Ivysaur', generationNumber: 1, fromId: 1, isProtected: 1 }, + { name: 'Venusaur', generationNumber: 1, fromId: 2, isProtected: 1 }, + { name: 'Charmander', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Charmeleon', generationNumber: 1, fromId: 4, isProtected: 1 }, + { name: 'Charizard', generationNumber: 1, fromId: 5, isProtected: 1 }, + { name: 'Squirtle', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Wartortle', generationNumber: 1, fromId: 7, isProtected: 1 }, + { name: 'Blastoise', generationNumber: 1, fromId: 8, isProtected: 1 }, + { name: 'Caterpie', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Metapod', generationNumber: 1, fromId: 10, isProtected: 1 }, + { name: 'Butterfree', generationNumber: 1, fromId: 11, isProtected: 1 }, + { name: 'Weedle', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Kakuna', generationNumber: 1, fromId: 13, isProtected: 1 }, + { name: 'Beedrill', generationNumber: 1, fromId: 14, isProtected: 1 }, + { name: 'Pidgey', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Pidgeotto', generationNumber: 1, fromId: 16, isProtected: 1 }, + { name: 'Pidgeot', generationNumber: 1, fromId: 17, isProtected: 1 }, + { name: 'Rattata', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Raticate', generationNumber: 1, fromId: 19, isProtected: 1 }, + { name: 'Spearow', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Fearow', generationNumber: 1, fromId: 21, isProtected: 1 }, + { name: 'Ekans', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Arbok', generationNumber: 1, fromId: 23, isProtected: 1 }, + { name: 'Pikachu', generationNumber: 1, fromId: 172, isProtected: 1 }, + { name: 'Raichu', generationNumber: 1, fromId: 25, isProtected: 1 }, + { name: 'Sandshrew', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Sandslash', generationNumber: 1, fromId: 27, isProtected: 1 }, + { name: 'Nidoran♀', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Nidorina', generationNumber: 1, fromId: 29, isProtected: 1 }, + { name: 'Nidoqueen', generationNumber: 1, fromId: 30, isProtected: 1 }, + { name: 'Nidoran♂', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Nidorino', generationNumber: 1, fromId: 32, isProtected: 1 }, + { name: 'Nidoking', generationNumber: 1, fromId: 33, isProtected: 1 }, + { name: 'Clefairy', generationNumber: 1, fromId: 173, isProtected: 1 }, + { name: 'Clefable', generationNumber: 1, fromId: 35, isProtected: 1 }, + { name: 'Vulpix', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Ninetales', generationNumber: 1, fromId: 37, isProtected: 1 }, + { name: 'Jigglypuff', generationNumber: 1, fromId: 174, isProtected: 1 }, + { name: 'Wigglytuff', generationNumber: 1, fromId: 39, isProtected: 1 }, + { name: 'Zubat', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Golbat', generationNumber: 1, fromId: 41, isProtected: 1 }, + { name: 'Oddish', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Gloom', generationNumber: 1, fromId: 43, isProtected: 1 }, + { name: 'Vileplume', generationNumber: 1, fromId: 44, isProtected: 1 }, + { name: 'Paras', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Parasect', generationNumber: 1, fromId: 46, isProtected: 1 }, + { name: 'Venonat', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Venomoth', generationNumber: 1, fromId: 48, isProtected: 1 }, + { name: 'Diglett', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Dugtrio', generationNumber: 1, fromId: 50, isProtected: 1 }, + { name: 'Meowth', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Persian', generationNumber: 1, fromId: 52, isProtected: 1 }, + { name: 'Psyduck', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Golduck', generationNumber: 1, fromId: 55, isProtected: 1 }, + { name: 'Mankey', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Primeape', generationNumber: 1, fromId: 56, isProtected: 1 }, + { name: 'Growlithe', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Arcanine', generationNumber: 1, fromId: 58, isProtected: 1 }, + { name: 'Poliwag', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Poliwhirl', generationNumber: 1, fromId: 60, isProtected: 1 }, + { name: 'Poliwrath', generationNumber: 1, fromId: 61, isProtected: 1 }, + { name: 'Abra', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Kadabra', generationNumber: 1, fromId: 63, isProtected: 1 }, + { name: 'Alakazam', generationNumber: 1, fromId: 64, isProtected: 1 }, + { name: 'Machop', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Machoke', generationNumber: 1, fromId: 66, isProtected: 1 }, + { name: 'Machamp', generationNumber: 1, fromId: 67, isProtected: 1 }, + { name: 'Bellsprout', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Weepinbell', generationNumber: 1, fromId: 69, isProtected: 1 }, + { name: 'Victreebel', generationNumber: 1, fromId: 70, isProtected: 1 }, + { name: 'Tentacool', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Tentacruel', generationNumber: 1, fromId: 72, isProtected: 1 }, + { name: 'Geodude', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Graveler', generationNumber: 1, fromId: 74, isProtected: 1 }, + { name: 'Golem', generationNumber: 1, fromId: 75, isProtected: 1 }, + { name: 'Ponyta', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Rapidash', generationNumber: 1, fromId: 77, isProtected: 1 }, + { name: 'Slowpoke', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Slowbro', generationNumber: 1, fromId: 79, isProtected: 1 }, + { name: 'Magnemite', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Magneton', generationNumber: 1, fromId: 81, isProtected: 1 }, + { name: 'Farfetch\'d', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Doduo', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Dodrio', generationNumber: 1, fromId: 84, isProtected: 1 }, + { name: 'Seel', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Dewgong', generationNumber: 1, fromId: 86, isProtected: 1 }, + { name: 'Grimer', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Muk', generationNumber: 1, fromId: 88, isProtected: 1 }, + { name: 'Shellder', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Cloyster', generationNumber: 1, fromId: 90, isProtected: 1 }, + { name: 'Gastly', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Haunter', generationNumber: 1, fromId: 92, isProtected: 1 }, + { name: 'Gengar', generationNumber: 1, fromId: 93, isProtected: 1 }, + { name: 'Onix', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Drowzee', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Hypno', generationNumber: 1, fromId: 96, isProtected: 1 }, + { name: 'Krabby', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Kingler', generationNumber: 1, fromId: 98, isProtected: 1 }, + { name: 'Voltorb', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Electrode', generationNumber: 1, fromId: 100, isProtected: 1 }, + { name: 'Exeggcute', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Exeggutor', generationNumber: 1, fromId: 102, isProtected: 1 }, + { name: 'Cubone', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Marowak', generationNumber: 1, fromId: 104, isProtected: 1 }, + { name: 'Hitmonlee', generationNumber: 1, fromId: 236, isProtected: 1 }, + { name: 'Hitmonchan', generationNumber: 1, fromId: 236, isProtected: 1 }, + { name: 'Lickitung', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Koffing', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Weezing', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Rhyhorn', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Rhydon', generationNumber: 1, fromId: 111, isProtected: 1 }, + { name: 'Chansey', generationNumber: 1, fromId: 440, isProtected: 1 }, + { name: 'Tangela', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Kangaskhan', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Horsea', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Seadra', generationNumber: 1, fromId: 116, isProtected: 1 }, + { name: 'Goldeen', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Seaking', generationNumber: 1, fromId: 118, isProtected: 1 }, + { name: 'Staryu', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Starmie', generationNumber: 1, fromId: 120, isProtected: 1 }, + { name: 'Mr. Mime', generationNumber: 1, fromId: 439, isProtected: 1 }, + { name: 'Scyther', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Jynx', generationNumber: 1, fromId: 238, isProtected: 1 }, + { name: 'Electabuzz', generationNumber: 1, fromId: 239, isProtected: 1 }, + { name: 'Magmar', generationNumber: 1, fromId: 240, isProtected: 1 }, + { name: 'Pinsir', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Tauros', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Magikarp', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Gyrados', generationNumber: 1, fromId: 129, isProtected: 1 }, + { name: 'Lapras', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Ditto', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Eevee', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Vaporeon', generationNumber: 1, fromId: 133, isProtected: 1 }, + { name: 'Jolteon', generationNumber: 1, fromId: 133, isProtected: 1 }, + { name: 'Flareon', generationNumber: 1, fromId: 133, isProtected: 1 }, + { name: 'Porygon', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Omanyte', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Omastar', generationNumber: 1, fromId: 138, isProtected: 1 }, + { name: 'Kabuto', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Kabutops', generationNumber: 1, fromId: 140, isProtected: 1 }, + { name: 'Aerodactyl', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Snorlax', generationNumber: 1, fromId: 446, isProtected: 1 }, + { name: 'Articuno', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Zapdos', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Moltres', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Dratini', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Dragonair', generationNumber: 1, fromId: 147, isProtected: 1 }, + { name: 'Dragonite', generationNumber: 1, fromId: 148, isProtected: 1 }, + { name: 'Mewtwo', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Mew', generationNumber: 1, fromId: null, isProtected: 1 }, + { name: 'Chikorita', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Bayleef', generationNumber: 2, fromId: 153, isProtected: 1 }, + { name: 'Meganium', generationNumber: 2, fromId: 154, isProtected: 1 }, + { name: 'Cyndaquil', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Quilava', generationNumber: 2, fromId: 155, isProtected: 1 }, + { name: 'Typhlosion', generationNumber: 2, fromId: 156, isProtected: 1 }, + { name: 'Totodile', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Croconaw', generationNumber: 2, fromId: 158, isProtected: 1 }, + { name: 'Feraligatr', generationNumber: 2, fromId: 159, isProtected: 1 }, + { name: 'Sentret', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Furret', generationNumber: 2, fromId: 161, isProtected: 1 }, + { name: 'Hoothoot', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Noctowl', generationNumber: 2, fromId: 163, isProtected: 1 }, + { name: 'Ledyba', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Ledian', generationNumber: 2, fromId: 165, isProtected: 1 }, + { name: 'Spinarak', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Ariados', generationNumber: 2, fromId: 167, isProtected: 1 }, + { name: 'Crobat', generationNumber: 2, fromId: 42, isProtected: 1 }, + { name: 'Chinchou', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Lanturn', generationNumber: 2, fromId: 170, isProtected: 1 }, + { name: 'Pichu', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Cleffa', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Igglybuff', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Togepi', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Togetic', generationNumber: 2, fromId: 175, isProtected: 1 }, + { name: 'Natu', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Xatu', generationNumber: 2, fromId: 177, isProtected: 1 }, + { name: 'Mareep', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Flaaffy', generationNumber: 2, fromId: 179, isProtected: 1 }, + { name: 'Ampharos', generationNumber: 2, fromId: 180, isProtected: 1 }, + { name: 'Bellossom', generationNumber: 2, fromId: 44, isProtected: 1 }, + { name: 'Marill', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Azumarill', generationNumber: 2, fromId: 183, isProtected: 1 }, + { name: 'Sudowoodo', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Politoed', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Hoppip', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Skiploom', generationNumber: 2, fromId: 187, isProtected: 1 }, + { name: 'Jumpluff', generationNumber: 2, fromId: 188, isProtected: 1 }, + { name: 'Aipom', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Sunkern', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Sunflora', generationNumber: 2, fromId: 191, isProtected: 1 }, + { name: 'Yanma', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Wooper', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Quagsire', generationNumber: 2, fromId: 194, isProtected: 1 }, + { name: 'Espeon', generationNumber: 2, fromId: 133, isProtected: 1 }, + { name: 'Umbreon', generationNumber: 2, fromId: 133, isProtected: 1 }, + { name: 'Murkrow', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Slowking', generationNumber: 2, fromId: 79, isProtected: 1 }, + { name: 'Misdreavus', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Unown', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Wobbuffet', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Girafarig', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Pineco', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Forretress', generationNumber: 2, fromId: 204, isProtected: 1 }, + { name: 'Dunsparce', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Gligar', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Steelix', generationNumber: 2, fromId: 95, isProtected: 1 }, + { name: 'Snubbull', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Granbull', generationNumber: 2, fromId: 209, isProtected: 1 }, + { name: 'Qwilfish', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Scizor', generationNumber: 2, fromId: 12, isProtected: 1 }, + { name: 'Shuckle', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Heracross', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Sneasel', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Teddiursa', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Ursaring', generationNumber: 2, fromId: 216, isProtected: 1 }, + { name: 'Slugma', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Magcargo', generationNumber: 2, fromId: 218, isProtected: 1 }, + { name: 'Swinub', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Piloswine', generationNumber: 2, fromId: 220, isProtected: 1 }, + { name: 'Corsola', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Remoraid', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Octillery', generationNumber: 2, fromId: 223, isProtected: 1 }, + { name: 'Delibird', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Mantine', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Skarmory', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Houndour', generationNumber: 2, fromId: 228, isProtected: 1 }, + { name: 'Houndoom', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Kingdra', generationNumber: 2, fromId: 117, isProtected: 1 }, + { name: 'Phanpy', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Donphan', generationNumber: 2, fromId: 231, isProtected: 1 }, + { name: 'Porygon2', generationNumber: 2, fromId: 137, isProtected: 1 }, + { name: 'Stantler', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Smeargle', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Tyrogue', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Hitmontop', generationNumber: 2, fromId: 236, isProtected: 1 }, + { name: 'Smoochum', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Elekid', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Magby', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Miltank', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Blissey', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Raikou', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Entei', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Suicune', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Larvitar', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Pupitar', generationNumber: 2, fromId: 246, isProtected: 1 }, + { name: 'Tyranitar', generationNumber: 2, fromId: 247, isProtected: 1 }, + { name: 'Lugia', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Ho-Oh', generationNumber: 2, fromId: null, isProtected: 1 }, + { name: 'Celebi', generationNumber: 2, fromId: null, isProtected: 1 }, + ]) + + await queryInterface.bulkInsert('Types', [ + { name: 'Bug' }, + { name: 'Dark' }, + { name: 'Dragon' }, + { name: 'Electric' }, + { name: 'Fairy' }, + { name: 'Fighting' }, + { name: 'Fire' }, + { name: 'Flying' }, + { name: 'Ghost' }, + { name: 'Grass' }, + { name: 'Ground' }, + { name: 'Ice' }, + { name: 'Normal' }, + { name: 'Poison' }, + { name: 'Psychic' }, + { name: 'Rock' }, + { name: 'Steel' }, + { name: 'Water' } + ]) + + await queryInterface.bulkInsert('Forms', [ + { name: 'Gender' }, + { name: 'Alternate' }, + { name: 'Mega' }, + { name: 'Alolan' }, + { name: 'Galarian' }, + { name: 'Gigantamax' } + ]) + + await queryInterface.bulkInsert('PokemonTypes', [ + { PokemonPokedexNumber: 1, typeId: 10 }, + { PokemonPokedexNumber: 1, typeId: 14 }, + { PokemonPokedexNumber: 2, typeId: 10 }, + { PokemonPokedexNumber: 2, typeId: 14 }, + { PokemonPokedexNumber: 3, typeId: 10 }, + { PokemonPokedexNumber: 3, typeId: 14 }, + { PokemonPokedexNumber: 4, typeId: 7 }, + { PokemonPokedexNumber: 5, typeId: 7 }, + { PokemonPokedexNumber: 6, typeId: 7 }, + { PokemonPokedexNumber: 6, typeId: 8 }, + { PokemonPokedexNumber: 7, typeId: 18 }, + { PokemonPokedexNumber: 8, typeId: 18 }, + { PokemonPokedexNumber: 9, typeId: 18 }, + { PokemonPokedexNumber: 10, typeId: 1 }, + { PokemonPokedexNumber: 11, typeId: 1 }, + { PokemonPokedexNumber: 12, typeId: 1 }, + { PokemonPokedexNumber: 12, typeId: 8 }, + { PokemonPokedexNumber: 13, typeId: 1 }, + { PokemonPokedexNumber: 13, typeId: 14 }, + { PokemonPokedexNumber: 14, typeId: 1 }, + { PokemonPokedexNumber: 14, typeId: 14 }, + { PokemonPokedexNumber: 15, typeId: 1 }, + { PokemonPokedexNumber: 15, typeId: 14 }, + { PokemonPokedexNumber: 16, typeId: 13 }, + { PokemonPokedexNumber: 16, typeId: 8 }, + { PokemonPokedexNumber: 17, typeId: 13 }, + { PokemonPokedexNumber: 17, typeId: 8 }, + { PokemonPokedexNumber: 18, typeId: 13 }, + { PokemonPokedexNumber: 18, typeId: 8 }, + { PokemonPokedexNumber: 19, typeId: 13 }, + { PokemonPokedexNumber: 20, typeId: 13 }, + { PokemonPokedexNumber: 21, typeId: 13 }, + { PokemonPokedexNumber: 21, typeId: 8 }, + { PokemonPokedexNumber: 22, typeId: 13 }, + { PokemonPokedexNumber: 22, typeId: 8 }, + { PokemonPokedexNumber: 23, typeId: 14 }, + { PokemonPokedexNumber: 24, typeId: 14 }, + { PokemonPokedexNumber: 25, typeId: 4 }, + { PokemonPokedexNumber: 26, typeId: 4 }, + { PokemonPokedexNumber: 27, typeId: 11 }, + { PokemonPokedexNumber: 28, typeId: 11 }, + { PokemonPokedexNumber: 29, typeId: 14 }, + { PokemonPokedexNumber: 30, typeId: 14 }, + { PokemonPokedexNumber: 31, typeId: 14 }, + { PokemonPokedexNumber: 31, typeId: 11 }, + { PokemonPokedexNumber: 32, typeId: 14 }, + { PokemonPokedexNumber: 33, typeId: 14 }, + { PokemonPokedexNumber: 34, typeId: 14 }, + { PokemonPokedexNumber: 34, typeId: 11 }, + { PokemonPokedexNumber: 35, typeId: 5 }, + { PokemonPokedexNumber: 36, typeId: 5 }, + { PokemonPokedexNumber: 37, typeId: 7 }, + { PokemonPokedexNumber: 38, typeId: 7 }, + { PokemonPokedexNumber: 39, typeId: 13 }, + { PokemonPokedexNumber: 39, typeId: 5 }, + { PokemonPokedexNumber: 40, typeId: 13 }, + { PokemonPokedexNumber: 40, typeId: 5 }, + { PokemonPokedexNumber: 41, typeId: 14 }, + { PokemonPokedexNumber: 41, typeId: 8 }, + { PokemonPokedexNumber: 42, typeId: 14 }, + { PokemonPokedexNumber: 42, typeId: 8 }, + { PokemonPokedexNumber: 43, typeId: 10 }, + { PokemonPokedexNumber: 43, typeId: 14 }, + { PokemonPokedexNumber: 44, typeId: 10 }, + { PokemonPokedexNumber: 44, typeId: 14 }, + { PokemonPokedexNumber: 45, typeId: 10 }, + { PokemonPokedexNumber: 45, typeId: 14 }, + { PokemonPokedexNumber: 46, typeId: 1 }, + { PokemonPokedexNumber: 46, typeId: 10 }, + { PokemonPokedexNumber: 47, typeId: 1 }, + { PokemonPokedexNumber: 47, typeId: 10 }, + { PokemonPokedexNumber: 48, typeId: 1 }, + { PokemonPokedexNumber: 48, typeId: 14 }, + { PokemonPokedexNumber: 49, typeId: 1 }, + { PokemonPokedexNumber: 49, typeId: 14 }, + { PokemonPokedexNumber: 50, typeId: 11 }, + { PokemonPokedexNumber: 51, typeId: 11 }, + { PokemonPokedexNumber: 52, typeId: 13 }, + { PokemonPokedexNumber: 53, typeId: 13 }, + { PokemonPokedexNumber: 54, typeId: 18 }, + { PokemonPokedexNumber: 55, typeId: 18 }, + { PokemonPokedexNumber: 56, typeId: 6 }, + { PokemonPokedexNumber: 57, typeId: 6 }, + { PokemonPokedexNumber: 58, typeId: 7 }, + { PokemonPokedexNumber: 59, typeId: 7 }, + { PokemonPokedexNumber: 60, typeId: 18 }, + { PokemonPokedexNumber: 61, typeId: 18 }, + { PokemonPokedexNumber: 62, typeId: 18 }, + { PokemonPokedexNumber: 62, typeId: 6 }, + { PokemonPokedexNumber: 63, typeId: 15 }, + { PokemonPokedexNumber: 64, typeId: 15 }, + { PokemonPokedexNumber: 65, typeId: 15 }, + { PokemonPokedexNumber: 66, typeId: 6 }, + { PokemonPokedexNumber: 67, typeId: 6 }, + { PokemonPokedexNumber: 68, typeId: 6 }, + { PokemonPokedexNumber: 69, typeId: 10 }, + { PokemonPokedexNumber: 69, typeId: 14 }, + { PokemonPokedexNumber: 70, typeId: 10 }, + { PokemonPokedexNumber: 70, typeId: 14 }, + { PokemonPokedexNumber: 71, typeId: 10 }, + { PokemonPokedexNumber: 71, typeId: 14 }, + { PokemonPokedexNumber: 72, typeId: 18 }, + { PokemonPokedexNumber: 72, typeId: 14 }, + { PokemonPokedexNumber: 73, typeId: 18 }, + { PokemonPokedexNumber: 73, typeId: 14 }, + { PokemonPokedexNumber: 74, typeId: 16 }, + { PokemonPokedexNumber: 74, typeId: 11 }, + { PokemonPokedexNumber: 75, typeId: 16 }, + { PokemonPokedexNumber: 75, typeId: 11 }, + { PokemonPokedexNumber: 76, typeId: 16 }, + { PokemonPokedexNumber: 76, typeId: 11 }, + { PokemonPokedexNumber: 77, typeId: 7 }, + { PokemonPokedexNumber: 78, typeId: 7 }, + { PokemonPokedexNumber: 79, typeId: 18 }, + { PokemonPokedexNumber: 79, typeId: 15 }, + { PokemonPokedexNumber: 80, typeId: 18 }, + { PokemonPokedexNumber: 80, typeId: 15 }, + { PokemonPokedexNumber: 81, typeId: 4 }, + { PokemonPokedexNumber: 81, typeId: 17 }, + { PokemonPokedexNumber: 82, typeId: 4 }, + { PokemonPokedexNumber: 82, typeId: 17 }, + { PokemonPokedexNumber: 83, typeId: 13 }, + { PokemonPokedexNumber: 83, typeId: 8 }, + { PokemonPokedexNumber: 84, typeId: 13 }, + { PokemonPokedexNumber: 84, typeId: 8 }, + { PokemonPokedexNumber: 85, typeId: 13 }, + { PokemonPokedexNumber: 85, typeId: 8 }, + { PokemonPokedexNumber: 86, typeId: 18 }, + { PokemonPokedexNumber: 87, typeId: 18 }, + { PokemonPokedexNumber: 87, typeId: 12 }, + { PokemonPokedexNumber: 88, typeId: 14 }, + { PokemonPokedexNumber: 89, typeId: 14 }, + { PokemonPokedexNumber: 90, typeId: 18 }, + { PokemonPokedexNumber: 91, typeId: 18 }, + { PokemonPokedexNumber: 91, typeId: 12 }, + { PokemonPokedexNumber: 92, typeId: 9 }, + { PokemonPokedexNumber: 92, typeId: 14 }, + { PokemonPokedexNumber: 93, typeId: 9 }, + { PokemonPokedexNumber: 93, typeId: 14 }, + { PokemonPokedexNumber: 94, typeId: 9 }, + { PokemonPokedexNumber: 94, typeId: 14 }, + { PokemonPokedexNumber: 95, typeId: 16 }, + { PokemonPokedexNumber: 95, typeId: 11 }, + { PokemonPokedexNumber: 96, typeId: 15 }, + { PokemonPokedexNumber: 97, typeId: 15 }, + { PokemonPokedexNumber: 98, typeId: 18 }, + { PokemonPokedexNumber: 99, typeId: 18 }, + { PokemonPokedexNumber: 100, typeId: 4 }, + { PokemonPokedexNumber: 101, typeId: 4 }, + { PokemonPokedexNumber: 102, typeId: 10 }, + { PokemonPokedexNumber: 102, typeId: 15 }, + { PokemonPokedexNumber: 103, typeId: 10 }, + { PokemonPokedexNumber: 103, typeId: 15 }, + { PokemonPokedexNumber: 104, typeId: 11 }, + { PokemonPokedexNumber: 105, typeId: 11 }, + { PokemonPokedexNumber: 106, typeId: 6 }, + { PokemonPokedexNumber: 107, typeId: 6 }, + { PokemonPokedexNumber: 108, typeId: 13 }, + { PokemonPokedexNumber: 109, typeId: 14 }, + { PokemonPokedexNumber: 110, typeId: 14 }, + { PokemonPokedexNumber: 111, typeId: 11 }, + { PokemonPokedexNumber: 111, typeId: 16 }, + { PokemonPokedexNumber: 112, typeId: 11 }, + { PokemonPokedexNumber: 112, typeId: 16 }, + { PokemonPokedexNumber: 113, typeId: 13 }, + { PokemonPokedexNumber: 114, typeId: 10 }, + { PokemonPokedexNumber: 115, typeId: 13 }, + { PokemonPokedexNumber: 116, typeId: 18 }, + { PokemonPokedexNumber: 117, typeId: 18 }, + { PokemonPokedexNumber: 118, typeId: 18 }, + { PokemonPokedexNumber: 119, typeId: 18 }, + { PokemonPokedexNumber: 120, typeId: 18 }, + { PokemonPokedexNumber: 121, typeId: 18 }, + { PokemonPokedexNumber: 121, typeId: 15 }, + { PokemonPokedexNumber: 122, typeId: 15 }, + { PokemonPokedexNumber: 122, typeId: 5 }, + { PokemonPokedexNumber: 123, typeId: 1 }, + { PokemonPokedexNumber: 123, typeId: 8 }, + { PokemonPokedexNumber: 124, typeId: 12 }, + { PokemonPokedexNumber: 124, typeId: 15 }, + { PokemonPokedexNumber: 125, typeId: 4 }, + { PokemonPokedexNumber: 126, typeId: 7 }, + { PokemonPokedexNumber: 127, typeId: 1 }, + { PokemonPokedexNumber: 128, typeId: 13 }, + { PokemonPokedexNumber: 129, typeId: 18 }, + { PokemonPokedexNumber: 130, typeId: 18 }, + { PokemonPokedexNumber: 130, typeId: 8 }, + { PokemonPokedexNumber: 131, typeId: 18 }, + { PokemonPokedexNumber: 131, typeId: 12 }, + { PokemonPokedexNumber: 132, typeId: 13 }, + { PokemonPokedexNumber: 133, typeId: 13 }, + { PokemonPokedexNumber: 134, typeId: 18 }, + { PokemonPokedexNumber: 135, typeId: 4 }, + { PokemonPokedexNumber: 136, typeId: 7 }, + { PokemonPokedexNumber: 137, typeId: 13 }, + { PokemonPokedexNumber: 138, typeId: 16 }, + { PokemonPokedexNumber: 138, typeId: 18 }, + { PokemonPokedexNumber: 139, typeId: 16 }, + { PokemonPokedexNumber: 139, typeId: 18 }, + { PokemonPokedexNumber: 140, typeId: 16 }, + { PokemonPokedexNumber: 140, typeId: 18 }, + { PokemonPokedexNumber: 141, typeId: 16 }, + { PokemonPokedexNumber: 141, typeId: 18 }, + { PokemonPokedexNumber: 142, typeId: 16 }, + { PokemonPokedexNumber: 142, typeId: 8 }, + { PokemonPokedexNumber: 143, typeId: 13 }, + { PokemonPokedexNumber: 144, typeId: 12 }, + { PokemonPokedexNumber: 144, typeId: 8 }, + { PokemonPokedexNumber: 145, typeId: 4 }, + { PokemonPokedexNumber: 145, typeId: 8 }, + { PokemonPokedexNumber: 146, typeId: 7 }, + { PokemonPokedexNumber: 146, typeId: 8 }, + { PokemonPokedexNumber: 147, typeId: 3 }, + { PokemonPokedexNumber: 148, typeId: 3 }, + { PokemonPokedexNumber: 149, typeId: 3 }, + { PokemonPokedexNumber: 149, typeId: 8 }, + { PokemonPokedexNumber: 150, typeId: 15 }, + { PokemonPokedexNumber: 151, typeId: 15 }, + { PokemonPokedexNumber: 152, typeId: 10 }, + { PokemonPokedexNumber: 153, typeId: 10 }, + { PokemonPokedexNumber: 154, typeId: 10 }, + { PokemonPokedexNumber: 155, typeId: 7 }, + { PokemonPokedexNumber: 156, typeId: 7 }, + { PokemonPokedexNumber: 157, typeId: 7 }, + { PokemonPokedexNumber: 158, typeId: 18 }, + { PokemonPokedexNumber: 159, typeId: 18 }, + { PokemonPokedexNumber: 160, typeId: 18 }, + { PokemonPokedexNumber: 161, typeId: 13 }, + { PokemonPokedexNumber: 162, typeId: 13 }, + { PokemonPokedexNumber: 163, typeId: 13 }, + { PokemonPokedexNumber: 163, typeId: 8 }, + { PokemonPokedexNumber: 164, typeId: 13 }, + { PokemonPokedexNumber: 164, typeId: 8 }, + { PokemonPokedexNumber: 165, typeId: 1 }, + { PokemonPokedexNumber: 165, typeId: 8 }, + { PokemonPokedexNumber: 166, typeId: 1 }, + { PokemonPokedexNumber: 166, typeId: 8 }, + { PokemonPokedexNumber: 167, typeId: 1 }, + { PokemonPokedexNumber: 167, typeId: 14 }, + { PokemonPokedexNumber: 168, typeId: 1 }, + { PokemonPokedexNumber: 168, typeId: 14 }, + { PokemonPokedexNumber: 169, typeId: 14 }, + { PokemonPokedexNumber: 169, typeId: 8 }, + { PokemonPokedexNumber: 170, typeId: 18 }, + { PokemonPokedexNumber: 170, typeId: 4 }, + { PokemonPokedexNumber: 171, typeId: 18 }, + { PokemonPokedexNumber: 171, typeId: 4 }, + { PokemonPokedexNumber: 172, typeId: 4 }, + { PokemonPokedexNumber: 173, typeId: 5 }, + { PokemonPokedexNumber: 174, typeId: 13 }, + { PokemonPokedexNumber: 174, typeId: 5 }, + { PokemonPokedexNumber: 175, typeId: 5 }, + { PokemonPokedexNumber: 176, typeId: 5 }, + { PokemonPokedexNumber: 176, typeId: 8 }, + { PokemonPokedexNumber: 177, typeId: 15 }, + { PokemonPokedexNumber: 177, typeId: 8 }, + { PokemonPokedexNumber: 178, typeId: 15 }, + { PokemonPokedexNumber: 178, typeId: 8 }, + { PokemonPokedexNumber: 179, typeId: 4 }, + { PokemonPokedexNumber: 180, typeId: 4 }, + { PokemonPokedexNumber: 181, typeId: 4 }, + { PokemonPokedexNumber: 182, typeId: 10 }, + { PokemonPokedexNumber: 183, typeId: 18 }, + { PokemonPokedexNumber: 183, typeId: 5 }, + { PokemonPokedexNumber: 184, typeId: 18 }, + { PokemonPokedexNumber: 184, typeId: 5 }, + { PokemonPokedexNumber: 185, typeId: 16 }, + { PokemonPokedexNumber: 186, typeId: 18 }, + { PokemonPokedexNumber: 187, typeId: 10 }, + { PokemonPokedexNumber: 187, typeId: 8 }, + { PokemonPokedexNumber: 188, typeId: 10 }, + { PokemonPokedexNumber: 188, typeId: 8 }, + { PokemonPokedexNumber: 189, typeId: 10 }, + { PokemonPokedexNumber: 189, typeId: 8 }, + { PokemonPokedexNumber: 190, typeId: 13 }, + { PokemonPokedexNumber: 191, typeId: 10 }, + { PokemonPokedexNumber: 192, typeId: 10 }, + { PokemonPokedexNumber: 193, typeId: 1 }, + { PokemonPokedexNumber: 193, typeId: 8 }, + { PokemonPokedexNumber: 194, typeId: 18 }, + { PokemonPokedexNumber: 194, typeId: 11 }, + { PokemonPokedexNumber: 195, typeId: 18 }, + { PokemonPokedexNumber: 195, typeId: 11 }, + { PokemonPokedexNumber: 196, typeId: 15 }, + { PokemonPokedexNumber: 197, typeId: 2 }, + { PokemonPokedexNumber: 198, typeId: 2 }, + { PokemonPokedexNumber: 198, typeId: 8 }, + { PokemonPokedexNumber: 199, typeId: 18 }, + { PokemonPokedexNumber: 199, typeId: 15 }, + { PokemonPokedexNumber: 200, typeId: 9 }, + { PokemonPokedexNumber: 201, typeId: 15 }, + { PokemonPokedexNumber: 202, typeId: 15 }, + { PokemonPokedexNumber: 203, typeId: 13 }, + { PokemonPokedexNumber: 203, typeId: 15 }, + { PokemonPokedexNumber: 204, typeId: 1 }, + { PokemonPokedexNumber: 205, typeId: 1 }, + { PokemonPokedexNumber: 205, typeId: 17 }, + { PokemonPokedexNumber: 206, typeId: 13 }, + { PokemonPokedexNumber: 207, typeId: 11 }, + { PokemonPokedexNumber: 207, typeId: 8 }, + { PokemonPokedexNumber: 208, typeId: 17 }, + { PokemonPokedexNumber: 208, typeId: 11 }, + { PokemonPokedexNumber: 209, typeId: 5 }, + { PokemonPokedexNumber: 210, typeId: 5 }, + { PokemonPokedexNumber: 211, typeId: 18 }, + { PokemonPokedexNumber: 211, typeId: 14 }, + { PokemonPokedexNumber: 212, typeId: 1 }, + { PokemonPokedexNumber: 212, typeId: 17 }, + { PokemonPokedexNumber: 213, typeId: 16 }, + { PokemonPokedexNumber: 214, typeId: 1 }, + { PokemonPokedexNumber: 214, typeId: 16 }, + { PokemonPokedexNumber: 215, typeId: 1 }, + { PokemonPokedexNumber: 215, typeId: 6 }, + { PokemonPokedexNumber: 216, typeId: 13 }, + { PokemonPokedexNumber: 217, typeId: 13 }, + { PokemonPokedexNumber: 218, typeId: 7 }, + { PokemonPokedexNumber: 219, typeId: 7 }, + { PokemonPokedexNumber: 219, typeId: 16 }, + { PokemonPokedexNumber: 220, typeId: 12 }, + { PokemonPokedexNumber: 220, typeId: 11 }, + { PokemonPokedexNumber: 221, typeId: 12 }, + { PokemonPokedexNumber: 221, typeId: 11 }, + { PokemonPokedexNumber: 222, typeId: 18 }, + { PokemonPokedexNumber: 222, typeId: 16 }, + { PokemonPokedexNumber: 223, typeId: 18 }, + { PokemonPokedexNumber: 224, typeId: 18 }, + { PokemonPokedexNumber: 225, typeId: 12 }, + { PokemonPokedexNumber: 225, typeId: 8 }, + { PokemonPokedexNumber: 226, typeId: 18 }, + { PokemonPokedexNumber: 226, typeId: 8 }, + { PokemonPokedexNumber: 227, typeId: 17 }, + { PokemonPokedexNumber: 227, typeId: 8 }, + { PokemonPokedexNumber: 228, typeId: 2 }, + { PokemonPokedexNumber: 228, typeId: 7 }, + { PokemonPokedexNumber: 229, typeId: 2 }, + { PokemonPokedexNumber: 229, typeId: 7 }, + { PokemonPokedexNumber: 230, typeId: 18 }, + { PokemonPokedexNumber: 230, typeId: 3 }, + { PokemonPokedexNumber: 231, typeId: 11 }, + { PokemonPokedexNumber: 232, typeId: 11 }, + { PokemonPokedexNumber: 233, typeId: 13 }, + { PokemonPokedexNumber: 234, typeId: 13 }, + { PokemonPokedexNumber: 235, typeId: 13 }, + { PokemonPokedexNumber: 236, typeId: 6 }, + { PokemonPokedexNumber: 237, typeId: 6 }, + { PokemonPokedexNumber: 238, typeId: 12 }, + { PokemonPokedexNumber: 238, typeId: 15 }, + { PokemonPokedexNumber: 239, typeId: 4 }, + { PokemonPokedexNumber: 240, typeId: 7 }, + { PokemonPokedexNumber: 241, typeId: 13 }, + { PokemonPokedexNumber: 242, typeId: 13 }, + { PokemonPokedexNumber: 243, typeId: 4 }, + { PokemonPokedexNumber: 244, typeId: 7 }, + { PokemonPokedexNumber: 245, typeId: 18 }, + { PokemonPokedexNumber: 246, typeId: 16 }, + { PokemonPokedexNumber: 246, typeId: 11 }, + { PokemonPokedexNumber: 247, typeId: 16 }, + { PokemonPokedexNumber: 247, typeId: 11 }, + { PokemonPokedexNumber: 248, typeId: 16 }, + { PokemonPokedexNumber: 248, typeId: 2 }, + { PokemonPokedexNumber: 249, typeId: 15 }, + { PokemonPokedexNumber: 249, typeId: 8 }, + { PokemonPokedexNumber: 250, typeId: 7 }, + { PokemonPokedexNumber: 250, typeId: 8 }, + { PokemonPokedexNumber: 251, typeId: 15 }, + { PokemonPokedexNumber: 251, typeId: 10 }, + ]) + + return queryInterface.bulkInsert('PokemonForms', [ + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Venusaur\')'), + FormId: 1 + }, + + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Butterfree\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Rattata\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Raticate\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Pickachu\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Raichu\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Nidoran♀\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Nidoran♂\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Zubat\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Golbat\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Gloom\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Vileplume\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Kadabra\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Alakazam\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Doduo\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Dodrio\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Hypno\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Rhyhorn\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Rhydon\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Goldeen\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Seaking\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Scyther\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Magikarp\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Gyarados\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Eevee\')'), + FormId: 1 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Venusaur\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Charizard\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Charizard\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Blastoise\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Alakazam\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Gengar\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Kangaskhan\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Pinsir\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Gyarados\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Aerodactyl\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Mewtwo\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Mewtwo\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Beedrill\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Pidgeot\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Slowbro\')'), + FormId: 3 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Rattata\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Raticate\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Raichu\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Sandshrew\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Sandslash\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Ninetales\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Vulpix\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Diglett\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Dugtrio\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Meowth\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Persian\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Geodude\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Graveler\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Golem\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Grimer\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Muk\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Exeggutor\')'), + FormId: 4 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Marowak\')'), + FormId: 4 + }, + + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Meowth\')'), + FormId: 5 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Ponyta\')'), + FormId: 5 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Rapidash\')'), + FormId: 5 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Slowpoke\')'), + FormId: 5 + }, + { PokemonPokedexNumber: 83, FormId: 5 }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Weezing\')'), + FormId: 5 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Mr. Mime\')'), + FormId: 5 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Venusaur\')'), + FormId: 6 + }, + + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Charizard\')'), + FormId: 6 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Blastoise\')'), + FormId: 6 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Butterfree\')'), + FormId: 6 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Pikachu\')'), + FormId: 6 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Meowth\')'), + FormId: 6 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Machamp\')'), + FormId: 6 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Gengar\')'), + FormId: 6 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Kingler\')'), + FormId: 6 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Lapras\')'), + FormId: 6 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Eevee\')'), + FormId: 6 + }, + { + PokemonPokedexNumber: Sequelize.literal('(SELECT pokedexNumber FROM Pokemons WHERE name = \'Snorlax\')'), + FormId: 6 + }, + ]) + }, + + down: async (queryInterface) => { + /* + Add reverting commands here. + Return a promise to correctly handle asynchronicity. + + Example: + return queryInterface.dropTable('users'); + */ + await queryInterface.bulkDelete('PokemonTypes') + + await queryInterface.bulkDelete('PokemonForms') + + await queryInterface.bulkDelete('Forms') + + await queryInterface.bulkDelete('Types') + + return queryInterface.bulkDelete('Pokemons') + } +} diff --git a/models/Forms.js b/models/Forms.js new file mode 100644 index 0000000..0cdb20c --- /dev/null +++ b/models/Forms.js @@ -0,0 +1,14 @@ +const Forms = (connection, Sequelize) => { + return connection.define('Forms', { + id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, + name: { type: Sequelize.STRING, allowNull: false } + }, { + defaultScope: { + attributes: { exclude: ['deletedAt'] } + } + }, { + paranoid: true, + }) +} + +module.exports = Forms diff --git a/models/PokemonForms.js b/models/PokemonForms.js new file mode 100644 index 0000000..2a3e008 --- /dev/null +++ b/models/PokemonForms.js @@ -0,0 +1,22 @@ +const PokemonForms = (connection, Sequelize, Forms, Pokemons) => { + return connection.define('PokemonForms', { + id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, + PokemonPokedexNumber: { + type: Sequelize.INTEGER, + references: { model: Pokemons, key: 'pokedexNumber' } + }, + FormId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { model: Forms, key: 'id' } + } + }, { + defaultScope: { + attributes: { exclude: ['deletedAt'] } + } + }, { + paranoid: true, + }) +} + +module.exports = PokemonForms diff --git a/models/PokemonTypes.js b/models/PokemonTypes.js new file mode 100644 index 0000000..a1cdba0 --- /dev/null +++ b/models/PokemonTypes.js @@ -0,0 +1,19 @@ +const PokemonTypes = (connection, Sequelize, Pokemons, Types) => { + return connection.define('PokemonTypes', { + PokemonPokedexNumber: { + type: Sequelize.INTEGER, + autoIncrement: true, + primaryKey: true, + references: { model: Pokemons, key: 'pokedexNumber' } + }, + TypeId: { type: Sequelize.INTEGER, allowNull: false, primaryKey: true, references: { model: Types, key: 'id' } } + }, { + defaultScope: { + attributes: { exclude: ['deletedAt'] } + } + }, { + paranoid: true, + }) +} + +module.exports = PokemonTypes diff --git a/models/Pokemons.js b/models/Pokemons.js new file mode 100644 index 0000000..64556c9 --- /dev/null +++ b/models/Pokemons.js @@ -0,0 +1,17 @@ +const Pokemons = (connection, Sequelize) => { + return connection.define('Pokemons', { + pokedexNumber: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, + name: { type: Sequelize.STRING, allowNull: false }, + generationNumber: { type: Sequelize.INTEGER, allowNull: false }, + fromId: { type: Sequelize.INTEGER, allowNull: true }, + isProtected: { type: Sequelize.TINYINT, default: 0 } + }, { + defaultScope: { + attributes: { exclude: ['deletedAt'] } + } + }, { + paranoid: true, + }) +} + +module.exports = Pokemons diff --git a/models/Types.js b/models/Types.js new file mode 100644 index 0000000..17c9860 --- /dev/null +++ b/models/Types.js @@ -0,0 +1,14 @@ +const Types = (connection, Sequelize) => { + return connection.define('Types', { + id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, + name: { type: Sequelize.STRING, allowNull: false }, + }, { + defaultScope: { + attributes: { exclude: ['deletedAt'] } + } + }, { + paranoid: true, + }) +} + +module.exports = Types diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..cf57598 --- /dev/null +++ b/models/index.js @@ -0,0 +1,35 @@ +const Sequelize = require('sequelize') +const PokemonsModel = require('./Pokemons') +const FormsModel = require('./Forms') +const TypesModel = require('./Types') +const PokemonFormsModel = require('./PokemonForms') +const PokemonTypesModel = require('./PokemonTypes') +const allConfigs = require('../configs/sequelize') + +const environment = process.env.NODE_ENV || 'development' +const config = allConfigs[environment] + +const connection = new Sequelize(config.database, config.username, config.password, { + host: config.host, dialect: config.dialect +}) + +const Pokemons = PokemonsModel(connection, Sequelize) +const Forms = FormsModel(connection, Sequelize) +const Types = TypesModel(connection, Sequelize) +const PokemonForms = PokemonFormsModel(connection, Sequelize, Forms, Pokemons) +const PokemonTypes = PokemonTypesModel(connection, Sequelize, Pokemons, Types) + +Pokemons.belongsToMany(Types, { through: PokemonTypes }) +Types.belongsToMany(Pokemons, { through: PokemonTypes }) + +Pokemons.belongsToMany(Forms, { through: PokemonForms }) +Forms.belongsToMany(Pokemons, { through: PokemonForms }) + +module.exports = { + Pokemons, + Forms, + Types, + PokemonForms, + PokemonTypes, + Op: Sequelize.Op +} diff --git a/package-lock.json b/package-lock.json index fffa8bf..0cb017f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,51 @@ "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", "dev": true }, + "@sinonjs/commons": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", + "integrity": "sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz", + "integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, "@szmarczak/http-timer": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", @@ -64,11 +109,15 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/node": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.1.tgz", + "integrity": "sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "accepts": { "version": "1.3.7", @@ -163,6 +212,12 @@ } } }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, "ansi-escapes": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", @@ -190,11 +245,20 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } }, + "ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=" + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, "anymatch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", @@ -224,6 +288,12 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -258,8 +328,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "binary-extensions": { "version": "2.0.0", @@ -267,6 +336,11 @@ "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -371,7 +445,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -386,6 +459,12 @@ "fill-range": "^7.0.1" } }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -432,8 +511,16 @@ "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", + "requires": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + } }, "center-align": { "version": "0.1.3", @@ -444,6 +531,20 @@ "lazy-cache": "^1.0.3" } }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -469,6 +570,12 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "chokidar": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", @@ -505,6 +612,26 @@ "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", "dev": true }, + "cli-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", + "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", + "requires": { + "ansi-regex": "^2.1.1", + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.14", + "timers-ext": "^0.1.5" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -539,11 +666,19 @@ "mimic-response": "^1.0.0" } }, + "cls-bluebird": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", + "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", + "requires": { + "is-bluebird": "^1.0.2", + "shimmer": "^1.1.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -551,20 +686,26 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } }, "configstore": { "version": "5.0.1", @@ -652,11 +793,19 @@ "integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==", "dev": true }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -675,6 +824,15 @@ "mimic-response": "^1.0.0" } }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -693,6 +851,20 @@ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "dev": true }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "denque": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -703,6 +875,12 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -726,12 +904,49 @@ "is-obj": "^2.0.0" } }, + "dottie": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", + "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, + "editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "requires": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -757,6 +972,128 @@ "once": "^1.4.0" } }, + "env-cmd": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz", + "integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==", + "requires": { + "commander": "^4.0.0", + "cross-spawn": "^7.0.0" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" + }, + "cross-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, "escape-goat": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", @@ -858,8 +1195,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { "version": "1.3.1", @@ -903,6 +1239,15 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -955,6 +1300,21 @@ } } }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" + } + } + }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -1046,6 +1406,31 @@ "integrity": "sha1-2wAjj/hoVRoYLnShA0FtKVqYyMo=", "dev": true }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + } + } + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -1073,11 +1458,20 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "2.1.2", @@ -1097,6 +1491,25 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "^1.0.2" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -1110,7 +1523,6 @@ "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1169,7 +1581,12 @@ "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, "has": { @@ -1186,12 +1603,24 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, "has-yarn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", "dev": true }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -1259,11 +1688,15 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1272,14 +1705,12 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { "version": "7.1.0", @@ -1377,11 +1808,22 @@ "binary-extensions": "^2.0.0" } }, + "is-bluebird": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", + "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -1391,6 +1833,12 @@ "ci-info": "^2.0.0" } }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, "is-expression": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", @@ -1467,6 +1915,11 @@ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", @@ -1475,6 +1928,15 @@ "has": "^1.0.3" } }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -1487,11 +1949,44 @@ "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", "dev": true }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-beautify": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.11.0.tgz", + "integrity": "sha512-a26B+Cx7USQGSWnz9YxgJNMmML/QG2nqIaL7VVYPCXbqiKz8PN0waSNvroMtvAK6tY7g/wPdNWGEP+JTNIBr6A==", + "requires": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "mkdirp": "~1.0.3", + "nopt": "^4.0.3" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + } + } }, "js-stringify": { "version": "1.0.2", @@ -1532,6 +2027,14 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, "jstransformer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", @@ -1541,6 +2044,12 @@ "promise": "^7.0.1" } }, + "just-extend": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", + "dev": true + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -1582,11 +2091,40 @@ "type-check": "~0.3.2" } }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -1598,6 +2136,22 @@ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "requires": { + "es5-ext": "~0.10.2" + } + }, "make-dir": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", @@ -1612,6 +2166,21 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "memoizee": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", + "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", + "requires": { + "d": "1", + "es5-ext": "^0.10.45", + "es6-weak-map": "^2.0.2", + "event-emitter": "^0.3.5", + "is-promise": "^2.1", + "lru-queue": "0.1", + "next-tick": "1", + "timers-ext": "^0.1.5" + } + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -1656,7 +2225,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -1676,11 +2244,178 @@ "minimist": "^1.2.5" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "mocha": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", + "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + } + } + }, + "moment": { + "version": "2.25.3", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.25.3.tgz", + "integrity": "sha512-PuYv0PHxZvzc15Sp8ybUCoQ+xpyPWvjOuK72a5ovzp2LI32rJXOiIfyoFoYvG3s6EwwrdkMyWuRiEHSZRLJNdg==" + }, + "moment-timezone": { + "version": "0.5.28", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.28.tgz", + "integrity": "sha512-TDJkZvAyKIVWg5EtVqRzU97w0Rb0YVbfpqyjgu6GwXCAohVRqwZjf4fOzDE6p1Ch98Sro/8hQQi65WDXW5STPw==", + "requires": { + "moment": ">= 2.9.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "mute-stream": { "version": "0.0.8", @@ -1688,6 +2423,56 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "mysql2": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.1.0.tgz", + "integrity": "sha512-9kGVyi930rG2KaHrz3sHwtc6K+GY9d8wWk1XRSYxQiunvGcn4DwuZxOwmK11ftuhhwrYDwGx9Ta4VBwznJn36A==", + "requires": { + "cardinal": "^2.1.1", + "denque": "^1.4.1", + "generate-function": "^2.3.1", + "iconv-lite": "^0.5.0", + "long": "^4.0.0", + "lru-cache": "^5.1.1", + "named-placeholders": "^1.1.2", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.1" + }, + "dependencies": { + "iconv-lite": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.1.tgz", + "integrity": "sha512-ONHr16SQvKZNSqjQT9gy5z24Jw+uqfO02/ngBSBoqChZ+W8qXX7GPRa1RoUnzGADw8K63R1BXUMzarCVQBpY8Q==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "named-placeholders": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", + "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", + "requires": { + "lru-cache": "^4.1.3" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -1699,12 +2484,59 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "nise": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.3.tgz", + "integrity": "sha512-EGlhjm7/4KvmmE6B/UFsKh7eHykRl9VH+au8dduHLCyWUO/hr7+N+WtTvDUwc9zHuM1IaIJs/0lQ6Ag1jDkQSg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, "nodemon": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.3.tgz", @@ -1766,6 +2598,40 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -1778,7 +2644,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -1812,11 +2677,24 @@ "word-wrap": "~1.2.3" } }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } }, "p-cancelable": { "version": "1.1.0", @@ -1824,6 +2702,27 @@ "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", "dev": true }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, "package-json": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", @@ -1850,11 +2749,15 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-key": { "version": "2.0.1", @@ -1872,6 +2775,12 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -1904,6 +2813,11 @@ "asap": "~2.0.3" } }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", @@ -1913,6 +2827,11 @@ "ipaddr.js": "1.9.1" } }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, "pstree.remy": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", @@ -2143,6 +3062,14 @@ "picomatch": "^2.0.7" } }, + "redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", + "requires": { + "esprima": "~4.0.0" + } + }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", @@ -2177,6 +3104,16 @@ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, "resolve": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.1.tgz", @@ -2210,6 +3147,14 @@ "signal-exit": "^3.0.2" } }, + "retry-as-promised": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", + "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", + "requires": { + "any-promise": "^1.3.0" + } + }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", @@ -2245,11 +3190,6 @@ "tslib": "^1.9.0" } }, - "s": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/s/-/s-1.0.0.tgz", - "integrity": "sha512-Tz63UXhdEBvvIV6Q0a+AV2Dx1TPq+vVWNYBxyCT9TG0uqn9kySwFTjfq3C1YuGBRwYtt9Tof11L6GCKi88foqw==" - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -2263,8 +3203,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, "semver-diff": { "version": "3.1.1", @@ -2317,6 +3256,102 @@ } } }, + "seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" + }, + "sequelize": { + "version": "5.21.8", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.21.8.tgz", + "integrity": "sha512-UOxGMJ7eSnProTMWX9wRr0T9TcuW0YedFmU7s+YBZT9/RmfJeANYPdJXjXg4E+Yg+dJl4WWvBEu9r2oe+d/1/Q==", + "requires": { + "bluebird": "^3.5.0", + "cls-bluebird": "^2.1.0", + "debug": "^4.1.1", + "dottie": "^2.0.0", + "inflection": "1.12.0", + "lodash": "^4.17.15", + "moment": "^2.24.0", + "moment-timezone": "^0.5.21", + "retry-as-promised": "^3.2.0", + "semver": "^6.3.0", + "sequelize-pool": "^2.3.0", + "toposort-class": "^1.0.1", + "uuid": "^3.3.3", + "validator": "^10.11.0", + "wkx": "^0.4.8" + } + }, + "sequelize-cli": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-5.5.1.tgz", + "integrity": "sha512-ZM4kUZvY3y14y+Rq3cYxGH7YDJz11jWHcN2p2x7rhAIemouu4CEXr5ebw30lzTBtyXV4j2kTO+nUjZOqzG7k+Q==", + "requires": { + "bluebird": "^3.5.3", + "cli-color": "^1.4.0", + "fs-extra": "^7.0.1", + "js-beautify": "^1.8.8", + "lodash": "^4.17.5", + "resolve": "^1.5.0", + "umzug": "^2.1.0", + "yargs": "^13.1.0" + }, + "dependencies": { + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + } + } + }, + "sequelize-pool": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-2.3.0.tgz", + "integrity": "sha512-Ibz08vnXvkZ8LJTiUOxRcj1Ckdn7qafNZ2t59jYHMX1VIebTAOYefWdRYFt6z6+hy52WGthAHAoLc9hvk3onqA==" + }, "serve-static": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", @@ -2328,6 +3363,11 @@ "send": "0.17.1" } }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", @@ -2348,12 +3388,66 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, + "sinon": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz", + "integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.2", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.0.3", + "diff": "^4.0.2", + "nise": "^4.0.1", + "supports-color": "^7.1.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "sinon-chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.5.0.tgz", + "integrity": "sha512-IifbusYiQBpUxxFJkR3wTU68xzBN0+bxCScEaKMjBvAQERg6FnTTc1F17rseLb1tjmkJ23730AXpFI0c47FgAg==", + "dev": true + }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -2384,6 +3478,11 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sqlstring": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", + "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -2411,11 +3510,52 @@ } } }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, "requires": { "ansi-regex": "^4.1.0" }, @@ -2423,8 +3563,7 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" } } }, @@ -2498,6 +3637,15 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "requires": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -2537,6 +3685,11 @@ "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz", "integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo=" }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, "touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -2552,6 +3705,11 @@ "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", "dev": true }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -2561,6 +3719,12 @@ "prelude-ls": "~1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -2608,6 +3772,14 @@ "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "optional": true }, + "umzug": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", + "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "requires": { + "bluebird": "^3.7.2" + } + }, "undefsafe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", @@ -2643,6 +3815,11 @@ "crypto-random-string": "^2.0.0" } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -2744,12 +3921,22 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, "v8-compile-cache": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", "dev": true }, + "validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -2769,6 +3956,53 @@ "isexe": "^2.0.0" } }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -2799,6 +4033,14 @@ } } }, + "wkx": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.8.tgz", + "integrity": "sha512-ikPXMM9IR/gy/LwiOSqWlSL3X/J5uk9EO2hHNRXS41eTLXaUFEVw9fn/593jW/tE5tedNg8YjT5HkCa4FqQZyQ==", + "requires": { + "@types/node": "*" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -2810,11 +4052,42 @@ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { "version": "1.0.3", @@ -2843,6 +4116,16 @@ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "yargs": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", @@ -2860,6 +4143,80 @@ "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" } } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "dependencies": { + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + } + } } } } diff --git a/package.json b/package.json index 3e4bcde..b86b08a 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,13 @@ "description": "", "main": ".eslintrc.js", "scripts": { - "dev": "./node_modules/.bin/nodemon index.js", - "lint": "run lint:pug-lint && run lint:eslint", + "dev": "./node_modules/.bin/env-cmd ./node_modules/.bin/nodemon index.js", + "dev:migrate": "./node_modules/.bin/env-cmd ./node_modules/.bin/sequelize db:migrate --env development --config ./configs/sequelize.js", + "lint": "npm run lint:pug && npm run lint:eslint", "lint:eslint": "./node_modules/.bin/eslint --format codeframe .", - "lint:puglint": "./node_modules/.bin/pug-lint ." + "lint:esfix": "./node_modules/.bin/eslint --fix --format codeframe .", + "lint:pug": "./node_modules/.bin/pug-lint .", + "test": "./node_modules/.bin/env-cmd ./node_modules/.bin/mocha tests/**/*.tests.js" }, "repository": { "type": "git", @@ -20,13 +23,21 @@ }, "homepage": "https://github.com/orbitalbitmap/pokemon-api#readme", "devDependencies": { + "chai": "^4.2.0", "eslint": "^6.8.0", + "env-cmd": "^10.1.0", + "mocha": "^7.1.2", "nodemon": "^2.0.3", - "pug-lint": "^2.6.0" + "pug-lint": "^2.6.0", + "sinon": "^9.0.2", + "sinon-chai": "^3.5.0" }, "dependencies": { + "body-parser": "^1.19.0", "express": "^4.17.1", + "mysql2": "^2.1.0", "pug": "^2.0.4", - "s": "^1.0.0" + "sequelize": "^5.21.8", + "sequelize-cli": "^5.5.1" } } \ No newline at end of file diff --git a/public/css/styles.css b/public/css/styles.css new file mode 100644 index 0000000..eacee55 --- /dev/null +++ b/public/css/styles.css @@ -0,0 +1,88 @@ +body{ + margin-top: 150px; +} + +h1{ + text-align: center; +} + +h2{ + margin-bottom: 5px; +} + +span{ + font-size: 0.9em; + font-weight: bold; +} + +.delete{ + color: crimson; + font-weight: bold; +} + +.delete, .get, .post{ + padding-right: 10px; +} + +.get{ + color: green; + font-weight: bold; +} + +.hidden{ + display: none; +} + +.highlighted{ + background-color: lightgray; + position: relative; + width: 320px; +} + +.highlighted:after { + bottom: 0; + border-bottom: 15px solid transparent; + border-left: 15px solid lightgray; + border-top: 14px solid transparent; + content: ""; + position: absolute; + right: -15px; + width: 0; +} + +.left-container{ + margin: 0px 30px; + width: 320px; +} + +.main-container{ + display: flex; + flex-direction: row; + justify-content: center; +} + +.post{ + color: darkorange; + font-weight: bold; +} + +.right-container{ + margin: 80px 20px; + position: relative; + width: 440px; +} + +.spacing{ + margin: 20px 0px; + padding-left: 20px; +} + +.tabs{ + cursor: pointer; + font-size: 20px; + letter-spacing: 1px; + margin: 30px 0; + padding-top: 4px; + padding-left: 5px; + padding-bottom: 3px; +} diff --git a/public/javascripts/indexPugInteraction.js b/public/javascripts/indexPugInteraction.js new file mode 100644 index 0000000..d3ad3af --- /dev/null +++ b/public/javascripts/indexPugInteraction.js @@ -0,0 +1,18 @@ +/* eslint-disable no-undef */ +// eslint-disable-next-line no-unused-vars +const updateSelected = (id) => { + const tabs = document.getElementsByClassName('tabs') + const methods = document.getElementsByClassName('method') + + for (let i = 0; i < tabs.length; i++) { + tabs[i].id === id + ? tabs[i].classList.add('highlighted') + : tabs[i].classList.remove('highlighted') + } + + for (let i = 0; i < methods.length; i++) { + methods[i].id === id + ? methods[i].classList.remove('hidden') + : methods[i].classList.add('hidden') + } +} diff --git a/tests/controllers/api.tests.js b/tests/controllers/api.tests.js new file mode 100644 index 0000000..faf8d7a --- /dev/null +++ b/tests/controllers/api.tests.js @@ -0,0 +1,413 @@ +/* eslint-disable max-len */ +const chai = require('chai') +const sinon = require('sinon') +const sinonChai = require('sinon-chai') +const models = require('../../models') +const { + after, afterEach, before, beforeEach, describe, it +} = require('mocha') +const { getAllForms, getFormById } = require('../../controllers/Forms.js') +const { getAllTypes, getTypeById } = require('../../controllers/Types.js') + +const { + pokemonList, + singlePokemonWithAltForm, + newPokemon, + formsList, + singleAltFormWithPokemon, + unprotectedPokemon, + protectedPokemon +} = require('../mocks/pokemonData') + +const { + getAllPokemon, + getPokemonById, + getPokemonByGenerationId, + saveNewPokemon, + deletePokemon +} = require('../../controllers/Pokemons.js') + +chai.use(sinonChai) +const { expect } = chai + +describe('Controllers - API', () => { + let sandbox + let stubbedSend + let response + let stubbedSendStatus + let stubbedStatusDotSend + let stubbedStatus + + let stubbedPokemonsDestroy + let stubbedPokemonsFindAll + let stubbedPokemonsFindOne + let stubbedPokemonsFindOrCreate + + let stubbedFormsFindAll + let stubbedFormsFindOne + + let stubbedTypesFindAll + let stubbedTypesFindOne + let stubbedTypesFindOrCreate + + let stubbedPokemonTypesDestroy + let stubbedPokemonTypesFindOrCreate + + before(() => { + sandbox = sinon.createSandbox() + stubbedPokemonsDestroy = sandbox.stub(models.Pokemons, 'destroy') + stubbedPokemonsFindAll = sandbox.stub(models.Pokemons, 'findAll') + stubbedPokemonsFindOne = sandbox.stub(models.Pokemons, 'findOne') + stubbedPokemonsFindOrCreate = sandbox.stub(models.Pokemons, 'findOrCreate') + + stubbedFormsFindAll = sandbox.stub(models.Forms, 'findAll') + stubbedFormsFindOne = sandbox.stub(models.Forms, 'findOne') + + + stubbedTypesFindAll = sandbox.stub(models.Types, 'findAll') + stubbedTypesFindOne = sandbox.stub(models.Types, 'findOne') + stubbedTypesFindOrCreate = sandbox.stub(models.Types, 'findOrCreate') + + stubbedPokemonTypesDestroy = sandbox.stub(models.PokemonTypes, 'destroy') + stubbedPokemonTypesFindOrCreate = sandbox.stub(models.PokemonTypes, 'findOrCreate') + + + stubbedSend = sandbox.stub() + stubbedSendStatus = sandbox.stub() + stubbedStatusDotSend = sandbox.stub() + stubbedStatus = sandbox.stub() + + response = { + send: stubbedSend, + sendStatus: stubbedSendStatus, + status: stubbedStatus, + } + }) + + beforeEach(() => { + stubbedStatus.returns({ send: stubbedStatusDotSend }) + }) + + afterEach(() => { + sandbox.reset() + }) + + after(() => { + sandbox.restore() + }) + + describe('Controller - Pokemons', () => { + describe('getAllPokemon', () => { + it('retrieves a list of all pokemon.', async () => { + stubbedPokemonsFindAll.returns(pokemonList) + + await getAllPokemon({}, response) + + expect(stubbedPokemonsFindAll).to.have.been.calledWith() + expect(stubbedSend).to.have.been.calledWith(pokemonList) + }) + + it('returns a 500 error with a message when the database call throws an error.', async () => { + stubbedPokemonsFindAll.throws('ERROR!') + + await getAllPokemon({}, response) + + expect(stubbedStatus).to.have.been.calledWith(500) + expect(stubbedStatusDotSend).to.have.been.calledWith('Could not retrieve all pokemon, please try again.') + }) + }) + + describe('getPokemonById', () => { + it('retrieves the pokemon associated with the id passed by the user with the pokemon\'s alternate form and types and responds with a 200 status and sends the list of pokemon back.', async () => { + stubbedPokemonsFindOne.returns(singlePokemonWithAltForm) + const request = { params: { id: 'Grimer' } } + + await getPokemonById(request, response) + + expect(stubbedPokemonsFindOne).to.be.calledWith({ + where: { name: request.params.id }, + include: [{ model: models.Forms }, { model: models.Types }] + }) + expect(stubbedStatus).to.have.been.calledWith(200) + expect(stubbedStatusDotSend).to.have.been.calledWith(singlePokemonWithAltForm) + }) + + it('returns a 404 status with a message when no pokemon is found matching the id provided by the user.', async () => { + stubbedPokemonsFindOne.returns(null) + const request = { params: { id: 'ratata' } } + + await getPokemonById(request, response) + + expect(stubbedPokemonsFindOne).to.be.calledWith({ + where: { name: request.params.id }, + include: [{ model: models.Forms }, { model: models.Types }] + }) + expect(stubbedStatus).to.have.been.calledWith(404) + expect(stubbedStatusDotSend).to.have.been.calledWith('Could not find the pokemon ratata.') + }) + + it('returns a 500 status with a message when the database call throws an error.', async () => { + stubbedPokemonsFindOne.throws('ERROR!') + + await getPokemonById({}, response) + + expect(stubbedStatus).to.have.been.calledWith(500) + expect(stubbedStatusDotSend).to.have.been.calledWith('Could not retrieve the pokemon, please try again.') + }) + }) + + describe('getPokemonByGenerationId', () => { + it('retrieves all the pokemon in a generation provided by the user specified id.', async () => { + stubbedPokemonsFindAll.returns(pokemonList) + + const request = { params: { id: '1' } } + + + await getPokemonByGenerationId(request, response) + + expect(stubbedPokemonsFindAll).to.have.been.calledWith({ where: { generationNumber: request.params.id } }) + expect(stubbedSend).to.have.been.calledWith(pokemonList) + }) + + it('returns a 404 error when a user searches for a generation that does not exist in the database.', async () => { + stubbedPokemonsFindAll.returns('') + const request = { params: { id: 4 } } + + await getPokemonByGenerationId(request, response) + + expect(stubbedPokemonsFindAll).to.be.calledWith({ where: { generationNumber: request.params.id } }) + expect(stubbedStatus).to.have.been.calledWith(404) + expect(stubbedStatusDotSend).to.have.been.calledWith(`No generation ${request.params.id} pokemon currently exists.`) + }) + + it('returns a 500 status with a message when the database call throws an error.', async () => { + stubbedPokemonsFindAll.throws('ERROR!') + + await getPokemonByGenerationId({}, response) + + expect(stubbedStatus).to.have.been.calledWith(500) + expect(stubbedStatusDotSend).to.have.been.calledWith('Could not retrieve the pokemon by the sepcified generation, please try again.') + }) + }) + + describe('saveNewPokemon', () => { + it('either finds a pokemon matching the name provided or creates a new pokemon based on the id input by user.', async () => { + stubbedPokemonsFindOrCreate.returns([newPokemon, false]) + stubbedTypesFindOrCreate.onCall(1).returns(7) + stubbedTypesFindOrCreate.onCall(2).returns(8) + stubbedPokemonTypesFindOrCreate.onCall(3).returns({ PokemonPokedexNumber: 154, typeId: 7 }) + stubbedPokemonTypesFindOrCreate.onCall(4).returns({ PokemonPokedexNumber: 154, typeId: 8 }) + + const request = { + body: { + name: 'Leafeon', + generationNumber: 1, + fromId: 'null', + types: ['Fire', 'Flying'] + } + } + + await saveNewPokemon(request, response) + + expect(stubbedStatus).to.have.been.calledWith(201) + expect(stubbedStatusDotSend).to.have.been.calledWith(newPokemon) + }) + + it('returns a 400 status and a message when no pokemon is found matching the id provided by the user.', async () => { + stubbedPokemonsFindOne.returns(null) + const request = { + body: { + generationNumber: 1, + fromId: 'null', + types: ['Fire', 'Flying'] + } + } + + await saveNewPokemon(request, response) + + expect(stubbedStatus).to.have.been.calledWith(400) + expect(stubbedStatusDotSend).to.have.been.calledWith('At least one of the following attributes is missing: pokedexNumber, name, or generationNumber') + }) + + it('returns a 500 status with a message when the database call throws an error.', async () => { + stubbedPokemonsFindOne.throws('ERROR!') + + await saveNewPokemon({}, response) + + expect(stubbedStatus).to.have.been.calledWith(500) + expect(stubbedStatusDotSend).to.have.been.calledWith('Could not reach the database, please try again.') + }) + }) + + describe('deletePokemon', () => { + it('deletes a user named pokemon from the database as long as its not protected.', async () => { + stubbedPokemonsFindOne.returns(unprotectedPokemon) + + + const request = { params: { name: 'Jolion' } } + + await deletePokemon(request, response) + + expect(stubbedPokemonTypesDestroy).to.have.calledWith({ where: { PokemonPokedexNumber: unprotectedPokemon.pokedexNumber } }) + expect(stubbedPokemonsDestroy).to.have.calledWith({ where: { name: request.params.name } }) + expect(stubbedSend).to.have.been.calledWith(`Successfully deleted the pokemon: ${request.params.name}.`) + }) + + it('returns a 404 status and a message when no pokemon is found matching the id provided by the user.', async () => { + stubbedPokemonsFindOne.returns(null) + + const request = { params: { name: 'Fakemon' } } + + await deletePokemon(request, response) + + expect(stubbedPokemonsDestroy).to.have.callCount(0) + expect(stubbedStatus).to.have.been.calledWith(404) + expect(stubbedStatusDotSend).to.have.been.calledWith(`No pokemon matching the name: ${request.params.name}`) + }) + + it('returns a 409 status and a message when trying to delete a protected pokemon.', async () => { + stubbedPokemonsFindOne.returns(protectedPokemon) + + const request = { params: { name: 'Fakemon' } } + + await deletePokemon(request, response) + + expect(stubbedPokemonsDestroy).to.have.callCount(0) + expect(stubbedStatus).to.have.been.calledWith(409) + expect(stubbedStatusDotSend).to.have.been.calledWith('Cannot delete protected pokemon') + }) + + it('returns a 500 status with a message when the database call throws an error.', async () => { + stubbedPokemonsFindOne.throws('ERROR!') + + await deletePokemon({}, response) + + expect(stubbedPokemonsDestroy).to.have.callCount(0) + expect(stubbedStatus).to.have.been.calledWith(500) + expect(stubbedStatusDotSend).to.have.been.calledWith('Unknown error while deleting pokemon, please try again.') + }) + }) + }) + + describe('Controllers - Forms', () => { + describe('getAllForms', () => { + it('retrieves a list of all form names.', async () => { + stubbedFormsFindAll.returns(formsList) + + await getAllForms({}, response) + + expect(stubbedFormsFindAll).to.have.been.calledWith() + expect(stubbedSend).to.have.been.calledWith(formsList) + }) + + it('returns a 500 error with an error message when the database call throws an error.', async () => { + stubbedFormsFindAll.throws('ERROR!') + + await getAllForms({}, response) + + expect(stubbedStatus).to.have.been.calledWith(500) + expect(stubbedStatusDotSend).to.have.been.calledWith('Unable to retrieve all the forms, please try again.') + }) + }) + + describe('getFormById', () => { + it('retrieves a form and the associated pokemon to the form and responds with a 200 status and sends the list of pokemon back.', async () => { + stubbedFormsFindOne.returns(singleAltFormWithPokemon) + const request = { params: { id: 'alolan' } } + + await getFormById(request, response) + + expect(stubbedFormsFindOne).to.be.calledWith({ + where: { name: request.params.id }, + include: [{ model: models.Pokemons }] + }) + expect(stubbedStatus).to.have.been.calledWith(200) + expect(stubbedStatusDotSend).to.have.been.calledWith(singleAltFormWithPokemon) + }) + + it('returns a 404 status and a message when no form is found matching the id provided by the user.', async () => { + stubbedFormsFindOne.returns(null) + const request = { params: { id: 'pikachu' } } + + await getFormById(request, response) + + expect(stubbedFormsFindOne).to.be.calledWith({ + where: { name: request.params.id }, + include: [{ model: models.Pokemons }] + }) + expect(stubbedStatus).to.have.been.calledWith(404) + expect(stubbedStatusDotSend).to.have.been.calledWith('It appears there is no form called \'pikachu\' does not exist.') + }) + + it('returns a 500 status with a message when the database call throws an error.', async () => { + stubbedFormsFindOne.throws('ERROR!') + + await getFormById({}, response) + + expect(stubbedStatus).to.have.been.calledWith(500) + expect(stubbedStatusDotSend).to.have.been.calledWith('Unable to retrieve the form, please try again.') + }) + }) + }) + + describe('Controllers - Types', () => { + describe('getAllTypes', () => { + it('retrieves a list of all types.', async () => { + stubbedTypesFindAll.returns(pokemonList) + + await getAllTypes({}, response) + + expect(stubbedTypesFindAll).to.have.been.calledWith() + expect(stubbedSend).to.have.been.calledWith(pokemonList) + }) + + it('returns a 500 error with an error message when the database call throws an error.', async () => { + stubbedTypesFindAll.throws('ERROR!') + + await getAllTypes({}, response) + + expect(stubbedStatus).to.have.been.calledWith(500) + expect(stubbedStatusDotSend).to.have.been.calledWith('Could not retrieve all the types, please try again.') + }) + }) + + describe('getTypeById', () => { + it('retrieves all the pokemon under a user specified type and responds with a 200 status and sends the list of pokemon back.', async () => { + stubbedTypesFindOne.returns(singleAltFormWithPokemon) + const request = { params: { id: 'alolan' } } + + await getTypeById(request, response) + + expect(stubbedTypesFindOne).to.be.calledWith({ + where: { name: request.params.id }, + include: [{ model: models.Pokemons }] + }) + expect(stubbedStatus).to.have.been.calledWith(200) + expect(stubbedStatusDotSend).to.have.been.calledWith(singleAltFormWithPokemon) + }) + + it('returns a 404 status and a message when no type is found matching the id provided by the user.', async () => { + stubbedTypesFindOne.returns(null) + const request = { params: { id: 'shadow' } } + + await getTypeById(request, response) + + expect(stubbedTypesFindOne).to.be.calledWith({ + where: { name: request.params.id }, + include: [{ model: models.Pokemons }] + }) + expect(stubbedStatus).to.have.been.calledWith(404) + expect(stubbedStatusDotSend).to.have.been.calledWith('Could not find the type: shadow.') + }) + + it('returns a 500 status with a message when the database call throws an error.', async () => { + stubbedTypesFindOne.throws('ERROR!') + + await getTypeById({}, response) + + expect(stubbedStatus).to.have.been.calledWith(500) + expect(stubbedStatusDotSend).to.have.been.calledWith('Could not retrieve the specified type, please try again.') + }) + }) + }) +}) diff --git a/tests/mocks/pokemonData.js b/tests/mocks/pokemonData.js new file mode 100644 index 0000000..8a0c0ee --- /dev/null +++ b/tests/mocks/pokemonData.js @@ -0,0 +1,161 @@ +const pokemonList = [{ + pokedexNumber: 1, + name: 'Bulbasaur', + generationNumber: 1, + fromId: null, + isProtected: 1, + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z' +}, { + pokedexNumber: 1, + name: 'Bulbasaur', + generationNumber: 1, + fromId: null, + isProtected: 1, + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z' +}] + +const formsList = [{ + id: 4, + name: 'Alolan', + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z' +}] + +const typesList = [{ + id: 1, + name: 'Bug', + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z' +}] + +const singlePokemonWithAltForm = { + pokedexNumber: 88, + name: 'Grimer', + generationNumber: 1, + fromId: null, + isProtected: 1, + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z', + 'AlternateForms': [ + { + id: 4, + name: 'Alolan', + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z', + PokemonAlternateForms: { + PokemonPokedexNumber: 88, + AlternateFormId: 4, + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z' + } + } + ], + Types: [ + { + id: 14, + name: 'Poison', + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z', + PokemonTypes: { + PokemonPokedexNumber: 88, + TypeId: 14, + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z', + } + } + ] +} + +const singleAltFormWithPokemon = { + id: 4, + name: 'Alolan', + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z', + Pokemons: [ + { + pokedexNumber: 19, + name: 'Rattata', + generationNumber: 1, + fromId: null, + isProtected: 1, + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z', + PokemonAlternateForms: { + PokemonPokedexNumber: 19, + AlternateFormId: 4, + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z' + } + } + ] +} + +const singleTypeWithPokemon = { + id: 1, + name: 'Bug', + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z', + Pokemons: [ + { + pokedexNumber: 10, + name: 'Caterpie', + generationNumber: 1, + fromId: null, + isProtected: 1, + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z', + PokemonTypes: { + PokemonPokedexNumber: 10, + TypeId: 1, + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z', + } + } + ] +} + +const newPokemon = { + pokedexNumber: 154, + generationNumber: 1, + fromId: null, + isProtected: 0, + name: 'Leafeon', + updatedAt: '2020-05-24T16:42:32.743Z', + createdAt: '2020-05-24T16:42:32.743Z' +} + +const unprotectedPokemon = { + pokedexNumber: 88, + generationNumber: 1, + fromId: null, + isisProtected: 0, + name: 'Jolion', + updatedAt: '2020-05-24T16:42:32.743Z', + createdAt: '2020-05-24T16:42:32.743Z' +} + +const protectedPokemon = { + pokedexNumber: 1, + name: 'Fakemon', + generationNumber: 1, + fromId: null, + isProtected: 1, + createdAt: '2020-05-23T11:42:42.000Z', + updatedAt: '2020-05-23T11:42:42.000Z', + deletedAt: null, +} + + +module.exports = { + pokemonList, + formsList, + typesList, + singlePokemonWithAltForm, + singleAltFormWithPokemon, + singleTypeWithPokemon, + newPokemon, + unprotectedPokemon, + protectedPokemon +} diff --git a/views/index.pug b/views/index.pug new file mode 100644 index 0000000..2f59885 --- /dev/null +++ b/views/index.pug @@ -0,0 +1,13 @@ +html + head + title Pokemon API + link(rel="stylesheet" href="/css/styles.css") + script(src="/javascripts/indexPugInteraction.js") + + body + h1 Welcome to the Pokemon API + div(class="main-container") + + include partials/leftSideDocumentation.pug + + include partials/rightSideDocumentaion.pug diff --git a/views/partials/leftSideDocumentation.pug b/views/partials/leftSideDocumentation.pug new file mode 100644 index 0000000..80d7393 --- /dev/null +++ b/views/partials/leftSideDocumentation.pug @@ -0,0 +1,36 @@ +div(class="left-container") + div(class="tabs highlighted" id="getAll" onclick="updateSelected('getAll')") + span(class="get") GET + span /pokemon + + div(class="tabs" id="getPokemonById" onclick="updateSelected('getPokemonById')") + span(class="get") GET + span /pokemon/{name} + + div(class="tabs" id="getGeneration" onclick="updateSelected('getGeneration')") + span(class="get") GET + span /generation/{genId} + + div(class="tabs" id="getTypes" onclick="updateSelected('getTypes')") + span(class="get") GET + span /types/ + + div(class="tabs" id="getTypesById" onclick="updateSelected('getTypesById')") + span(class="get") GET + span /types/{name} + + div(class="tabs" id="getForms" onclick="updateSelected('getForms')") + span(class="get") GET + span /forms/ + + div(class="tabs" id="getFormsById" onclick="updateSelected('getFormsById')") + span(class="get") GET + span /forms/{name} + + div(class="tabs" id="postPokemon" onclick="updateSelected('postPokemon')") + span(class="post") POST + span /pokemon + + div(class="tabs" id="deletePokemonById" onclick="updateSelected('deletePokemonById')") + span(class="delete") DELETE + span /pokemon/{name} diff --git a/views/partials/rightSideDocumentaion.pug b/views/partials/rightSideDocumentaion.pug new file mode 100644 index 0000000..c673cbc --- /dev/null +++ b/views/partials/rightSideDocumentaion.pug @@ -0,0 +1,95 @@ +div(class="right-container") + div(class="method" id="getAll") + h2 Method + h3(class="get spacing") GET + h2 Route + h3(class="spacing") http://localhost:1337/pokemon + h2 Headers + h3(class="spacing") None needed + h2 Decription + h3(class="spacing") Returns a list all of the pokemon in the database. + + div(class="method hidden" id="getPokemonById") + h2 Method + h3(class="spacing get") GET + h2 Route + h3(class="spacing") http://localhost:1337/pokemon/{name} + h2 Headers + h3(class="spacing") None needed + h2 Decription + h3(class="spacing") Returns the pokemon associated with the {name}. + + div(class="method hidden" id="getGeneration") + h2 Method + h3(class="spacing get") GET + h2 Route + h3(class="spacing") http://localhost:1337/generation/{genId} + h2 Headers + h3(class="spacing") None needed + h2 Decription + h3(class="spacing") Returns the list of pokemon from gemeration passed with {genId}. + + div(class="method hidden" id="getTypes") + h2 Method + h3(class="spacing get") GET + h2 Route + h3(class="spacing") http://localhost:1337/types/ + h2 Headers + h3(class="spacing") None needed + h2 Decription + h3(class="spacing") Returns a list of all the types. + + div(class="method hidden" id="getTypesById") + h2 Method + h3(class="spacing get") GET + h2 Route + h3(class="spacing") http://localhost:1337/types/{name} + h2 Headers + h3(class="spacing") None needed + h2 Decription + h3(class="spacing") Returns the type and all pokemon associated with the type {name} provided. + + div(class="method hidden" id="getForms") + h2 Method + h3(class="spacing get") GET + h2 Route + h3(class="spacing") http://localhost:1337/forms/ + h2 Headers + h3(class="spacing") None needed + h2 Decription + h3(class="spacing") Returns a list of all the forms. + + div(class="method hidden" id="getFormsById") + h2 Method + h3(class="spacing get") GET + h2 Route + h3(class="spacing") http://localhost:1337/forms/{name} + h2 Headers + h3(class="spacing") None needed + h2 Decription + h3(class="spacing") Returns the form and all pokemon associated with the form {name} provided. + + div(class="method hidden" id="postPokemon") + h2 Method + h3(class="spacing post") POST + h2 Route + h3(class="spacing") http://localhost:1337/pokemon + h2 Headers + h3(class="spacing") Content-Type: application/json + h2 Body + h3(class="spacing") { "generationNumber": "1", "name": "Bulbasaur", "Types": "['grass', 'poison']", "fromId": "null" } + h2 Decription + h3(class="spacing") + | Saves a new pokemon to the database. (Note: the fromId is if the pokemon is an evolution of + | another pokemon Bulbasuar has 'fromId: null' as its a base evolution where as Ivysaur has + | 'fromId: 1' as it evolves from Bulbasaur) + + div(class="method hidden" id="deletePokemonById") + h2 Method + h3(class="spacing delete") DELETE + h2 Route + h3(class="spacing") http://localhost:1337/pokemon/{name} + h2 Headers + h3(class="spacing") None needed + h2 Decription + h3(class="spacing") Deletes the pokemon associated with the {name}.