From d38e8612abf0f3d49981acaed1f5e35d6896dbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br> Date: Mon, 24 Oct 2016 10:08:58 -0200 Subject: [PATCH] Migrate API to v2 database schema Change SQL queries in the following routes: * city * state * region * school * enrollment Also, change tests to reflect the new schema where appropriate. Specially in the case of cities, the primary key now becomes pk_cod_ibge (city IBGE code) and, therefore, any query that relies on the city id should use this value instead of the old primary key. Aliases of fields that have different names were added to ensure compatibility with the UI of LDE. Please refer to the database repository in order to understand how the current schema works. The corresponding ER diagram can be located there. --- src/libs/routes/city.js | 27 +++++++--- src/libs/routes/enrollment.js | 97 +++++++++++++++++++---------------- src/libs/routes/region.js | 4 +- src/libs/routes/school.js | 31 ++++++----- src/libs/routes/simulation.js | 47 +++++++++++++++++ src/libs/routes/state.js | 6 +-- src/test/test.js | 19 +++---- 7 files changed, 154 insertions(+), 77 deletions(-) create mode 100644 src/libs/routes/simulation.js diff --git a/src/libs/routes/city.js b/src/libs/routes/city.js index 733da6f3..d324330e 100644 --- a/src/libs/routes/city.js +++ b/src/libs/routes/city.js @@ -12,27 +12,42 @@ const response = require(`${libs}/middlewares/response`); // Return all cities cityApp.get('/', (req, res, next) => { - req.sql.from('municipios'); + req.sql.from('municipio') + .field('pk_cod_ibge', 'pk_municipio_id') + .field('nome') + .field('pk_cod_ibge', 'codigo_ibge') + .field('fk_estado_id'); next(); }, query, response('city')); // Return a specific city by it's id cityApp.get('/:id', (req, res, next) => { - req.sql.from('municipios') - .where('pk_municipio_id = ?', parseInt(req.params.id, 10)); + req.sql.from('municipio') + .field('pk_cod_ibge', 'pk_municipio_id') + .field('nome', 'nome') + .field('pk_cod_ibge', 'codigo_ibge') + .field('fk_estado_id') + .where('pk_cod_ibge = ?', parseInt(req.params.id, 10)); next(); }, query, response('city')); // Return a specific city by it's IBGE code +// TODO: this route becomes obsolete in the new schema, deprecate it cityApp.get('/ibge/:id', (req, res, next) => { - req.sql.from('municipios') - .where('codigo_ibge = ?', req.params.id); + req.sql.from('municipio') + .field('pk_cod_ibge', 'pk_municipio_id') + .field('nome') + .field('fk_estado_id') + .where('pk_cod_ibge = ?', parseInt(req.params.id, 10)); next(); }, query, response('city')); // Return all the cities from a specific state cityApp.get('/state/:id', (req, res, next) => { - req.sql.from('municipios') + req.sql.from('municipio') + .field('pk_cod_ibge', 'pk_municipio_id') + .field('nome') + .field('pk_cod_ibge', 'codigo_ibge') .where('fk_estado_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('city')); diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js index 446d7aca..0c950044 100644 --- a/src/libs/routes/enrollment.js +++ b/src/libs/routes/enrollment.js @@ -21,9 +21,9 @@ const parseParams = require(`${libs}/middlewares/parseParams`); // Returns a tuple of start and ending years of the complete enrollments dataset. enrollmentApp.get('/year_range', (req, res, next) => { req.sql = squel.select() - .from('turmas') - .field('MIN(turmas.ano_censo)', 'start_year') - .field('MAX(turmas.ano_censo)', 'end_year'); + .from('turma') + .field('MIN(turma.ano_censo)', 'start_year') + .field('MAX(turma.ano_censo)', 'end_year'); next(); }, query, response('range')); @@ -41,7 +41,7 @@ enrollmentApp.get('/education_level', (req, res, next) => { // Returns all adm dependencies enrollmentApp.get('/adm_dependency', (req, res, next) => { req.sql = squel.select() - .from('dependencia_adms') + .from('dependencia_adm') .field('pk_dependencia_adm_id', 'id') .field('nome', 'name'); @@ -74,27 +74,28 @@ enrollmentApp.use('/', parseParams('filter', [ // Do the joins if(typeof req.filter.adm_dependency !== 'undefined' || typeof req.dims.adm_dependency !== 'undefined') { - req.sql.join('dependencia_adms', null, 'fk_dependencia_adm_id=dependencia_adms.pk_dependencia_adm_id'); + req.sql.join('dependencia_adm', null, + 'turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id'); } if(typeof req.filter.education_level !== 'undefined' || typeof req.dims.education_level !== 'undefined') { - req.sql.join('etapa_ensino', null, 'fk_etapa_ensino_id=etapa_ensino.pk_etapa_ensino_id'); + req.sql.join('etapa_ensino', null, + 'turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id'); } if(typeof req.filter.region !== 'undefined' || typeof req.dims.region !== 'undefined') { - req.sql.join('municipios', null, 'fk_municipio_id=municipios.pk_municipio_id') - .join('estados', null, 'municipios.fk_estado_id=estados.pk_estado_id') - .join('regioes', null, 'estados.fk_regiao_id=regioes.pk_regiao_id'); + req.sql.join('regiao', null, + 'turma.fk_regiao_id = regiao.pk_regiao_id'); } if((typeof req.filter.state !== 'undefined' || typeof req.dims.state !== 'undefined') && (typeof req.filter.region === 'undefined' && typeof req.dims.region === 'undefined')) { - req.sql.join('municipios', null, 'fk_municipio_id=municipios.pk_municipio_id') - .join('estados', null, 'municipios.fk_estado_id=estados.pk_estado_id'); + req.sql.join('estado', + null, 'turma.fk_estado_id = estado.pk_estado_id'); } if((typeof req.filter.city !== 'undefined' @@ -103,11 +104,12 @@ enrollmentApp.use('/', parseParams('filter', [ && typeof req.dims.state === 'undefined') && (typeof req.filter.region === 'undefined' && typeof req.dims.region === 'undefined')) { - req.sql.join('municipios', null, 'fk_municipio_id=municipios.pk_municipio_id'); + req.sql.join('municipio', null, + 'turma.fk_municipio_id = municipio.pk_cod_ibge'); } if(typeof req.dims.school !== 'undefined') { - req.sql.join('escolas', null, 'fk_escola_id=escolas.pk_escola_id'); + req.sql.join('escolas', null, 'turma.cod_entidade = escola.cod_entidade'); } // Dimensions (add fields) @@ -119,39 +121,48 @@ enrollmentApp.use('/', parseParams('filter', [ } if(typeof req.dims.region !== 'undefined') { - req.sql.field('regioes.nome', 'region_name') - .group('regioes.nome') - .order('regioes.nome'); + req.sql.field('regiao.nome', 'region_name') + .group('regiao.nome') + .order('regiao.nome'); } if(typeof req.dims.state !== 'undefined') { - req.sql.field('estados.nome', 'state_name') - .group('estados.nome') - .order('estados.nome'); + req.sql.field('estado.nome', 'state_name') + .group('estado.nome') + .order('estado.nome'); } if(typeof req.dims.city !== 'undefined') { req.sql.field('municipios.nome', 'city_name') - .group('municipios.nome') - .order('municipios.nome'); + .group('municipio.nome') + .order('municipio.nome'); } + /** + * TODO: field nome_entidade is not present in the new schema, remove this part if(typeof req.dims.school !== 'undefined') { - req.sql.field('escolas.nome_entidade', 'school_name') - .group('escolas.nome_entidade') - .order('escolas.nome_entidade'); + req.sql.field('escola.nome_entidade', 'school_name') + .group('escola.nome_entidade') + .order('escola.nome_entidade'); + } + */ + + if(typeof req.dims.school !== 'undefined') { + req.sql.field('escola.cod_entidade', 'school_code') + .group('escola.cod_entidade') + .order('escola.cod_entidade'); } if(typeof req.dims.adm_dependency !== 'undefined') { - req.sql.field('dependencia_adms.nome', 'adm_dependency_name') - .group('dependencia_adms.nome') - .order('dependencia_adms.nome'); + req.sql.field('dependencia_adm.nome', 'adm_dependency_name') + .group('dependencia_adm.nome') + .order('dependencia_adm.nome'); } if(typeof req.dims.location !== 'undefined') { - req.sql.field('turmas.id_localizacao', 'location_name') - .group('turmas.id_localizacao') - .order('turmas.id_localizacao'); + req.sql.field('turma.id_localizacao', 'location_name') + .group('turma.id_localizacao') + .order('turma.id_localizacao'); } if(typeof req.dims.region === 'undefined' @@ -164,39 +175,39 @@ enrollmentApp.use('/', parseParams('filter', [ // Filter (add where) if (typeof req.filter.min_year !== 'undefined') { - req.sql.where('turmas.ano_censo>=?', parseInt(req.filter.min_year, 10)); + req.sql.where('turma.ano_censo >= ?', parseInt(req.filter.min_year, 10)); } if (typeof req.filter.max_year !== 'undefined') { - req.sql.where('turmas.ano_censo<=?', parseInt(req.filter.max_year, 10)); + req.sql.where('turma.ano_censo <= ?', parseInt(req.filter.max_year, 10)); } if (typeof req.filter.adm_dependency !== 'undefined') { - req.sql.where('pk_dependencia_adm_id=?', parseInt(req.filter.adm_dependency, 10)); + req.sql.where('turma.fk_dependencia_adm_id = ?', parseInt(req.filter.adm_dependency, 10)); } if (typeof req.filter.location !== 'undefined') { - req.sql.where('turmas.id_localizacao=?', parseInt(req.filter.location, 10)); + req.sql.where('turma.id_localizacao = ?', parseInt(req.filter.location, 10)); } if (typeof req.filter.education_level !== 'undefined') { - req.sql.where('pk_etapa_ensino_id=?', parseInt(req.filter.education_level, 10)); + req.sql.where('turma.fk_etapa_ensino_id = ?', parseInt(req.filter.education_level, 10)); } if (typeof req.filter.region !== 'undefined') { - req.sql.where('pk_regiao_id=?', parseInt(req.filter.region, 10)); + req.sql.where('turma.fk_regiao_id = ?', parseInt(req.filter.region, 10)); } if (typeof req.filter.state !== 'undefined') { - req.sql.where('pk_estado_id=?', parseInt(req.filter.state, 10)); + req.sql.where('turma.fk_estado_id = ?', parseInt(req.filter.state, 10)); } if (typeof req.filter.city !== 'undefined') { - req.sql.where('turmas.fk_municipio_id=?', parseInt(req.filter.city, 10)); + req.sql.where('turma.fk_municipio_id = ?', parseInt(req.filter.city, 10)); } if (typeof req.filter.school !== 'undefined') { - req.sql.where('turmas.fk_escola_id=?', parseInt(req.filter.school, 10)); + req.sql.where('turma.cod_entidade = ?', parseInt(req.filter.school, 10)); } log.debug(req.sql.toParam()); next(); @@ -204,10 +215,10 @@ enrollmentApp.use('/', parseParams('filter', [ enrollmentApp.get('/', (req, res, next) => { req.sql.field('COALESCE(SUM(num_matriculas), 0)', 'total') - .field('turmas.ano_censo', 'year') - .from('turmas') - .group('turmas.ano_censo') - .order('turmas.ano_censo'); + .field('turma.ano_censo', 'year') + .from('turma') + .group('turma.ano_censo') + .order('turma.ano_censo'); next(); }, query, (req, res, next) => { // 'Sanitize' result diff --git a/src/libs/routes/region.js b/src/libs/routes/region.js index 773ad347..0a8b65f8 100644 --- a/src/libs/routes/region.js +++ b/src/libs/routes/region.js @@ -12,13 +12,13 @@ const response = require(`${libs}/middlewares/response`); // Get all regions regionApp.get('/', (req, res, next) => { - req.sql.from('regioes'); + req.sql.from('regiao'); next(); }, query, response('region')); // Get a region by it's id regionApp.get('/:id', (req, res, next) => { - req.sql.from('regioes') + req.sql.from('regiao') .where('pk_regiao_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('region')); diff --git a/src/libs/routes/school.js b/src/libs/routes/school.js index 6c92430b..ec415a86 100644 --- a/src/libs/routes/school.js +++ b/src/libs/routes/school.js @@ -28,32 +28,35 @@ const response = require(`${libs}/middlewares/response`); // Get a school by it's id schoolApp.get('/:id', (req, res, next) => { - req.sql.from('escolas') - .where('pk_escola_id = ?', parseInt(req.params.id, 10)); + req.sql.from('escola') + .field('cod_entidade', 'pk_escola_id') + .field('cod_entidade') + .field('ano_censo') + .field('fk_municipio_id') + .field('fk_estado_id') + .where('cod_entidade = ?', parseInt(req.params.id, 10)); next(); }, query, response('school')); // Get all schools from a state schoolApp.get('/state/:id', (req, res, next) => { - req.sql.from('escolas') - .field('pk_escola_id') - .field('nome_entidade') + req.sql.from('escola') + .field('cod_entidade', 'pk_escola_id') + .field('cod_entidade') .field('ano_censo') - .field('fk_cod_estado') - .field('fk_cod_municipio') - .where('fk_cod_estado = ?', parseInt(req.params.id, 10)); + .field('fk_municipio_id') + .where('fk_estado_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('school')); // Get all schools from a city schoolApp.get('/city/:id', (req, res, next) => { - req.sql.from('escolas') - .field('pk_escola_id') - .field('nome_entidade') + req.sql.from('escola') + .field('cod_entidade', 'pk_escola_id') + .field('cod_entidade') .field('ano_censo') - .field('fk_cod_estado') - .field('fk_cod_municipio') - .where('fk_cod_municipio = ?', parseInt(req.params.id, 10)); + .field('fk_estado_id') + .where('fk_municipio_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('school')); diff --git a/src/libs/routes/simulation.js b/src/libs/routes/simulation.js new file mode 100644 index 00000000..d197b39d --- /dev/null +++ b/src/libs/routes/simulation.js @@ -0,0 +1,47 @@ +const express = require('express'); + +const libs = `${process.cwd()}/libs`; + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`); + +const response = require(`${libs}/middlewares/response`); + +const simulationApp = express(); + +simulationApp.get('/', (req, res, next) => { + req.sql = squel.select().from('simulacao').toParam(); + next(); +}, query, response('simulacao')); + +simulationApp.get('/:uid:/all', (req, res, next) => { + // TODO: implement user checking + + req.sql = squel.select().from('simulacao').toParam(); + next(); +}, query, response('simulacao')); + +simulationApp.get('/:uid:/:simulation_id:/view', (req, res, next) => { + // TODO: implement checking if the simulation belongs to the current user + + req.sql = squel.select().from('simulacao').toParam(); + next(); +}); + +simulationApp.get('/:uid:/:simulation_id:/delete', (req, res, next) => { + // TODO: implement checking if the simulation belongs to the current user + + req.sql = squel.select().from('simulacao').toParam(); + next(); +}); + +simulationApp.get('/:uid:/:simulation_id:/edit', (req, res, next) => { + // TODO: implement checking if the simulation belongs to the current user + + req.sql = squel.select().from('simulacao').toParam(); + next(); +}); + +module.exports = simulationApp; + diff --git a/src/libs/routes/state.js b/src/libs/routes/state.js index 75e1c0b7..8567ec05 100644 --- a/src/libs/routes/state.js +++ b/src/libs/routes/state.js @@ -12,20 +12,20 @@ const response = require(`${libs}/middlewares/response`); // Get all states stateApp.get('/', (req, res, next) => { - req.sql.from('estados'); + req.sql.from('estado'); next(); }, query, response('state')); // Get a state stateApp.get('/:id', (req, res, next) => { - req.sql.from('estados') + req.sql.from('estado') .where('pk_estado_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('state')); // Get all states from a region stateApp.get('/region/:id', (req, res, next) => { - req.sql.from('estados') + req.sql.from('estado') .where('fk_regiao_id = ?', parseInt(req.params.id, 10)); next(); }, query, response('state')); diff --git a/src/test/test.js b/src/test/test.js index 110be7d6..ddd1f897 100644 --- a/src/test/test.js +++ b/src/test/test.js @@ -96,7 +96,7 @@ describe('request enrollments', () => { it('should list enrollments with valid filters', (done) => { chai.request(server) - .get('/api/v1/enrollment?filter=min_year:2010,state:41') + .get('/api/v1/enrollment?filter=min_year:2014,state:41') .end((err, res) => { res.should.have.status(200); res.should.be.json; @@ -292,7 +292,7 @@ describe('request cities', () => { it('should list a city by id', (done) => { chai.request(server) - .get('/api/v1/city/1') + .get('/api/v1/city/4102802') .end((err, res) => { res.should.have.status(200); res.should.be.json; @@ -317,7 +317,6 @@ describe('request cities', () => { res.body.result[0].should.have.property('pk_municipio_id'); res.body.result[0].should.have.property('fk_estado_id'); res.body.result[0].should.have.property('nome'); - res.body.result[0].should.have.property('codigo_ibge'); done(); }); }); @@ -331,7 +330,6 @@ describe('request cities', () => { res.body.should.have.property('result'); res.body.result.should.be.a('array'); res.body.result[0].should.have.property('pk_municipio_id'); - res.body.result[0].should.have.property('fk_estado_id'); res.body.result[0].should.have.property('nome'); res.body.result[0].should.have.property('codigo_ibge'); done(); @@ -342,7 +340,7 @@ describe('request cities', () => { describe('request schools', () => { it('should list a school by id', (done) => { chai.request(server) - .get('/api/v1/school/185588') + .get('/api/v1/school/11000023') .end((err, res) => { res.should.have.status(200); res.should.be.json; @@ -351,7 +349,8 @@ describe('request schools', () => { res.body.result[0].should.have.property('pk_escola_id'); res.body.result[0].should.have.property('ano_censo'); res.body.result[0].should.have.property('cod_entidade'); - res.body.result[0].should.have.property('nome_entidade'); + res.body.result[0].should.have.property('fk_municipio_id'); + res.body.result[0].should.have.property('fk_estado_id'); done(); }); }); @@ -366,14 +365,15 @@ describe('request schools', () => { res.body.result.should.be.a('array'); res.body.result[0].should.have.property('pk_escola_id'); res.body.result[0].should.have.property('ano_censo'); - res.body.result[0].should.have.property('nome_entidade'); + res.body.result[0].should.have.property('cod_entidade'); + res.body.result[0].should.have.property('fk_municipio_id'); done(); }); }); it('should list all schools from a city', (done) => { chai.request(server) - .get('/api/v1/school/city/3287') + .get('/api/v1/school/city/4102802') .end((err, res) => { res.should.have.status(200); res.should.be.json; @@ -381,7 +381,8 @@ describe('request schools', () => { res.body.result.should.be.a('array'); res.body.result[0].should.have.property('pk_escola_id'); res.body.result[0].should.have.property('ano_censo'); - res.body.result[0].should.have.property('nome_entidade'); + res.body.result[0].should.have.property('cod_entidade'); + res.body.result[0].should.have.property('fk_estado_id'); done(); }) }) -- GitLab