diff --git a/src/libs/app.js b/src/libs/app.js index 8be3a95b9a3e78f9ce54093196facfed9f0223c1..1184e1e026ac6d17e79a90e975d273f1a700f918 100644 --- a/src/libs/app.js +++ b/src/libs/app.js @@ -44,6 +44,18 @@ app.use((req, res, next) => { }; }; req.resetSql(); + + req.sql.oldClone = req.sql.clone; + req.sql.clone = () => { + let cloned = req.sql.oldClone(); + cloned.oldFrom = cloned.from; + cloned.from = (name, alias = null) => { + cloned.oldFrom(name, alias || null); + cloned.tableFrom = name; + return cloned; + }; + return cloned; + }; next(); }); app.use(passport.initialize()); diff --git a/src/libs/middlewares/reqQueryFields.js b/src/libs/middlewares/reqQueryFields.js index c821852b423fb9d9d41d60a579e3b064b88ab427..993aae5bd282199b33d5ff8228cd90dcaf8c275c 100644 --- a/src/libs/middlewares/reqQueryFields.js +++ b/src/libs/middlewares/reqQueryFields.js @@ -192,126 +192,142 @@ class ReqQueryFields { }; } - build() { + buildQuery(req, sql) { // "Constrói" o SQL - return (req, res, next) => { - let hasJoined = {}; - let thisTable = req.sql.tableFrom; - // Foreach no campos - Object.keys(this.fields).forEach((key) => { - // Campo - let field = this.fields[key]; - log.debug(field); - // `param` aqui é o atributo no objeto `req` (dims, filter, search, ...) - let param = req[field.name]; - // Fazemos um foreach nos parametros dentro do atributo - Object.keys(param).forEach((k) => { - let values = _.merge(this.fieldValues, field.values); - if(typeof values[k] !== 'undefined') { - // Clonamos para não alterar o original - let value = _.clone(values[k]); - if(value.parseOnly) return; - // Checa se não fizemos o join para este valor e se é necessário fazer - if(!hasJoined[value.table] && typeof value.join !== 'undefined') { - let foreignTable = ''; - if(value.join.foreignTable) foreignTable = value.join.foreignTable+'.'; - if(value.join.foreignTable === '@') foreignTable = thisTable+'.'; - // Fazemos o join - 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.table] = true; + let hasJoined = {}; + let thisTable = sql.tableFrom; + // Foreach no campos + Object.keys(this.fields).forEach((key) => { + // Campo + let field = this.fields[key]; + log.debug(field); + // `param` aqui é o atributo no objeto `req` (dims, filter, search, ...) + let param = req[field.name]; + // Fazemos um foreach nos parametros dentro do atributo + Object.keys(param).forEach((k) => { + let values = _.merge(this.fieldValues, field.values); + if(typeof values[k] !== 'undefined') { + // Clonamos para não alterar o original + let value = _.clone(values[k]); + if(value.parseOnly) return; + // Checa se não fizemos o join para este valor e se é necessário fazer + if(!hasJoined[value.table] && typeof value.join !== 'undefined') { + let foreignTable = ''; + if(value.join.foreignTable) foreignTable = value.join.foreignTable+'.'; + if(value.join.foreignTable === '@') foreignTable = thisTable+'.'; + // Fazemos o join + 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; } - // Se o valor é um campo a ser incluÃdo no SELECT - if(typeof field.field !== 'undefined' && field.field) { - log.debug('SELECT'); - let table = value.table; - if(table === '@') table = thisTable; - if (Array.isArray(value.resultField)) { - value.tableField.forEach((f, i) => { - req.sql.field(table+'.'+f, value.resultField[i] || f) - .group(table+'.'+f) - .order(table+'.'+f); - }) - }else{ - req.sql.field(table+'.'+value.tableField, value.resultField || value.tableField) - .order(table+'.'+value.tableField) - .group(table+'.'+value.tableField); - } + sql.join(value.table, null, onClause); + // Marcamos o join como feito para não ter problemas + hasJoined[value.table] = true; + } + // Se o valor é um campo a ser incluÃdo no SELECT + if(typeof field.field !== 'undefined' && field.field) { + log.debug('SELECT'); + let table = value.table; + if(table === '@') table = thisTable; + if (Array.isArray(value.resultField)) { + value.tableField.forEach((f, i) => { + sql.field(table+'.'+f, value.resultField[i] || f) + .group(table+'.'+f) + .order(table+'.'+f); + }) + }else{ + sql.field(table+'.'+value.tableField, value.resultField || value.tableField) + .order(table+'.'+value.tableField) + .group(table+'.'+value.tableField); } - // Se o valor é um campo para ser usado no WHERE - if(typeof field.where !== 'undefined' && field.where) { - log.debug('WHERE'); - // Valor do where - - let whereValue = param[k]; - log.debug('whereValue'); - log.debug(whereValue); - log.debug(`Where value é array? ${Array.isArray(whereValue)}`); + } + // Se o valor é um campo para ser usado no WHERE + if(typeof field.where !== 'undefined' && field.where) { + log.debug('WHERE'); + // Valor do where - let tbl = value.where.table || value.table; - if (tbl === '@') tbl = thisTable; - // multiple where - if (Array.isArray(value.where.field)) { - let lower = (value.where.type === 'string') ? ' LOWER(?) ' : ' ? '; - let whereField = ''; - let whereValues = []; - value.where.field.forEach((f, i, arr) => { - whereField += (value.where.type === 'string') ? 'LOWER(' + tbl + '.' + value.where.field[i] + ')' : tbl + '.' + value.where.field[i]; - whereField += ' ' + value.where.relation + ' ?'; - if (i < arr.length - 1) { - whereField += ' ' + value.where.condition + ' '; - } + let whereValue = param[k]; + log.debug('whereValue'); + log.debug(whereValue); + log.debug(`Where value é array? ${Array.isArray(whereValue)}`); - if (Array.isArray(whereValue)) { - let whereString = '('; - for(let i = 0; i < whereValue.length; ++i) { - whereString += whereField; - whereValues.push(parseWhereValue(value.where.type, whereValue[i])); - if(i < whereValue.length-1) { - whereString += ' OR '; - } - } - whereString += ')'; - } else { - whereValues.push(parseWhereValue(value.where.type, whereValue)); - } - }); + let tbl = value.where.table || value.table; + if (tbl === '@') tbl = thisTable; + // multiple where + if (Array.isArray(value.where.field)) { + let lower = (value.where.type === 'string') ? ' LOWER(?) ' : ' ? '; + let whereField = ''; + let whereValues = []; + value.where.field.forEach((f, i, arr) => { + whereField += (value.where.type === 'string') ? 'LOWER(' + tbl + '.' + value.where.field[i] + ')' : tbl + '.' + value.where.field[i]; + whereField += ' ' + value.where.relation + ' ?'; + if (i < arr.length - 1) { + whereField += ' ' + value.where.condition + ' '; + } - req.sql.where(whereField, ...whereValues); - } else { - let whereField = (value.where.type === 'string') ? 'LOWER(' + tbl + '.' + value.where.field + ')' : tbl + '.' + value.where.field; - let lower = (value.where.type === 'string') ? ' LOWER(?) ' : ' ? '; - if(Array.isArray(whereValue)) { + if (Array.isArray(whereValue)) { let whereString = '('; - let arrayWhereValues = []; for(let i = 0; i < whereValue.length; ++i) { - whereString += whereField + ' ' + value.where.relation + lower; - arrayWhereValues.push(parseWhereValue(value.where.type, whereValue[i])); + whereString += whereField; + whereValues.push(parseWhereValue(value.where.type, whereValue[i])); if(i < whereValue.length-1) { whereString += ' OR '; } } whereString += ')'; - req.sql.where(whereString, ...arrayWhereValues); } else { - req.sql.where(whereField + ' ' + value.where.relation + lower, parseWhereValue(value.where.type, whereValue)); + whereValues.push(parseWhereValue(value.where.type, whereValue)); } + }); + + sql.where(whereField, ...whereValues); + } else { + let whereField = (value.where.type === 'string') ? 'LOWER(' + tbl + '.' + value.where.field + ')' : tbl + '.' + value.where.field; + let lower = (value.where.type === 'string') ? ' LOWER(?) ' : ' ? '; + if(Array.isArray(whereValue)) { + let whereString = '('; + let arrayWhereValues = []; + for(let i = 0; i < whereValue.length; ++i) { + whereString += whereField + ' ' + value.where.relation + lower; + arrayWhereValues.push(parseWhereValue(value.where.type, whereValue[i])); + if(i < whereValue.length-1) { + whereString += ' OR '; + } + } + whereString += ')'; + sql.where(whereString, ...arrayWhereValues); + } else { + sql.where(whereField + ' ' + value.where.relation + lower, parseWhereValue(value.where.type, whereValue)); } } } - }); + } + }); + }); + return sql; + } + + build() { + return (req, res, next) => { + req.sql = this.buildQuery(req, req.sql); + next(); + }; + } + + multibuild() { + return (req, res, next) => { + req.querySet.forEach((query) => { + console.log("query"); + console.log(query.tableFrom); + query = this.buildQuery(req, query); }); next(); }; diff --git a/src/libs/routes/api.js b/src/libs/routes/api.js index 590ff356b310c4e1258db1c85d9fe41ec49c2cee..e205726df4fdc6fe117337cebd5eaf4b66f0091f 100644 --- a/src/libs/routes/api.js +++ b/src/libs/routes/api.js @@ -50,6 +50,8 @@ const infrastructure = require(`${libs}/routes/infrastructure`); const distributionFactor = require(`${libs}/routes/distributionFactor`); +const siope = require(`${libs}/routes/siope`); + api.get('/', (req, res) => { res.json({ msg: 'SimCAQ API is running' }); }); @@ -77,5 +79,6 @@ api.use('/reset', resetToken); api.use('/education_years', educationYears); api.use('/infrastructure', infrastructure); api.use('/distribution_factor', distributionFactor); +api.use('/siope', siope); module.exports = api; diff --git a/src/libs/routes/siope.js b/src/libs/routes/siope.js new file mode 100644 index 0000000000000000000000000000000000000000..622da904d074ff80b1d328bcada59ad23eb317ec --- /dev/null +++ b/src/libs/routes/siope.js @@ -0,0 +1,166 @@ +const express = require('express'); + +const siopeApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const squel = require('squel'); + +const query = require(`${libs}/middlewares/query`); + +const multiQuery = require(`${libs}/middlewares/multiQuery`); + +const response = require(`${libs}/middlewares/response`); + +const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); + +const id2str = require(`${libs}/middlewares/id2str`); + +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +let rqf = new ReqQueryFields(); + +siopeApp.use(cache('15 day')); + +siopeApp.get('/years', (req, res, next) => { + req.sql.from('siope_mun') + .field('DISTINCT siope_mun.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + req.oldResult = req.result; + + req.sql = squel.select(); + + req.sql.from('siope_uf') + .field('DISTINCT siope_uf.ano_censo', 'year'); + next(); +}, query, (req, res, next) => { + let result = Object.assign(req.oldResult, req.result); + req.result = result; + next(); +}, response('years')); + +rqf.addField({ + name: 'filter', + field: true, + where: true +}).addField({ + name: 'dims', + field: true, + where: false +}).addValue({ + name: 'city', + table: 'municipio', + tableField: 'nome', + resultField: 'city_name', + where: { + relation: '=', + type: 'integer', + field: 'municipio_id', + table: 'siope_mun' + }, + join: { + primary: 'id', + foreign: 'municipio_id', + foreignTable: 'siope_mun' + } +}).addValue({ + name: 'state', + table: 'estado', + tableField: ['id','nome','sigla'], + resultField: ['state_id','state_name','state_abbreviation'], + where: { + relation: '=', + type: 'integer', + field: 'estado_id', + table: '@' + }, + join: { + primary: 'id', + foreign: 'estado_id', + foreignTable: '@' + } +}).addValue({ + name: 'min_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '>=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}).addValue({ + name: 'max_year', + table: '@', + tableField: 'ano_censo', + resultField: 'year', + where: { + relation: '<=', + type: 'integer', + table: '@', + field: 'ano_censo' + } +}); + + + +siopeApp.get('/', rqf.parse(), (req, res, next) => { + req.querySet = []; + req.queryIndex = {}; + + let siopeUf = req.sql.clone(); + siopeUf.from('siope_uf') + .field('siope_uf.ano_censo', 'year') + .field('siope_uf.estado_id', 'state_id') + .field('siope_uf.fundeb', 'fundeb') + .field('siope_uf.total_impostos', 'impostos') + .field('siope_uf.total_mde', 'MDE') + .group('siope_uf.ano_censo') + .group('siope_uf.estado_id') + .group('siope_uf.fundeb') + .group('siope_uf.total_impostos') + .group('siope_uf.total_mde') + .order('siope_uf.ano_censo'); + req.queryIndex.siopeUf = req.querySet.push(siopeUf) - 1; + + let siopeMun = req.sql.clone(); + siopeMun.from('siope_mun') + .field('siope_mun.ano_censo', 'year') + .field('siope_mun.estado_id', 'state_id') + .field('siope_mun.municipio_id', 'city_id') + .field('siope_mun.fundeb', 'fundeb') + .field('siope_mun.total_impostos', 'impostos') + .field('siope_mun.total_mde', 'MDE') + .group('siope_mun.ano_censo') + .group('siope_mun.estado_id') + .group('siope_mun.municipio_id') + .group('siope_mun.fundeb') + .group('siope_mun.total_impostos') + .group('siope_mun.total_mde') + .order('siope_mun.ano_censo'); + req.queryIndex.siopeMun = req.querySet.push(siopeMun) - 1; + + next(); +}, rqf.multibuild(), multiQuery, (req, res, next) => { + + let result = [] + + req.result[req.queryIndex.siopeUf].forEach((item) => { + result.push(item) + }); + req.result[req.queryIndex.siopeMun].forEach((item) => { + result.push(item) + }); + + req.result = result; + next(); + +}, response('siope')); + +module.exports = siopeApp;