diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 04cdb1f9f46441a3617636eea51bf6403f1e2ab9..90d49bbe2acae1aa3d36e0b4a42ae3cdf0ead3e2 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,6 +18,7 @@ run_tests:
     - ping -W1 -c1 mongo
     - mv config.json.example config.json
     - sed -i -e 's/false/true/g' config.json
+    - sed -i -e 's/simcaq_dev/simcaq_dev2/g' config.json
     - gulp build
     - gulp test
   tags:
diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index e75f65bf5208dacdfb44e4a94fe77ffbfea0a262..11e9416f87c8528c84d0bbb64f5312c8455215b4 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -75,7 +75,7 @@ gulp.task('pre-test', () => {
 gulp.task('test', ['pre-test'], () => {
     process.chdir('build');
     gulp.src(['test/**/*.js'], {read: false})
-    .pipe(mocha({timeout: 15000}))
+    .pipe(mocha({timeout: 60000}))
     .pipe(istanbul.writeReports())
     .pipe(istanbul.enforceThresholds({
         thresholds: {
@@ -84,7 +84,7 @@ gulp.task('test', ['pre-test'], () => {
                 branches: 70,
                 lines: 80,
                 functions: 80
-            } 
+            }
         }
     }))
     .on('error', () => {
@@ -115,4 +115,4 @@ gulp.task('run', () => {
     });
 });
 
-gulp.task('default', ['run']);
\ No newline at end of file
+gulp.task('default', ['run']);
diff --git a/src/libs/db/query_exec.js b/src/libs/db/query_exec.js
index 1a2f7387574bc2f886550ef39f86f221c6a98e49..c43b1dbee3640a71e1957db722e6eab84e1d8533 100644
--- a/src/libs/db/query_exec.js
+++ b/src/libs/db/query_exec.js
@@ -22,7 +22,6 @@ function execSqlQuery(sqlQuery, sqlQueryParams = []) {
         conn.prepare(sqlQuery, true).then((dbQuery) => {
             // Execute query
             dbQuery.exec(sqlQueryParams).then((dbResult) => {
-                log.debug(`Query result: ${dbResult.data}`);
                 // release resources allocated for the prepared statement
                 dbQuery.release();
                 resolve(dbResult.data);
diff --git a/src/libs/middlewares/reqQueryFields.js b/src/libs/middlewares/reqQueryFields.js
index 1fe597d38f2cd97e7ea5c96b4ff4c5ae96eb97e1..6a194c845357c189b860f6b3fee4838f0f9ffdbe 100644
--- a/src/libs/middlewares/reqQueryFields.js
+++ b/src/libs/middlewares/reqQueryFields.js
@@ -113,15 +113,11 @@ class ReqQueryFields {
                 let params = [];
                 // f é o campo
                 let f = this.fields[key];
-                log.debug('f');
-                log.debug(f);
                 // Unimos os valores parametros globalmente com os aceitos apenas pelo campo
                 let values = _.merge(this.fieldValues, f.values);
                 // Fazemos um foreach nos parametros aceitos
                 Object.keys(values).map((k, i) => {
                     let value = values[k];
-                    log.debug('value');
-                    log.debug(value);
                     // Pushamos o parametro
                     params.push(value.name);
                 });
@@ -186,25 +182,29 @@ class ReqQueryFields {
                 // Fazemos um foreach nos parametros dentro do atributo
                 Object.keys(param).forEach((k) => {
                     let values = _.merge(this.fieldValues, field.values);
-                    // log.debug('ValueS');
-                    // log.debug(values);
-                    // log.debug('k');
-                    // log.debug(k);
                     if(typeof values[k] !== 'undefined') {
                         // Clonamos para não alterar o original
                         let value = _.clone(values[k]);
-                        // log.debug('value');
-                        // log.debug(value);
-                        // log.debug(hasJoined);
                         // Checa se não fizemos o join para este valor e se é necessário fazer
-                        if(!hasJoined[value.name] && typeof value.join !== 'undefined') {
+                        if(!hasJoined[value.table] && typeof value.join !== 'undefined') {
                             let foreignTable = '';
                             if(value.join.foreignTable) foreignTable = value.join.foreignTable+'.';
                             // Fazemos o join
-                            req.sql.join(value.table, null, foreignTable+value.join.foreign+'='+value.table+'.'+value.join.primary);
+                            let onClause = '';
+                            if(Array.isArray(value.join.primary)) {
+                                // Se é um array, montamos a cláusula ON com mais de uma coluna
+                                value.join.primary.forEach((column, index, arr) => {
+                                    onClause += foreignTable+value.join.foreign[index]+'='+value.table+'.'+column;
+                                    if(index < arr.length-1) {
+                                        onClause+=' AND ';
+                                    }
+                                });
+                            } else {
+                                onClause = foreignTable+value.join.foreign+'='+value.table+'.'+value.join.primary;
+                            }
+                            req.sql.join(value.table, null, onClause);
                             // Marcamos o join como feito para não ter problemas
-                            hasJoined[value.name] = true;
-                            // values[k].hasJoined = true;
+                            hasJoined[value.table] = true;
                         }
                         // Se o valor é um campo a ser incluído no SELECT
                         if(typeof field.field !== 'undefined' && field.field) {
diff --git a/src/libs/routes/api.js b/src/libs/routes/api.js
index 2c29a24680987a9b6c572cf5fa4ba86bc0b0c83c..ce905d8bd1f8476c38795a03a78347c85ed9cda3 100644
--- a/src/libs/routes/api.js
+++ b/src/libs/routes/api.js
@@ -18,7 +18,7 @@ const city = require('./city');
 
 const school = require('./school');
 
-const location = require('./location');
+const spatial = require('./spatial');
 
 const simulation = require('./simulation');
 
@@ -36,6 +36,6 @@ api.use('/state', cache('15 day'), state);
 api.use('/region', cache('15 day'), region);
 api.use('/city', cache('15 day'), city);
 api.use('/school', cache('15 day'), school);
-api.use('/location', cache('1 day'), location);
+api.use('/spatial', cache('1 day'), spatial);
 
 module.exports = api;
diff --git a/src/libs/routes/city.js b/src/libs/routes/city.js
index 3b03ef9c3899450503aff7eeb7ffcf087104034c..b7999a8ef9e35fa7fd8011ae73c2149f2d4d02e3 100644
--- a/src/libs/routes/city.js
+++ b/src/libs/routes/city.js
@@ -21,11 +21,11 @@ rqf.addField({
 }).addValue({
     name: 'id',
     table: 'municipio',
-    tableField: 'pk_cod_ibge',
+    tableField: 'id',
     where: {
         relation: '=',
         type: 'integer',
-        field: 'pk_cod_ibge'
+        field: 'id'
     }
 }).addValue({
     name: 'state',
@@ -35,12 +35,12 @@ rqf.addField({
     where: {
         relation: '=',
         type: 'integer',
-        field: 'fk_estado_id',
+        field: 'estado_id',
         table: 'municipio'
     },
     join: {
-        primary: 'pk_estado_id',
-        foreign: 'fk_estado_id',
+        primary: 'id',
+        foreign: 'estado_id',
         foreignTable: 'municipio'
     }
 }).addField({
@@ -62,8 +62,8 @@ rqf.addField({
 cityApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
     req.sql.from('municipio')
     .field('municipio.nome', 'name')
-    .field('municipio.pk_cod_ibge', 'id')
-    .field('municipio.fk_estado_id', 'state_id');
+    .field('municipio.id')
+    .field('municipio.estado_id', 'state_id');
     next();
 }, query, response('city'));
 
diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js
index 74ba538adc9d010a2c3ed8f748a9f8cf90996030..e8664c4f98b8190df1bb65f856ee9ca64f32856d 100644
--- a/src/libs/routes/enrollment.js
+++ b/src/libs/routes/enrollment.js
@@ -19,16 +19,15 @@ let rqf = new ReqQueryFields();
 // 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.from('turma')
-    .field('MIN(turma.ano_censo)', 'start_year')
-    .field('MAX(turma.ano_censo)', 'end_year');
-
+    req.sql.from('matricula')
+    .field('MIN(matricula.ano_censo)', 'start_year')
+    .field('MAX(matricula.ano_censo)', 'end_year');
     next();
 }, query, response('range'));
 
 enrollmentApp.get('/location', (req, res, next) => {
     req.sql = squel.select()
-        .field('pk_localizacao_id', 'id')
+        .field('id')
         .field('descricao', 'name')
         .from('localizacao');
     next();
@@ -36,21 +35,51 @@ enrollmentApp.get('/location', (req, res, next) => {
 
 // Returns all educational levels avaible
 enrollmentApp.get('/education_level', (req, res, next) => {
-    req.sql.from('etapa_ensino')
-    .field('pk_etapa_ensino_id', 'id')
-    .field('desc_etapa', 'name');
-
+    req.sql.from('serie_ano')
+    .field('id')
+    .field('nome', 'name');
     next();
 }, query, response('education_level'));
 
 // Returns all adm dependencies
 enrollmentApp.get('/adm_dependency', (req, res, next) => {
     req.sql.from('dependencia_adm')
-    .field('pk_dependencia_adm_id', 'id')
+    .field('id')
+    .field('nome', 'name')
+    .where('id <= 4');
+    next();
+}, query, response('adm_dependency'));
+
+enrollmentApp.get('/adm_dependency_detailed', (req, res, next) => {
+    req.sql.from('dependencia_adm')
+    .field('id', 'id')
     .field('nome', 'name');
+    next();
+}, query, response('adm_dependency_detailed'));
 
+// Return genders
+enrollmentApp.get('/gender', (req, res, next) => {
+    req.result = [
+        {id: 1, name: 'Masculino'},
+        {id: 2, name: 'Feminino'}
+    ];
     next();
-}, query, response('adm_dependency'));
+}, response('gender'));
+
+// Return ethnic group
+enrollmentApp.get('/ethnic_group', (req, res, next) => {
+    req.sql.from('cor_raca')
+    .field('id')
+    .field('nome', 'name');
+    next();
+}, query, response('ethnic_group'));
+
+enrollmentApp.get('/period', (req, res, next) => {
+    req.sql.from('turma_turno')
+    .field('id')
+    .field('nome', 'name');
+    next();
+}, query, response('period'));
 
 rqf.addField({
     name: 'filter',
@@ -68,27 +97,42 @@ rqf.addField({
     where: {
         relation: '=',
         type: 'integer',
-        field: 'pk_dependencia_adm_id'
+        field: 'id'
     },
     join: {
-        primary: 'pk_dependencia_adm_id',
-        foreign: 'fk_dependencia_adm_id',
-        foreignTable: 'turma'
+        primary: 'id',
+        foreign: 'dependencia_adm_id',
+        foreignTable: 'matricula'
+    }
+}).addValue({
+    name: 'adm_dependency_detailed',
+    table: 'dependencia_adm',
+    tableField: 'nome',
+    resultField: 'adm_dependency_detailed_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'id'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'dependencia_adm_priv',
+        foreignTable: 'matricula'
     }
 }).addValue({
     name: 'education_level',
-    table: 'etapa_ensino',
-    tableField: 'desc_etapa',
-    resultField: 'education_level',
+    table: 'serie_ano',
+    tableField: 'nome',
+    resultField: 'education_level_name',
     where: {
         relation: '=',
         type: 'integer',
-        field: 'pk_etapa_ensino_id'
+        field: 'id'
     },
     join: {
-        primary: 'pk_etapa_ensino_id',
-        foreign: 'fk_etapa_ensino_id',
-        foreignTable: 'turma'
+        primary: 'id',
+        foreign: 'serie_ano_id',
+        foreignTable: 'matricula'
     }
 }).addValue({
     name: 'region',
@@ -98,12 +142,12 @@ rqf.addField({
     where: {
         relation: '=',
         type: 'integer',
-        field: 'pk_regiao_id'
+        field: 'id'
     },
     join: {
-        primary: 'pk_regiao_id',
-        foreign: 'fk_regiao_id',
-        foreignTable: 'turma'
+        primary: 'id',
+        foreign: 'regiao_id',
+        foreignTable: 'matricula'
     }
 }).addValue({
     name: 'state',
@@ -113,12 +157,12 @@ rqf.addField({
     where: {
         relation: '=',
         type: 'integer',
-        field: 'pk_estado_id'
+        field: 'id'
     },
     join: {
-        primary: 'pk_estado_id',
-        foreign: 'fk_estado_id',
-        foreignTable: 'turma'
+        primary: 'id',
+        foreign: 'escola_estado_id',
+        foreignTable: 'matricula'
     }
 }).addValue({
     name: 'city',
@@ -128,27 +172,27 @@ rqf.addField({
     where: {
         relation: '=',
         type: 'integer',
-        field: 'pk_cod_ibge'
+        field: 'id'
     },
     join: {
-        primary: 'pk_cod_ibge',
-        foreign: 'fk_municipio_id',
-        foreignTable: 'turma'
+        primary: 'id',
+        foreign: 'escola_municipio_id',
+        foreignTable: 'matricula'
     }
 }).addValue({
     name: 'school',
     table: 'escola',
-    tableField: 'cod_entidade',
+    tableField: 'nome_escola',
     resultField: 'school_name',
     where: {
         relation: '=',
         type: 'integer',
-        field: 'cod_entidade'
+        field: 'id'
     },
     join: {
-        primary: 'cod_entidade',
-        foreign: 'cod_entidade',
-        foreignTable: 'turma'
+        primary: ['id', 'ano_censo'],
+        foreign: ['escola_id', 'ano_censo'],
+        foreignTable: 'matricula'
     }
 }).addValue({
     name: 'location',
@@ -158,31 +202,16 @@ rqf.addField({
     where: {
         relation: '=',
         type: 'integer',
-        field: 'pk_localizacao_id'
-    },
-    join: {
-        primary: 'pk_localizacao_id',
-        foreign: 'fk_localizacao_id',
-        foreignTable: 'turma'
-    }
-}).addValue({
-    name: 'city',
-    table: 'municipio',
-    tableField: 'nome',
-    resultField: 'city_name',
-    where: {
-        relation: '=',
-        type: 'integer',
-        field: 'pk_cod_ibge'
+        field: 'id'
     },
     join: {
-        primary: 'pk_cod_ibge',
-        foreign: 'fk_municipio_id',
-        foreignTable: 'turma'
+        primary: 'id',
+        foreign: 'localizacao_id',
+        foreignTable: 'matricula'
     }
 }).addValue({
     name: 'min_year',
-    table: 'turma',
+    table: 'matricula',
     tableField: 'ano_censo',
     resultField: 'year',
     where: {
@@ -192,7 +221,7 @@ rqf.addField({
     }
 }).addValue({
     name: 'max_year',
-    table: 'turma',
+    table: 'matricula',
     tableField: 'ano_censo',
     resultField: 'year',
     where: {
@@ -200,17 +229,91 @@ rqf.addField({
         type: 'integer',
         field: 'ano_censo'
     }
+}).addValue({
+    name: 'gender',
+    table: 'matricula',
+    tableField: 'sexo',
+    resultField: 'gender_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'sexo'
+    }
+}).addValue({
+    name: 'ethnic_group',
+    table: 'cor_raca',
+    tableField: 'nome',
+    resultField: 'ethnic_group_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'id'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'cor_raca_id',
+        foreignTable: 'matricula'
+    }
+}).addValue({
+    name: 'period',
+    table: 'turma',
+    tableField: 'turno',
+    resultField: 'period_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'turno'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'turma_id',
+        foreignTable: 'matricula'
+    }
 });
 
 enrollmentApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
     log.debug(req.sql.toParam());
-    req.sql.field('COALESCE(SUM(num_matriculas), 0)', 'total')
+    req.sql.field('COALESCE(COUNT(matricula.id), 0)', 'total')
     .field("'Brasil'", 'name')
-    .field('turma.ano_censo', 'year')
-    .from('turma')
-    .group('turma.ano_censo')
-    .order('turma.ano_censo');
+    .field('matricula.ano_censo', 'year')
+    .from('matricula')
+    .group('matricula.ano_censo')
+    .order('matricula.ano_censo')
+    .where('matricula.tipo=0 OR matricula.tipo=1 OR matricula.tipo=2 OR matricula.tipo=3');
+    next();
+}, query, (req, res, next) => {
+    // ids to strings
+    req.result.forEach((result) => {
+        if(typeof result.gender_id !== 'undefined') {
+            switch (result.gender_id) {
+                case 1:
+                    result.gender_name = 'Masculino';
+                    break;
+                case 2:
+                    result.gender_name = 'Feminino';
+                    break;
+            }
+            delete result.gender_id;
+        }
+        if(typeof result.period_id !== 'undefined') {
+            switch (result.period_id) {
+                case 1:
+                    result.period_name = 'Diurno';
+                    break;
+                case 2:
+                    result.period_name = 'Noturno';
+                    break;
+                case 3:
+                    result.period_name = 'Integral';
+                    break;
+                default:
+                    result.period_name = 'Indefinido';
+                    break;
+            }
+            delete result.period_id;
+        }
+    });
     next();
-}, query, response('enrollment'));
+}, response('enrollment'));
 
 module.exports = enrollmentApp;
diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
deleted file mode 100644
index f5476f5ea451876aa2e4c6ad0d4fe67a5b214879..0000000000000000000000000000000000000000
--- a/src/libs/routes/location.js
+++ /dev/null
@@ -1,1279 +0,0 @@
-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 = 'Total';
-    switch(locationId) {
-        case 1:
-            locationStr = 'Urbana';                         break;
-        case 2:
-            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;
-}
-
-function schoolYearIdToStr(schoolYearId)
-{
-    let schoolYearStr;
-    switch(schoolYearId) {
-        case 11:
-            schoolYearStr = 'Creche';
-            break;
-        case 21:
-            schoolYearStr = 'Pré-escola';
-            break;
-        case 31:
-            schoolYearStr = '1 Ano';
-            break;
-        case 32:
-            schoolYearStr = '2 Ano - 1 Serie';
-            break;
-        case 33:
-            schoolYearStr = '3 Ano - 2 Serie';
-            break;
-        case 34:
-            schoolYearStr = '4 Ano - 3 Serie';
-            break;
-        case 35:
-            schoolYearStr = '5 Ano - 4 Serie';
-            break;
-        case 41:
-            schoolYearStr = '6 Ano - 5 Serie';
-            break;
-        case 42:
-            schoolYearStr = '7 Ano - 6 Serie';
-            break;
-        case 43:
-            schoolYearStr = '8 Ano - 7 Serie';
-            break;
-        case 44:
-            schoolYearStr = '9 Ano - 8 Serie';
-            break;
-        case 51:
-            schoolYearStr = '1 Ano'; // equivalent to 'EM 1 Série'
-            break;
-        case 52:
-            schoolYearStr = '2 Ano'; // equivalent to 'EM 2 Série'
-            break;
-        case 53:
-            schoolYearStr = '3 Ano'; // equivalent to 'EM 3 Série'
-            break;
-        case 54:
-            schoolYearStr = '4 Ano'; // equivalent to '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;
-    // loop relies on the fact that Promise.all maintains the order of the original iterable
-    for(let result of querySet) {
-        const resultLbl = querySetLabels[resultIdx];
-        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);
-    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)')
-        .from('ibge_populacao');
-
-    const populationQry = squel.select()
-        .field('\'Brasil\'', 'name')
-        .field('SUM(populacao)', 'population')
-        .field('ibge_populacao.ano_censo', 'census_year')
-        .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\'', 'name')
-        .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
-        .field('ibge_pib.ano_censo', 'census_year')
-        .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\'', 'name')
-        .field('AVG(idhm)', 'idhm')
-        .field('adh_idh.ano_censo', 'census_year')
-        .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\'', 'name')
-        .field('AVG(t_analf15m)', 'analfabetism')
-        .field('adh_analfabetismo.ano_censo', 'census_year')
-        .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\'', 'name')
-        .field('AVG(gini)', 'gini')
-        .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", "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) => {
-        req.result = processResultSet(queryResults, queryLabels, true);
-        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', 'name')
-        .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', 'name')
-        .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', 'name')
-        .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', 'name')
-        .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', 'name')
-        .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');
-    // map query objects to their respective response labels
-    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) => {
-        req.result = processResultSet(queryResults, queryLabels, true);
-        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', 'name')
-        .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', 'name')
-        .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', 'name')
-        .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', 'name')
-        .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', 'name')
-        .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');
-    // map query objects to their respective response labels
-    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) => {
-        req.result = processResultSet(queryResults, queryLabels, true);
-        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', 'name')
-        .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', 'name')
-        .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', 'name')
-        .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', 'name')
-        .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', 'name')
-        .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');
-    // map query objects to their respective response labels
-    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) => {
-        req.result = processResultSet(queryResults, queryLabels, true);
-        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('\'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.id_tipo_turma = 0')
-        .group('escola.ano_censo');
-
-    const schoolsPerLocationQry = squel.select()
-        .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})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('escola.tipo_localizacao')
-        .group('escola.ano_censo')
-        .order('escola.tipo_localizacao');
-
-    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')
-        .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')
-        .order('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('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')
-        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
-        .group('turma.ano_censo')
-        .group('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" ];
-    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) {
-            for(let row of req.result[label]) {
-                if (row.hasOwnProperty('location')) {
-                    row.location = locationIdToStr(row.location);
-                }
-            }
-        }
-        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', 'name')
-        .field('0', 'location')
-        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
-        .field('escola.ano_censo', 'census_year')
-        .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})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('regiao.nome')
-        .group('escola.ano_censo')
-        .order('regiao.nome');
-
-    const schoolsPerLocationQry = squel.select()
-        .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')
-        .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})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('regiao.nome')
-        .group('escola.tipo_localizacao')
-        .group('escola.ano_censo')
-        .order('regiao.nome')
-        .order('escola.tipo_localizacao');
-
-    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')
-        .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')
-        .order('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')
-        .order('regiao.nome')
-        .order('dependencia_adm.nome');
-
-    const enrollmentsPerSchoolLevelQry = squel.select()
-        .field('regiao.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('etapa_ensino.desc_etapa', 'school_level')
-        .from('turma')
-        .from('etapa_ensino')
-        .from('regiao')
-        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
-        .where(`turma.fk_regiao_id = ${regionId}`)
-        .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('etapa_ensino.desc_etapa')
-        .group('regiao.nome')
-        .group('etapa_ensino.pk_etapa_ensino_id')
-        .order('regiao.nome')
-        .order('etapa_ensino.pk_etapa_ensino_id');
-
-    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) {
-            for(let row of req.result[label]) {
-                if (row.hasOwnProperty('location')) {
-                    row.location = locationIdToStr(row.location);
-                }
-            }
-        }
-        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', '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})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('estado.nome')
-        .group('escola.ano_censo')
-        .order('estado.nome');
-
-    const schoolsPerLocationQry = squel.select()
-        .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.tipo_localizacao')
-        .group('escola.ano_censo')
-        .order('estado.nome')
-        .order('escola.tipo_localizacao');
-
-    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')
-        .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')
-        .order('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')
-        .order('estado.nome')
-        .order('dependencia_adm.nome');
-
-    const enrollmentsPerSchoolLevelQry = squel.select()
-        .field('estado.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('etapa_ensino.desc_etapa', 'school_level')
-        .from('turma')
-        .from('etapa_ensino')
-        .from('estado')
-        .where('turma.fk_estado_id = estado.pk_estado_id')
-        .where(`turma.fk_estado_id = ${stateId}`)
-        .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('etapa_ensino.desc_etapa')
-        .group('etapa_ensino.pk_etapa_ensino_id')
-        .group('estado.nome')
-        .order('estado.nome')
-        .order('etapa_ensino.pk_etapa_ensino_id');
-
-    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) {
-            for(let row of req.result[label]) {
-                if (row.hasOwnProperty('location')) {
-                    row.location = locationIdToStr(row.location);
-                }
-            }
-        }
-        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', '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})`)
-        .where('escola.id_tipo_turma = 0')
-        .group('municipio.nome')
-        .group('escola.ano_censo')
-        .order('municipio.nome');
-
-    const schoolsPerLocationQry = squel.select()
-        .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.tipo_localizacao')
-        .group('escola.ano_censo')
-        .order('municipio.nome')
-        .order('escola.tipo_localizacao');
-
-    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')
-        .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')
-        .order('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')
-        .order('municipio.nome')
-        .order('dependencia_adm.nome');
-
-    const enrollmentsPerSchoolLevelQry = squel.select()
-        .field('municipio.nome', 'name')
-        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'census_year')
-        .field('etapa_ensino.desc_etapa', 'school_level')
-        .from('turma')
-        .from('etapa_ensino')
-        .from('municipio')
-        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
-        .where(`turma.fk_municipio_id = ${cityId}`)
-        .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('etapa_ensino.desc_etapa')
-        .group('etapa_ensino.pk_etapa_ensino_id')
-        .group('municipio.nome')
-        .order('municipio.nome')
-        .order('etapa_ensino.pk_etapa_ensino_id');
-
-    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) {
-            for(let row of req.result[label]) {
-                if (row.hasOwnProperty('location')) {
-                    row.location = locationIdToStr(row.location);
-                }
-            }
-        }
-        next();
-    }).catch((error) => {
-        log.error(`[SQL query error] ${error}`);
-        next(error);
-    });
-}, response('location'));
-
-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')
-        .field('turma.serie_ano', 'school_year')
-        .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')
-        .group('etapa_ensino.pk_etapa_ensino_id')
-        .group('turma.serie_ano')
-        .group('turma.ano_censo')
-        .order('etapa_ensino.pk_etapa_ensino_id')
-        .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'));
-
-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('etapa_ensino.pk_etapa_ensino_id')
-        .group('turma.serie_ano')
-        .group('turma.ano_censo')
-        .order('regiao.nome')
-        .order('etapa_ensino.pk_etapa_ensino_id')
-        .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'));
-
-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('etapa_ensino.pk_etapa_ensino_id')
-        .group('turma.serie_ano')
-        .group('turma.ano_censo')
-        .order('estado.nome')
-        .order('etapa_ensino.pk_etapa_ensino_id')
-        .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'));
-
-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('etapa_ensino.pk_etapa_ensino_id')
-        .group('turma.serie_ano')
-        .group('turma.ano_censo')
-        .order('municipio.nome')
-        .order('etapa_ensino.pk_etapa_ensino_id')
-        .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/libs/routes/region.js b/src/libs/routes/region.js
index f152d899c05b99334725f52d17b71199b4a2f4dc..a752fa1b6169522d1f2f0983f3c4b7d94748f551 100644
--- a/src/libs/routes/region.js
+++ b/src/libs/routes/region.js
@@ -21,11 +21,11 @@ rqf.addField({
 }).addValue({
     name: 'id',
     table: 'regiao',
-    tableField: 'pk_regiao_id',
+    tableField: 'id',
     where: {
         relation: '=',
         type: 'integer',
-        field: 'pk_regiao_id',
+        field: 'id',
         table: 'regiao'
     }
 }).addField({
@@ -46,7 +46,7 @@ rqf.addField({
 
 regionApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
     req.sql.from('regiao')
-        .field('pk_regiao_id', 'id')
+        .field('id')
         .field('nome', 'name');
     next();
 }, query, response('region'));
diff --git a/src/libs/routes/school.js b/src/libs/routes/school.js
index 6420db5d6b1fd64940e82eefa3e624b065ba3c90..d6e5f7d013f5b0bf11f14a3456273bf64ff0cfca 100644
--- a/src/libs/routes/school.js
+++ b/src/libs/routes/school.js
@@ -21,11 +21,11 @@ rqf.addField({
 }).addValue({
     name: 'id',
     table: 'escola',
-    tableField: 'cod_entidade',
+    tableField: 'id',
     where: {
         relation: '=',
         type: 'integer',
-        field: 'cod_entidade'
+        field: 'id'
     }
 }).addValue({
     name: 'city',
@@ -35,12 +35,12 @@ rqf.addField({
     where: {
         relation: '=',
         type: 'integer',
-        field: 'fk_municipio_id',
+        field: 'municipio_id',
         table: 'escola'
     },
     join: {
-        primary: 'pk_cod_ibge',
-        foreign: 'fk_municipio_id',
+        primary: 'id',
+        foreign: 'municipio_id',
         foreignTable: 'escola'
     }
 }).addValue({
@@ -51,14 +51,25 @@ rqf.addField({
     where: {
         relation: '=',
         type: 'integer',
-        field: 'fk_estado_id',
+        field: 'estado_id',
         table: 'escola'
     },
     join: {
-        primary: 'pk_estado_id',
-        foreign: 'fk_estado_id',
+        primary: 'id',
+        foreign: 'estado_id',
         foreignTable: 'escola'
     }
+}).addValue({
+    name: 'year',
+    table: 'escola',
+    tableField: 'ano_censo',
+    resultField: 'year',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'ano_censo',
+        table: 'escola'
+    }
 });
 
 schoolApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
@@ -71,10 +82,11 @@ schoolApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
         });
     }
     req.sql.from('escola')
-        .field('escola.cod_entidade', 'id')
+        .field('escola.id')
         .field('escola.ano_censo', 'year')
-        .field('escola.fk_estado_id', 'state_id')
-        .field('escola.fk_municipio_id', 'city_id');
+        .field('escola.nome_escola', 'name')
+        .field('escola.estado_id', 'state_id')
+        .field('escola.municipio_id', 'city_id');
     next();
 }, query, response('school'));
 
diff --git a/src/libs/routes/spatial.js b/src/libs/routes/spatial.js
new file mode 100644
index 0000000000000000000000000000000000000000..2196c7a2d961ea54591abb63d808c7268c02394f
--- /dev/null
+++ b/src/libs/routes/spatial.js
@@ -0,0 +1,459 @@
+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 ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
+
+const spatialApp = express();
+
+let rqf = new ReqQueryFields();
+
+function schoolYearIdToStr(schoolYearId) {
+    let schoolYearStr;
+    switch(schoolYearId) {
+        case 11:
+            schoolYearStr = 'Creche';
+            break;
+        case 21:
+            schoolYearStr = 'Pré-escola';
+            break;
+        case 31:
+            schoolYearStr = '1 Ano';
+            break;
+        case 32:
+            schoolYearStr = '2 Ano - 1 Serie';
+            break;
+        case 33:
+            schoolYearStr = '3 Ano - 2 Serie';
+            break;
+        case 34:
+            schoolYearStr = '4 Ano - 3 Serie';
+            break;
+        case 35:
+            schoolYearStr = '5 Ano - 4 Serie';
+            break;
+        case 41:
+            schoolYearStr = '6 Ano - 5 Serie';
+            break;
+        case 42:
+            schoolYearStr = '7 Ano - 6 Serie';
+            break;
+        case 43:
+            schoolYearStr = '8 Ano - 7 Serie';
+            break;
+        case 44:
+            schoolYearStr = '9 Ano - 8 Serie';
+            break;
+        case 51:
+            schoolYearStr = '1 Ano'; // equivalent to 'EM 1 Série'
+            break;
+        case 52:
+            schoolYearStr = '2 Ano'; // equivalent to 'EM 2 Série'
+            break;
+        case 53:
+            schoolYearStr = '3 Ano'; // equivalent to 'EM 3 Série'
+            break;
+        case 54:
+            schoolYearStr = '4 Ano'; // equivalent to '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;
+    // loop relies on the fact that Promise.all maintains the order of the original iterable
+    for(let result of querySet) {
+        const resultLbl = querySetLabels[resultIdx];
+        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);
+    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()); });
+}
+
+rqf.addField({
+    name: 'filter',
+    field: true,
+    where: true
+}).addValue({
+    name: 'region',
+    table: 'regiao',
+    tableField: 'nome',
+    resultField: 'region_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'id'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'regiao_id'
+    }
+}).addValue({
+    name: 'state',
+    table: 'estado',
+    tableField: 'nome',
+    resultField: 'state_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'id'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'estado_id'
+    }
+}).addValue({
+    name: 'city',
+    table: 'municipio',
+    tableField: 'nome',
+    resultField: 'city_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'id'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'municipio_id'
+    }
+}).addValue({
+    name: 'school',
+    table: 'escola',
+    tableField: 'nome_escola',
+    resultField: 'school_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'id'
+    }
+});
+
+spatialApp.get('/sociodemographic', rqf.parse(), rqf.build(), (req, res, next) => {
+    const populationYearQry = squel.select()
+        .field('MAX(ibge_populacao.ano_censo)')
+        .from('ibge_populacao');
+
+    const populationQry = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('SUM(populacao)', 'population')
+        .field('ibge_populacao.ano_censo', 'census_year')
+        .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 = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
+        .field('ibge_pib.ano_censo', 'census_year')
+        .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 = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('AVG(idhm)', 'idhm')
+        .field('adh_idh.ano_censo', 'census_year')
+        .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 = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('AVG(t_analf15m)', 'analfabetism')
+        .field('adh_analfabetismo.ano_censo', 'census_year')
+        .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 = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('AVG(gini)', 'gini')
+        .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", "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) => {
+        req.result = processResultSet(queryResults, queryLabels, true);
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('spatial'));
+
+spatialApp.get('/educational', rqf.parse(), rqf.build(), (req, res, next) => {
+    const censusYearQry = squel.select()
+        .field('MAX(escola.ano_censo)', 'ano_censo')
+        .from('escola')
+        .toString();
+
+    const totalSchoolsQry = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('\'Total\'', 'location_name')
+        .field('COUNT(DISTINCT(escola.id))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .from('turma')
+        .from('escola')
+        .where('escola.ano_censo=turma.ano_censo AND escola.id=turma.escola_id')
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('turma.tipo_turma_id = 0')
+        .group('escola.ano_censo');
+
+    const schoolsPerLocationQry = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('COUNT(DISTINCT(escola.id))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .field('localizacao.descricao', 'location_name')
+        .from('localizacao')
+        .from('turma')
+        .from('escola')
+        .where('escola.cod_localizacao=localizacao.id')
+        .where('escola.ano_censo=turma.ano_censo AND escola.id=turma.escola_id')
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('turma.tipo_turma_id = 0')
+        .group('escola.cod_localizacao')
+        .group('escola.ano_censo')
+        .group('localizacao.descricao')
+        .order('localizacao.descricao');
+
+    const schoolsPerAdmDependencyQry = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('COUNT(DISTINCT(escola.id))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency_name')
+        .from('dependencia_adm')
+        .from('escola')
+        .where('escola.dependencia_adm_id=dependencia_adm.id')
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .group('escola.ano_censo')
+        .group('dependencia_adm.nome')
+        .order('escola.ano_censo')
+        .order('dependencia_adm.nome');
+
+    const schoolClassYearQry = squel.select()
+        .field('MAX(matricula.ano_censo)')
+        .from('matricula')
+        .toString();
+
+    const enrollmentsQry = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(COUNT(matricula.id), 0)', 'total')
+        .field('matricula.ano_censo', 'census_year')
+        .from('matricula')
+        .where(`matricula.ano_censo IN (${schoolClassYearQry})`)
+        .where('matricula.tipo<=3')
+        .group('matricula.ano_censo');
+
+    const enrollmentsPerAdmDepQry = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(COUNT(matricula.id), 0)', 'total')
+        .field('matricula.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency_name')
+        .from('dependencia_adm')
+        .from('matricula')
+        .where('matricula.dependencia_adm_id=dependencia_adm.id')
+        .where('matricula.tipo <= 3')
+        .where(`matricula.ano_censo IN (${schoolClassYearQry})`)
+        .group('matricula.ano_censo')
+        .group('dependencia_adm.nome')
+        .order('dependencia_adm.nome');
+
+    const enrollmentsPerSchoolLevelQry = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(COUNT(matricula.id), 0)', 'total')
+        .field('matricula.ano_censo', 'census_year')
+        .field('etapa_ensino.desc_etapa', 'school_level_name')
+        .from('etapa_ensino')
+        .from('matricula')
+        .where('matricula.etapa_ensino_id=etapa_ensino.id')
+        .where('matricula.tipo <= 3')
+        .where(`matricula.ano_censo IN (${schoolClassYearQry})`)
+        .group('matricula.ano_censo')
+        .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.id')
+        .order('etapa_ensino.id');
+
+    const enrollmentsPerLocationQry = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(COUNT(matricula.id), 0)', 'total')
+        .field('matricula.ano_censo', 'census_year')
+        .field('localizacao.descricao', 'location_name')
+        .from('localizacao')
+        .from('matricula')
+        .where('matricula.localizacao_id=localizacao.id')
+        .where('matricula.tipo <= 3')
+        .where(`matricula.ano_censo IN (${schoolClassYearQry})`)
+        .group('matricula.ano_censo')
+        .group('localizacao.descricao')
+        .order('ano_censo')
+        .order('localizacao.descricao');
+
+    const enrollmentsPerSchoolLevelAndAdmDependencyQry = req.sql.clone()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(COUNT(matricula.id), 0)', 'total')
+        .field('matricula.ano_censo', 'census_year')
+        .field('etapa_ensino.desc_etapa', 'school_level_name')
+        .field('dependencia_adm.nome', 'adm_dependency_name')
+        .from('etapa_ensino')
+        .from('dependencia_adm')
+        .from('matricula')
+        .where('matricula.etapa_ensino_id=etapa_ensino.id')
+        .where('matricula.dependencia_adm_id=dependencia_adm.id')
+        .where('matricula.tipo <= 3')
+        .where(`matricula.ano_censo IN (${schoolClassYearQry})`)
+        .group('matricula.ano_censo')
+        .group('etapa_ensino.desc_etapa')
+        .group('dependencia_adm.nome')
+        .order('matricula.ano_censo')
+        .order('etapa_ensino.desc_etapa')
+        .order('dependencia_adm.nome');
+
+    const queryLabels = [ "school", "school_per_location", "school_per_adm_dependency", "enrollment", "enrollment_per_adm_dep",
+        "enrollment_per_school_level", "enrollment_per_location", "enrollment_per_school_level_adm_dependency" ];
+    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, schoolsPerAdmDependencyQry, enrollmentsQry,
+        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry, enrollmentsPerLocationQry, enrollmentsPerSchoolLevelAndAdmDependencyQry];
+    // 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}`);
+        next(error);
+    });
+}, response('spatial'));
+
+spatialApp.get('/educational/school_level', rqf.parse(), rqf.build(), (req, res, next) => {
+    const enrollmentsPerSchoolLevelYearQry = squel.select()
+        .field('MAX(matricula.ano_censo)', 'census_year')
+        .from('matricula');
+
+    const enrollmentsPerSchoolLevelQry = req.sql.clone()
+        .field('COALESCE(COUNT(matricula.id), 0)', 'total')
+        .field('matricula.ano_censo', 'census_year')
+        .field('matricula.serie_ano_id', 'school_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('etapa_ensino')
+        .from('matricula')
+        .where(`matricula.ano_censo IN (${enrollmentsPerSchoolLevelYearQry.toString()})`)
+        .where('matricula.etapa_ensino_id = etapa_ensino.id')
+        .where('matricula.tipo <= 3')
+        .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.id')
+        .group('matricula.serie_ano_id')
+        .group('matricula.ano_censo')
+        .order('etapa_ensino.id')
+        .order('matricula.serie_ano_id')
+        .order('matricula.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('spatial'));
+
+module.exports = spatialApp;
diff --git a/src/libs/routes/state.js b/src/libs/routes/state.js
index 4da632605c9fd580937a5569450abfaad3b16e89..2663fe9890849aea38ae51244e330454983a3742 100644
--- a/src/libs/routes/state.js
+++ b/src/libs/routes/state.js
@@ -21,11 +21,11 @@ rqf.addField({
 }).addValue({
     name: 'id',
     table: 'estado',
-    tableField: 'pk_estado_id',
+    tableField: 'id',
     where: {
         relation: '=',
         type: 'integer',
-        field: 'pk_estado_id'
+        field: 'id'
     }
 }).addValue({
     name: 'region',
@@ -35,12 +35,12 @@ rqf.addField({
     where: {
         relation: '=',
         type: 'integer',
-        field: 'fk_regiao_id',
+        field: 'regiao_id',
         table: 'estado'
     },
     join: {
-        primary: 'pk_regiao_id',
-        foreign: 'fk_regiao_id',
+        primary: 'id',
+        foreign: 'regiao_id',
         foreignTable: 'estado'
     }
 }).addField({
@@ -60,10 +60,10 @@ rqf.addField({
 
 stateApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
     req.sql.from('estado')
-        .field('pk_estado_id', 'id')
-        .group('pk_estado_id')
-        .field('fk_regiao_id', 'region_id')
-        .group('fk_regiao_id')
+        .field('estado.id')
+        .group('estado.id')
+        .field('regiao_id', 'region_id')
+        .group('regiao_id')
         .field('estado.nome', 'name')
         .group('estado.nome')
         .field('estado.sigla', 'abbreviation')
diff --git a/src/test/enrollment.js b/src/test/enrollment.js
index b40c2de866873f131bd35bc85eb44ee2a9597eee..48bebc5f0beaa7883e618f3a9d64004f023f9e1c 100644
--- a/src/test/enrollment.js
+++ b/src/test/enrollment.js
@@ -68,7 +68,63 @@ describe('request enrollments', () => {
 
     it('should list the administrative dependencies', (done) => {
         chai.request(server)
-            .get('/api/v1/enrollment/adm_dependency ')
+            .get('/api/v1/enrollment/adm_dependency_detailed')
+            .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 detailed', (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 genders', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment/gender')
+            .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 ethnic groups', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment/ethnic_group')
+            .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 periods', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment/period')
             .end((err, res) => {
                 res.should.have.status(200);
                 res.should.be.json;
@@ -155,7 +211,7 @@ describe('request enrollments', () => {
 
     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')
+            .get('/api/v1/enrollment?dims=region,state,education_level,school,gender,period&filter=min_year:2015,max_year:2015,city:4106902')
             .end((err, res) => {
                 res.should.have.status(200);
                 res.should.be.json;
@@ -163,8 +219,8 @@ describe('request enrollments', () => {
                 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('school_name');
+                res.body.result[0].should.have.property('education_level_name');
                 res.body.result[0].should.have.property('total');
                 res.body.result[0].should.have.property('year');
                 done();
diff --git a/src/test/query.js b/src/test/query.js
index 6d3454452d882fb34f3d75092e63d74cb3d3642d..ed492e8a3c30aa7de2bae19dab1bc23398a43bfd 100644
--- a/src/test/query.js
+++ b/src/test/query.js
@@ -77,7 +77,7 @@ describe('Query middleware', () => {
 
     it('should return 404 with an empty query result', (done) => {
         let req = {
-            sql: squel.select().field('*').from('regiao').where('pk_regiao_id>6')
+            sql: squel.select().field('*').from('regiao').where('id>6')
         };
         let res = {};
         query(req, {},  (error)=>{
diff --git a/src/test/location.js b/src/test/spatial.js
similarity index 93%
rename from src/test/location.js
rename to src/test/spatial.js
index 42761a8dadf84c63b1c4202fe27e17b9fa2aa920..b4422e7911a30b19e2d0f7a73a9b1d62389df1b4 100644
--- a/src/test/location.js
+++ b/src/test/spatial.js
@@ -24,12 +24,12 @@ const server = require(`${libs}/app`);
 
 chai.use(chaiHttp);
 
-const testTimeout = 5000;
+const testTimeout = 60000;
 
-describe('test location', () => {
+describe('test spatial', () => {
     it('should return the expected response format for sociodemographic data for the whole country', (done) => {
         chai.request(server)
-            .get('/api/v1/location/sociodemographic')
+            .get('/api/v1/spatial/sociodemographic')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -69,7 +69,7 @@ describe('test location', () => {
 
     it('should return the expected response format for sociodemographic data for a region', (done) => {
         chai.request(server)
-            .get('/api/v1/location/sociodemographic/region/1')
+            .get('/api/v1/spatial/sociodemographic?filter=region:1')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -109,7 +109,7 @@ describe('test location', () => {
 
     it('should return the expected response format for sociodemographic data for a state', (done) => {
         chai.request(server)
-            .get('/api/v1/location/sociodemographic/state/42')
+            .get('/api/v1/spatial/sociodemographic?filter=state:42')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -149,7 +149,7 @@ describe('test location', () => {
 
     it('should return the expected response format for sociodemographic data for a city', (done) => {
         chai.request(server)
-            .get('/api/v1/location/sociodemographic/city/4106902')
+            .get('/api/v1/spatial/sociodemographic?filter=city:4106902')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -189,7 +189,7 @@ describe('test location', () => {
 
     it('should return the expected response format for educational data for the whole country', (done) => {
         chai.request(server)
-            .get('/api/v1/location/educational')
+            .get('/api/v1/spatial/educational')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -209,11 +209,10 @@ describe('test location', () => {
                 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.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('location_name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
                 });
@@ -221,7 +220,7 @@ describe('test location', () => {
                 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('location_name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
                 });
@@ -238,7 +237,7 @@ describe('test location', () => {
                     row.should.have.property('name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
-                    row.should.have.property('adm_dependency');
+                    row.should.have.property('adm_dependency_name');
                 });
                 // test response attributes for enrollment_per_school_level
                 res.body.result.enrollment_per_school_level.forEach((row) => {
@@ -246,7 +245,7 @@ describe('test location', () => {
                     row.should.have.property('name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
-                    row.should.have.property('school_level');
+                    row.should.have.property('school_level_name');
                 });
                 done();
             });
@@ -254,7 +253,7 @@ describe('test location', () => {
 
     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')
+            .get('/api/v1/spatial/educational?filter=region:1')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -278,7 +277,7 @@ describe('test location', () => {
                 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('location_name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
                 });
@@ -286,7 +285,7 @@ describe('test location', () => {
                 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('location_name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
                 });
@@ -303,7 +302,7 @@ describe('test location', () => {
                     row.should.have.property('name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
-                    row.should.have.property('adm_dependency');
+                    row.should.have.property('adm_dependency_name');
                 });
                 // test response attributes for enrollment_per_school_level
                 res.body.result.enrollment_per_school_level.forEach((row) => {
@@ -311,7 +310,7 @@ describe('test location', () => {
                     row.should.have.property('name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
-                    row.should.have.property('school_level');
+                    row.should.have.property('school_level_name');
                 });
                 done();
             });
@@ -319,7 +318,7 @@ describe('test location', () => {
 
     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')
+            .get('/api/v1/spatial/educational?filter=state:42')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -343,7 +342,7 @@ describe('test location', () => {
                 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('location_name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
                 });
@@ -351,7 +350,7 @@ describe('test location', () => {
                 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('location_name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
                 });
@@ -368,7 +367,7 @@ describe('test location', () => {
                     row.should.have.property('name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
-                    row.should.have.property('adm_dependency');
+                    row.should.have.property('adm_dependency_name');
                 });
                 // test response attributes for enrollment_per_school_level
                 res.body.result.enrollment_per_school_level.forEach((row) => {
@@ -376,7 +375,7 @@ describe('test location', () => {
                     row.should.have.property('name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
-                    row.should.have.property('school_level');
+                    row.should.have.property('school_level_name');
                 });
                 done();
             });
@@ -384,7 +383,7 @@ describe('test location', () => {
 
     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')
+            .get('/api/v1/spatial/educational?filter=city:4106902')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -408,7 +407,7 @@ describe('test location', () => {
                 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('location_name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
                 });
@@ -416,7 +415,7 @@ describe('test location', () => {
                 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('location_name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
                 });
@@ -433,7 +432,7 @@ describe('test location', () => {
                     row.should.have.property('name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
-                    row.should.have.property('adm_dependency');
+                    row.should.have.property('adm_dependency_name');
                 });
                 // test response attributes for enrollment_per_school_level
                 res.body.result.enrollment_per_school_level.forEach((row) => {
@@ -441,7 +440,7 @@ describe('test location', () => {
                     row.should.have.property('name');
                     row.should.have.property('total');
                     row.should.have.property('census_year');
-                    row.should.have.property('school_level');
+                    row.should.have.property('school_level_name');
                 });
                 done();
             });
@@ -449,7 +448,7 @@ describe('test location', () => {
 
     it('should return the correct format of enrollments per school level', (done) => {
         chai.request(server)
-            .get('/api/v1/location/educational/school_level')
+            .get('/api/v1/spatial/educational/school_level')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -478,7 +477,7 @@ describe('test location', () => {
 
     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')
+            .get('/api/v1/spatial/educational/school_level?filter=region:1')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -507,7 +506,7 @@ describe('test location', () => {
 
     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')
+            .get('/api/v1/spatial/educational/school_level?filter=state:42')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format
@@ -536,7 +535,7 @@ describe('test location', () => {
 
     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')
+            .get('/api/v1/spatial/educational/school_level?filter=city:4106902')
             .end((err, res) => {
                 res.should.have.status(200);
                 // test response format