Skip to content

Commit

Permalink
Implement sequelize
Browse files Browse the repository at this point in the history
  • Loading branch information
fsodano committed Jul 19, 2020
1 parent b5860bc commit c6c909c
Show file tree
Hide file tree
Showing 31 changed files with 841 additions and 153 deletions.
1 change: 1 addition & 0 deletions .env.dist
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
DB_PATH=./data/database.db
API_FOOTBALL_DATA=
8 changes: 6 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"extends": ["airbnb-base", "prettier"],
"plugins": ["prettier"],
"plugins": ["prettier", "jest"],
"rules": {
"prettier/prettier": ["error"]
"prettier/prettier": ["error"],
"class-methods-use-this": "off"
},
"env": {
"jest/globals": true
}
}
1 change: 1 addition & 0 deletions data/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
database.db
Empty file removed data/datatbase.db
Empty file.
403 changes: 297 additions & 106 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"main": "index.js",
"scripts": {
"start": "node src/app.js",
"dev": "nodemon -e 'js,njk' src/app.js",
"test": "echo \"Error: no test specified\" && exit 1"
"dev": "nodemon -e 'js,njk,html' src/app.js",
"test": "jest"
},
"repository": {
"type": "git",
Expand All @@ -19,17 +19,21 @@
},
"homepage": "https://github.com/r-argentina-programa/crud-clubes#readme",
"devDependencies": {
"@types/jest": "^26.0.5",
"cypress": "^4.9.0",
"eslint": "^7.2.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^23.18.0",
"eslint-plugin-prettier": "^3.1.4",
"jest": "^26.1.0",
"nodemon": "^2.0.4",
"prettier": "^2.0.5"
},
"dependencies": {
"axios": "^0.19.2",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"nunjucks": "^3.2.1",
"rsdi": "^1.0.5",
Expand Down
2 changes: 2 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require('dotenv').config();
const express = require('express');
const nunjucks = require('nunjucks');
const configureDependencyInjection = require('./config/di');
Expand All @@ -6,6 +7,7 @@ const { init: initClubModule } = require('./module/club/module');
const app = express();
const port = process.env.PORT || 3000;

app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));

// https://mozilla.github.io/nunjucks/getting-started.html#when-using-node
Expand Down
13 changes: 10 additions & 3 deletions src/config/di.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
// configure DI container
const { default: DIContainer, object, get, factory } = require('rsdi');
const { Sequelize } = require('sequelize');
const { ClubController, ClubService, ClubRepository } = require('../module/club/module');
const { ClubController, ClubService, ClubRepository, ClubModel } = require('../module/club/module');

function configureSequelize() {
return new Sequelize({
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: process.env.DB_PATH,
});
sequelize.sync();
return sequelize;
}

function configureClubModule(di) {
return ClubModel.setup(di.get('Sequelize'));
}

module.exports = function configureDI() {
const container = new DIContainer();
container.addDefinitions({
ClubController: object(ClubController).construct(get('ClubService')),
ClubService: object(ClubService).construct(get('ClubRepository')),
ClubRepository: object(ClubRepository).construct(get('Sequelize')),
ClubRepository: object(ClubRepository).construct(get('ClubModel')),
ClubModel: factory(configureClubModule),
Sequelize: factory(configureSequelize),
});
return container;
Expand Down
40 changes: 40 additions & 0 deletions src/module/club/controller/__tests__/club.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const ClubController = require('../club');

const serviceMock = {
save: jest.fn(),
delete: jest.fn(),
};
const controller = new ClubController(serviceMock);

test('Index renderea index.html', () => {
const renderMock = jest.fn();
controller.index({}, { render: renderMock });
expect(renderMock).toHaveBeenCalledTimes(1);
expect(renderMock).toHaveBeenCalledWith('club/view/index.html');
});

test('View renderea form.html', () => {
const renderMock = jest.fn();
controller.view({}, { render: renderMock });
expect(renderMock).toHaveBeenCalledTimes(1);
expect(renderMock).toHaveBeenCalledWith('club/view/form.html');
});

test('Save llama al servicio con el body y redirecciona a /club', () => {
const redirectMock = jest.fn();
const bodyMock = { id: 1 };
controller.save({ body: bodyMock }, { redirect: redirectMock });
expect(serviceMock.save).toHaveBeenCalledTimes(1);
expect(serviceMock.save).toHaveBeenCalledWith(bodyMock);
expect(redirectMock).toHaveBeenCalledTimes(1);
expect(redirectMock).toHaveBeenCalledWith('/club');
});

test('Delete llama al servicio con el id del body y redirecciona a /club', () => {
const redirectMock = jest.fn();
controller.delete({ body: { id: 1 } }, { redirect: redirectMock });
expect(serviceMock.delete).toHaveBeenCalledTimes(1);
expect(serviceMock.delete).toHaveBeenCalledWith(1);
expect(redirectMock).toHaveBeenCalledTimes(1);
expect(redirectMock).toHaveBeenCalledWith('/club');
});
17 changes: 0 additions & 17 deletions src/module/club/controller/club.js

This file was deleted.

51 changes: 51 additions & 0 deletions src/module/club/controller/clubController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const { formDataToEntity } = require('../mapper/clubMapper');

module.exports = class ClubController {
/**
* @param {import('../service/clubService')} clubService
*/
constructor(clubService) {
this.clubService = clubService;
}

/**
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
async index(req, res) {
const clubs = await this.clubService.getAll();
res.render('club/view/index.html', { data: { clubs } });
}

/**
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
view(req, res) {
res.render('club/view/form.html');
}

/**
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
async save(req, res) {
try {
await this.clubService.save(formDataToEntity(req.body));
res.redirect('/club');
} catch (e) {
console.error(e);
res.end();
// res.render('club/view/form.html', { error: e });
}
}

/**
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
delete(req, res) {
this.clubService.delete(req.body.id);
res.redirect('/club');
}
};
29 changes: 29 additions & 0 deletions src/module/club/entity/club.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module.exports = class Club {
constructor({
id,
name,
shortName,
tla,
crestUrl,
address,
phone,
website,
email,
founded,
clubColors,
venue,
}) {
this.id = id;
this.name = name;
this.shortName = shortName;
this.tla = tla;
this.crestUrl = crestUrl;
this.address = address;
this.phone = phone;
this.website = website;
this.email = email;
this.founded = founded;
this.clubColors = clubColors;
this.venue = venue;
}
};
55 changes: 55 additions & 0 deletions src/module/club/job/download-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const axios = require('axios');
const fs = require('fs');
require('dotenv').config();

if (process.env.API_FOOTBALL_DATA.length === 0) {
console.log(
'Se debe crear un archivo.env (copiar el .env.dist y cambiarle el nombre) y configurar la API key gratuita de https://www.football-data.org/'
);
process.exit(1);
}

const API_TOKEN = process.env.API_FOOTBALL_DATA;
const API_BASE = 'http://api.football-data.org/v2';
const ENGLAND_ID = 2021;

async function obtenerEquipos() {
console.log('obteniendo equipos...');
const resultado = await axios.get(`${API_BASE}/competitions/${ENGLAND_ID}/teams`, {
headers: { 'X-Auth-Token': API_TOKEN },
});
return resultado.data.teams;
}

async function obtenerPlantel(id) {
console.log(`obteniendo plantel id ${id}...`);
const respuesta = await axios.get(`${API_BASE}/teams/${id}`, {
headers: { 'X-Auth-Token': API_TOKEN },
});

return respuesta.data;
}

async function iniciar() {
const DIRECTORIO = './data';
const archivo = `${DIRECTORIO}/equipos.json`;

let equipos;

if (!fs.existsSync(archivo)) {
equipos = await obtenerEquipos();
fs.writeFileSync(archivo, JSON.stringify(equipos));
}

equipos = JSON.parse(fs.readFileSync(archivo));

equipos.forEach(async (equipo) => {
const archivoPlantel = `${DIRECTORIO}/equipos/${equipo.tla}.json`;

if (!fs.existsSync(archivoPlantel)) {
fs.writeFileSync(archivoPlantel, JSON.stringify(await obtenerPlantel(equipo.id)));
}
});
}

iniciar();
43 changes: 43 additions & 0 deletions src/module/club/mapper/clubMapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// map from Controller to Entity
// map from Entity to Controller
// map from Entity to Model
// map from Model to Entity

const Club = require('../entity/club');

module.exports = {
/**
*
* @param {Object} formData
* @returns Club
*/
formDataToEntity({
id,
name,
'short-name': shortName,
tla,
'crest-url': crestUrl,
address,
phone,
website,
email,
founded,
'club-colors': clubColors,
venue,
}) {
return new Club({
id,
name,
shortName,
tla,
crestUrl,
address,
phone,
website,
email,
founded,
clubColors,
venue,
});
},
};
5 changes: 0 additions & 5 deletions src/module/club/model/repository/club.js

This file was deleted.

5 changes: 0 additions & 5 deletions src/module/club/model/service/club.js

This file was deleted.

8 changes: 5 additions & 3 deletions src/module/club/module.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const configureRoutes = require('./routes');
const ClubController = require('./controller/club');
const ClubRepository = require('./model/repository/club');
const ClubService = require('./model/service/club');
const ClubController = require('./controller/clubController');
const ClubRepository = require('./repository/sqlite/clubRepository');
const ClubService = require('./service/clubService');
const ClubModel = require('./repository/sqlite/clubModel');

function init(app, container) {
configureRoutes(container.get('ClubController'), app);
Expand All @@ -12,4 +13,5 @@ module.exports = {
ClubController,
ClubService,
ClubRepository,
ClubModel,
};
31 changes: 31 additions & 0 deletions src/module/club/repository/abstractClubRepository.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint-disable no-empty-function */
/* eslint-disable no-unused-vars */
const AbstractRepositoryError = require('./error/abstractRepositoryError');

module.exports = class AbstractClubRepository {
constructor() {
throw new AbstractRepositoryError('No se puede instanciar el repositorio de clubes abstracto.');
}

/**
* @param {import('../entity/club')} club
* @returns {import('../entity/club')}
*/
async save(club) {}

/**
* @param {Number} id
*/
async delete(id) {}

/**
* @param {Number} id
* @returns {import('../entity/club')}
*/
async get(id) {}

/**
* @returns {Array<import('../entity/club')>}
*/
async getAll() {}
};
Loading

0 comments on commit c6c909c

Please sign in to comment.