Commit 568d4c3f authored by Vytor Calixto's avatar Vytor Calixto 👾

Merge branch 'release_v1.4.0'

parents 9262c873 7063e290
Pipeline #16349 canceled with stage
in 9 seconds
......@@ -22,3 +22,5 @@ build/*
config.json
docs/
.vscode/
package-lock.json
......@@ -4,6 +4,16 @@ 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/).
## 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
- Removed restriction of year > 2014 of school count route
......@@ -48,7 +58,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Liquid enrollment ratio indicator
- Gloss enrollment ratio indicator
## 1.0.3 - 2018-04-27
### Changed
- Fixed bug undefined field in some indicators
......
module.exports = function ageRange(id) {
switch (id) {
case 1:
return '0-3';
return '0 a 3 anos';
case 2:
return '4-5';
return '4 a 5 anos';
case 3:
return '6-10';
return '6 a 10 anos';
case 4:
return '11-14';
return '11 a 14 anos';
case 5:
return '15-17';
return '15 a 17 anos';
case 6:
return '18-24';
return '18 a 24 anos';
default:
return 'Não declarada';
}
......
module.exports = function ageRange(id) {
switch (id) {
case 1:
return '0-3';
return '0 a 3 anos';
case 2:
return '4-5';
return '4 a 5 anos';
case 3:
return '6-10';
return '6 a 10 anos';
case 4:
return '11-14';
return '11 a 14 anos';
case 5:
return '15-17';
return '15 a 17 anos';
case 6:
return '18-24';
return '18 a 24 anos';
case 7:
return '25-29';
return '25 a 29 anos';
case 8:
return '30-40';
return '30 a 40 anos';
case 9:
return '41-50';
return '41 a 50 anos';
case 10:
return '51-64';
return '51 a 64 anos';
case 11:
return '64+';
return 'Mais de 64 anos';
default:
return 'Não declarada';
}
......
module.exports = function citySize(id) {
module.exports = function incomeLevel(id) {
switch (id) {
case 1:
return '1º quintil – 20% menores';
......
module.exports = function transportationManager(id) {
switch(id) {
case 1:
return 'Estadual';
case 2:
return 'Municipal';
}
};
......@@ -38,7 +38,6 @@ module.exports = function addMissing(rqf){
result.forEach((r) => {
let resultDim1 = r[rqfName];
let resultDim2 = r[rqfName2];
G[rqfName][resultDim1][rqfName2][resultDim2] = true;
});
......
......@@ -25,6 +25,9 @@ const genderPnad = require(`${libs}/convert/genderPnad`);
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 = {
gender_id: gender,
......@@ -61,7 +64,10 @@ const ids = {
full_age_range_id: fullAgeRange,
gender_pnad_id: genderPnad,
fifth_household_income_id: fifthHouseholdIncome,
extremes_household_income_id: extremesHouseholdIncome
extremes_household_income_id: extremesHouseholdIncome,
use_transport_id: useTransport,
use_transport_public_id: useTransportPublic,
transportation_manager_id: transportationManager
};
function transform(removeId=false) {
......@@ -127,5 +133,7 @@ module.exports = {
fullAgeRange,
genderPnad,
fifthHouseholdIncome,
extremesHouseholdIncome
extremesHouseholdIncome,
useTransport,
transportationManager
};
......@@ -3,13 +3,51 @@ const log = require(`${libs}/log`)(module);
const xml = require('js2xmlparser');
const csv = require('csv-express');
// Custom generic middleware used respond requests.
// The function reads the req.query.format param and respond in json, xml or csv
// Função para transformar um resultado que contém objetos com arrays aninhados em vários objetos
// sem arrays aninhandos
function flatObj(obj) {
let flatList = [];
let tempObj = {};
Object.keys(obj).forEach((key) => {
if(obj[key] instanceof Array) {
obj[key].forEach((i) => {
let flatten = flatObj(i);
if(flatten instanceof Array) {
flatten.forEach((j) => {
flatList.push(Object.assign({}, tempObj, j));
});
} else {
flatList.push(Object.assign({}, tempObj, flatten));
}
});
} else if(obj[key] instanceof Object) {
tempObj = Object.assign({}, tempObj, obj[key]);
} else {
tempObj[key] = obj[key];
}
});
if(flatList.length > 0) return flatList;
return tempObj;
}
// Custom generic middleware used to answer requests.
// The function reads the req.query.format param and answers in json, xml or csv
function response(value) {
return (req, res, next) => {
if (req.query.format === 'csv') {
let result = [];
req.result.forEach((i) => {
let flatten = flatObj(i);
if(flatten instanceof Array) {
result = [...result, ...flatten];
} else {
result.push(flatten);
}
});
res.attachment(`${value}.csv`);
res.csv(req.result, true);
res.csv(result, true);
} else if (req.query.format === 'xml') {
res.send(xml.parse('result', { [value]: req.result }));
} else {
......
......@@ -64,8 +64,14 @@ const outOfSchool = require(`${libs}/routes/outOfSchool`);
const classroomCount = require(`${libs}/routes/classroomCount`);
const transport = require(`./transport`);
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' });
});
......@@ -101,5 +107,8 @@ api.use('/siope', siope);
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;
const express = require('express');
const auxiliarApp = 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 ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
const id2str = require(`${libs}/middlewares/id2str`);
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();
auxiliarApp.use(cache('15 day'));
auxiliarApp.get('/year_range', (req, res, next) => {
req.sql.from('docente')
.field('MIN(docente.ano_censo)', 'start_year')
.field('MAX(docente.ano_censo)', 'end_year');
next();
}, query, response('range'));
auxiliarApp.get('/years', (req, res, next) => {
req.sql.from('docente').
field('DISTINCT docente.ano_censo', 'year');
next();
}, query, response('years'));
auxiliarApp.get('/source', (req, res, next) => {
req.sql.from('fonte')
.field('fonte', 'source')
.where('tabela = \'docente\'');
next();
}, query, response('source'))
auxiliarApp.get('/adm_dependency_detailed', (req, res, next) => {
req.result = [];
for(let i = 1; i <= 6; ++i) {
req.result.push({
id: i,
name: id2str.admDependencyPriv(i)
});
};
next();
}, response('adm_dependency_detailed'));
auxiliarApp.get('/adm_dependency', (req, res, next) => {
req.result = [];
for(let i = 1; i <= 4; ++i) {
req.result.push({
id: i,
name: id2str.admDependency(i)
});
};
next();
}, response('adm_dependency'));
auxiliarApp.get('/location', (req, res, next) => {
req.result = [];
for(let i = 1; i <= 2; ++i) {
req.result.push({
id: i,
name: id2str.location(i)
});
};
next();
}, response('location'));
auxiliarApp.get('/rural_location', (req, res, next) => {
req.result = [
{id: 1, name: "Urbana"},
{id: 2, name: "Rural"},
{id: 3, name: "Rural - Área de assentamento"},
{id: 4, name: "Rural - Terra indígena"},
{id: 5, name: "Rural - Área remanescente de quilombos"},
{id: 6, name: "Rural - Unidade de uso sustentável"}
];
next();
}, response('rural_location'));
auxiliarApp.get('/education_level_mod', (req, res, next) => {
req.result = [];
for(let i = 1; i <= 11; ++i) {
req.result.push({
id: i,
name: id2str.educationLevelMod(i)
});
}
req.result.push({
id: 99,
name: id2str.educationLevelMod(99)
});
next();
}, response('education_level_mod'));
auxiliarApp.get('/gender', (req, res, next) => {
req.result = [
{id: 1, name: 'Masculino'},
{id: 2, name: 'Feminino'}
];
next();
}, response('gender'));
auxiliarApp.get('/ethnic_group', (req, res, next) => {
req.result = [];
for(let i = 0; i <=5; ++i) {
req.result.push({
id: i,
name: id2str.ethnicGroup(i)
});
}
next();
}, response('ethnic_group'));
rqf.addField({
name: 'filter',
field: false,
where: true
}).addField({
name: 'dims',
field: true,
where: false
}).addValue({
name: 'adm_dependency',
table: 'docente',
tableField: 'dependencia_adm_id',
resultField: 'adm_dependency_id',
where: {
relation: '=',
type: 'integer',
field: 'dependencia_adm_id'
}
}).addValue({
name: 'adm_dependency_detailed',
table: 'docente',
tableField: 'dependencia_adm_priv',
resultField: 'adm_dependency_detailed_id',
where: {
relation: '=',
type: 'integer',
field: 'dependencia_adm_priv'
}
}).addValue({
name: 'education_level_mod',
table: 'docente',
tableField: 'etapas_mod_ensino_segmento_id',
resultField: 'education_level_mod_id',
where: {
relation: '=',
type: 'integer',
field: 'etapas_mod_ensino_segmento_id'
}
}).addValue({
name: 'region',
table: 'regiao',
tableField: 'nome',
resultField: 'region_name',
where: {
relation: '=',
type: 'integer',
field: 'id'
},
join: {
primary: 'id',
foreign: 'escola_regiao_id',
foreignTable: 'docente'
}
}).addValue({
name: 'state',
table: 'estado',
tableField: 'nome',
resultField: 'state_name',
where: {
relation: '=',
type: 'integer',
field: 'id'
},
join: {
primary: 'id',
foreign: 'escola_estado_id',
foreignTable: 'docente'
}
}).addValue({
name: 'rural_location',
table: 'docente',
tableField: 'localidade_area_rural',
resultField: 'rural_location_id',
where: {
relation: '=',
type: 'integer',
field: 'localidade_area_rural'
}
}).addValueToField({
name: 'city',
table: 'municipio',
tableField: ['nome', 'id'],
resultField: ['city_name', 'city_id'],
where: {
relation: '=',
type: 'integer',
field: 'id'
},
join: {
primary: 'id',
foreign: 'escola_municipio_id',
foreignTable: 'docente'
}
}, 'dims').addValueToField({
name: 'city',
table: 'municipio',
tableField: 'nome',
resultField: 'city_name',
where: {
relation: '=',
type: 'integer',
field: 'id'
},
join: {
primary: 'id',
foreign: 'escola_municipio_id',
foreignTable: 'docente'
}
}, 'filter').addValue({
name: 'location',
table: 'docente',
tableField: 'cod_localizacao',
resultField: 'location_id',
where: {
relation: '=',
type: 'integer',
field: 'cod_localizacao'
}
}).addValue({
name: 'min_year',
table: 'docente',
tableField: 'ano_censo',
resultField: 'year',
where: {
relation: '>=',
type: 'integer',
field: 'ano_censo'
}
}).addValue({
name: 'max_year',
table: 'docente',
tableField: 'ano_censo',
resultField: 'year',
where: {
relation: '<=',
type: 'integer',
field: 'ano_censo'
}
}).addValue({
name: 'gender',
table: 'docente',
tableField: 'sexo',
resultField: 'gender_id',
where: {
relation: '=',
type: 'integer',
field: 'sexo'
}
}).addValue({
name: 'ethnic_group',
table: 'docente',
tableField: 'cor_raca',
resultField: 'ethnic_group_id',
where: {
relation: '=',
type: 'integer',
field: 'cor_raca'
}
});
// LDE
auxiliarApp.get('/', rqf.parse(), (req, res, next) => {
req.sql.field('COUNT(DISTINCT docente.id)', 'total')
.field("'Brasil'", 'name')
.field('docente.ano_censo', 'year')
.from('docente')
.group('docente.ano_censo')
.order('docente.ano_censo')
.where('(docente.tipo_turma_id <= 3 AND docente.dependencia_adm_id > 1 AND docente.tipo_docente = 2)');
next();
}, rqf.build(), query, addMissing(rqf), id2str.transform(), response('auxiliar'));
// SimCAQ
auxiliarApp.get('/count', rqf.parse(), (req, res, next) => {
req.sql.field('COUNT(DISTINCT docente.id)', 'total')
.field("'Brasil'", 'name')
.field('docente.ano_censo', 'year')
.from('docente')
.group('docente.ano_censo')
.order('docente.ano_censo')
.where('((docente.tipo_turma_id <= 3) AND (docente.dependencia_adm_id = 2 OR docente.dependencia_adm_id = 3) AND (docente.tipo_docente = 2))');
next();
}, rqf.build(), query, addMissing(rqf), id2str.transform(), response('auxiliar'));
auxiliarApp.get('/download', passport.authenticate('bearer', { session: false }), rqf.parse(), rqf.build(), download('docente', 'mapping_docente'));
module.exports = auxiliarApp;
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",