diff --git a/CHANGELOG.md b/CHANGELOG.md index fa0623bcc181226f977fbff32008824c93aa9063..6ffc657d792d9a0358b82c4ad7f0d2c49e2a7173 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## UNRELEASED -### Changed +## 1.4.0 - 2018-06-27 +### Added - Add school building filter/dimension to school count route +- Add transport indicator +- Add cub route +### Changed - Fixed CSV output when result objects have nested arrays and/or objects +- Limit year range to 2007-2015 in out of school indicator +- Fix auxiliar indicator ## 1.3.3 - 2018-06-27 ### Changed diff --git a/src/libs/middlewares/id2str.js b/src/libs/middlewares/id2str.js index d8c4ce7094776dda3e48913272c34bdebbef7771..c2fa1fab15eded3a1190bdbe5c918275b2e9b5c5 100644 --- a/src/libs/middlewares/id2str.js +++ b/src/libs/middlewares/id2str.js @@ -26,6 +26,7 @@ const fifthHouseholdIncome = require(`${libs}/convert/fifthHouseholdIncome`); const extremesHouseholdIncome = require(`${libs}/convert/extremesHouseholdIncome`); const educationLevelBasic = require(`${libs}/convert/educationLevelBasic`); const useTransport = require(`${libs}/convert/booleanVariable`); +const useTransportPublic = require(`${libs}/convert/booleanVariable`); const transportationManager = require(`${libs}/convert/transportationManager`); const ids = { @@ -65,6 +66,7 @@ const ids = { fifth_household_income_id: fifthHouseholdIncome, extremes_household_income_id: extremesHouseholdIncome, use_transport_id: useTransport, + use_transport_public_id: useTransportPublic, transportation_manager_id: transportationManager }; diff --git a/src/libs/routes/api.js b/src/libs/routes/api.js index 0a1b047f6545006fc8954d5d966d8f8b38df602d..f5742fd5aad548d1bf98e9435fb0ef496b4b9afb 100644 --- a/src/libs/routes/api.js +++ b/src/libs/routes/api.js @@ -70,6 +70,8 @@ const auxiliar = require(`${libs}/routes/auxiliar`); const dailyChargeAmount = require(`${libs}/routes/dailyChargeAmount`); +const cub = require(`${libs}/routes/cub`); + api.get('/', (req, res) => { res.json({ msg: 'SimCAQ API is running' }); }); @@ -106,6 +108,7 @@ api.use('/out_of_school', outOfSchool); api.use('/classroom_count', classroomCount); api.use('/daily_charge_amount', dailyChargeAmount); api.use('/transport', transport); +api.use('/cub', cub); api.use('/auxiliar', auxiliar); module.exports = api; diff --git a/src/libs/routes/cub.js b/src/libs/routes/cub.js new file mode 100644 index 0000000000000000000000000000000000000000..5310f0be248f191f0e41325fb84d03525f638e40 --- /dev/null +++ b/src/libs/routes/cub.js @@ -0,0 +1,178 @@ +const express = require('express'); + +const cubApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`).query; + +const response = require(`${libs}/middlewares/response`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const request = require(`request`); + +const config = require(`${libs}/config`); + +const passport = require('passport'); + +const download = require(`${libs}/middlewares/downloadDatabase`); + +const addMissing = require(`${libs}/middlewares/addMissing`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); +let rqfCount = new ReqQueryFields(); + +cubApp.get('/year_range', (req, res, next) => { + req.sql.from('cub') + .field('MIN(cub.ano_censo)', 'start_year') + .field('MAX(cub.ano_censo)', 'end_year'); + next(); +}, query, response('range')); + +cubApp.get('/years', (req, res, next) => { + req.sql.from('cub') + .field('DISTINCT cub.ano_censo', 'year'); + next(); +}, query, response('years')); + +cubApp.get('/months', (req, res, next) => { + req.sql.from('cub') + .field('DISTINCT cub.mes_censo', 'month'); + next(); +}, query, response('months')); + +cubApp.get('/years_months', (req, res, next) => { + req.sql.from('cub') + .field('DISTINCT cub.ano_censo AS "year", cub.mes_censo AS "month"'); + next(); +}, query, response('years_months')); + +cubApp.get('/price_type', (req, res, next) => { + req.sql.from('cub') + .field('DISTINCT cub.tipo_preco', 'price_type'); + next(); +}, query, response('price_type')); + +rqf.addField({ + name: 'filter', + field: false, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['sigla', 'id'], + resultField: ['sigla_uf', 'cod_uf'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: 'cub' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: 'cub' + } +}).addValue({ + name: 'min_year', + table: 'cub', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: 'cub', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: 'cub', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: 'cub', + field: 'ano_censo' + } +}).addValue({ + name: 'min_month', + table: 'cub', + tableField: 'mes_censo', + resultField: 'month', + where: { + relation: '>=', + type: 'integer', + table: 'cub', + field: 'mes_censo' + } +}).addValue({ + name: 'max_month', + table: 'cub', + tableField: 'mes_censo', + resultField: 'month', + where: { + relation: '<=', + type: 'integer', + table: 'cub', + field: 'mes_censo' + } +}); + +cubApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { + if (req.filter.size || req.filter.dims) { + if ('state' in req.filter || 'state' in req.dims) { + req.sql.from('cub') + .field('cub.estado_id', 'cod_uf') + .field('estado.sigla', 'sigla_uf') + .field('cub.tipo_preco', 'tipo_preco') + .field('cub.preco', 'preco') + .join('estado', null, 'cub.estado_id=estado.id') + .group('cub.ano_censo') + .group('cub.mes_censo') + .group('cub.estado_id') + .group('estado.sigla') + .group('cub.tipo_preco') + .group('cub.preco') + } else { + req.sql.from('cub') + .field("'BR'", 'sigla_uf') + .field("cub.tipo_preco", 'tipo_preco') + .field('AVG(cub.preco)', 'preco') + .join('estado', null, 'cub.estado_id=estado.id') + .group('cub.ano_censo') + .group('cub.mes_censo') + .group('cub.tipo_preco') + } + } else { + req.sql.from('cub') + .field('cub.estado_id', 'cod_uf') + .field('estado.sigla', 'sigla_uf') + .field('cub.tipo_preco', 'tipo_preco') + .field('cub.preco', 'preco') + .join('estado', null, 'cub.estado_id=estado.id') + .group('cub.ano_censo') + .group('cub.mes_censo') + .group('cub.estado_id') + .group('estado.sigla') + .group('cub.tipo_preco') + .group('cub.preco') + } + + next(); +}, query, addMissing(rqf), id2str.transform(), response('cub')); + +module.exports = cubApp; diff --git a/src/libs/routes/outOfSchool.js b/src/libs/routes/outOfSchool.js index 822ef3a8e2bf5959b977a0fc2b1e807756efbd9c..d7e3915a624bac28541ecbe2460f8ae54d8e0e0c 100644 --- a/src/libs/routes/outOfSchool.js +++ b/src/libs/routes/outOfSchool.js @@ -29,13 +29,15 @@ outOfSchoolApp.use(cache('15 day')); outOfSchoolApp.get('/year_range', (req, res, next) => { req.sql.from('pnad') .field('MIN(pnad.ano_censo)', 'start_year') - .field('MAX(pnad.ano_censo)', 'end_year'); + .field('MAX(pnad.ano_censo)', 'end_year') + .where('pnad.ano_censo >= 2007 AND pnad.ano_censo <= 2015'); next(); }, query, response('range')); outOfSchoolApp.get('/years', (req, res, next) => { req.sql.from('pnad'). - field('DISTINCT pnad.ano_censo', 'year'); + field('DISTINCT pnad.ano_censo', 'year') + .where('pnad.ano_censo >= 2007 AND pnad.ano_censo <= 2015'); next(); }, query, response('years')); diff --git a/src/libs/routes/transport.js b/src/libs/routes/transport.js index 7af1b9907366b1de7be37f1db0c4d5d4d7dc8487..38c81c9c1e6361b40371363c3b19e6b60390ef65 100644 --- a/src/libs/routes/transport.js +++ b/src/libs/routes/transport.js @@ -95,6 +95,18 @@ transportApp.get('/education_level_basic', (req, res, next) => { next(); }, response('education_level_basic')); +transportApp.get('/service_type', (req, res, next) => { + req.result = [ + {id: 0, name: 'Não se aplica'}, + {id: 1, name: 'Classe hospitalar'}, + {id: 2, name: 'Unidade de Atendimento Socioeducativo'}, + {id: 3, name: 'Unidade Prisional'}, + {id: 4, name: 'Atividade Complementar '}, + {id: 5, name: 'Atendimento Educacional Especializado (AEE)'} + ]; + next(); +}, response('service_type')); + transportApp.get('/transportation_manager', (req, res, next) => { req.result = [ {id: null, name: 'Não classificada'}, @@ -119,6 +131,36 @@ rqf.addField({ name: 'dims', field: true, where: false +}).addValue({ + name: 'school', + table: 'escola', + tableField: ['nome_escola', 'id'], + resultField: ['school_name', 'school_id'], + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: ['id', 'ano_censo'], + foreign: ['escola_id', 'ano_censo'], + foreignTable: 'matricula' + } +}).addValue({ + name: 'region', + table: 'regiao', + tableField: 'nome', + resultField: 'region_name', + where: { + relation: '=', + type: 'integer', + field: 'id' + }, + join: { + primary: 'id', + foreign: 'regiao_id', + foreignTable: 'matricula' + } }).addValue({ name: 'city', table: 'municipio', @@ -313,6 +355,17 @@ transportApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { .field('matricula.transporte_escolar_publico', 'use_transport_id') .from('matricula') .group('matricula.ano_censo') + .order('matricula.ano_censo') + .where('matricula.tipo <= 3'); + req.queryIndex.allEnrollmentTransport = req.querySet.push(allEnrollmentTransport) - 1; + + let allEnrollmentTransport = req.sql.clone() + allEnrollmentTransport.field('COUNT(*)', 'total') + .field("'Brasil'", 'name') + .field('matricula.ano_censo', 'year') + .field('matricula.transporte_escolar_publico', 'use_transport_public_id') + .from('matricula') + .group('matricula.ano_censo') .group('matricula.transporte_escolar_publico') .order('matricula.ano_censo') .where('matricula.tipo <= 3'); @@ -429,9 +482,9 @@ transportApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { //modifica adicionando use_transport_id=false, com os mesmos valores //do transport_id=true, usado para dar o match e fazer a divisão. for (let i = 0; i < all_enrollment_match_0.length; i++) { - all_enrollment_match_0[i].use_transport_id = true; + all_enrollment_match_0[i].use_transport_public_id = true; all_enrollment_match.push(all_enrollment_match_0[i]) - all_enrollment_match_1[i].use_transport_id = false; + all_enrollment_match_1[i].use_transport_public_id = false; all_enrollment_match.push(all_enrollment_match_1[i]) } diff --git a/src/test/cub.js b/src/test/cub.js new file mode 100644 index 0000000000000000000000000000000000000000..751ca40a2a77ff9fe7275f0a2f3c769c5318e4f3 --- /dev/null +++ b/src/test/cub.js @@ -0,0 +1,109 @@ +process.env.NODE_ENV = 'test'; + +const chai = require('chai'); + +const dirtyChai = require('dirty-chai'); + +chai.use(dirtyChai); + +const chaiXml = require('chai-xml'); + +chai.use(chaiXml); + +const chaiHttp = require('chai-http'); + +const assert = chai.assert; + +const expect = chai.expect; + +const should = chai.should(); // actually call the function + +const libs = `${process.cwd()}/libs`; + +const server = require(`${libs}/app`); + +chai.use(chaiHttp); +describe('request cub', () => { + it('should return default query cub', (done) => { + chai.request(server) + .get('/api/v1/cub') + .end((err, res) => { + res.should.have.status(200); + res.should.be.json; + res.body.should.have.property('result'); + res.body.result.should.be.a('array'); + res.body.result[0].should.have.property('cod_uf'); + res.body.result[0].should.have.property('sigla_uf'); + res.body.result[0].should.have.property('tipo_preco'); + res.body.result[0].should.have.property('preco'); + done(); + }); + }); + + it('should list the years', (done) => { + chai.request(server) + .get('/api/v1/cub/years') + .end((err, res) => { + res.should.have.status(200); + res.should.be.json; + res.body.should.have.property('result'); + res.body.result.should.be.a('array'); + res.body.result[0].should.have.property('year'); + done(); + }); + }); + + it('should list the year range', (done) => { + chai.request(server) + .get('/api/v1/cub/year_range') + .end((err, res) => { + res.should.have.status(200); + res.should.be.json; + res.body.should.have.property('result'); + res.body.result.should.be.a('array'); + res.body.result[0].should.have.property('start_year'); + res.body.result[0].should.have.property('end_year'); + done(); + }); + }); + + it('should list the months', (done) => { + chai.request(server) + .get('/api/v1/cub/months') + .end((err, res) => { + res.should.have.status(200); + res.should.be.json; + res.body.should.have.property('result'); + res.body.result.should.be.a('array'); + res.body.result[0].should.have.property('month'); + done(); + }); + }); + + it('should list the years and months', (done) => { + chai.request(server) + .get('/api/v1/cub/year_range') + .end((err, res) => { + res.should.have.status(200); + res.should.be.json; + res.body.should.have.property('result'); + res.body.result.should.be.a('array'); + res.body.result[0].should.have.property('year'); + res.body.result[0].should.have.property('month'); + done(); + }); + }); + + it('should list the price type', (done) => { + chai.request(server) + .get('/api/v1/cub/price_type') + .end((err, res) => { + res.should.have.status(200); + res.should.be.json; + res.body.should.have.property('result'); + res.body.result.should.be.a('array'); + res.body.result[0].should.have.property('price_type'); + done(); + }); + }); +});