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 01/32] 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


From 675bac1316d06e043744d03af9ef9d21c74197b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Thu, 27 Oct 2016 12:05:42 -0200
Subject: [PATCH 02/32] Implement routes for sociodemographic and school in
 location module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/libs/routes/location.js | 657 ++++++++++++++++++++++++++++++++++++
 1 file changed, 657 insertions(+)
 create mode 100644 src/libs/routes/location.js

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
new file mode 100644
index 00000000..a4289272
--- /dev/null
+++ b/src/libs/routes/location.js
@@ -0,0 +1,657 @@
+const express = require('express');
+
+const libs = `${process.cwd()}/libs`;
+
+const squel = require('squel');
+
+const log = require(`${libs}/log`)(module);
+
+const query = require(`${libs}/middlewares/query`);
+
+const sqlQuery = require(`${libs}/db/query_exec`);
+
+const response = require(`${libs}/middlewares/response`);
+
+const locationApp = express();
+
+function locationIdToStr(locationId) {
+    let locationStr = 'Todas';
+    switch(locationId) {
+        case 1:
+            locationStr = 'Urbana';
+            break;
+        case 2:
+            locationStr = 'Rural';
+            break;
+    }
+    return locationStr;
+}
+
+locationApp.get('/sociodemographic', (req, res, next) => {
+    const populationYearQry = squel.select()
+        .field('MAX(ibge_populacao.ano_censo)')
+        .from('ibge_populacao');
+
+    const populationQry = squel.select()
+        .field('\'Brasil\'', 'location')
+        .field('SUM(populacao)', 'population')
+        .field('ibge_populacao.ano_censo')
+        .from('ibge_populacao')
+        .where(`ibge_populacao.ano_censo IN (${populationYearQry.toString()})`)
+        .group('ibge_populacao.ano_censo');
+
+    const pibYearQry = squel.select()
+        .field('MAX(ibge_pib.ano_censo)')
+        .from('ibge_pib');
+
+    const pibQry = squel.select()
+        .field('\'Brasil\'', 'location')
+        .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
+        .field('ibge_pib.ano_censo')
+        .from('ibge_pib')
+        .where(`ibge_pib.ano_censo IN (${pibYearQry.toString()})`)
+        .group('ibge_pib.ano_censo');
+
+    const idhYearQry = squel.select()
+        .field('MAX(adh_idh.ano_censo)')
+        .from('adh_idh');
+
+    const idhQry = squel.select()
+        .field('\'Brasil\'', 'location')
+        .field('AVG(idhm)', 'idhm')
+        .field('adh_idh.ano_censo')
+        .from('adh_idh')
+        .where(`adh_idh.ano_censo IN (${idhYearQry.toString()})`)
+        .group('adh_idh.ano_censo');
+
+    const analfabYearQry = squel.select()
+        .field('MAX(adh_analfabetismo.ano_censo)')
+        .from('adh_analfabetismo');
+
+    const analfabQry = squel.select()
+        .field('\'Brasil\'', 'location')
+        .field('AVG(t_analf15m)', 'analfabetism')
+        .field('adh_analfabetismo.ano_censo')
+        .from('adh_analfabetismo')
+        .where(`adh_analfabetismo.ano_censo IN (${analfabYearQry.toString()})`)
+        .group('adh_analfabetismo.ano_censo');
+
+    const giniYearQry = squel.select()
+        .field('MAX(adh_gini.ano_censo)')
+        .from('adh_gini');
+
+    const giniQry = squel.select()
+        .field('\'Brasil\'', 'location')
+        .field('AVG(gini)', 'gini')
+        .field('adh_gini.ano_censo')
+        .from('adh_gini')
+        .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`)
+        .group('adh_gini.ano_censo');
+
+    const queries = [populationQry, pibQry, idhQry, analfabQry, giniQry].map((qry) => {
+        return sqlQuery(qry.toString());
+    });
+
+    // execute all queries concurrently
+    Promise.all(queries).then((queryResults) => {
+        req.result = [];
+        for(let result of queryResults) {
+            log.debug(result);
+            req.result.push(result[0]);
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/sociodemographic/region/:id', (req, res, next) => {
+    const regionId = parseInt(req.params.id, 10);
+
+    const populationYearQry = squel.select()
+        .field('MAX(ibge_populacao.ano_censo)')
+        .from('ibge_populacao');
+
+    const populationQry = squel.select()
+        .field('regiao.nome', 'location')
+        .field('SUM(populacao)', 'population')
+        .field('ano_censo', 'census_year')
+        .from('ibge_populacao')
+        .from('municipio')
+        .from('estado')
+        .from('regiao')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`ibge_populacao.ano_censo IN (${populationYearQry.toString()})`)
+        .where('ibge_populacao.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .group('regiao.nome')
+        .group('ibge_populacao.ano_censo')
+        .order('regiao.nome');
+
+    const pibYearQry = squel.select()
+        .field('MAX(ibge_pib.ano_censo)')
+        .from('ibge_pib');
+
+    const pibQry = squel.select()
+        .field('regiao.nome', 'location')
+        .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
+        .field('ano_censo', 'census_year')
+        .from('ibge_pib')
+        .from('municipio')
+        .from('estado')
+        .from('regiao')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`ibge_pib.ano_censo IN (${pibYearQry.toString()})`)
+        .where('ibge_pib.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .group('regiao.nome')
+        .group('ibge_pib.ano_censo')
+        .order('regiao.nome');
+
+    const idhYearQry = squel.select()
+        .field('MAX(adh_idh.ano_censo)')
+        .from('adh_idh');
+
+    const idhQry = squel.select()
+        .field('regiao.nome', 'location')
+        .field('AVG(idhm)', 'idhm')
+        .field('ano_censo', 'census_year')
+        .from('adh_idh')
+        .from('municipio')
+        .from('estado')
+        .from('regiao')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`adh_idh.ano_censo IN (${idhYearQry.toString()})`)
+        .where('adh_idh.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .group('regiao.nome')
+        .group('adh_idh.ano_censo')
+        .order('regiao.nome');
+
+    const analfabYearQry = squel.select()
+        .field('MAX(adh_analfabetismo.ano_censo)')
+        .from('adh_analfabetismo');
+
+    const analfabQry = squel.select()
+        .field('regiao.nome', 'location')
+        .field('AVG(t_analf15m)', 'analfabetism')
+        .field('ano_censo', 'census_year')
+        .from('adh_analfabetismo')
+        .from('municipio')
+        .from('estado')
+        .from('regiao')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`adh_analfabetismo.ano_censo IN (${analfabYearQry.toString()})`)
+        .where('adh_analfabetismo.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .group('regiao.nome')
+        .group('adh_analfabetismo.ano_censo')
+        .order('regiao.nome');
+
+    const giniYearQry = squel.select()
+        .field('MAX(adh_gini.ano_censo)')
+        .from('adh_gini');
+
+    const giniQry = squel.select()
+        .field('regiao.nome', 'location')
+        .field('AVG(gini)', 'gini')
+        .field('ano_censo', 'census_year')
+        .from('adh_gini')
+        .from('municipio')
+        .from('estado')
+        .from('regiao')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`)
+        .where('adh_gini.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .group('regiao.nome')
+        .group('adh_gini.ano_censo')
+        .order('regiao.nome');
+
+    const queries = [populationQry, pibQry, idhQry, analfabQry, giniQry].map((qry) => {
+        return sqlQuery(qry.toString());
+    });
+
+    // execute all queries concurrently
+    Promise.all(queries).then((queryResults) => {
+        req.result = [];
+        for(let result of queryResults) {
+            log.debug(result);
+            req.result.push(result[0]);
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/sociodemographic/state/:id', (req, res, next) => {
+    const stateId = parseInt(req.params.id, 10);
+
+    const populationYearQry = squel.select()
+        .field('MAX(ibge_populacao.ano_censo)')
+        .from('ibge_populacao');
+    // load all cities by state and compute the sociodemographic and educational information
+    const populationQry = squel.select()
+        .field('estado.nome', 'location')
+        .field('SUM(populacao)', 'population')
+        .field('ibge_populacao.ano_censo', 'census_year')
+        .from('ibge_populacao')
+        .from('municipio')
+        .from('estado')
+        .where(`estado.pk_estado_id = ${stateId}`)
+        .where(`ibge_populacao.ano_censo IN (${populationYearQry.toString()})`)
+        .where('ibge_populacao.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .group('estado.nome')
+        .group('ibge_populacao.ano_censo')
+        .order('estado.nome');
+
+    const pibYearQry = squel.select()
+        .field('MAX(ibge_pib.ano_censo)')
+        .from('ibge_pib');
+
+    const pibQry = squel.select()
+        .field('estado.nome', 'location')
+        .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
+        .field('ibge_pib.ano_censo', 'census_year')
+        .from('ibge_pib')
+        .from('municipio')
+        .from('estado')
+        .where(`estado.pk_estado_id = ${stateId}`)
+        .where(`ibge_pib.ano_censo IN (${pibYearQry.toString()})`)
+        .where('ibge_pib.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .group('estado.nome')
+        .group('ibge_pib.ano_censo')
+        .order('estado.nome');
+
+    const idhYearQry = squel.select()
+        .field('MAX(adh_idh.ano_censo)')
+        .from('adh_idh');
+
+    const idhQry = squel.select()
+        .field('estado.nome', 'location')
+        .field('AVG(idhm)', 'idhm')
+        .field('adh_idh.ano_censo', 'census_year')
+        .from('adh_idh')
+        .from('municipio')
+        .from('estado')
+        .where(`estado.pk_estado_id = ${stateId}`)
+        .where(`adh_idh.ano_censo IN (${idhYearQry.toString()})`)
+        .where('adh_idh.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .group('estado.nome')
+        .group('adh_idh.ano_censo')
+        .order('estado.nome');
+
+    const analfabYearQry = squel.select()
+        .field('MAX(adh_analfabetismo.ano_censo)')
+        .from('adh_analfabetismo');
+
+    const analfabQry = squel.select()
+        .field('estado.nome', 'location')
+        .field('AVG(t_analf15m)', 'analfabetism')
+        .field('adh_analfabetismo.ano_censo', 'census_year')
+        .from('adh_analfabetismo')
+        .from('municipio')
+        .from('estado')
+        .where(`estado.pk_estado_id = ${stateId}`)
+        .where(`adh_analfabetismo.ano_censo IN (${analfabYearQry.toString()})`)
+        .where('adh_analfabetismo.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .group('estado.nome')
+        .group('adh_analfabetismo.ano_censo')
+        .order('estado.nome');
+
+    const giniYearQry = squel.select()
+        .field('MAX(adh_gini.ano_censo)')
+        .from('adh_gini');
+
+    const giniQry = squel.select()
+        .field('estado.nome', 'location')
+        .field('AVG(gini)', 'gini')
+        .field('adh_gini.ano_censo', 'census_year')
+        .from('adh_gini')
+        .from('municipio')
+        .from('estado')
+        .where(`estado.pk_estado_id = ${stateId}`)
+        .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`)
+        .where('adh_gini.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .group('estado.nome')
+        .group('adh_gini.ano_censo')
+        .order('estado.nome');
+
+    const queries = [populationQry, pibQry, idhQry, analfabQry, giniQry].map((qry) => {
+        return sqlQuery(qry.toString());
+    });
+
+    // execute all queries concurrently
+    Promise.all(queries).then((queryResults) => {
+        req.result = [];
+        for(let result of queryResults) {
+            log.debug(result);
+            req.result.push(result[0]);
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/sociodemographic/city/:id', (req, res, next) => {
+    const cityId = parseInt(req.params.id, 10);
+
+    const populationYearQry = squel.select()
+        .field('MAX(ibge_populacao.ano_censo)')
+        .from('ibge_populacao');
+    // load all cities by state and compute the sociodemographic and educational information
+    const populationQry = squel.select()
+        .field('municipio.nome', 'location')
+        .field('SUM(populacao)', 'population')
+        .field('ibge_populacao.ano_censo', 'census_year')
+        .from('ibge_populacao')
+        .from('municipio')
+        .where(`municipio.pk_cod_ibge = ${cityId}`)
+        .where(`ibge_populacao.ano_censo IN (${populationYearQry.toString()})`)
+        .where('ibge_populacao.fk_municipio_id = municipio.pk_cod_ibge')
+        .group('municipio.nome')
+        .group('ibge_populacao.ano_censo')
+        .order('municipio.nome');
+
+    const pibYearQry = squel.select()
+        .field('MAX(ibge_pib.ano_censo)')
+        .from('ibge_pib');
+
+    const pibQry = squel.select()
+        .field('municipio.nome', 'location')
+        .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
+        .field('ibge_pib.ano_censo', 'census_year')
+        .from('ibge_pib')
+        .from('municipio')
+        .where(`municipio.pk_cod_ibge = ${cityId}`)
+        .where(`ibge_pib.ano_censo IN (${pibYearQry.toString()})`)
+        .where('ibge_pib.fk_municipio_id = municipio.pk_cod_ibge')
+        .group('municipio.nome')
+        .group('ibge_pib.ano_censo')
+        .order('municipio.nome');
+
+    const idhYearQry = squel.select()
+        .field('MAX(adh_idh.ano_censo)')
+        .from('adh_idh');
+
+    const idhQry = squel.select()
+        .field('municipio.nome', 'location')
+        .field('AVG(idhm)', 'idhm')
+        .field('adh_idh.ano_censo', 'census_year')
+        .from('adh_idh')
+        .from('municipio')
+        .where(`municipio.pk_cod_ibge = ${cityId}`)
+        .where(`adh_idh.ano_censo IN (${idhYearQry.toString()})`)
+        .where('adh_idh.fk_municipio_id = municipio.pk_cod_ibge')
+        .group('municipio.nome')
+        .group('adh_idh.ano_censo')
+        .order('municipio.nome');
+
+    const analfabYearQry = squel.select()
+        .field('MAX(adh_analfabetismo.ano_censo)')
+        .from('adh_analfabetismo');
+
+    const analfabQry = squel.select()
+        .field('municipio.nome', 'location')
+        .field('AVG(t_analf15m)', 'analfabetism')
+        .field('adh_analfabetismo.ano_censo', 'census_year')
+        .from('adh_analfabetismo')
+        .from('municipio')
+        .where(`municipio.pk_cod_ibge = ${cityId}`)
+        .where(`adh_analfabetismo.ano_censo IN (${analfabYearQry.toString()})`)
+        .where('adh_analfabetismo.fk_municipio_id = municipio.pk_cod_ibge')
+        .group('municipio.nome')
+        .group('adh_analfabetismo.ano_censo')
+        .order('municipio.nome');
+
+    const giniYearQry = squel.select()
+        .field('MAX(adh_gini.ano_censo)')
+        .from('adh_gini');
+
+    const giniQry = squel.select()
+        .field('municipio.nome', 'location')
+        .field('AVG(gini)', 'gini')
+        .field('adh_gini.ano_censo', 'census_year')
+        .from('adh_gini')
+        .from('municipio')
+        .where(`municipio.pk_cod_ibge = ${cityId}`)
+        .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`)
+        .where('adh_gini.fk_municipio_id = municipio.pk_cod_ibge')
+        .group('municipio.nome')
+        .group('adh_gini.ano_censo')
+        .order('municipio.nome');
+
+    const queries = [populationQry, pibQry, idhQry, analfabQry, giniQry].map((qry) => {
+        return sqlQuery(qry.toString());
+    });
+
+    // execute all queries concurrently
+    Promise.all(queries).then((queryResults) => {
+        req.result = [];
+        for(let result of queryResults) {
+            log.debug(result);
+            req.result.push(result[0]);
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational', (req, res, next) => {
+    const censusYearQry = squel.select()
+        .field('MAX(escola.ano_censo)', 'ano_censo')
+        .from('escola')
+        .toString();
+
+    const totalSchoolsQry = squel.select()
+        .field('0', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .from('escola')
+        .where(`escola.ano_censo IN (${censusYearQry})`);
+
+    const schoolsPerLocationQry = squel.select()
+        .field('escola.id_localizacao', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .from('escola')
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .group('escola.id_localizacao');
+
+    const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
+        return sqlQuery(qry.toString());
+    });
+
+    // execute all queries concurrently
+    Promise.all(queries).then((queryResults) => {
+        req.result = [];
+        for(let result of queryResults) {
+            log.debug(result);
+            for(let row of result) {
+                row.location = locationIdToStr(row.location);
+                req.result.push(row);
+            }
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational/region/:id', (req, res, next) => {
+    const regionId = parseInt(req.params.id, 10);
+
+    const censusYearQry = squel.select()
+        .field('MAX(escola.ano_censo)', 'ano_censo')
+        .from('escola')
+        .toString();
+
+    const totalSchoolsQry = squel.select()
+        .field('regiao.nome')
+        .field('0', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .from('escola')
+        .from('estado')
+        .from('regiao')
+        .where('escola.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .group('regiao.nome');
+
+    const schoolsPerLocationQry = squel.select()
+        .field('regiao.nome')
+        .field('escola.id_localizacao', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .from('escola')
+        .from('estado')
+        .from('regiao')
+        .where('escola.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .group('regiao.nome')
+        .group('escola.id_localizacao');
+
+    const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
+        return sqlQuery(qry.toString());
+    });
+
+    // execute all queries concurrently
+    Promise.all(queries).then((queryResults) => {
+        req.result = [];
+        for(let result of queryResults) {
+            log.debug(result);
+            for(let row of result) {
+                row.location = locationIdToStr(row.location);
+                req.result.push(row);
+            }
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational/state/:id', (req, res, next) => {
+    const stateId = parseInt(req.params.id, 10);
+
+    const censusYearQry = squel.select()
+        .field('MAX(escola.ano_censo)', 'ano_censo')
+        .from('escola')
+        .toString();
+
+    const totalSchoolsQry = squel.select()
+        .field('estado.nome')
+        .field('0', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .from('escola')
+        .from('estado')
+        .where('escola.fk_estado_id = estado.pk_estado_id')
+        .where(`escola.fk_estado_id = ${stateId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .group('estado.nome');
+
+    const schoolsPerLocationQry = squel.select()
+        .field('estado.nome')
+        .field('escola.id_localizacao', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .from('escola')
+        .from('estado')
+        .where('escola.fk_estado_id = estado.pk_estado_id')
+        .where(`escola.fk_estado_id = ${stateId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .group('estado.nome')
+        .group('escola.id_localizacao');
+
+    const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
+        return sqlQuery(qry.toString());
+    });
+
+    // execute all queries concurrently
+    Promise.all(queries).then((queryResults) => {
+        req.result = [];
+        for(let result of queryResults) {
+            log.debug(result);
+            for(let row of result) {
+                row.location = locationIdToStr(row.location);
+                req.result.push(row);
+            }
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational/city/:id', (req, res, next) => {
+    const cityId = parseInt(req.params.id, 10);
+
+    const censusYearQry = squel.select()
+        .field('MAX(escola.ano_censo)', 'ano_censo')
+        .from('escola')
+        .toString();
+
+    const totalSchoolsQry = squel.select()
+        .field('municipio.nome')
+        .field('0', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .from('escola')
+        .from('municipio')
+        .where('escola.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`escola.fk_municipio_id = ${cityId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .group('municipio.nome');
+
+    const schoolsPerLocationQry = squel.select()
+        .field('municipio.nome')
+        .field('escola.id_localizacao', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .from('escola')
+        .from('municipio')
+        .where('escola.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`escola.fk_municipio_id = ${cityId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .group('municipio.nome')
+        .group('escola.id_localizacao');
+
+    const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
+        return sqlQuery(qry.toString());
+    });
+
+    // execute all queries concurrently
+    Promise.all(queries).then((queryResults) => {
+        req.result = [];
+        for(let result of queryResults) {
+            log.debug(result);
+            for(let row of result) {
+                row.location = locationIdToStr(row.location);
+                req.result.push(row);
+            }
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+module.exports = locationApp;
-- 
GitLab


From 7a234c5f191a3aab52c30bcee6b0bcff0a6f9d11 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Thu, 27 Oct 2016 12:06:40 -0200
Subject: [PATCH 03/32] Mount /location route on api module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/libs/routes/api.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/libs/routes/api.js b/src/libs/routes/api.js
index 3faaa926..0522a8d0 100644
--- a/src/libs/routes/api.js
+++ b/src/libs/routes/api.js
@@ -12,6 +12,8 @@ const city = require('./city');
 
 const school = require('./school');
 
+const location = require('./location');
+
 api.get('/', (req, res) => {
     res.json({ msg: 'SimCAQ API is running' });
 });
@@ -22,5 +24,6 @@ api.use('/state', state);
 api.use('/region', region);
 api.use('/city', city);
 api.use('/school', school);
+api.use('/location', location);
 
 module.exports = api;
-- 
GitLab


From 9554c18b151551ea708612fdd24ed4fa5dc54f92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Risso?= <joaovictor.risso@gmail.com>
Date: Fri, 28 Oct 2016 11:01:36 -0200
Subject: [PATCH 04/32] Fix location type in school queries

- Change id_localizacao to tipo_localizacao when querying escola (school) table
- Add missing condition for querying escola table, which is tuples that have id_tipo_turma = 0, according to the use case.
---
 src/libs/routes/location.js | 119 +++++++++++++++++++++++-------------
 1 file changed, 76 insertions(+), 43 deletions(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index a4289272..241fdcac 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -15,14 +15,21 @@ const response = require(`${libs}/middlewares/response`);
 const locationApp = express();
 
 function locationIdToStr(locationId) {
-    let locationStr = 'Todas';
+    let locationStr = 'Total';
     switch(locationId) {
         case 1:
-            locationStr = 'Urbana';
-            break;
+            locationStr = 'Urbana';                         break;
         case 2:
-            locationStr = 'Rural';
-            break;
+            locationStr = 'Rural';                          break;
+        case 3:
+            locationStr = 'Área de assentamento';           break;
+        case 4:
+            locationStr = 'Terra indígena';                 break;
+        case 5:
+            locationStr = 'Área remanescente de quilombos'; break;
+        case 6:
+            locationStr = 'Unidade de uso sustentável';     break;
+
     }
     return locationStr;
 }
@@ -33,7 +40,7 @@ locationApp.get('/sociodemographic', (req, res, next) => {
         .from('ibge_populacao');
 
     const populationQry = squel.select()
-        .field('\'Brasil\'', 'location')
+        .field('\'Brasil\'', 'name')
         .field('SUM(populacao)', 'population')
         .field('ibge_populacao.ano_censo')
         .from('ibge_populacao')
@@ -45,7 +52,7 @@ locationApp.get('/sociodemographic', (req, res, next) => {
         .from('ibge_pib');
 
     const pibQry = squel.select()
-        .field('\'Brasil\'', 'location')
+        .field('\'Brasil\'', 'name')
         .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
         .field('ibge_pib.ano_censo')
         .from('ibge_pib')
@@ -57,7 +64,7 @@ locationApp.get('/sociodemographic', (req, res, next) => {
         .from('adh_idh');
 
     const idhQry = squel.select()
-        .field('\'Brasil\'', 'location')
+        .field('\'Brasil\'', 'name')
         .field('AVG(idhm)', 'idhm')
         .field('adh_idh.ano_censo')
         .from('adh_idh')
@@ -69,7 +76,7 @@ locationApp.get('/sociodemographic', (req, res, next) => {
         .from('adh_analfabetismo');
 
     const analfabQry = squel.select()
-        .field('\'Brasil\'', 'location')
+        .field('\'Brasil\'', 'name')
         .field('AVG(t_analf15m)', 'analfabetism')
         .field('adh_analfabetismo.ano_censo')
         .from('adh_analfabetismo')
@@ -81,7 +88,7 @@ locationApp.get('/sociodemographic', (req, res, next) => {
         .from('adh_gini');
 
     const giniQry = squel.select()
-        .field('\'Brasil\'', 'location')
+        .field('\'Brasil\'', 'name')
         .field('AVG(gini)', 'gini')
         .field('adh_gini.ano_censo')
         .from('adh_gini')
@@ -114,7 +121,7 @@ locationApp.get('/sociodemographic/region/:id', (req, res, next) => {
         .from('ibge_populacao');
 
     const populationQry = squel.select()
-        .field('regiao.nome', 'location')
+        .field('regiao.nome', 'name')
         .field('SUM(populacao)', 'population')
         .field('ano_censo', 'census_year')
         .from('ibge_populacao')
@@ -135,7 +142,7 @@ locationApp.get('/sociodemographic/region/:id', (req, res, next) => {
         .from('ibge_pib');
 
     const pibQry = squel.select()
-        .field('regiao.nome', 'location')
+        .field('regiao.nome', 'name')
         .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
         .field('ano_censo', 'census_year')
         .from('ibge_pib')
@@ -156,7 +163,7 @@ locationApp.get('/sociodemographic/region/:id', (req, res, next) => {
         .from('adh_idh');
 
     const idhQry = squel.select()
-        .field('regiao.nome', 'location')
+        .field('regiao.nome', 'name')
         .field('AVG(idhm)', 'idhm')
         .field('ano_censo', 'census_year')
         .from('adh_idh')
@@ -177,7 +184,7 @@ locationApp.get('/sociodemographic/region/:id', (req, res, next) => {
         .from('adh_analfabetismo');
 
     const analfabQry = squel.select()
-        .field('regiao.nome', 'location')
+        .field('regiao.nome', 'name')
         .field('AVG(t_analf15m)', 'analfabetism')
         .field('ano_censo', 'census_year')
         .from('adh_analfabetismo')
@@ -198,7 +205,7 @@ locationApp.get('/sociodemographic/region/:id', (req, res, next) => {
         .from('adh_gini');
 
     const giniQry = squel.select()
-        .field('regiao.nome', 'location')
+        .field('regiao.nome', 'name')
         .field('AVG(gini)', 'gini')
         .field('ano_censo', 'census_year')
         .from('adh_gini')
@@ -240,7 +247,7 @@ locationApp.get('/sociodemographic/state/:id', (req, res, next) => {
         .from('ibge_populacao');
     // load all cities by state and compute the sociodemographic and educational information
     const populationQry = squel.select()
-        .field('estado.nome', 'location')
+        .field('estado.nome', 'name')
         .field('SUM(populacao)', 'population')
         .field('ibge_populacao.ano_censo', 'census_year')
         .from('ibge_populacao')
@@ -259,7 +266,7 @@ locationApp.get('/sociodemographic/state/:id', (req, res, next) => {
         .from('ibge_pib');
 
     const pibQry = squel.select()
-        .field('estado.nome', 'location')
+        .field('estado.nome', 'name')
         .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
         .field('ibge_pib.ano_censo', 'census_year')
         .from('ibge_pib')
@@ -278,7 +285,7 @@ locationApp.get('/sociodemographic/state/:id', (req, res, next) => {
         .from('adh_idh');
 
     const idhQry = squel.select()
-        .field('estado.nome', 'location')
+        .field('estado.nome', 'name')
         .field('AVG(idhm)', 'idhm')
         .field('adh_idh.ano_censo', 'census_year')
         .from('adh_idh')
@@ -297,7 +304,7 @@ locationApp.get('/sociodemographic/state/:id', (req, res, next) => {
         .from('adh_analfabetismo');
 
     const analfabQry = squel.select()
-        .field('estado.nome', 'location')
+        .field('estado.nome', 'name')
         .field('AVG(t_analf15m)', 'analfabetism')
         .field('adh_analfabetismo.ano_censo', 'census_year')
         .from('adh_analfabetismo')
@@ -316,7 +323,7 @@ locationApp.get('/sociodemographic/state/:id', (req, res, next) => {
         .from('adh_gini');
 
     const giniQry = squel.select()
-        .field('estado.nome', 'location')
+        .field('estado.nome', 'name')
         .field('AVG(gini)', 'gini')
         .field('adh_gini.ano_censo', 'census_year')
         .from('adh_gini')
@@ -356,7 +363,7 @@ locationApp.get('/sociodemographic/city/:id', (req, res, next) => {
         .from('ibge_populacao');
     // load all cities by state and compute the sociodemographic and educational information
     const populationQry = squel.select()
-        .field('municipio.nome', 'location')
+        .field('municipio.nome', 'name')
         .field('SUM(populacao)', 'population')
         .field('ibge_populacao.ano_censo', 'census_year')
         .from('ibge_populacao')
@@ -373,7 +380,7 @@ locationApp.get('/sociodemographic/city/:id', (req, res, next) => {
         .from('ibge_pib');
 
     const pibQry = squel.select()
-        .field('municipio.nome', 'location')
+        .field('municipio.nome', 'name')
         .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
         .field('ibge_pib.ano_censo', 'census_year')
         .from('ibge_pib')
@@ -390,7 +397,7 @@ locationApp.get('/sociodemographic/city/:id', (req, res, next) => {
         .from('adh_idh');
 
     const idhQry = squel.select()
-        .field('municipio.nome', 'location')
+        .field('municipio.nome', 'name')
         .field('AVG(idhm)', 'idhm')
         .field('adh_idh.ano_censo', 'census_year')
         .from('adh_idh')
@@ -407,7 +414,7 @@ locationApp.get('/sociodemographic/city/:id', (req, res, next) => {
         .from('adh_analfabetismo');
 
     const analfabQry = squel.select()
-        .field('municipio.nome', 'location')
+        .field('municipio.nome', 'name')
         .field('AVG(t_analf15m)', 'analfabetism')
         .field('adh_analfabetismo.ano_censo', 'census_year')
         .from('adh_analfabetismo')
@@ -424,7 +431,7 @@ locationApp.get('/sociodemographic/city/:id', (req, res, next) => {
         .from('adh_gini');
 
     const giniQry = squel.select()
-        .field('municipio.nome', 'location')
+        .field('municipio.nome', 'name')
         .field('AVG(gini)', 'gini')
         .field('adh_gini.ano_censo', 'census_year')
         .from('adh_gini')
@@ -461,17 +468,25 @@ locationApp.get('/educational', (req, res, next) => {
         .toString();
 
     const totalSchoolsQry = squel.select()
+        .field('\'Brasil\'', 'name')
         .field('0', 'location')
         .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
         .from('escola')
-        .where(`escola.ano_censo IN (${censusYearQry})`);
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
+        .group('escola.ano_censo');
 
     const schoolsPerLocationQry = squel.select()
-        .field('escola.id_localizacao', 'location')
+        .field('\'Brasil\'', 'name')
+        .field('escola.tipo_localizacao', 'location')
         .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
         .from('escola')
         .where(`escola.ano_censo IN (${censusYearQry})`)
-        .group('escola.id_localizacao');
+        .where('escola.id_tipo_turma = 0')
+        .group('escola.tipo_localizacao')
+        .group('escola.ano_censo');
 
     const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
         return sqlQuery(qry.toString());
@@ -503,9 +518,10 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .toString();
 
     const totalSchoolsQry = squel.select()
-        .field('regiao.nome')
+        .field('regiao.nome', 'name')
         .field('0', 'location')
         .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
         .from('escola')
         .from('estado')
         .from('regiao')
@@ -513,12 +529,15 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .where('estado.fk_regiao_id = regiao.pk_regiao_id')
         .where(`regiao.pk_regiao_id = ${regionId}`)
         .where(`escola.ano_censo IN (${censusYearQry})`)
-        .group('regiao.nome');
+        .where('escola.id_tipo_turma = 0')
+        .group('regiao.nome')
+        .group('escola.ano_censo');
 
     const schoolsPerLocationQry = squel.select()
-        .field('regiao.nome')
-        .field('escola.id_localizacao', 'location')
+        .field('regiao.nome', 'name')
+        .field('escola.tipo_localizacao', 'location')
         .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
         .from('escola')
         .from('estado')
         .from('regiao')
@@ -526,8 +545,10 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .where('estado.fk_regiao_id = regiao.pk_regiao_id')
         .where(`regiao.pk_regiao_id = ${regionId}`)
         .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
         .group('regiao.nome')
-        .group('escola.id_localizacao');
+        .group('escola.tipo_localizacao')
+        .group('escola.ano_censo');
 
     const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
         return sqlQuery(qry.toString());
@@ -559,27 +580,33 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
         .toString();
 
     const totalSchoolsQry = squel.select()
-        .field('estado.nome')
+        .field('estado.nome', 'name')
         .field('0', 'location')
         .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
         .from('escola')
         .from('estado')
         .where('escola.fk_estado_id = estado.pk_estado_id')
         .where(`escola.fk_estado_id = ${stateId}`)
         .where(`escola.ano_censo IN (${censusYearQry})`)
-        .group('estado.nome');
+        .where('escola.id_tipo_turma = 0')
+        .group('estado.nome')
+        .group('escola.ano_censo');
 
     const schoolsPerLocationQry = squel.select()
-        .field('estado.nome')
-        .field('escola.id_localizacao', 'location')
+        .field('estado.nome', 'name')
+        .field('escola.tipo_localizacao', 'location')
         .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
         .from('escola')
         .from('estado')
         .where('escola.fk_estado_id = estado.pk_estado_id')
         .where(`escola.fk_estado_id = ${stateId}`)
         .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
         .group('estado.nome')
-        .group('escola.id_localizacao');
+        .group('escola.tipo_localizacao')
+        .group('escola.ano_censo');
 
     const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
         return sqlQuery(qry.toString());
@@ -611,27 +638,33 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
         .toString();
 
     const totalSchoolsQry = squel.select()
-        .field('municipio.nome')
+        .field('municipio.nome', 'name')
         .field('0', 'location')
         .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
         .from('escola')
         .from('municipio')
         .where('escola.fk_municipio_id = municipio.pk_cod_ibge')
         .where(`escola.fk_municipio_id = ${cityId}`)
         .where(`escola.ano_censo IN (${censusYearQry})`)
-        .group('municipio.nome');
+        .where('escola.id_tipo_turma = 0')
+        .group('municipio.nome')
+        .group('escola.ano_censo');
 
     const schoolsPerLocationQry = squel.select()
-        .field('municipio.nome')
-        .field('escola.id_localizacao', 'location')
+        .field('municipio.nome', 'name')
+        .field('escola.tipo_localizacao', 'location')
         .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
         .from('escola')
         .from('municipio')
         .where('escola.fk_municipio_id = municipio.pk_cod_ibge')
         .where(`escola.fk_municipio_id = ${cityId}`)
         .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
         .group('municipio.nome')
-        .group('escola.id_localizacao');
+        .group('escola.tipo_localizacao')
+        .group('escola.ano_censo');
 
     const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
         return sqlQuery(qry.toString());
-- 
GitLab


From 7e2b5dcdbf54ce9a185d217e3d6c98a7a2d47a58 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Risso?= <joaovictor.risso@gmail.com>
Date: Fri, 28 Oct 2016 11:43:36 -0200
Subject: [PATCH 05/32] Add enrollment queries for the country in location
 module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Risso <joaovictor.risso@gmail.com>
---
 src/libs/routes/location.js | 49 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index 241fdcac..84d1ee9e 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -488,7 +488,54 @@ locationApp.get('/educational', (req, res, next) => {
         .group('escola.tipo_localizacao')
         .group('escola.ano_censo');
 
-    const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
+    const schoolClassYearQry = squel.select()
+        .field('MAX(turma.ano_censo)')
+        .from('turma')
+        .toString();
+
+    const enrollmentsQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('\'Total\'', 'adm_dependency')
+        .from('turma')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('turma.ano_censo');
+
+    const enrollmentsPerAdmDepQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .from('turma')
+        .from('dependencia_adm')
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('dependencia_adm')
+        .from('etapa_ensino')
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .group('etapa_ensino.desc_etapa')
+        .order('dependencia_adm.nome')
+        .order('etapa_ensino.desc_etapa');
+
+    const queries = [totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry, enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry].map((qry) => {
         return sqlQuery(qry.toString());
     });
 
-- 
GitLab


From 227f1e390a6006b9f174409d19577477c6af22b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Risso?= <joaovictor.risso@gmail.com>
Date: Fri, 28 Oct 2016 11:52:18 -0200
Subject: [PATCH 06/32] Add enrollment queries for a given region in location
 module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Risso <joaovictor.risso@gmail.com>
---
 src/libs/routes/location.js | 62 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index 84d1ee9e..e5629e66 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -597,7 +597,67 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .group('escola.tipo_localizacao')
         .group('escola.ano_censo');
 
-    const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
+    const schoolClassYearQry = squel.select()
+        .field('MAX(turma.ano_censo)')
+        .from('turma')
+        .toString();
+
+    const enrollmentsQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('\'Total\'', 'adm_dependency')
+        .from('turma')
+        .from('regiao')
+        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`turma.fk_regiao_id = ${regionId}`)
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('turma.ano_censo')
+        .group('regiao.nome');
+
+    const enrollmentsPerAdmDepQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .from('turma')
+        .from('dependencia_adm')
+        .from('regiao')
+        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`turma.fk_regiao_id = ${regionId}`)
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .group('regiao.nome');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('dependencia_adm')
+        .from('etapa_ensino')
+        .from('regiao')
+        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`turma.fk_regiao_id = ${regionId}`)
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .group('etapa_ensino.desc_etapa')
+        .group('regiao.nome')
+        .order('regiao.nome')
+        .order('dependencia_adm.nome')
+        .order('etapa_ensino.desc_etapa');
+
+    const queries = [totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry, enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry].map((qry) => {
         return sqlQuery(qry.toString());
     });
 
-- 
GitLab


From 3d39bf79a5695739df33229e6546c404a3031af3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Risso?= <joaovictor.risso@gmail.com>
Date: Fri, 28 Oct 2016 11:56:39 -0200
Subject: [PATCH 07/32] Add enrollment queries for a given state in location
 module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Risso <joaovictor.risso@gmail.com>
---
 src/libs/routes/location.js | 62 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index e5629e66..39b5b6d9 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -715,7 +715,67 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
         .group('escola.tipo_localizacao')
         .group('escola.ano_censo');
 
-    const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
+    const schoolClassYearQry = squel.select()
+        .field('MAX(turma.ano_censo)')
+        .from('turma')
+        .toString();
+
+    const enrollmentsQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('\'Total\'', 'adm_dependency')
+        .from('turma')
+        .from('estado')
+        .where('turma.fk_estado_id = estado.pk_estado_id')
+        .where(`turma.fk_estado_id = ${stateId}`)
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('turma.ano_censo')
+        .group('estado.nome');
+
+    const enrollmentsPerAdmDepQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .from('turma')
+        .from('dependencia_adm')
+        .from('estado')
+        .where('turma.fk_estado_id = estado.pk_estado_id')
+        .where(`turma.fk_estado_id = ${stateId}`)
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .group('estado.nome');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('dependencia_adm')
+        .from('etapa_ensino')
+        .from('estado')
+        .where('turma.fk_estado_id = estado.pk_estado_id')
+        .where(`turma.fk_estado_id = ${stateId}`)
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .group('etapa_ensino.desc_etapa')
+        .group('estado.nome')
+        .order('estado.nome')
+        .order('dependencia_adm.nome')
+        .order('etapa_ensino.desc_etapa');
+
+    const queries = [totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry, enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry].map((qry) => {
         return sqlQuery(qry.toString());
     });
 
-- 
GitLab


From 203053cbff1c831ddf4df20f88fe58d10cfdc38a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Risso?= <joaovictor.risso@gmail.com>
Date: Fri, 28 Oct 2016 12:02:54 -0200
Subject: [PATCH 08/32] Add enrollment queries for a given city in location
 module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Risso <joaovictor.risso@gmail.com>
---
 src/libs/routes/location.js | 62 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index 39b5b6d9..a7d86f5b 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -833,7 +833,67 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
         .group('escola.tipo_localizacao')
         .group('escola.ano_censo');
 
-    const queries = [totalSchoolsQry, schoolsPerLocationQry].map((qry) => {
+    const schoolClassYearQry = squel.select()
+        .field('MAX(turma.ano_censo)')
+        .from('turma')
+        .toString();
+
+    const enrollmentsQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('\'Total\'', 'adm_dependency')
+        .from('turma')
+        .from('municipio')
+        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`turma.fk_municipio_id = ${cityId}`)
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('turma.ano_censo')
+        .group('municipio.nome');
+
+    const enrollmentsPerAdmDepQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .from('turma')
+        .from('dependencia_adm')
+        .from('municipio')
+        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`turma.fk_municipio_id = ${cityId}`)
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .group('municipio.nome');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('dependencia_adm')
+        .from('etapa_ensino')
+        .from('municipio')
+        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`turma.fk_municipio_id = ${cityId}`)
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .group('etapa_ensino.desc_etapa')
+        .group('municipio.nome')
+        .order('municipio.nome')
+        .order('dependencia_adm.nome')
+        .order('etapa_ensino.desc_etapa');
+
+    const queries = [totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry, enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry].map((qry) => {
         return sqlQuery(qry.toString());
     });
 
-- 
GitLab


From 75cfb91181f8e1e9eae5e60da55335939457d0bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Risso?= <joaovictor.risso@gmail.com>
Date: Fri, 28 Oct 2016 14:38:16 -0200
Subject: [PATCH 09/32] Rename config.json to config.json.example
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Risso <joaovictor.risso@gmail.com>
---
 config.json => config.json.example | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename config.json => config.json.example (100%)

diff --git a/config.json b/config.json.example
similarity index 100%
rename from config.json
rename to config.json.example
-- 
GitLab


From 1179684a74251b530853b5899bed7e532df2a5ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Mon, 31 Oct 2016 12:42:30 -0200
Subject: [PATCH 10/32] Refactor location module to include response formatting
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Move concurrent query execution into dbExecAll function
* Add custom response formatting through route labels. For each query in the set, there is an associated label, which will then be used to identify the corresponding result in the response JSON object. For example:
	- labels = [ "a", "b" ]
	- querySet = [ squel.select().from('y'), squel.select().from('x') ]
	- response = { "result" : { "a" : { // result for query a }, "b" : { //result for query b } }

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/libs/routes/location.js | 191 +++++++++++++++++-------------------
 1 file changed, 92 insertions(+), 99 deletions(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index a7d86f5b..7a870e5f 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -34,6 +34,38 @@ function locationIdToStr(locationId) {
     return locationStr;
 }
 
+function processResultSet(querySet, querySetLabels = ["result"]) {
+    const resultMap = new Map();
+    if (querySetLabels.length === 1 && querySetLabels[0] === "result") {
+        resultMap["result"] = [];
+        // loop relies on the fact that Promise.all maintains the order of the original iterable
+        for(let result of querySet) {
+            // each query only returns one object in an array, so we get rid of the array
+            const resultObj = result[0];
+            resultMap["result"].push(resultObj);
+            resultIdx++;
+        }
+    } else {
+        let resultIdx = 0;
+        // loop relies on the fact that Promise.all maintains the order of the original iterable
+        for(let result of querySet) {
+            const resultLbl = querySetLabels[resultIdx];
+            // each query only returns one object in an array, so we get rid of the array
+            const resultObj = result[0];
+            resultMap[resultLbl] = resultObj;
+            resultIdx++;
+        }
+    }
+    log.debug(resultMap);
+    return resultMap;
+}
+
+function dbExecAll(querySet = []) {
+    // Issue all queries concurrently to the database, for every query object in the iterable
+    // NOTE: Array.map() returns a copy of the original array with each object 'mapped'.
+    return querySet.map((qry) => { return sqlQuery(qry.toString()); });
+}
+
 locationApp.get('/sociodemographic', (req, res, next) => {
     const populationYearQry = squel.select()
         .field('MAX(ibge_populacao.ano_censo)')
@@ -95,17 +127,12 @@ locationApp.get('/sociodemographic', (req, res, next) => {
         .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`)
         .group('adh_gini.ano_censo');
 
-    const queries = [populationQry, pibQry, idhQry, analfabQry, giniQry].map((qry) => {
-        return sqlQuery(qry.toString());
-    });
-
-    // execute all queries concurrently
-    Promise.all(queries).then((queryResults) => {
-        req.result = [];
-        for(let result of queryResults) {
-            log.debug(result);
-            req.result.push(result[0]);
-        }
+    // map query objects to their respective response labels
+    const queryLabels = [ "population", "pib", "idh", "analfab", "gini" ];
+    const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
         next();
     }).catch((error) => {
         log.error(`[SQL query error] ${error}`);
@@ -220,18 +247,12 @@ locationApp.get('/sociodemographic/region/:id', (req, res, next) => {
         .group('regiao.nome')
         .group('adh_gini.ano_censo')
         .order('regiao.nome');
-
-    const queries = [populationQry, pibQry, idhQry, analfabQry, giniQry].map((qry) => {
-        return sqlQuery(qry.toString());
-    });
-
-    // execute all queries concurrently
-    Promise.all(queries).then((queryResults) => {
-        req.result = [];
-        for(let result of queryResults) {
-            log.debug(result);
-            req.result.push(result[0]);
-        }
+    // map query objects to their respective response labels
+    const queryLabels = [ "population", "pib", "idh", "analfab", "gini" ];
+    const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
         next();
     }).catch((error) => {
         log.error(`[SQL query error] ${error}`);
@@ -336,18 +357,12 @@ locationApp.get('/sociodemographic/state/:id', (req, res, next) => {
         .group('estado.nome')
         .group('adh_gini.ano_censo')
         .order('estado.nome');
-
-    const queries = [populationQry, pibQry, idhQry, analfabQry, giniQry].map((qry) => {
-        return sqlQuery(qry.toString());
-    });
-
-    // execute all queries concurrently
-    Promise.all(queries).then((queryResults) => {
-        req.result = [];
-        for(let result of queryResults) {
-            log.debug(result);
-            req.result.push(result[0]);
-        }
+    // map query objects to their respective response labels
+    const queryLabels = [ "population", "pib", "idh", "analfab", "gini" ];
+    const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
         next();
     }).catch((error) => {
         log.error(`[SQL query error] ${error}`);
@@ -442,18 +457,12 @@ locationApp.get('/sociodemographic/city/:id', (req, res, next) => {
         .group('municipio.nome')
         .group('adh_gini.ano_censo')
         .order('municipio.nome');
-
-    const queries = [populationQry, pibQry, idhQry, analfabQry, giniQry].map((qry) => {
-        return sqlQuery(qry.toString());
-    });
-
-    // execute all queries concurrently
-    Promise.all(queries).then((queryResults) => {
-        req.result = [];
-        for(let result of queryResults) {
-            log.debug(result);
-            req.result.push(result[0]);
-        }
+    // map query objects to their respective response labels
+    const queryLabels = [ "population", "pib", "idh", "analfab", "gini" ];
+    const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
         next();
     }).catch((error) => {
         log.error(`[SQL query error] ${error}`);
@@ -535,19 +544,15 @@ locationApp.get('/educational', (req, res, next) => {
         .order('dependencia_adm.nome')
         .order('etapa_ensino.desc_etapa');
 
-    const queries = [totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry, enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry].map((qry) => {
-        return sqlQuery(qry.toString());
-    });
-
-    // execute all queries concurrently
-    Promise.all(queries).then((queryResults) => {
-        req.result = [];
-        for(let result of queryResults) {
-            log.debug(result);
-            for(let row of result) {
-                row.location = locationIdToStr(row.location);
-                req.result.push(row);
-            }
+    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
+        "enrollment_per_school_level" ];
+    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
+        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
+        for(let label in req.result) {
+            req.result[label].location = locationIdToStr(req.result[label].location);
         }
         next();
     }).catch((error) => {
@@ -657,19 +662,15 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .order('dependencia_adm.nome')
         .order('etapa_ensino.desc_etapa');
 
-    const queries = [totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry, enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry].map((qry) => {
-        return sqlQuery(qry.toString());
-    });
-
-    // execute all queries concurrently
-    Promise.all(queries).then((queryResults) => {
-        req.result = [];
-        for(let result of queryResults) {
-            log.debug(result);
-            for(let row of result) {
-                row.location = locationIdToStr(row.location);
-                req.result.push(row);
-            }
+    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
+        "enrollment_per_school_level" ];
+    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
+        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
+        for(let label in req.result) {
+            req.result[label].location = locationIdToStr(req.result[label].location);
         }
         next();
     }).catch((error) => {
@@ -775,19 +776,15 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
         .order('dependencia_adm.nome')
         .order('etapa_ensino.desc_etapa');
 
-    const queries = [totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry, enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry].map((qry) => {
-        return sqlQuery(qry.toString());
-    });
-
-    // execute all queries concurrently
-    Promise.all(queries).then((queryResults) => {
-        req.result = [];
-        for(let result of queryResults) {
-            log.debug(result);
-            for(let row of result) {
-                row.location = locationIdToStr(row.location);
-                req.result.push(row);
-            }
+    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
+        "enrollment_per_school_level" ];
+    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
+        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
+        for(let label in req.result) {
+            req.result[label].location = locationIdToStr(req.result[label].location);
         }
         next();
     }).catch((error) => {
@@ -893,19 +890,15 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
         .order('dependencia_adm.nome')
         .order('etapa_ensino.desc_etapa');
 
-    const queries = [totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry, enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry].map((qry) => {
-        return sqlQuery(qry.toString());
-    });
-
-    // execute all queries concurrently
-    Promise.all(queries).then((queryResults) => {
-        req.result = [];
-        for(let result of queryResults) {
-            log.debug(result);
-            for(let row of result) {
-                row.location = locationIdToStr(row.location);
-                req.result.push(row);
-            }
+    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
+        "enrollment_per_school_level" ];
+    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
+        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
+        for(let label in req.result) {
+            req.result[label].location = locationIdToStr(req.result[label].location);
         }
         next();
     }).catch((error) => {
-- 
GitLab


From 7734694414ae5887ab09376fae4f41aca3d8001e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Tue, 1 Nov 2016 10:45:15 -0200
Subject: [PATCH 11/32] Change ano_censo to census_year in sociodemographic
 route for the whole country
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/libs/routes/location.js | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index 7a870e5f..159b1dbd 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -74,7 +74,7 @@ locationApp.get('/sociodemographic', (req, res, next) => {
     const populationQry = squel.select()
         .field('\'Brasil\'', 'name')
         .field('SUM(populacao)', 'population')
-        .field('ibge_populacao.ano_censo')
+        .field('ibge_populacao.ano_censo', 'census_year')
         .from('ibge_populacao')
         .where(`ibge_populacao.ano_censo IN (${populationYearQry.toString()})`)
         .group('ibge_populacao.ano_censo');
@@ -86,7 +86,7 @@ locationApp.get('/sociodemographic', (req, res, next) => {
     const pibQry = squel.select()
         .field('\'Brasil\'', 'name')
         .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
-        .field('ibge_pib.ano_censo')
+        .field('ibge_pib.ano_censo', 'census_year')
         .from('ibge_pib')
         .where(`ibge_pib.ano_censo IN (${pibYearQry.toString()})`)
         .group('ibge_pib.ano_censo');
@@ -98,7 +98,7 @@ locationApp.get('/sociodemographic', (req, res, next) => {
     const idhQry = squel.select()
         .field('\'Brasil\'', 'name')
         .field('AVG(idhm)', 'idhm')
-        .field('adh_idh.ano_censo')
+        .field('adh_idh.ano_censo', 'census_year')
         .from('adh_idh')
         .where(`adh_idh.ano_censo IN (${idhYearQry.toString()})`)
         .group('adh_idh.ano_censo');
@@ -110,7 +110,7 @@ locationApp.get('/sociodemographic', (req, res, next) => {
     const analfabQry = squel.select()
         .field('\'Brasil\'', 'name')
         .field('AVG(t_analf15m)', 'analfabetism')
-        .field('adh_analfabetismo.ano_censo')
+        .field('adh_analfabetismo.ano_censo', 'census_year')
         .from('adh_analfabetismo')
         .where(`adh_analfabetismo.ano_censo IN (${analfabYearQry.toString()})`)
         .group('adh_analfabetismo.ano_censo');
@@ -122,13 +122,13 @@ locationApp.get('/sociodemographic', (req, res, next) => {
     const giniQry = squel.select()
         .field('\'Brasil\'', 'name')
         .field('AVG(gini)', 'gini')
-        .field('adh_gini.ano_censo')
+        .field('adh_gini.ano_censo', 'census_year')
         .from('adh_gini')
         .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`)
         .group('adh_gini.ano_censo');
 
     // map query objects to their respective response labels
-    const queryLabels = [ "population", "pib", "idh", "analfab", "gini" ];
+    const queryLabels = [ "population", "gdp", "idh", "analfab", "gini" ];
     const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
     // wait until all queries finish or one of them fail
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
@@ -248,7 +248,7 @@ locationApp.get('/sociodemographic/region/:id', (req, res, next) => {
         .group('adh_gini.ano_censo')
         .order('regiao.nome');
     // map query objects to their respective response labels
-    const queryLabels = [ "population", "pib", "idh", "analfab", "gini" ];
+    const queryLabels = [ "population", "gdp", "idh", "analfab", "gini" ];
     const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
     // wait until all queries finish or one of them fail
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
@@ -358,7 +358,7 @@ locationApp.get('/sociodemographic/state/:id', (req, res, next) => {
         .group('adh_gini.ano_censo')
         .order('estado.nome');
     // map query objects to their respective response labels
-    const queryLabels = [ "population", "pib", "idh", "analfab", "gini" ];
+    const queryLabels = [ "population", "gdp", "idh", "analfab", "gini" ];
     const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
     // wait until all queries finish or one of them fail
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
@@ -458,7 +458,7 @@ locationApp.get('/sociodemographic/city/:id', (req, res, next) => {
         .group('adh_gini.ano_censo')
         .order('municipio.nome');
     // map query objects to their respective response labels
-    const queryLabels = [ "population", "pib", "idh", "analfab", "gini" ];
+    const queryLabels = [ "population", "gdp", "idh", "analfab", "gini" ];
     const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
     // wait until all queries finish or one of them fail
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
-- 
GitLab


From d5e05b00782a09cbc1e6387374230a7bae411868 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Tue, 1 Nov 2016 10:45:33 -0200
Subject: [PATCH 12/32] Add test cases for location routes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/test/location.js | 385 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 385 insertions(+)
 create mode 100644 src/test/location.js

diff --git a/src/test/location.js b/src/test/location.js
new file mode 100644
index 00000000..334e3faf
--- /dev/null
+++ b/src/test/location.js
@@ -0,0 +1,385 @@
+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);
+
+const testTimeout = 5000;
+
+describe('test location', () => {
+    it('should return the expected response format for sociodemographic data for the whole country', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/sociodemographic')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('population');
+                res.body.result.should.have.property('gdp');
+                res.body.result.should.have.property('idh');
+                res.body.result.should.have.property('analfab');
+                res.body.result.should.have.property('gini');
+                // test response attributes for population
+                res.body.result.population.should.have.property('name');
+                res.body.result.population.should.have.property('population');
+                res.body.result.population.should.have.property('census_year');
+                // test response attributes for gdp
+                res.body.result.gdp.should.have.property('name');
+                res.body.result.gdp.should.have.property('gdp_per_capita');
+                res.body.result.gdp.should.have.property('census_year');
+                // test response attributes for idh
+                res.body.result.idh.should.have.property('name');
+                res.body.result.idh.should.have.property('idhm');
+                res.body.result.idh.should.have.property('census_year');
+                // test response attributes for analfab
+                res.body.result.analfab.should.have.property('name');
+                res.body.result.analfab.should.have.property('analfabetism');
+                res.body.result.analfab.should.have.property('census_year');
+                // test response attributes for gini
+                res.body.result.gini.should.have.property('name');
+                res.body.result.gini.should.have.property('gini');
+                res.body.result.gini.should.have.property('census_year');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for sociodemographic data for a country region', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/sociodemographic/region/1')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('population');
+                res.body.result.should.have.property('gdp');
+                res.body.result.should.have.property('idh');
+                res.body.result.should.have.property('analfab');
+                res.body.result.should.have.property('gini');
+                // test response attributes for population
+                res.body.result.population.should.have.property('name');
+                res.body.result.population.should.have.property('population');
+                res.body.result.population.should.have.property('census_year');
+                // test response attributes for gdp
+                res.body.result.gdp.should.have.property('name');
+                res.body.result.gdp.should.have.property('gdp_per_capita');
+                res.body.result.gdp.should.have.property('census_year');
+                // test response attributes for idh
+                res.body.result.idh.should.have.property('name');
+                res.body.result.idh.should.have.property('idhm');
+                res.body.result.idh.should.have.property('census_year');
+                // test response attributes for analfab
+                res.body.result.analfab.should.have.property('name');
+                res.body.result.analfab.should.have.property('analfabetism');
+                res.body.result.analfab.should.have.property('census_year');
+                // test response attributes for gini
+                res.body.result.gini.should.have.property('name');
+                res.body.result.gini.should.have.property('gini');
+                res.body.result.gini.should.have.property('census_year');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for sociodemographic data for a country state', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/sociodemographic/state/42')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('population');
+                res.body.result.should.have.property('gdp');
+                res.body.result.should.have.property('idh');
+                res.body.result.should.have.property('analfab');
+                res.body.result.should.have.property('gini');
+                // test response attributes for population
+                res.body.result.population.should.have.property('name');
+                res.body.result.population.should.have.property('population');
+                res.body.result.population.should.have.property('census_year');
+                // test response attributes for gdp
+                res.body.result.gdp.should.have.property('name');
+                res.body.result.gdp.should.have.property('gdp_per_capita');
+                res.body.result.gdp.should.have.property('census_year');
+                // test response attributes for idh
+                res.body.result.idh.should.have.property('name');
+                res.body.result.idh.should.have.property('idhm');
+                res.body.result.idh.should.have.property('census_year');
+                // test response attributes for analfab
+                res.body.result.analfab.should.have.property('name');
+                res.body.result.analfab.should.have.property('analfabetism');
+                res.body.result.analfab.should.have.property('census_year');
+                // test response attributes for gini
+                res.body.result.gini.should.have.property('name');
+                res.body.result.gini.should.have.property('gini');
+                res.body.result.gini.should.have.property('census_year');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for sociodemographic data for a country city', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/sociodemographic/city/4106902')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('population');
+                res.body.result.should.have.property('gdp');
+                res.body.result.should.have.property('idh');
+                res.body.result.should.have.property('analfab');
+                res.body.result.should.have.property('gini');
+                // test response attributes for population
+                res.body.result.population.should.have.property('name');
+                res.body.result.population.should.have.property('population');
+                res.body.result.population.should.have.property('census_year');
+                // test response attributes for gdp
+                res.body.result.gdp.should.have.property('name');
+                res.body.result.gdp.should.have.property('gdp_per_capita');
+                res.body.result.gdp.should.have.property('census_year');
+                // test response attributes for idh
+                res.body.result.idh.should.have.property('name');
+                res.body.result.idh.should.have.property('idhm');
+                res.body.result.idh.should.have.property('census_year');
+                // test response attributes for analfab
+                res.body.result.analfab.should.have.property('name');
+                res.body.result.analfab.should.have.property('analfabetism');
+                res.body.result.analfab.should.have.property('census_year');
+                // test response attributes for gini
+                res.body.result.gini.should.have.property('name');
+                res.body.result.gini.should.have.property('gini');
+                res.body.result.gini.should.have.property('census_year');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for educational data for the whole country', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('school');
+                res.body.result.should.have.property('school_per_location');
+                res.body.result.should.have.property('enrollment');
+                res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.should.have.property('enrollment_per_school_level');
+                // test response attributes for school
+                res.body.result.school.should.have.property('name');
+                res.body.result.school.should.have.property('location');
+                res.body.result.school.should.have.property('total');
+                res.body.result.school.should.have.property('census_year');
+                // test response attributes for school_per_location
+                res.body.result.school_per_location.should.have.property('name');
+                res.body.result.school_per_location.should.have.property('location');
+                res.body.result.school_per_location.should.have.property('total');
+                res.body.result.school_per_location.should.have.property('census_year');
+                // test response attributes for enrollment
+                res.body.result.enrollment.should.have.property('name');
+                res.body.result.enrollment.should.have.property('total');
+                res.body.result.enrollment.should.have.property('census_year');
+                res.body.result.enrollment.should.have.property('adm_dependency');
+                res.body.result.enrollment.should.have.property('location');
+                // test response attributes for enrollment_per_adm_dep
+                res.body.result.enrollment_per_adm_dep.should.have.property('name');
+                res.body.result.enrollment_per_adm_dep.should.have.property('total');
+                res.body.result.enrollment_per_adm_dep.should.have.property('census_year');
+                res.body.result.enrollment_per_adm_dep.should.have.property('adm_dependency');
+                res.body.result.enrollment_per_adm_dep.should.have.property('location');
+                // test response attributes for enrollment_per_school_level
+                res.body.result.enrollment_per_school_level.should.have.property('name');
+                res.body.result.enrollment_per_school_level.should.have.property('total');
+                res.body.result.enrollment_per_school_level.should.have.property('census_year');
+                res.body.result.enrollment_per_school_level.should.have.property('adm_dependency');
+                res.body.result.enrollment_per_school_level.should.have.property('school_level');
+                res.body.result.enrollment_per_school_level.should.have.property('location');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for educational data for a country region', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/region/1')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('school');
+                res.body.result.should.have.property('school_per_location');
+                res.body.result.should.have.property('enrollment');
+                res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.should.have.property('enrollment_per_school_level');
+                // test response attributes for school
+                res.body.result.school.should.have.property('name');
+                res.body.result.school.should.have.property('location');
+                res.body.result.school.should.have.property('total');
+                res.body.result.school.should.have.property('census_year');
+                // test response attributes for school_per_location
+                res.body.result.school_per_location.should.have.property('name');
+                res.body.result.school_per_location.should.have.property('location');
+                res.body.result.school_per_location.should.have.property('total');
+                res.body.result.school_per_location.should.have.property('census_year');
+                // test response attributes for enrollment
+                res.body.result.enrollment.should.have.property('name');
+                res.body.result.enrollment.should.have.property('total');
+                res.body.result.enrollment.should.have.property('census_year');
+                res.body.result.enrollment.should.have.property('adm_dependency');
+                res.body.result.enrollment.should.have.property('location');
+                // test response attributes for enrollment_per_adm_dep
+                res.body.result.enrollment_per_adm_dep.should.have.property('name');
+                res.body.result.enrollment_per_adm_dep.should.have.property('total');
+                res.body.result.enrollment_per_adm_dep.should.have.property('census_year');
+                res.body.result.enrollment_per_adm_dep.should.have.property('adm_dependency');
+                res.body.result.enrollment_per_adm_dep.should.have.property('location');
+                // test response attributes for enrollment_per_school_level
+                res.body.result.enrollment_per_school_level.should.have.property('name');
+                res.body.result.enrollment_per_school_level.should.have.property('total');
+                res.body.result.enrollment_per_school_level.should.have.property('census_year');
+                res.body.result.enrollment_per_school_level.should.have.property('adm_dependency');
+                res.body.result.enrollment_per_school_level.should.have.property('school_level');
+                res.body.result.enrollment_per_school_level.should.have.property('location');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for educational data for a country state', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/state/42')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('school');
+                res.body.result.should.have.property('school_per_location');
+                res.body.result.should.have.property('enrollment');
+                res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.should.have.property('enrollment_per_school_level');
+                // test response attributes for school
+                res.body.result.school.should.have.property('name');
+                res.body.result.school.should.have.property('location');
+                res.body.result.school.should.have.property('total');
+                res.body.result.school.should.have.property('census_year');
+                // test response attributes for school_per_location
+                res.body.result.school_per_location.should.have.property('name');
+                res.body.result.school_per_location.should.have.property('location');
+                res.body.result.school_per_location.should.have.property('total');
+                res.body.result.school_per_location.should.have.property('census_year');
+                // test response attributes for enrollment
+                res.body.result.enrollment.should.have.property('name');
+                res.body.result.enrollment.should.have.property('total');
+                res.body.result.enrollment.should.have.property('census_year');
+                res.body.result.enrollment.should.have.property('adm_dependency');
+                res.body.result.enrollment.should.have.property('location');
+                // test response attributes for enrollment_per_adm_dep
+                res.body.result.enrollment_per_adm_dep.should.have.property('name');
+                res.body.result.enrollment_per_adm_dep.should.have.property('total');
+                res.body.result.enrollment_per_adm_dep.should.have.property('census_year');
+                res.body.result.enrollment_per_adm_dep.should.have.property('adm_dependency');
+                res.body.result.enrollment_per_adm_dep.should.have.property('location');
+                // test response attributes for enrollment_per_school_level
+                res.body.result.enrollment_per_school_level.should.have.property('name');
+                res.body.result.enrollment_per_school_level.should.have.property('total');
+                res.body.result.enrollment_per_school_level.should.have.property('census_year');
+                res.body.result.enrollment_per_school_level.should.have.property('adm_dependency');
+                res.body.result.enrollment_per_school_level.should.have.property('school_level');
+                res.body.result.enrollment_per_school_level.should.have.property('location');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for educational data for a country city', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/city/4106902')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('school');
+                res.body.result.should.have.property('school_per_location');
+                res.body.result.should.have.property('enrollment');
+                res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.should.have.property('enrollment_per_school_level');
+                // test response attributes for school
+                res.body.result.school.should.have.property('name');
+                res.body.result.school.should.have.property('location');
+                res.body.result.school.should.have.property('total');
+                res.body.result.school.should.have.property('census_year');
+                // test response attributes for school_per_location
+                res.body.result.school_per_location.should.have.property('name');
+                res.body.result.school_per_location.should.have.property('location');
+                res.body.result.school_per_location.should.have.property('total');
+                res.body.result.school_per_location.should.have.property('census_year');
+                // test response attributes for enrollment
+                res.body.result.enrollment.should.have.property('name');
+                res.body.result.enrollment.should.have.property('total');
+                res.body.result.enrollment.should.have.property('census_year');
+                res.body.result.enrollment.should.have.property('adm_dependency');
+                res.body.result.enrollment.should.have.property('location');
+                // test response attributes for enrollment_per_adm_dep
+                res.body.result.enrollment_per_adm_dep.should.have.property('name');
+                res.body.result.enrollment_per_adm_dep.should.have.property('total');
+                res.body.result.enrollment_per_adm_dep.should.have.property('census_year');
+                res.body.result.enrollment_per_adm_dep.should.have.property('adm_dependency');
+                res.body.result.enrollment_per_adm_dep.should.have.property('location');
+                // test response attributes for enrollment_per_school_level
+                res.body.result.enrollment_per_school_level.should.have.property('name');
+                res.body.result.enrollment_per_school_level.should.have.property('total');
+                res.body.result.enrollment_per_school_level.should.have.property('census_year');
+                res.body.result.enrollment_per_school_level.should.have.property('adm_dependency');
+                res.body.result.enrollment_per_school_level.should.have.property('school_level');
+                res.body.result.enrollment_per_school_level.should.have.property('location');
+                done();
+            });
+    }).timeout(testTimeout);
+});
-- 
GitLab


From b9c21e88d784ebae77e112a38ae1b7f8388a2313 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Tue, 1 Nov 2016 11:45:34 -0200
Subject: [PATCH 13/32] Change simcaqdb1 to simcaqdb3 in config.json.example
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 config.json.example | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.json.example b/config.json.example
index 136ee928..d4b032fe 100644
--- a/config.json.example
+++ b/config.json.example
@@ -3,7 +3,7 @@
     "ip": "127.0.0.1",
     "debug" : false,
     "monetdb": {
-        "host": "simcaqdb1",
+        "host": "simcaqdb3",
         "port": 50000,
         "dbname": "simcaq_dev",
         "user": "monetdb",
-- 
GitLab


From 2298f5de35033fc63bc80f1ff024212208a34a7e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Fri, 4 Nov 2016 11:46:37 -0200
Subject: [PATCH 14/32] Fix conflicts in enrollment and config.json
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 config.json                   |  4 +-
 src/libs/routes/enrollment.js | 89 ++++++++++++++++++-----------------
 2 files changed, 49 insertions(+), 44 deletions(-)

diff --git a/config.json b/config.json
index 136ee928..cdcbd4ae 100644
--- a/config.json
+++ b/config.json
@@ -1,9 +1,9 @@
 {
     "port": 3000,
     "ip": "127.0.0.1",
-    "debug" : false,
+    "debug" : true,
     "monetdb": {
-        "host": "simcaqdb1",
+        "host": "127.0.0.1",
         "port": 50000,
         "dbname": "simcaq_dev",
         "user": "monetdb",
diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js
index 446d7aca..fd8ff2a7 100644
--- a/src/libs/routes/enrollment.js
+++ b/src/libs/routes/enrollment.js
@@ -16,14 +16,13 @@ const parseParams = require(`${libs}/middlewares/parseParams`);
 
 // **Temporary** solution to add where clauses that are common to all requests
 
-
 // Complete range of the enrollments dataset.
 // 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 +40,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');
 
@@ -71,30 +70,34 @@ enrollmentApp.use('/', parseParams('filter', [
     log.debug(req.filter);
     log.debug(req.dims);
 
+    //applyJoins(req.sql, req.filter, req.dims);
+
     // 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,
+            '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,
+            '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('municipio', null, 'fk_municipio_id = municipio.pk_cod_ibge')
+                .join('estado', null, 'municipio.fk_estado_id = estado.pk_estado_id')
+                .join('regiao', null, 'estado.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('municipio', null, 'fk_municipio_id = municipio.pk_cod_ibge')
+                .join('estado', null, 'municipio.fk_estado_id = estado.pk_estado_id');
     }
 
     if((typeof req.filter.city !== 'undefined'
@@ -103,11 +106,11 @@ 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, '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('escola', null, 'turma.cod_entidade = escola.cod_entidade');
     }
 
     // Dimensions (add fields)
@@ -119,39 +122,41 @@ 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');
+        req.sql.field('municipio.nome', 'city_name')
+            .group('municipio.nome')
+            .order('municipio.nome');
     }
 
+    /*
     if(typeof req.dims.school !== 'undefined') {
         req.sql.field('escolas.nome_entidade', 'school_name')
             .group('escolas.nome_entidade')
             .order('escolas.nome_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 +169,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('pk_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('pk_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('pk_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('pk_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.fk_escola_id = ?', parseInt(req.filter.school, 10));
     }
     log.debug(req.sql.toParam());
     next();
@@ -204,10 +209,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
-- 
GitLab


From 4e3bcab73c49f537ce789dd891371bcc0723f135 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Fri, 4 Nov 2016 13:05:51 -0200
Subject: [PATCH 15/32] Add basic test to check for invalid routes and the API
 is running
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/test/api.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 src/test/api.js

diff --git a/src/test/api.js b/src/test/api.js
new file mode 100644
index 00000000..1430f9ac
--- /dev/null
+++ b/src/test/api.js
@@ -0,0 +1,49 @@
+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('API is running', () => {
+    it('should respond it\'s running', (done) => {
+        chai.request(server)
+            .get('/api/v1')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('msg');
+                done();
+            })
+    });
+
+    it('should respond with 404 error', (done) => {
+        chai.request(server)
+            .get('/api/v1/thisrouteshouldgivea404')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('msg');
+                done();
+            })
+    });
+});
-- 
GitLab


From 46b622b5a818f5d86a51e98f918d27295c9c2d16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Fri, 4 Nov 2016 13:13:39 -0200
Subject: [PATCH 16/32] Fix 404 test in api.js test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/test/api.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/test/api.js b/src/test/api.js
index 1430f9ac..b5476ea6 100644
--- a/src/test/api.js
+++ b/src/test/api.js
@@ -40,9 +40,9 @@ describe('API is running', () => {
         chai.request(server)
             .get('/api/v1/thisrouteshouldgivea404')
             .end((err, res) => {
-                res.should.have.status(200);
+                res.should.have.status(404);
                 res.should.be.json;
-                res.body.should.have.property('msg');
+                res.body.should.have.property('error');
                 done();
             })
     });
-- 
GitLab


From d5aa93b74b0ba342f2c11aaefecb0d7d56d434f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Mon, 7 Nov 2016 14:23:49 -0200
Subject: [PATCH 17/32] Fix response format for educational routes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/libs/routes/location.js |  70 +++++-----
 src/test/location.js        | 262 ++++++++++++++++++++++--------------
 2 files changed, 197 insertions(+), 135 deletions(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index 0a124574..3db23d54 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -34,15 +34,21 @@ function locationIdToStr(locationId) {
     return locationStr;
 }
 
-function processResultSet(querySet, querySetLabels = ["result"]) {
+function processResultSet(querySet, querySetLabels = ["result"], singleResult = false) {
     const resultMap = new Map();
     let resultIdx = 0;
     // loop relies on the fact that Promise.all maintains the order of the original iterable
     for(let result of querySet) {
         const resultLbl = querySetLabels[resultIdx];
-        // each query only returns one object in an array, so we get rid of the array
-        const resultObj = result[0];
-        resultMap[resultLbl] = resultObj;
+        resultMap[resultLbl] = [];
+        if (singleResult) {
+            resultMap[resultLbl] = result[0];
+        } else {
+            for(let row of result) {
+                log.debug(row);
+                resultMap[resultLbl].push(row);
+            }
+        }
         resultIdx++;
     }
     log.debug(resultMap);
@@ -121,7 +127,7 @@ locationApp.get('/sociodemographic', (req, res, next) => {
     const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
     // wait until all queries finish or one of them fail
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
-        req.result = processResultSet(queryResults, queryLabels);
+        req.result = processResultSet(queryResults, queryLabels, true);
         next();
     }).catch((error) => {
         log.error(`[SQL query error] ${error}`);
@@ -241,7 +247,7 @@ locationApp.get('/sociodemographic/region/:id', (req, res, next) => {
     const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
     // wait until all queries finish or one of them fail
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
-        req.result = processResultSet(queryResults, queryLabels);
+        req.result = processResultSet(queryResults, queryLabels, true);
         next();
     }).catch((error) => {
         log.error(`[SQL query error] ${error}`);
@@ -351,7 +357,7 @@ locationApp.get('/sociodemographic/state/:id', (req, res, next) => {
     const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
     // wait until all queries finish or one of them fail
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
-        req.result = processResultSet(queryResults, queryLabels);
+        req.result = processResultSet(queryResults, queryLabels, true);
         next();
     }).catch((error) => {
         log.error(`[SQL query error] ${error}`);
@@ -451,7 +457,7 @@ locationApp.get('/sociodemographic/city/:id', (req, res, next) => {
     const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
     // wait until all queries finish or one of them fail
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
-        req.result = processResultSet(queryResults, queryLabels);
+        req.result = processResultSet(queryResults, queryLabels, true);
         next();
     }).catch((error) => {
         log.error(`[SQL query error] ${error}`);
@@ -495,7 +501,6 @@ locationApp.get('/educational', (req, res, next) => {
         .field('\'Brasil\'', 'name')
         .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
         .field('turma.ano_censo', 'census_year')
-        .field('\'Total\'', 'adm_dependency')
         .from('turma')
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .where('turma.fk_tipo_turma_id <= 3')
@@ -518,19 +523,14 @@ locationApp.get('/educational', (req, res, next) => {
         .field('\'Brasil\'', 'name')
         .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
         .field('turma.ano_censo', 'census_year')
-        .field('dependencia_adm.nome', 'adm_dependency')
         .field('etapa_ensino.desc_etapa', 'school_level')
         .from('turma')
-        .from('dependencia_adm')
         .from('etapa_ensino')
-        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
         .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
         .where('turma.fk_tipo_turma_id <= 3')
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
-        .group('dependencia_adm.nome')
         .group('etapa_ensino.desc_etapa')
-        .order('dependencia_adm.nome')
         .order('etapa_ensino.desc_etapa');
 
     const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
@@ -541,7 +541,11 @@ locationApp.get('/educational', (req, res, next) => {
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
         req.result = processResultSet(queryResults, queryLabels);
         for(let label in req.result) {
-            req.result[label].location = locationIdToStr(req.result[label].location);
+            for(let row of req.result[label]) {
+                if (row.hasOwnProperty('location')) {
+                    row.location = locationIdToStr(row.location);
+                }
+            }
         }
         next();
     }).catch((error) => {
@@ -600,7 +604,6 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .field('regiao.nome', 'name')
         .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
         .field('turma.ano_censo', 'census_year')
-        .field('\'Total\'', 'adm_dependency')
         .from('turma')
         .from('regiao')
         .where('turma.fk_regiao_id = regiao.pk_regiao_id')
@@ -631,24 +634,19 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .field('regiao.nome', 'name')
         .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
         .field('turma.ano_censo', 'census_year')
-        .field('dependencia_adm.nome', 'adm_dependency')
         .field('etapa_ensino.desc_etapa', 'school_level')
         .from('turma')
-        .from('dependencia_adm')
         .from('etapa_ensino')
         .from('regiao')
         .where('turma.fk_regiao_id = regiao.pk_regiao_id')
         .where(`turma.fk_regiao_id = ${regionId}`)
-        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
         .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
         .where('turma.fk_tipo_turma_id <= 3')
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
-        .group('dependencia_adm.nome')
         .group('etapa_ensino.desc_etapa')
         .group('regiao.nome')
         .order('regiao.nome')
-        .order('dependencia_adm.nome')
         .order('etapa_ensino.desc_etapa');
 
     const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
@@ -659,7 +657,11 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
         req.result = processResultSet(queryResults, queryLabels);
         for(let label in req.result) {
-            req.result[label].location = locationIdToStr(req.result[label].location);
+            for(let row of req.result[label]) {
+                if (row.hasOwnProperty('location')) {
+                    row.location = locationIdToStr(row.location);
+                }
+            }
         }
         next();
     }).catch((error) => {
@@ -714,7 +716,6 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
         .field('estado.nome', 'name')
         .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
         .field('turma.ano_censo', 'census_year')
-        .field('\'Total\'', 'adm_dependency')
         .from('turma')
         .from('estado')
         .where('turma.fk_estado_id = estado.pk_estado_id')
@@ -745,24 +746,19 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
         .field('estado.nome', 'name')
         .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
         .field('turma.ano_censo', 'census_year')
-        .field('dependencia_adm.nome', 'adm_dependency')
         .field('etapa_ensino.desc_etapa', 'school_level')
         .from('turma')
-        .from('dependencia_adm')
         .from('etapa_ensino')
         .from('estado')
         .where('turma.fk_estado_id = estado.pk_estado_id')
         .where(`turma.fk_estado_id = ${stateId}`)
-        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
         .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
         .where('turma.fk_tipo_turma_id <= 3')
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
-        .group('dependencia_adm.nome')
         .group('etapa_ensino.desc_etapa')
         .group('estado.nome')
         .order('estado.nome')
-        .order('dependencia_adm.nome')
         .order('etapa_ensino.desc_etapa');
 
     const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
@@ -773,7 +769,11 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
         req.result = processResultSet(queryResults, queryLabels);
         for(let label in req.result) {
-            req.result[label].location = locationIdToStr(req.result[label].location);
+            for(let row of req.result[label]) {
+                if (row.hasOwnProperty('location')) {
+                    row.location = locationIdToStr(row.location);
+                }
+            }
         }
         next();
     }).catch((error) => {
@@ -828,7 +828,6 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
         .field('municipio.nome', 'name')
         .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
         .field('turma.ano_censo', 'census_year')
-        .field('\'Total\'', 'adm_dependency')
         .from('turma')
         .from('municipio')
         .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
@@ -859,24 +858,19 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
         .field('municipio.nome', 'name')
         .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
         .field('turma.ano_censo', 'census_year')
-        .field('dependencia_adm.nome', 'adm_dependency')
         .field('etapa_ensino.desc_etapa', 'school_level')
         .from('turma')
-        .from('dependencia_adm')
         .from('etapa_ensino')
         .from('municipio')
         .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
         .where(`turma.fk_municipio_id = ${cityId}`)
-        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
         .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
         .where('turma.fk_tipo_turma_id <= 3')
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
-        .group('dependencia_adm.nome')
         .group('etapa_ensino.desc_etapa')
         .group('municipio.nome')
         .order('municipio.nome')
-        .order('dependencia_adm.nome')
         .order('etapa_ensino.desc_etapa');
 
     const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
@@ -887,7 +881,11 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
     Promise.all(dbExecAll(querySet)).then((queryResults) => {
         req.result = processResultSet(queryResults, queryLabels);
         for(let label in req.result) {
-            req.result[label].location = locationIdToStr(req.result[label].location);
+            for(let row of req.result[label]) {
+                if (row.hasOwnProperty('location')) {
+                    row.location = locationIdToStr(row.location);
+                }
+            }
         }
         next();
     }).catch((error) => {
diff --git a/src/test/location.js b/src/test/location.js
index 334e3faf..7d8f202e 100644
--- a/src/test/location.js
+++ b/src/test/location.js
@@ -67,7 +67,7 @@ describe('test location', () => {
             });
     }).timeout(testTimeout);
 
-    it('should return the expected response format for sociodemographic data for a country region', (done) => {
+    it('should return the expected response format for sociodemographic data for a region', (done) => {
         chai.request(server)
             .get('/api/v1/location/sociodemographic/region/1')
             .end((err, res) => {
@@ -107,7 +107,7 @@ describe('test location', () => {
             });
     }).timeout(testTimeout);
 
-    it('should return the expected response format for sociodemographic data for a country state', (done) => {
+    it('should return the expected response format for sociodemographic data for a state', (done) => {
         chai.request(server)
             .get('/api/v1/location/sociodemographic/state/42')
             .end((err, res) => {
@@ -147,7 +147,7 @@ describe('test location', () => {
             });
     }).timeout(testTimeout);
 
-    it('should return the expected response format for sociodemographic data for a country city', (done) => {
+    it('should return the expected response format for sociodemographic data for a city', (done) => {
         chai.request(server)
             .get('/api/v1/location/sociodemographic/city/4106902')
             .end((err, res) => {
@@ -199,39 +199,55 @@ describe('test location', () => {
                 // test result type
                 res.body.result.should.be.a('object');
                 res.body.result.should.have.property('school');
+                res.body.result.school.should.be.a('array');
                 res.body.result.should.have.property('school_per_location');
+                res.body.result.school_per_location.should.be.a('array');
                 res.body.result.should.have.property('enrollment');
+                res.body.result.enrollment.should.be.a('array');
                 res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.enrollment_per_adm_dep.should.be.a('array');
                 res.body.result.should.have.property('enrollment_per_school_level');
+                res.body.result.enrollment_per_school_level.should.be.a('array');
                 // test response attributes for school
-                res.body.result.school.should.have.property('name');
-                res.body.result.school.should.have.property('location');
-                res.body.result.school.should.have.property('total');
-                res.body.result.school.should.have.property('census_year');
+                res.body.result.school.should.a('array');
+                res.body.result.school.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for school_per_location
-                res.body.result.school_per_location.should.have.property('name');
-                res.body.result.school_per_location.should.have.property('location');
-                res.body.result.school_per_location.should.have.property('total');
-                res.body.result.school_per_location.should.have.property('census_year');
+                res.body.result.school_per_location.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for enrollment
-                res.body.result.enrollment.should.have.property('name');
-                res.body.result.enrollment.should.have.property('total');
-                res.body.result.enrollment.should.have.property('census_year');
-                res.body.result.enrollment.should.have.property('adm_dependency');
-                res.body.result.enrollment.should.have.property('location');
+                res.body.result.enrollment.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for enrollment_per_adm_dep
-                res.body.result.enrollment_per_adm_dep.should.have.property('name');
-                res.body.result.enrollment_per_adm_dep.should.have.property('total');
-                res.body.result.enrollment_per_adm_dep.should.have.property('census_year');
-                res.body.result.enrollment_per_adm_dep.should.have.property('adm_dependency');
-                res.body.result.enrollment_per_adm_dep.should.have.property('location');
+                res.body.result.enrollment_per_adm_dep.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('adm_dependency');
+                });
                 // test response attributes for enrollment_per_school_level
-                res.body.result.enrollment_per_school_level.should.have.property('name');
-                res.body.result.enrollment_per_school_level.should.have.property('total');
-                res.body.result.enrollment_per_school_level.should.have.property('census_year');
-                res.body.result.enrollment_per_school_level.should.have.property('adm_dependency');
-                res.body.result.enrollment_per_school_level.should.have.property('school_level');
-                res.body.result.enrollment_per_school_level.should.have.property('location');
+                res.body.result.enrollment_per_school_level.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('school_level');
+                });
                 done();
             });
     }).timeout(testTimeout);
@@ -248,39 +264,55 @@ describe('test location', () => {
                 // test result type
                 res.body.result.should.be.a('object');
                 res.body.result.should.have.property('school');
+                res.body.result.school.should.be.a('array');
                 res.body.result.should.have.property('school_per_location');
+                res.body.result.school_per_location.should.be.a('array');
                 res.body.result.should.have.property('enrollment');
+                res.body.result.enrollment.should.be.a('array');
                 res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.enrollment_per_adm_dep.should.be.a('array');
                 res.body.result.should.have.property('enrollment_per_school_level');
+                res.body.result.enrollment_per_school_level.should.be.a('array');
                 // test response attributes for school
-                res.body.result.school.should.have.property('name');
-                res.body.result.school.should.have.property('location');
-                res.body.result.school.should.have.property('total');
-                res.body.result.school.should.have.property('census_year');
+                res.body.result.school.should.a('array');
+                res.body.result.school.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for school_per_location
-                res.body.result.school_per_location.should.have.property('name');
-                res.body.result.school_per_location.should.have.property('location');
-                res.body.result.school_per_location.should.have.property('total');
-                res.body.result.school_per_location.should.have.property('census_year');
+                res.body.result.school_per_location.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for enrollment
-                res.body.result.enrollment.should.have.property('name');
-                res.body.result.enrollment.should.have.property('total');
-                res.body.result.enrollment.should.have.property('census_year');
-                res.body.result.enrollment.should.have.property('adm_dependency');
-                res.body.result.enrollment.should.have.property('location');
+                res.body.result.enrollment.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for enrollment_per_adm_dep
-                res.body.result.enrollment_per_adm_dep.should.have.property('name');
-                res.body.result.enrollment_per_adm_dep.should.have.property('total');
-                res.body.result.enrollment_per_adm_dep.should.have.property('census_year');
-                res.body.result.enrollment_per_adm_dep.should.have.property('adm_dependency');
-                res.body.result.enrollment_per_adm_dep.should.have.property('location');
+                res.body.result.enrollment_per_adm_dep.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('adm_dependency');
+                });
                 // test response attributes for enrollment_per_school_level
-                res.body.result.enrollment_per_school_level.should.have.property('name');
-                res.body.result.enrollment_per_school_level.should.have.property('total');
-                res.body.result.enrollment_per_school_level.should.have.property('census_year');
-                res.body.result.enrollment_per_school_level.should.have.property('adm_dependency');
-                res.body.result.enrollment_per_school_level.should.have.property('school_level');
-                res.body.result.enrollment_per_school_level.should.have.property('location');
+                res.body.result.enrollment_per_school_level.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('school_level');
+                });
                 done();
             });
     }).timeout(testTimeout);
@@ -297,39 +329,55 @@ describe('test location', () => {
                 // test result type
                 res.body.result.should.be.a('object');
                 res.body.result.should.have.property('school');
+                res.body.result.school.should.be.a('array');
                 res.body.result.should.have.property('school_per_location');
+                res.body.result.school_per_location.should.be.a('array');
                 res.body.result.should.have.property('enrollment');
+                res.body.result.enrollment.should.be.a('array');
                 res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.enrollment_per_adm_dep.should.be.a('array');
                 res.body.result.should.have.property('enrollment_per_school_level');
+                res.body.result.enrollment_per_school_level.should.be.a('array');
                 // test response attributes for school
-                res.body.result.school.should.have.property('name');
-                res.body.result.school.should.have.property('location');
-                res.body.result.school.should.have.property('total');
-                res.body.result.school.should.have.property('census_year');
+                res.body.result.school.should.a('array');
+                res.body.result.school.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for school_per_location
-                res.body.result.school_per_location.should.have.property('name');
-                res.body.result.school_per_location.should.have.property('location');
-                res.body.result.school_per_location.should.have.property('total');
-                res.body.result.school_per_location.should.have.property('census_year');
+                res.body.result.school_per_location.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for enrollment
-                res.body.result.enrollment.should.have.property('name');
-                res.body.result.enrollment.should.have.property('total');
-                res.body.result.enrollment.should.have.property('census_year');
-                res.body.result.enrollment.should.have.property('adm_dependency');
-                res.body.result.enrollment.should.have.property('location');
+                res.body.result.enrollment.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for enrollment_per_adm_dep
-                res.body.result.enrollment_per_adm_dep.should.have.property('name');
-                res.body.result.enrollment_per_adm_dep.should.have.property('total');
-                res.body.result.enrollment_per_adm_dep.should.have.property('census_year');
-                res.body.result.enrollment_per_adm_dep.should.have.property('adm_dependency');
-                res.body.result.enrollment_per_adm_dep.should.have.property('location');
+                res.body.result.enrollment_per_adm_dep.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('adm_dependency');
+                });
                 // test response attributes for enrollment_per_school_level
-                res.body.result.enrollment_per_school_level.should.have.property('name');
-                res.body.result.enrollment_per_school_level.should.have.property('total');
-                res.body.result.enrollment_per_school_level.should.have.property('census_year');
-                res.body.result.enrollment_per_school_level.should.have.property('adm_dependency');
-                res.body.result.enrollment_per_school_level.should.have.property('school_level');
-                res.body.result.enrollment_per_school_level.should.have.property('location');
+                res.body.result.enrollment_per_school_level.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('school_level');
+                });
                 done();
             });
     }).timeout(testTimeout);
@@ -346,39 +394,55 @@ describe('test location', () => {
                 // test result type
                 res.body.result.should.be.a('object');
                 res.body.result.should.have.property('school');
+                res.body.result.school.should.be.a('array');
                 res.body.result.should.have.property('school_per_location');
+                res.body.result.school_per_location.should.be.a('array');
                 res.body.result.should.have.property('enrollment');
+                res.body.result.enrollment.should.be.a('array');
                 res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.enrollment_per_adm_dep.should.be.a('array');
                 res.body.result.should.have.property('enrollment_per_school_level');
+                res.body.result.enrollment_per_school_level.should.be.a('array');
                 // test response attributes for school
-                res.body.result.school.should.have.property('name');
-                res.body.result.school.should.have.property('location');
-                res.body.result.school.should.have.property('total');
-                res.body.result.school.should.have.property('census_year');
+                res.body.result.school.should.a('array');
+                res.body.result.school.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for school_per_location
-                res.body.result.school_per_location.should.have.property('name');
-                res.body.result.school_per_location.should.have.property('location');
-                res.body.result.school_per_location.should.have.property('total');
-                res.body.result.school_per_location.should.have.property('census_year');
+                res.body.result.school_per_location.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for enrollment
-                res.body.result.enrollment.should.have.property('name');
-                res.body.result.enrollment.should.have.property('total');
-                res.body.result.enrollment.should.have.property('census_year');
-                res.body.result.enrollment.should.have.property('adm_dependency');
-                res.body.result.enrollment.should.have.property('location');
+                res.body.result.enrollment.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
                 // test response attributes for enrollment_per_adm_dep
-                res.body.result.enrollment_per_adm_dep.should.have.property('name');
-                res.body.result.enrollment_per_adm_dep.should.have.property('total');
-                res.body.result.enrollment_per_adm_dep.should.have.property('census_year');
-                res.body.result.enrollment_per_adm_dep.should.have.property('adm_dependency');
-                res.body.result.enrollment_per_adm_dep.should.have.property('location');
+                res.body.result.enrollment_per_adm_dep.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('adm_dependency');
+                });
                 // test response attributes for enrollment_per_school_level
-                res.body.result.enrollment_per_school_level.should.have.property('name');
-                res.body.result.enrollment_per_school_level.should.have.property('total');
-                res.body.result.enrollment_per_school_level.should.have.property('census_year');
-                res.body.result.enrollment_per_school_level.should.have.property('adm_dependency');
-                res.body.result.enrollment_per_school_level.should.have.property('school_level');
-                res.body.result.enrollment_per_school_level.should.have.property('location');
+                res.body.result.enrollment_per_school_level.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('school_level');
+                });
                 done();
             });
     }).timeout(testTimeout);
-- 
GitLab


From 71db7dcc88edf9dc283f07ba50ea22ad0d07d7fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Mon, 7 Nov 2016 16:57:57 -0200
Subject: [PATCH 18/32] Add ordering to educational route queries in location
 module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/libs/routes/location.js | 167 +++++++++++++++++++++++++++++++++---
 1 file changed, 153 insertions(+), 14 deletions(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index 3db23d54..68ca03be 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -34,6 +34,79 @@ function locationIdToStr(locationId) {
     return locationStr;
 }
 
+function schoolYearIdToStr(schoolYearId)
+{
+    let schoolYearStr;
+    switch(schoolYearId) {
+        case 11:
+            schoolYearStr = 'Creche';
+            break;
+        case 21:
+            schoolYearStr = 'Pré-escola';
+            break;
+        case 31:
+            schoolYearStr = 'EF-AI 1 Ano';
+            break;
+        case 32:
+            schoolYearStr = 'EF-AI 2 Ano - 1 Serie';
+            break;
+        case 33:
+            schoolYearStr = 'EF-AI 3 Ano - 2 Serie';
+            break;
+        case 34:
+            schoolYearStr = 'EF-AI 4 Ano - 3 Serie';
+            break;
+        case 35:
+            schoolYearStr = 'EF-AI 5 Ano - 4 Serie';
+            break;
+        case 41:
+            schoolYearStr = 'EF-AF 6 Ano - 5 Serie';
+            break;
+        case 42:
+            schoolYearStr = 'EF-AF 7 Ano - 6 Serie';
+            break;
+        case 43:
+            schoolYearStr = 'EF-AF 8 Ano - 7 Serie';
+            break;
+        case 44:
+            schoolYearStr = 'EF-AF 9 Ano - 8 Serie';
+            break;
+        case 51:
+            schoolYearStr = 'EM 1 Série';
+            break;
+        case 52:
+            schoolYearStr = 'EM 2 Série';
+            break;
+        case 53:
+            schoolYearStr = 'EM 3 Série';
+            break;
+        case 54:
+            schoolYearStr = 'EM 4 Série';
+            break;
+        case 61:
+            schoolYearStr = 'EJA AI';
+            break;
+        case 62:
+            schoolYearStr = 'EJA AF';
+            break;
+        case 63:
+            schoolYearStr = 'EJA EM';
+            break;
+        case 64:
+            schoolYearStr = 'EJA semi-presencial';
+            break;
+        case 71:
+            schoolYearStr = 'EP';
+            break;
+        case 81:
+            schoolYearStr = 'Atividades complementares e AEE';
+            break;
+        default:
+            schoolYearStr = 'Não classificado';
+    }
+    return schoolYearStr;
+}
+
 function processResultSet(querySet, querySetLabels = ["result"], singleResult = false) {
     const resultMap = new Map();
     let resultIdx = 0;
@@ -490,7 +563,8 @@ locationApp.get('/educational', (req, res, next) => {
         .where(`escola.ano_censo IN (${censusYearQry})`)
         .where('escola.id_tipo_turma = 0')
         .group('escola.tipo_localizacao')
-        .group('escola.ano_censo');
+        .group('escola.ano_censo')
+        .order('escola.tipo_localizacao');
 
     const schoolClassYearQry = squel.select()
         .field('MAX(turma.ano_censo)')
@@ -517,7 +591,8 @@ locationApp.get('/educational', (req, res, next) => {
         .where('turma.fk_tipo_turma_id <= 3')
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
-        .group('dependencia_adm.nome');
+        .group('dependencia_adm.nome')
+        .order('dependencia_adm.nome');
 
     const enrollmentsPerSchoolLevelQry = squel.select()
         .field('\'Brasil\'', 'name')
@@ -576,7 +651,8 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .where(`escola.ano_censo IN (${censusYearQry})`)
         .where('escola.id_tipo_turma = 0')
         .group('regiao.nome')
-        .group('escola.ano_censo');
+        .group('escola.ano_censo')
+        .order('regiao.nome');
 
     const schoolsPerLocationQry = squel.select()
         .field('regiao.nome', 'name')
@@ -593,7 +669,9 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .where('escola.id_tipo_turma = 0')
         .group('regiao.nome')
         .group('escola.tipo_localizacao')
-        .group('escola.ano_censo');
+        .group('escola.ano_censo')
+        .order('regiao.nome')
+        .order('escola.tipo_localizacao');
 
     const schoolClassYearQry = squel.select()
         .field('MAX(turma.ano_censo)')
@@ -611,7 +689,8 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .where('turma.fk_tipo_turma_id <= 3')
         .group('turma.ano_censo')
-        .group('regiao.nome');
+        .group('regiao.nome')
+        .order('regiao.nome');
 
     const enrollmentsPerAdmDepQry = squel.select()
         .field('regiao.nome', 'name')
@@ -628,7 +707,9 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
         .group('dependencia_adm.nome')
-        .group('regiao.nome');
+        .group('regiao.nome')
+        .order('regiao.nome')
+        .order('dependencia_adm.nome');
 
     const enrollmentsPerSchoolLevelQry = squel.select()
         .field('regiao.nome', 'name')
@@ -690,7 +771,8 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
         .where(`escola.ano_censo IN (${censusYearQry})`)
         .where('escola.id_tipo_turma = 0')
         .group('estado.nome')
-        .group('escola.ano_censo');
+        .group('escola.ano_censo')
+        .order('estado.nome');
 
     const schoolsPerLocationQry = squel.select()
         .field('estado.nome', 'name')
@@ -705,7 +787,9 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
         .where('escola.id_tipo_turma = 0')
         .group('estado.nome')
         .group('escola.tipo_localizacao')
-        .group('escola.ano_censo');
+        .group('escola.ano_censo')
+        .order('estado.nome')
+        .order('escola.tipo_localizacao');
 
     const schoolClassYearQry = squel.select()
         .field('MAX(turma.ano_censo)')
@@ -723,7 +807,8 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .where('turma.fk_tipo_turma_id <= 3')
         .group('turma.ano_censo')
-        .group('estado.nome');
+        .group('estado.nome')
+        .order('estado.nome');
 
     const enrollmentsPerAdmDepQry = squel.select()
         .field('estado.nome', 'name')
@@ -740,7 +825,9 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
         .group('dependencia_adm.nome')
-        .group('estado.nome');
+        .group('estado.nome')
+        .order('estado.nome')
+        .order('dependencia_adm.nome');
 
     const enrollmentsPerSchoolLevelQry = squel.select()
         .field('estado.nome', 'name')
@@ -802,7 +889,8 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
         .where(`escola.ano_censo IN (${censusYearQry})`)
         .where('escola.id_tipo_turma = 0')
         .group('municipio.nome')
-        .group('escola.ano_censo');
+        .group('escola.ano_censo')
+        .order('municipio.nome');
 
     const schoolsPerLocationQry = squel.select()
         .field('municipio.nome', 'name')
@@ -817,7 +905,9 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
         .where('escola.id_tipo_turma = 0')
         .group('municipio.nome')
         .group('escola.tipo_localizacao')
-        .group('escola.ano_censo');
+        .group('escola.ano_censo')
+        .order('municipio.nome')
+        .order('escola.tipo_localizacao');
 
     const schoolClassYearQry = squel.select()
         .field('MAX(turma.ano_censo)')
@@ -835,7 +925,8 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .where('turma.fk_tipo_turma_id <= 3')
         .group('turma.ano_censo')
-        .group('municipio.nome');
+        .group('municipio.nome')
+        .order('municipio.nome');
 
     const enrollmentsPerAdmDepQry = squel.select()
         .field('municipio.nome', 'name')
@@ -852,7 +943,9 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
         .group('dependencia_adm.nome')
-        .group('municipio.nome');
+        .group('municipio.nome')
+        .order('municipio.nome')
+        .order('dependencia_adm.nome');
 
     const enrollmentsPerSchoolLevelQry = squel.select()
         .field('municipio.nome', 'name')
@@ -894,4 +987,50 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
     });
 }, response('location'));
 
+/* TODO: fix response format to nest objects by year
+locationApp.get('/educational/per_year', (req, res, next) => {
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('turma.serie_ano', 'school_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('etapa_ensino.desc_etapa')
+        .group('turma.serie_ano')
+        .group('turma.ano_censo')
+        .order('etapa_ensino.desc_etapa')
+        .order('turma.serie_ano')
+        .order('turma.ano_censo');
+
+    const queryLabels = [ "enrollment_per_school_level" ];
+    const querySet = [ enrollmentsPerSchoolLevelQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        const result = queryResults[0];
+        let response = {};
+        for(let i = 0; i < result.length; ++i) {
+            log.debug(result[i]);
+            const school_year  = schoolYearIdToStr(result[i].school_year);
+            const school_level = result[i].school_level;
+            const census_year = result[i].census_year;
+            if (typeof response[school_level] === "undefined") {
+                response[school_level] = {};
+            }
+            if (typeof response[school_level][school_year] === "undefined") {
+                response[school_level][school_year] = {};
+            }
+            response[school_level][school_year] = parseInt(result[i].total, 10);
+        }
+        req.result = response;
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+*/
+
 module.exports = locationApp;
-- 
GitLab


From a0bcb0edcb5d8b3e916535b86945d398a8a91576 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Tue, 8 Nov 2016 11:41:08 -0200
Subject: [PATCH 19/32] Implement route for UC408
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Add /location/educational/school_level route to query enrollments per school level;
- Add basic test case for the route. For now, it only checks if the format of the response is the expected one.

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/libs/routes/location.js | 71 +++++++++++++++++++++++--------------
 src/test/location.js        | 29 +++++++++++++++
 2 files changed, 74 insertions(+), 26 deletions(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index 68ca03be..b4a252d8 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -45,43 +45,43 @@ function schoolYearIdToStr(schoolYearId)
             schoolYearStr = 'Pré-escola';
             break;
         case 31:
-            schoolYearStr = 'EF-AI 1 Ano';
+            schoolYearStr = '1 Ano';
             break;
         case 32:
-            schoolYearStr = 'EF-AI 2 Ano - 1 Serie';
+            schoolYearStr = '2 Ano - 1 Serie';
             break;
         case 33:
-            schoolYearStr = 'EF-AI 3 Ano - 2 Serie';
+            schoolYearStr = '3 Ano - 2 Serie';
             break;
         case 34:
-            schoolYearStr = 'EF-AI 4 Ano - 3 Serie';
+            schoolYearStr = '4 Ano - 3 Serie';
             break;
         case 35:
-            schoolYearStr = 'EF-AI 5 Ano - 4 Serie';
+            schoolYearStr = '5 Ano - 4 Serie';
             break;
         case 41:
-            schoolYearStr = 'EF-AF 6 Ano - 5 Serie';
+            schoolYearStr = '6 Ano - 5 Serie';
             break;
         case 42:
-            schoolYearStr = 'EF-AF 7 Ano - 6 Serie';
+            schoolYearStr = '7 Ano - 6 Serie';
             break;
         case 43:
-            schoolYearStr = 'EF-AF 8 Ano - 7 Serie';
+            schoolYearStr = '8 Ano - 7 Serie';
             break;
         case 44:
-            schoolYearStr = 'EF-AF 9 Ano - 8 Serie';
+            schoolYearStr = '9 Ano - 8 Serie';
             break;
         case 51:
-            schoolYearStr = 'EM 1 Série';
+            schoolYearStr = '1 Ano'; // equivalent to 'EM 1 Série'
             break;
         case 52:
-            schoolYearStr = 'EM 2 Série';
+            schoolYearStr = '2 Ano'; // equivalent to 'EM 2 Série'
             break;
         case 53:
-            schoolYearStr = 'EM 3 Série';
+            schoolYearStr = '3 Ano'; // equivalent to 'EM 3 Série'
             break;
         case 54:
-            schoolYearStr = 'EM 4 Série';
+            schoolYearStr = '4 Ano'; // equivalent to 'EM 4 Série'
             break;
         case 61:
             schoolYearStr = 'EJA AI';
@@ -987,8 +987,11 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
     });
 }, response('location'));
 
-/* TODO: fix response format to nest objects by year
-locationApp.get('/educational/per_year', (req, res, next) => {
+locationApp.get('/educational/school_level', (req, res, next) => {
+    const enrollmentsPerSchoolLevelYearQry = squel.select()
+        .field('MAX(turma.ano_censo)', 'census_year')
+        .from('turma');
+
     const enrollmentsPerSchoolLevelQry = squel.select()
         .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
         .field('turma.ano_censo', 'census_year')
@@ -996,6 +999,7 @@ locationApp.get('/educational/per_year', (req, res, next) => {
         .field('etapa_ensino.desc_etapa', 'school_level')
         .from('turma')
         .from('etapa_ensino')
+        .where(`turma.ano_censo IN (${enrollmentsPerSchoolLevelYearQry.toString()})`)
         .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
         .where('turma.fk_tipo_turma_id <= 3')
         .group('etapa_ensino.desc_etapa')
@@ -1005,24 +1009,40 @@ locationApp.get('/educational/per_year', (req, res, next) => {
         .order('turma.serie_ano')
         .order('turma.ano_censo');
 
-    const queryLabels = [ "enrollment_per_school_level" ];
-    const querySet = [ enrollmentsPerSchoolLevelQry ];
+    const queryLabels = [ 'enrollment_per_school_level', 'enrollment_census_year' ];
+    const querySet = [ enrollmentsPerSchoolLevelQry, enrollmentsPerSchoolLevelYearQry ];
     // wait until all queries finish or one of them fail
-    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+    Promise.all(dbExecAll(querySet, enrollmentsPerSchoolLevelYearQry)).then((queryResults) => {
         const result = queryResults[0];
-        let response = {};
+        const censusYear = queryResults[1][0]['census_year'];
+
+        let school_levels = {};
         for(let i = 0; i < result.length; ++i) {
-            log.debug(result[i]);
             const school_year  = schoolYearIdToStr(result[i].school_year);
             const school_level = result[i].school_level;
             const census_year = result[i].census_year;
-            if (typeof response[school_level] === "undefined") {
-                response[school_level] = {};
+            if (typeof school_levels[school_level] === 'undefined') {
+                school_levels[school_level] = {};
             }
-            if (typeof response[school_level][school_year] === "undefined") {
-                response[school_level][school_year] = {};
+            school_levels[school_level][school_year] = parseInt(result[i].total, 10);
+        }
+
+        let response = [];
+        for(let level in school_levels) {
+            if (school_levels.hasOwnProperty(level)) {
+                let sclevel = {};
+                sclevel["degree"] = level;
+                sclevel["census_year"] = parseInt(censusYear, 10);
+                sclevel["table"] = [];
+                for(let school_year in school_levels[level]) {
+                    if (school_levels[level].hasOwnProperty(school_year)) {
+                        let enrollment = { 'title' : school_year,
+                                           'value' : school_levels[level][school_year] };
+                        sclevel["table"].push(enrollment);
+                    }
+                }
+                response.push(sclevel);
             }
-            response[school_level][school_year] = parseInt(result[i].total, 10);
         }
         req.result = response;
         next();
@@ -1031,6 +1051,5 @@ locationApp.get('/educational/per_year', (req, res, next) => {
         next(error);
     });
 }, response('location'));
-*/
 
 module.exports = locationApp;
diff --git a/src/test/location.js b/src/test/location.js
index 7d8f202e..06924a3b 100644
--- a/src/test/location.js
+++ b/src/test/location.js
@@ -446,4 +446,33 @@ describe('test location', () => {
                 done();
             });
     }).timeout(testTimeout);
+
+    it('should return the correct format of enrollments per school level', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/school_level')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                // test response attributes for school
+                res.body.result.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('degree');
+                    row.should.have.property('census_year');
+                    row.should.have.property('table');
+                    row.table.should.be.a('array');
+                    row.table.forEach((tableRow) => {
+                        tableRow.should.be.a('object');
+                        tableRow.should.have.property('title');
+                        tableRow.should.have.property('value');
+                        tableRow.title.should.be.a('String');
+                        tableRow.value.should.be.a('Number');
+                    });
+                });
+                done();
+            });
+    }).timeout(testTimeout);
 });
-- 
GitLab


From c57b5f5ead9697c8497ad0fa8d629d954f7c2979 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Risso?= <joaovictor.risso@gmail.com>
Date: Wed, 9 Nov 2016 11:24:11 -0200
Subject: [PATCH 20/32] Implement route to list enrollments per school level
 for a given region
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Risso <joaovictor.risso@gmail.com>
---
 src/libs/routes/location.js | 72 +++++++++++++++++++++++++++++++++++++
 src/test/location.js        | 29 +++++++++++++++
 2 files changed, 101 insertions(+)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index b4a252d8..8f2603a1 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -1052,4 +1052,76 @@ locationApp.get('/educational/school_level', (req, res, next) => {
     });
 }, response('location'));
 
+locationApp.get('/educational/school_level/region/:id', (req, res, next) => {
+    const regionId = parseInt(req.params.id, 10);
+
+    const enrollmentsPerSchoolLevelYearQry = squel.select()
+        .field('MAX(turma.ano_censo)', 'census_year')
+        .from('turma');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('turma.serie_ano', 'school_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .from('regiao')
+        .where(`turma.fk_regiao_id = ${regionId}`)
+        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`turma.ano_censo IN (${enrollmentsPerSchoolLevelYearQry.toString()})`)
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('regiao.nome')
+        .group('etapa_ensino.desc_etapa')
+        .group('turma.serie_ano')
+        .group('turma.ano_censo')
+        .order('regiao.nome')
+        .order('etapa_ensino.desc_etapa')
+        .order('turma.serie_ano')
+        .order('turma.ano_censo');
+
+    const queryLabels = [ 'enrollment_per_school_level', 'enrollment_census_year' ];
+    const querySet = [ enrollmentsPerSchoolLevelQry, enrollmentsPerSchoolLevelYearQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet, enrollmentsPerSchoolLevelYearQry)).then((queryResults) => {
+        const result = queryResults[0];
+        const censusYear = queryResults[1][0]['census_year'];
+
+        let school_levels = {};
+        for(let i = 0; i < result.length; ++i) {
+            const school_year  = schoolYearIdToStr(result[i].school_year);
+            const school_level = result[i].school_level;
+            const census_year = result[i].census_year;
+            if (typeof school_levels[school_level] === 'undefined') {
+                school_levels[school_level] = {};
+            }
+            school_levels[school_level][school_year] = parseInt(result[i].total, 10);
+        }
+
+        let response = [];
+        for(let level in school_levels) {
+            if (school_levels.hasOwnProperty(level)) {
+                let sclevel = {};
+                sclevel["degree"] = level;
+                sclevel["census_year"] = parseInt(censusYear, 10);
+                sclevel["table"] = [];
+                for(let school_year in school_levels[level]) {
+                    if (school_levels[level].hasOwnProperty(school_year)) {
+                        let enrollment = { 'title' : school_year,
+                                           'value' : school_levels[level][school_year] };
+                        sclevel["table"].push(enrollment);
+                    }
+                }
+                response.push(sclevel);
+            }
+        }
+        req.result = response;
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
 module.exports = locationApp;
diff --git a/src/test/location.js b/src/test/location.js
index 06924a3b..0012aa0a 100644
--- a/src/test/location.js
+++ b/src/test/location.js
@@ -475,4 +475,33 @@ describe('test location', () => {
                 done();
             });
     }).timeout(testTimeout);
+
+    it('should return the correct format of enrollments per school level for a region', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/school_level/region/1')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                // test response attributes for school
+                res.body.result.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('degree');
+                    row.should.have.property('census_year');
+                    row.should.have.property('table');
+                    row.table.should.be.a('array');
+                    row.table.forEach((tableRow) => {
+                        tableRow.should.be.a('object');
+                        tableRow.should.have.property('title');
+                        tableRow.should.have.property('value');
+                        tableRow.title.should.be.a('String');
+                        tableRow.value.should.be.a('Number');
+                    });
+                });
+                done();
+            });
+    }).timeout(testTimeout);
 });
-- 
GitLab


From 923b132a1f40954ab42fbd47f3218c3508887da3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Risso?= <joaovictor.risso@gmail.com>
Date: Wed, 9 Nov 2016 11:28:19 -0200
Subject: [PATCH 21/32] Implement route to list enrollments per school level
 for a given region
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Risso <joaovictor.risso@gmail.com>
---
 src/libs/routes/location.js | 72 +++++++++++++++++++++++++++++++++++++
 src/test/location.js        | 29 +++++++++++++++
 2 files changed, 101 insertions(+)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index 8f2603a1..c10d77b9 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -1124,4 +1124,76 @@ locationApp.get('/educational/school_level/region/:id', (req, res, next) => {
     });
 }, response('location'));
 
+locationApp.get('/educational/school_level/state/:id', (req, res, next) => {
+    const stateId = parseInt(req.params.id, 10);
+
+    const enrollmentsPerSchoolLevelYearQry = squel.select()
+        .field('MAX(turma.ano_censo)', 'census_year')
+        .from('turma');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('turma.serie_ano', 'school_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .from('estado')
+        .where(`turma.fk_estado_id = ${stateId}`)
+        .where('turma.fk_estado_id = estado.pk_estado_id')
+        .where(`turma.ano_censo IN (${enrollmentsPerSchoolLevelYearQry.toString()})`)
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('estado.nome')
+        .group('etapa_ensino.desc_etapa')
+        .group('turma.serie_ano')
+        .group('turma.ano_censo')
+        .order('estado.nome')
+        .order('etapa_ensino.desc_etapa')
+        .order('turma.serie_ano')
+        .order('turma.ano_censo');
+
+    const queryLabels = [ 'enrollment_per_school_level', 'enrollment_census_year' ];
+    const querySet = [ enrollmentsPerSchoolLevelQry, enrollmentsPerSchoolLevelYearQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet, enrollmentsPerSchoolLevelYearQry)).then((queryResults) => {
+        const result = queryResults[0];
+        const censusYear = queryResults[1][0]['census_year'];
+
+        let school_levels = {};
+        for(let i = 0; i < result.length; ++i) {
+            const school_year  = schoolYearIdToStr(result[i].school_year);
+            const school_level = result[i].school_level;
+            const census_year = result[i].census_year;
+            if (typeof school_levels[school_level] === 'undefined') {
+                school_levels[school_level] = {};
+            }
+            school_levels[school_level][school_year] = parseInt(result[i].total, 10);
+        }
+
+        let response = [];
+        for(let level in school_levels) {
+            if (school_levels.hasOwnProperty(level)) {
+                let sclevel = {};
+                sclevel["degree"] = level;
+                sclevel["census_year"] = parseInt(censusYear, 10);
+                sclevel["table"] = [];
+                for(let school_year in school_levels[level]) {
+                    if (school_levels[level].hasOwnProperty(school_year)) {
+                        let enrollment = { 'title' : school_year,
+                                           'value' : school_levels[level][school_year] };
+                        sclevel["table"].push(enrollment);
+                    }
+                }
+                response.push(sclevel);
+            }
+        }
+        req.result = response;
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
 module.exports = locationApp;
diff --git a/src/test/location.js b/src/test/location.js
index 0012aa0a..12d6e6c9 100644
--- a/src/test/location.js
+++ b/src/test/location.js
@@ -504,4 +504,33 @@ describe('test location', () => {
                 done();
             });
     }).timeout(testTimeout);
+
+    it('should return the correct format of enrollments per school level for a state', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/school_level/state/42')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                // test response attributes for school
+                res.body.result.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('degree');
+                    row.should.have.property('census_year');
+                    row.should.have.property('table');
+                    row.table.should.be.a('array');
+                    row.table.forEach((tableRow) => {
+                        tableRow.should.be.a('object');
+                        tableRow.should.have.property('title');
+                        tableRow.should.have.property('value');
+                        tableRow.title.should.be.a('String');
+                        tableRow.value.should.be.a('Number');
+                    });
+                });
+                done();
+            });
+    }).timeout(testTimeout);
 });
-- 
GitLab


From 3e7a27ed0b1d0417bd987f4f6d6726377da60fd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Risso?= <joaovictor.risso@gmail.com>
Date: Wed, 9 Nov 2016 11:32:10 -0200
Subject: [PATCH 22/32] Implement route to list enrollments per school level
 for a given city
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Risso <joaovictor.risso@gmail.com>
---
 src/libs/routes/location.js | 72 +++++++++++++++++++++++++++++++++++++
 src/test/location.js        | 29 +++++++++++++++
 2 files changed, 101 insertions(+)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index c10d77b9..0dd66531 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -1196,4 +1196,76 @@ locationApp.get('/educational/school_level/state/:id', (req, res, next) => {
     });
 }, response('location'));
 
+locationApp.get('/educational/school_level/city/:id', (req, res, next) => {
+    const cityId = parseInt(req.params.id, 10);
+
+    const enrollmentsPerSchoolLevelYearQry = squel.select()
+        .field('MAX(turma.ano_censo)', 'census_year')
+        .from('turma');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('turma.serie_ano', 'school_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .from('municipio')
+        .where(`turma.fk_municipio_id = ${cityId}`)
+        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`turma.ano_censo IN (${enrollmentsPerSchoolLevelYearQry.toString()})`)
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('municipio.nome')
+        .group('etapa_ensino.desc_etapa')
+        .group('turma.serie_ano')
+        .group('turma.ano_censo')
+        .order('municipio.nome')
+        .order('etapa_ensino.desc_etapa')
+        .order('turma.serie_ano')
+        .order('turma.ano_censo');
+
+    const queryLabels = [ 'enrollment_per_school_level', 'enrollment_census_year' ];
+    const querySet = [ enrollmentsPerSchoolLevelQry, enrollmentsPerSchoolLevelYearQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet, enrollmentsPerSchoolLevelYearQry)).then((queryResults) => {
+        const result = queryResults[0];
+        const censusYear = queryResults[1][0]['census_year'];
+
+        let school_levels = {};
+        for(let i = 0; i < result.length; ++i) {
+            const school_year  = schoolYearIdToStr(result[i].school_year);
+            const school_level = result[i].school_level;
+            const census_year = result[i].census_year;
+            if (typeof school_levels[school_level] === 'undefined') {
+                school_levels[school_level] = {};
+            }
+            school_levels[school_level][school_year] = parseInt(result[i].total, 10);
+        }
+
+        let response = [];
+        for(let level in school_levels) {
+            if (school_levels.hasOwnProperty(level)) {
+                let sclevel = {};
+                sclevel["degree"] = level;
+                sclevel["census_year"] = parseInt(censusYear, 10);
+                sclevel["table"] = [];
+                for(let school_year in school_levels[level]) {
+                    if (school_levels[level].hasOwnProperty(school_year)) {
+                        let enrollment = { 'title' : school_year,
+                                           'value' : school_levels[level][school_year] };
+                        sclevel["table"].push(enrollment);
+                    }
+                }
+                response.push(sclevel);
+            }
+        }
+        req.result = response;
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
 module.exports = locationApp;
diff --git a/src/test/location.js b/src/test/location.js
index 12d6e6c9..42761a8d 100644
--- a/src/test/location.js
+++ b/src/test/location.js
@@ -533,4 +533,33 @@ describe('test location', () => {
                 done();
             });
     }).timeout(testTimeout);
+
+    it('should return the correct format of enrollments per school level for a city', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/school_level/state/4106902')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                // test response attributes for school
+                res.body.result.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('degree');
+                    row.should.have.property('census_year');
+                    row.should.have.property('table');
+                    row.table.should.be.a('array');
+                    row.table.forEach((tableRow) => {
+                        tableRow.should.be.a('object');
+                        tableRow.should.have.property('title');
+                        tableRow.should.have.property('value');
+                        tableRow.title.should.be.a('String');
+                        tableRow.value.should.be.a('Number');
+                    });
+                });
+                done();
+            });
+    }).timeout(testTimeout);
 });
-- 
GitLab


From f1db5b4c7a1beff0c97bed03c630f6bfe91e0537 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Mon, 21 Nov 2016 17:14:51 -0200
Subject: [PATCH 23/32] Change order from etapa_ensino.desc_etapa to
 etapa_ensino.pk_etapa_ensino_id in location routes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/libs/routes/location.js | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
index 0dd66531..f5476f5e 100644
--- a/src/libs/routes/location.js
+++ b/src/libs/routes/location.js
@@ -606,7 +606,8 @@ locationApp.get('/educational', (req, res, next) => {
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
         .group('etapa_ensino.desc_etapa')
-        .order('etapa_ensino.desc_etapa');
+        .group('etapa_ensino.pk_etapa_ensino_id')
+        .order('etapa_ensino.pk_etapa_ensino_id');
 
     const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
         "enrollment_per_school_level" ];
@@ -727,8 +728,9 @@ locationApp.get('/educational/region/:id', (req, res, next) => {
         .group('turma.ano_censo')
         .group('etapa_ensino.desc_etapa')
         .group('regiao.nome')
+        .group('etapa_ensino.pk_etapa_ensino_id')
         .order('regiao.nome')
-        .order('etapa_ensino.desc_etapa');
+        .order('etapa_ensino.pk_etapa_ensino_id');
 
     const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
         "enrollment_per_school_level" ];
@@ -844,9 +846,10 @@ locationApp.get('/educational/state/:id', (req, res, next) => {
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
         .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
         .group('estado.nome')
         .order('estado.nome')
-        .order('etapa_ensino.desc_etapa');
+        .order('etapa_ensino.pk_etapa_ensino_id');
 
     const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
         "enrollment_per_school_level" ];
@@ -962,9 +965,10 @@ locationApp.get('/educational/city/:id', (req, res, next) => {
         .where(`turma.ano_censo IN (${schoolClassYearQry})`)
         .group('turma.ano_censo')
         .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
         .group('municipio.nome')
         .order('municipio.nome')
-        .order('etapa_ensino.desc_etapa');
+        .order('etapa_ensino.pk_etapa_ensino_id');
 
     const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
         "enrollment_per_school_level" ];
@@ -1003,9 +1007,10 @@ locationApp.get('/educational/school_level', (req, res, next) => {
         .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
         .where('turma.fk_tipo_turma_id <= 3')
         .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
         .group('turma.serie_ano')
         .group('turma.ano_censo')
-        .order('etapa_ensino.desc_etapa')
+        .order('etapa_ensino.pk_etapa_ensino_id')
         .order('turma.serie_ano')
         .order('turma.ano_censo');
 
@@ -1074,10 +1079,11 @@ locationApp.get('/educational/school_level/region/:id', (req, res, next) => {
         .where('turma.fk_tipo_turma_id <= 3')
         .group('regiao.nome')
         .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
         .group('turma.serie_ano')
         .group('turma.ano_censo')
         .order('regiao.nome')
-        .order('etapa_ensino.desc_etapa')
+        .order('etapa_ensino.pk_etapa_ensino_id')
         .order('turma.serie_ano')
         .order('turma.ano_censo');
 
@@ -1146,10 +1152,11 @@ locationApp.get('/educational/school_level/state/:id', (req, res, next) => {
         .where('turma.fk_tipo_turma_id <= 3')
         .group('estado.nome')
         .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
         .group('turma.serie_ano')
         .group('turma.ano_censo')
         .order('estado.nome')
-        .order('etapa_ensino.desc_etapa')
+        .order('etapa_ensino.pk_etapa_ensino_id')
         .order('turma.serie_ano')
         .order('turma.ano_censo');
 
@@ -1218,10 +1225,11 @@ locationApp.get('/educational/school_level/city/:id', (req, res, next) => {
         .where('turma.fk_tipo_turma_id <= 3')
         .group('municipio.nome')
         .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
         .group('turma.serie_ano')
         .group('turma.ano_censo')
         .order('municipio.nome')
-        .order('etapa_ensino.desc_etapa')
+        .order('etapa_ensino.pk_etapa_ensino_id')
         .order('turma.serie_ano')
         .order('turma.ano_censo');
 
-- 
GitLab


From aef1ec5e56a418de09d3d61bdfaa15cbfd8bd06d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Tozatti=20Risso?= <jvtr12@inf.ufpr.br>
Date: Tue, 22 Nov 2016 10:45:16 -0200
Subject: [PATCH 24/32] Rename auth test to user in order to correctly refer to
 the module it is testing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: João Victor Tozatti Risso <jvtr12@inf.ufpr.br>
---
 src/test/{auth.js => user.js} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename src/test/{auth.js => user.js} (100%)

diff --git a/src/test/auth.js b/src/test/user.js
similarity index 100%
rename from src/test/auth.js
rename to src/test/user.js
-- 
GitLab


From cce4a300ff96b9489f5171169db18141ea05c764 Mon Sep 17 00:00:00 2001
From: Vytor Calixto <vytorcalixto@gmail.com>
Date: Mon, 28 Nov 2016 10:48:45 -0200
Subject: [PATCH 25/32] Add more location_name(s)

---
 src/libs/routes/enrollment.js | 10 +++++++++-
 src/server.js                 |  3 ---
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js
index 94868295..4d51e98e 100644
--- a/src/libs/routes/enrollment.js
+++ b/src/libs/routes/enrollment.js
@@ -228,8 +228,16 @@ enrollmentApp.get('/', (req, res, next) => {
         if(req.dims.location) {
             if(data.location_name === 1) {
                 data.location_name = 'Urbana';
-            } else {
+            } else if (data.location_name === 2) {
                 data.location_name = 'Rural';
+            } else if (data.location_name === 3) {
+                data.location_name = 'Área de Assentamento';
+            } else if (data.location_name === 4) {
+                data.location_name = 'Terra Indígena';
+            } else if (data.location_name === 5) {
+                data.location_name = 'Área Remanescente de Quilombos';
+            } else if (data.location_name === 6) {
+                data.location_name = 'Unidade de uso sustentável';
             }
         }
     });
diff --git a/src/server.js b/src/server.js
index 4e097f28..2ebb897d 100644
--- a/src/server.js
+++ b/src/server.js
@@ -11,9 +11,6 @@ const app = require(`${libs}/app`);
 // Set default port: first environment variable PORT, then configuration and last 3000
 app.set('port', process.env.PORT || config.port || 3000);
 process.env.NODE_ENV = process.env.NODE_ENV || 'development';
-
-app.set('port', process.env.PORT || config.port || 3000);
-
 // Set default ip: first environment variable IOP, then configuration and last '127.0.0.1'
 app.set('ip', process.env.IP || config.ip || '127.0.0.1');
 
-- 
GitLab


From 736cdc956c9948a3ccbf175eb6e54234ef51bd86 Mon Sep 17 00:00:00 2001
From: Vytor Calixto <vytorcalixto@gmail.com>
Date: Wed, 30 Nov 2016 11:44:00 -0200
Subject: [PATCH 26/32] Add response type test

---
 src/test/response.js | 55 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)
 create mode 100644 src/test/response.js

diff --git a/src/test/response.js b/src/test/response.js
new file mode 100644
index 00000000..bdafc9d8
--- /dev/null
+++ b/src/test/response.js
@@ -0,0 +1,55 @@
+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('test response', () => {
+    it('should list all regions in json', (done) => {
+        chai.request(server)
+            .get('/api/v1/region')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                done();
+            });
+    });
+    it('should list all regions in xml', (done) => {
+        chai.request(server)
+            .get('/api/v1/region?format=xml')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.xml;
+                done();
+            });
+    });
+    it('should list all regions in csv', (done) => {
+        chai.request(server)
+            .get('/api/v1/region?format=csv')
+            .end((err, res) => {
+                res.should.have.status(200);
+                done();
+            });
+    });
+});
-- 
GitLab


From a6283f346a9a017597f29c8e9f0fe2a9465a2b10 Mon Sep 17 00:00:00 2001
From: Lucas Gabriel Lima <lgl15@inf.ufpr.br>
Date: Fri, 2 Dec 2016 09:40:21 -0200
Subject: [PATCH 27/32] fix bcrypt-nodejs error

---
 package.json            | 4 ++--
 src/libs/models/user.js | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/package.json b/package.json
index d923ed1f..9173c550 100644
--- a/package.json
+++ b/package.json
@@ -49,11 +49,11 @@
     "browserify": "^13.1.0",
     "chai-xml": "^0.3.1",
     "docdash": "^0.4.0",
-    "eslint": "^3.3.1",
+    "eslint": "^3.7.1",
     "eslint-config-airbnb": "^13.0.0",
     "eslint-plugin-import": "^2.2.0",
     "eslint-plugin-jsx-a11y": "^2.2.3",
-    "eslint-plugin-react": "^6.1.1",
+    "eslint-plugin-react": "^6.4.0",
     "gulp": "^3.9.1",
     "gulp-babel": "^6.1.2",
     "gulp-cli": "^1.2.2",
diff --git a/src/libs/models/user.js b/src/libs/models/user.js
index 83315b82..554fabf0 100644
--- a/src/libs/models/user.js
+++ b/src/libs/models/user.js
@@ -64,7 +64,7 @@ UserSchema.pre('save', function (next) {
             if (err) {
                 return next(err);
             }
-            bcrypt.hash(user.password, salt, function (err, hash) {
+            bcrypt.hash(user.password, salt, null, function (err, hash) {
                 if (err) {
                     return next(err);
                 }
-- 
GitLab


From 68946813ab2eeafb1ead69d45c51a2ea5c0b99c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Risso?= <joaovictor.risso@gmail.com>
Date: Fri, 2 Dec 2016 10:52:08 -0200
Subject: [PATCH 28/32] Add route for locations (CEBES014T1) in enrollments and
 school classes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Mount route under '/api/v1/enrollment/location'
- It should list the location names for enrollments and school classes
- The reponse format is a lista of objects with each object having a location_id (CEBES014T1) and a description

Signed-off-by: João Victor Risso <joaovictor.risso@gmail.com>
---
 src/libs/routes/enrollment.js | 16 ++++++++++++----
 src/test/enrollment.js        | 14 ++++++++++++++
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js
index 4d51e98e..9f013fba 100644
--- a/src/libs/routes/enrollment.js
+++ b/src/libs/routes/enrollment.js
@@ -27,6 +27,14 @@ enrollmentApp.get('/year_range', (req, res, next) => {
     next();
 }, query, response('range'));
 
+enrollmentApp.get('/location', (req, res, next) => {
+    req.sql = squel.select()
+        .field('pk_localizacao_id', 'location_id')
+        .field('descricao', 'description')
+        .from('localizacao');
+    next();
+}, query, response('location'));
+
 // Returns all educational levels avaible
 enrollmentApp.get('/education_level', (req, res, next) => {
     req.sql = squel.select()
@@ -161,9 +169,9 @@ enrollmentApp.use('/', parseParams('filter', [
     }
 
     if(typeof req.dims.location !== 'undefined') {
-        req.sql.field('turma.id_localizacao', 'location_name')
-            .group('turma.id_localizacao')
-            .order('turma.id_localizacao');
+        req.sql.field('turma.fk_localizacao_id', 'location_name')
+            .group('turma.fk_localizacao_id')
+            .order('turma.fk_localizacao_id');
     }
 
     if(typeof req.dims.region === 'undefined'
@@ -188,7 +196,7 @@ enrollmentApp.use('/', parseParams('filter', [
     }
 
     if (typeof req.filter.location !== 'undefined') {
-        req.sql.where('turma.id_localizacao = ?', parseInt(req.filter.location, 10));
+        req.sql.where('turma.fk_localizacao_id = ?', parseInt(req.filter.location, 10));
     }
 
     if (typeof req.filter.education_level !== 'undefined') {
diff --git a/src/test/enrollment.js b/src/test/enrollment.js
index 328b88d9..dc7fcb2e 100644
--- a/src/test/enrollment.js
+++ b/src/test/enrollment.js
@@ -38,6 +38,20 @@ describe('request enrollments', () => {
             });
     });
 
+    it('should list the locations', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment/location')
+            .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('location_id');
+                res.body.result[0].should.have.property('description');
+                done();
+            });
+    });
+
     it('should list the education level', (done) => {
         chai.request(server)
             .get('/api/v1/enrollment/education_level')
-- 
GitLab


From 2392727099a956ceecb29d53aceff804aa31c2f1 Mon Sep 17 00:00:00 2001
From: Vytor Calixto <vytorcalixto@gmail.com>
Date: Mon, 5 Dec 2016 10:18:44 -0200
Subject: [PATCH 29/32] Remove switch for location in enrollments route

---
 src/libs/routes/enrollment.js | 33 ++++++++-------------------------
 1 file changed, 8 insertions(+), 25 deletions(-)

diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js
index 9f013fba..1ad57f27 100644
--- a/src/libs/routes/enrollment.js
+++ b/src/libs/routes/enrollment.js
@@ -117,6 +117,10 @@ enrollmentApp.use('/', parseParams('filter', [
         req.sql.join('municipio', null, 'fk_municipio_id = municipio.pk_cod_ibge');
     }
 
+    if(typeof req.filter.location !== 'undefined' || typeof req.dims.location !== 'undefined') {
+        req.sql.join('localizacao', null, 'fk_localizacao_id = localizacao.pk_localizacao_id')
+    }
+
     if(typeof req.dims.school !== 'undefined') {
         req.sql.join('escola', null, 'turma.cod_entidade = escola.cod_entidade');
     }
@@ -169,9 +173,9 @@ enrollmentApp.use('/', parseParams('filter', [
     }
 
     if(typeof req.dims.location !== 'undefined') {
-        req.sql.field('turma.fk_localizacao_id', 'location_name')
-            .group('turma.fk_localizacao_id')
-            .order('turma.fk_localizacao_id');
+        req.sql.field('localizacao.descricao', 'location_name')
+            .group('localizacao.descricao')
+            .order('localizacao.descricao');
     }
 
     if(typeof req.dims.region === 'undefined'
@@ -229,27 +233,6 @@ enrollmentApp.get('/', (req, res, next) => {
         .group('turma.ano_censo')
         .order('turma.ano_censo');
     next();
-}, query, (req, res, next) => {
-    // 'Sanitize' result
-    let r = req.result;
-    r.forEach((data) => {
-        if(req.dims.location) {
-            if(data.location_name === 1) {
-                data.location_name = 'Urbana';
-            } else if (data.location_name === 2) {
-                data.location_name = 'Rural';
-            } else if (data.location_name === 3) {
-                data.location_name = 'Área de Assentamento';
-            } else if (data.location_name === 4) {
-                data.location_name = 'Terra Indígena';
-            } else if (data.location_name === 5) {
-                data.location_name = 'Área Remanescente de Quilombos';
-            } else if (data.location_name === 6) {
-                data.location_name = 'Unidade de uso sustentável';
-            }
-        }
-    });
-    next();
-}, response('enrollment'));
+}, query, response('enrollment'));
 
 module.exports = enrollmentApp;
-- 
GitLab


From 6da004e76f81b3e69a986f3a352ea58b3b0075ae Mon Sep 17 00:00:00 2001
From: Vytor Calixto <vytorcalixto@gmail.com>
Date: Mon, 5 Dec 2016 10:41:00 -0200
Subject: [PATCH 30/32] Add more user tests

---
 src/test/user.js | 540 ++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 469 insertions(+), 71 deletions(-)

diff --git a/src/test/user.js b/src/test/user.js
index 67b9d186..04ab8e9e 100644
--- a/src/test/user.js
+++ b/src/test/user.js
@@ -27,6 +27,367 @@ const mongoose = require('../libs/db/mongoose');
 const User = require('../libs/models/user');
 
 chai.use(chaiHttp);
+
+describe('Saves a user', () => {
+    beforeEach(() => {
+        User.remove({}, (err) => {
+            console.log('Test collection purged')
+        });
+    });
+
+    it('should save a user', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(true);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('Usuário cadastrado com sucesso!');
+            done();
+        });
+    });
+
+    it('should not save a user without email', (done) => {
+        let newUser = {};
+        newUser.email = null;
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Email é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without password', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Senha é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user with invalid email', (done) => {
+        let newUser = {};
+        newUser.email = 'invalid email';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O email informado é inválido.');
+            done();
+        });
+    });
+
+    it('should not save a user without a name', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Nome é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without CPF', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo CPF é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without schooling', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Escolaridade é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without segment', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Segmento é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without role', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Função é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without institution_name', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Instituição em que trabalha é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without state', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Estado é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without city', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'Paraná';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Cidade é obrigatório.');
+            done();
+        });
+    });
+
+})
+
 describe('Authenticates a user', () => {
 
     beforeEach(() => {
@@ -56,24 +417,24 @@ describe('Authenticates a user', () => {
             }
         }).then(function(newuser){
             chai.request(server)
-                .post('/api/v1/user/authenticate')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email: 'lorem@ipsum.com',
-                       password: '123mudar'})
-                .end((err, res) => {
-                    let token;
-
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(true);
-                    res.body.should.have.property('token');
-                    token = res.body.token;
-                    token.substr(0, 3).should.equal('JWT');
-                    done();
-                });
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({email: 'lorem@ipsum.com',
+            password: '123mudar'})
+            .end((err, res) => {
+                let token;
+
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(true);
+                res.body.should.have.property('token');
+                token = res.body.token;
+                token.substr(0, 3).should.equal('JWT');
+                done();
             });
+        });
     });
 
     it('should not authenticate a user with wrong password', (done) => {
@@ -97,21 +458,21 @@ describe('Authenticates a user', () => {
             }
         }).then(function(newuser){
             chai.request(server)
-                .post('/api/v1/user/authenticate')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email: 'lorem@ipsum.com',
-                       password: 'umasenhaerrada'})
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('A Senha informada é inválida.')
-                    done();
-                });
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({email: 'lorem@ipsum.com',
+            password: 'umasenhaerrada'})
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                res.body.should.have.property('msg');
+                res.body.msg.should.equal('A Senha informada é inválida.')
+                done();
             });
+        });
     });
 
     it('should not authenticate a user with wrong email', (done) => {
@@ -135,21 +496,21 @@ describe('Authenticates a user', () => {
             }
         }).then(function(newuser){
             chai.request(server)
-                .post('/api/v1/user/authenticate')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email: 'dolor@ipsum.com',
-                       password: '123mudar'})
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('O Email informado não está cadastrado.')
-                    done();
-                });
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({email: 'dolor@ipsum.com',
+            password: '123mudar'})
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                res.body.should.have.property('msg');
+                res.body.msg.should.equal('O Email informado não está cadastrado.')
+                done();
             });
+        });
     });
 
     it('should not authenticate a user with missing email', (done) => {
@@ -173,20 +534,20 @@ describe('Authenticates a user', () => {
             }
         }).then(function(newuser){
             chai.request(server)
-                .post('/api/v1/user/authenticate')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({password: '123mudar'})
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('O campo Email é obrigatório.')
-                    done();
-                });
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({password: '123mudar'})
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                res.body.should.have.property('msg');
+                res.body.msg.should.equal('O campo Email é obrigatório.')
+                done();
             });
+        });
     });
 
     it('should not authenticate a user with missing password', (done) => {
@@ -210,19 +571,56 @@ describe('Authenticates a user', () => {
             }
         }).then(function(newuser){
             chai.request(server)
-                .post('/api/v1/user/authenticate')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email:'lorem@ipsum.com'})
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('O campo Senha é obrigatório.')
-                    done();
-                });
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({email:'lorem@ipsum.com'})
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                res.body.should.have.property('msg');
+                res.body.msg.should.equal('O campo Senha é obrigatório.')
+                done();
             });
+        });
+    });
+
+    it('should not authenticate a user with wrong password', (done) => {
+        let newUser = new User();
+
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        newUser.save((err) => {
+            if (err) {
+                console.log('MongoDB error:' + err);
+            }
+        }).then(function(newuser){
+            chai.request(server)
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({email:'lorem@ipsum.com', password: '123'})
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                res.body.should.have.property('msg');
+                res.body.msg.should.equal('A Senha informada é inválida.')
+                done();
+            });
+        });
     });
 });
-- 
GitLab


From 5bdeca3db8a196d4ef48e4ccf00b6259644e0822 Mon Sep 17 00:00:00 2001
From: Vytor Calixto <vytorcalixto@gmail.com>
Date: Thu, 8 Dec 2016 10:24:19 -0200
Subject: [PATCH 31/32] :green_heart: Change coverage threshold for branches

Statements, functions and lines threshold at 80% global
Branches at 75% global
---
 gulpfile.babel.js | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index e67a5244..2ff461ff 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -79,7 +79,12 @@ gulp.task('test', ['pre-test'], () => {
     .pipe(istanbul.writeReports())
     .pipe(istanbul.enforceThresholds({
         thresholds: {
-            global: 80
+            global: {
+                statements: 80,
+                branches: 75,
+                lines: 80,
+                functions: 80
+            }
         }
     }))
     .on('error', () => {
-- 
GitLab


From cf9bbe62a768fa9ff4b5909f65e4e6a6ec0c2147 Mon Sep 17 00:00:00 2001
From: Vytor Calixto <vytorcalixto@gmail.com>
Date: Tue, 17 Jan 2017 09:49:43 -0200
Subject: [PATCH 32/32] :green_heart: Remove duplicate tests on simulation.js

---
 src/test/simulation.js | 851 -----------------------------------------
 1 file changed, 851 deletions(-)

diff --git a/src/test/simulation.js b/src/test/simulation.js
index 8804b435..c74ca3ae 100644
--- a/src/test/simulation.js
+++ b/src/test/simulation.js
@@ -28,392 +28,6 @@ const User = require('../libs/models/user');
 
 chai.use(chaiHttp);
 
-describe('API is running', () => {
-    it('should respond it\'s running', (done) => {
-        chai.request(server)
-            .get('/api/v1')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('msg');
-                done();
-            })
-    });
-});
-
-describe('request enrollments', () => {
-    it('should list the year range', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment/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 education level', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment/education_level')
-            .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('id');
-                res.body.result[0].should.have.property('name');
-                done();
-            });
-    });
-
-    it('should list the administrative dependencies', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment/adm_dependency ')
-            .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('id');
-                res.body.result[0].should.have.property('name');
-                done();
-            });
-    });
-
-    it('should list enrollments', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment')
-            .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('name');
-                res.body.result[0].should.have.property('total');
-                done();
-            });
-    });
-
-    it('should list enrollments with valid filters', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?filter=min_year:2010,state:41')
-            .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('name');
-                res.body.result[0].should.have.property('total');
-                done();
-            });
-    });
-
-    it('should list enrollments with invalid filters', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?filter=foo:2010,bar:41')
-            .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('name');
-                res.body.result[0].should.have.property('total');
-                done();
-            });
-    });
-
-    it('should list enrollments with valid dimensions', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?dims=region,state,adm_dependency,location&filter=min_year:2014,region:4')
-            .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('region_name');
-                res.body.result[0].should.have.property('state_name');
-                res.body.result[0].should.have.property('adm_dependency_name');
-                res.body.result[0].should.have.property('location_name');
-                res.body.result[0].should.have.property('total');
-                done();
-            });
-    });
-
-    it('should list enrollments with invalid dimensions', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?dims=foo,bar')
-            .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('name');
-                res.body.result[0].should.have.property('total');
-                done();
-            });
-    });
-
-    it('should list enrollments with valid dimensions and filters', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?dims=region,state,education_level,school&filter=min_year:2013,max_year:2014,city:4106902')
-            .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('region_name');
-                res.body.result[0].should.have.property('state_name');
-                res.body.result[0].should.have.property('school_name');
-                res.body.result[0].should.have.property('education_level');
-                res.body.result[0].should.have.property('total');
-                res.body.result[0].should.have.property('year');
-                done();
-            });
-    });
-
-    it('should list enrollments using all dimensions and filters', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?dims=region,state,city,education_level,school,adm_dependency,location&filter=min_year:2013,max_year:2014,city:4106902,adm_dependency:3,location:1,education_level:99')
-            .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('region_name');
-                res.body.result[0].should.have.property('state_name');
-                res.body.result[0].should.have.property('school_name');
-                res.body.result[0].should.have.property('education_level');
-                res.body.result[0].should.have.property('location_name');
-                res.body.result[0].should.have.property('adm_dependency_name');
-                res.body.result[0].should.have.property('total');
-                res.body.result[0].should.have.property('year');
-                done();
-            });
-    });
-
-
-});
-
-describe('request regions', () => {
-    it('should list all regions', (done) => {
-        chai.request(server)
-            .get('/api/v1/region')
-            .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('pk_regiao_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-
-    it('should list region by id', (done) => {
-        chai.request(server)
-            .get('/api/v1/region/1')
-            .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.should.have.length(1);
-                res.body.result[0].should.have.property('pk_regiao_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-});
-
-describe('request states', () => {
-    it('should list all states', (done) => {
-        chai.request(server)
-            .get('/api/v1/state')
-            .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('pk_estado_id');
-                res.body.result[0].should.have.property('fk_regiao_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-
-    it('should list a state by id', (done) => {
-        chai.request(server)
-            .get('/api/v1/state/11')
-            .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.should.have.length(1);
-                res.body.result[0].should.have.property('pk_estado_id');
-                res.body.result[0].should.have.property('fk_regiao_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-
-    it('should list states by region id', (done) => {
-        chai.request(server)
-            .get('/api/v1/state/region/1')
-            .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('pk_estado_id');
-                res.body.result[0].should.have.property('fk_regiao_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-});
-
-describe('request cities', () => {
-    it('should list all cities', (done) => {
-        chai.request(server)
-            .get('/api/v1/city')
-            .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('pk_cod_ibge');
-                res.body.result[0].should.have.property('nome');
-                res.body.result[0].should.have.property('fk_estado_id');
-                done();
-            });
-    });
-
-    it('should list a city by id', (done) => {
-        chai.request(server)
-            .get('/api/v1/city/4106902')
-            .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('pk_cod_ibge');
-                res.body.result[0].should.have.property('fk_estado_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-
-    it('should list a city by codigo_ibge', (done) => {
-        chai.request(server)
-            .get('/api/v1/city/ibge/4106902')
-            .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('pk_cod_ibge');
-                res.body.result[0].should.have.property('fk_estado_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-
-    it('should list all cities from a state', (done) => {
-        chai.request(server)
-            .get('/api/v1/city/state/41')
-            .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('pk_cod_ibge');
-                res.body.result[0].should.have.property('fk_estado_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            })
-    })
-});
-
-describe('request schools', () => {
-    it('should list a school by id', (done) => {
-        chai.request(server)
-            .get('/api/v1/school/41000021')
-            .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('ano_censo');
-                res.body.result[0].should.have.property('cod_entidade');
-                done();
-            });
-    });
-
-    it('should list all schools from a state', (done) => {
-        chai.request(server)
-            .get('/api/v1/school/state/41')
-            .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_entidade');
-                res.body.result[0].should.have.property('ano_censo');
-                done();
-            });
-    });
-
-    it('should list all schools from a city', (done) => {
-        chai.request(server)
-            .get('/api/v1/school/city/4106902')
-            .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_entidade');
-                res.body.result[0].should.have.property('ano_censo');
-                done();
-            })
-    })
-});
-
-describe('test response', () => {
-    it('should list all regions in json', (done) => {
-        chai.request(server)
-            .get('/api/v1/region')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                done();
-            });
-    });
-
-    it('should list all regions in xml', (done) => {
-        chai.request(server)
-            .get('/api/v1/region?format=xml')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.xml;
-                done();
-            });
-    });
-
-    it('should list all regions in csv', (done) => {
-        chai.request(server)
-            .get('/api/v1/region?format=csv')
-            .end((err, res) => {
-                res.should.have.status(200);
-                done();
-            });
-    });
-});
-
 describe('Requires a simulation', () => {
     let newSimulation;
 
@@ -792,468 +406,3 @@ describe('Requires a simulation', () => {
             });
     });
 });
-
-describe('Saves a user', () => {
-
-    beforeEach(() => {
-        User.remove({}, (err) => {
-            if(err) {
-                console.log('Error while purging: ' + err);
-            }
-            console.log('Test collection purged');
-        });
-    });
-
-    it('should create a new user', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila Baby',
-                   cpf: '48303270737',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(true);
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                    if (err){
-                        console.log('MongoDB error: ' + err);
-                    }
-
-                    user.should.have.property('email');
-                    done();
-                });
-            });
-    });
-
-    it('should not create a user with an email that is already in use', (done) => {
-        let newUser = new User();
-
-        newUser.email = 'lorem@ipsum.com';
-        newUser.password = '123mudar';
-        newUser.name = 'Gute';
-        newUser.cpf = '08236017907';
-        newUser.schooling = 'Doutorado';
-        newUser.course = 'Ciência da Computação';
-        newUser.segment = 'Comunidade acadêmica';
-        newUser.role = 'Pesquisador';
-        newUser.institution_name = 'UFPR';
-        newUser.state = 'PR';
-        newUser.city = 'Curitiba';
-
-        newUser.save((err) => {
-            if (err) {
-                console.log('MongoDB error:' + err);
-            }
-        }).then(function(newuser){
-            chai.request(server)
-                .post('/api/v1/user')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email: 'lorem@ipsum.com',
-                       password: '123mudar',
-                       name: 'Tequila Baby',
-                       cpf: '48303270737',
-                       schooling: 'Doutorado',
-                       course: 'Ciência da Computação',
-                       segment: 'Comunidade acadêmica',
-                       role: 'Pesquisador',
-                       institution_name: 'UFPR',
-                       state: 'PR',
-                       city: 'Cutiriba'})
-                .end((err, res) =>{
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('O email informado já está cadastrado.');
-                    User.findOne({'cpf': '48303270737'}, (err, user) => {
-                            expect(user).to.not.exist;
-                            done();
-                    });
-                });
-        });
-    });
-
-    it('should not create a user with a CPF that is already in use', (done) => {
-        let newUser = new User();
-
-        newUser.email = 'lorem@ipsum.com';
-        newUser.password = '123mudar';
-        newUser.name = 'Gute';
-        newUser.cpf = '08236017907';
-        newUser.schooling = 'Doutorado';
-        newUser.course = 'Ciência da Computação';
-        newUser.segment = 'Comunidade acadêmica';
-        newUser.role = 'Pesquisador';
-        newUser.institution_name = 'UFPR';
-        newUser.state = 'PR';
-        newUser.city = 'Curitiba';
-
-        newUser.save((err) => {
-            if (err) {
-                console.log('MongoDB error:' + err);
-            }
-        }).then(function(newuser){
-            chai.request(server)
-                .post('/api/v1/user')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email: 'dolor@ipsum.com',
-                       password: '123mudar',
-                       name: 'Tequila Baby',
-                       cpf: '08236017907',
-                       schooling: 'Doutorado',
-                       course: 'Ciência da Computação',
-                       segment: 'Comunidade acadêmica',
-                       role: 'Pesquisador',
-                       institution_name: 'UFPR',
-                       state: 'PR',
-                       city: 'Cutiriba'})
-                .end((err, res) =>{
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('O CPF informado já está cadastrado.');
-                    User.findOne({'email': 'dolor@ipsum.com'}, (err, user) => {
-                            expect(user).to.not.exist;
-                            done();
-                    });
-                });
-        });
-    });
-
-    it('should not save an user without email', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({password: '123mudar',
-                   name: 'Tequila Baby',
-                   cpf: '48303270737',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Email é obrigatório.');
-                User.findOne({'cpf': '48303270737'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without password', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   name: 'Tequila Baby',
-                   cpf: '48303270737',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Senha é obrigatório.');
-                User.findOne({'cpf': '48303270737'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user with invalid email', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'notavalidemail',
-                   password: '123mudar',
-                   name: 'Tequila Baby',
-                   cpf: '48303270737',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O email informado é inválido.');
-                User.findOne({'cpf': '48303270737'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without name', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   cpf: '48303270737',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Nome é obrigatório.');
-                User.findOne({'cpf': '48303270737'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without CPF', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo CPF é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without segment', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Segmento é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without schooling', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Escolaridade é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without role', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Função é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without institution', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Instituição em que trabalha é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without city', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   institution_name: 'UFPR',
-                   role: 'Pesquisador',
-                   state: 'PR'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Cidade é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without state', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   institution_name: 'UFPR',
-                   role: 'Pesquisador',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Estado é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-});
-- 
GitLab