387 lines
13 KiB
JavaScript

const _ = require('lodash');
const {
HttpStatusError
} = require('./errors');
const {
parse
} = require('./parser');
const {
raw
} = require('./transforms');
const Op = require('sequelize').Op;
class ModelHandler {
constructor(model, defaults = {
limit: 50,
offset: 0
}) {
this.model = model;
this.defaults = defaults;
this.custom = null;
this.name = this.model.getTableName();
}
create() {
const handle = (req, res, next) => {
this.model
.create(req.body)
.then(respond)
.catch(next);
function respond(row) {
res.status(201);
res.send(res.transform(row));
}
};
return [
raw,
handle
];
}
get() {
const handle = (req, res, next) => {
this
.findOne(req.params, req.options)
.then(respond)
.catch(next);
function respond(row) {
if (!row) {
throw new HttpStatusError(404, 'Not Found');
}
res.send(res.transform(row));
}
};
return [
raw,
handle
];
}
query() {
const customQuery = (req) => {
return new Promise((resolve, reject) => {
// TODO: Corregir y adecuar al nuevo funcionamiento
// if (req.query.searchPro == 1 && req.query.fIni && req.query.fFin) {
// options.where.fecha = {
// $between: [new Date(req.query.fIni) || fAct, new Date(req.query.fFin) || fAct]
// };
// }
if (!req.query.filter || req.query.filter === '') return resolve();
const condiciones = [];
const options = {};
options.attributes = _.keys(this.model.rawAttributes);
return this.model.describe().then(fields => {
for (const key in fields) {
const field = fields[key];
const obj = {};
let aux;
let tipo = field.type;
let buscar = (options.attributes == null) ? true : options.attributes.indexOf(key) != -1;
console.log('Revisndo l interpretacion del searchPRO', req.query.searchPro == 1);
if (req.query.searchPro == 1 && buscar && req.query.tipoBus == 'campo') buscar = req.query.campoSel == key;
if (req.query.searchPro == 1 && req.query.tipoBus == 'documento') {
console.log('SearchPro_Ddocumento'.bgWhite.red);
buscar = false;
if (key == 'plantilla_valor') {
obj[key] = {
"$ilike": `%${req.query.filter}%`
};
// xfilter.push(obj);
}
}
if (req.query.searchPro == 1 && req.query.tipoBus == 'flujo') {
console.log('SearchPro_Ddocumento'.bgWhite.red);
buscar = false;
if (key == 'grupo') {
obj[key] = req.query.filter;
// obj[i] = { $ilike:"%"+req.query.filter+"%" };
// xfilter.push(obj);
}
}
if (tipo.indexOf('CHARACTER VARYING') > -1) tipo = 'CHARACTER VARYING';
switch (tipo) {
case 'INTEGER':
aux = parseInt(req.query.filter);
if (!isNaN(aux) && req.query.filter.indexOf("/") == -1) {
obj[key] = aux;
}
break;
case 'USER-DEFINED':
aux = req.query.filter;
for (var j in field.special) {
if (field.special[j].toLowerCase().indexOf(aux.toLowerCase()) == 0) {
obj[key] = field.special[j];
}
}
break;
case 'TIMESTAMP WITH TIME ZONE':
// Busqueda de fechas del tipo: 2016-10-20, 2016/10/20, 20-10-2016, 20/10/2016.
// TODO: No se puede buscar por el mes.
console.log('TIMESTAMP WITH TIME ZONE __________________________'.magenta.bgWhite);
console.log('Primer procesado de fecha __________________'.magenta.bgWhite, procesarFecha(req.query.filter));
var consulta = procesarFecha(req.query.filter);
if (consulta != false) {
console.log('Fecha'.cyan, procesarFecha(req.query.filter));
obj[key] = procesarFecha(req.query.filter);
// condiciones.push(obj);
}
break;
case 'CHARACTER VARYING':
obj[key] = {
"$iLike": `%${req.query.filter}%`
};
break;
case 'TEXT':
obj[key] = {
"$iLike": `%${req.query.filter}%`
};
break;
case 'ARRAY':
// obj[key] = {"$iLike":`%${req.query.filter}%`};
break;
case 'BOOLEAN':
// obj[key] = {"$iLike":`%${req.query.filter}%`};
break;
default:
console.log('DEFAULT__________________________'.magenta.bgWhite, tipo);
obj[key] = req.query.filter;
break;
}
if (obj.hasOwnProperty(key)) {
condiciones.push(obj);
}
}
})
.then(() => {
console.log('Finalizando filtrado custom'.bgCyan.black);
this.custom = condiciones;
console.log('Checking custom condition'.bgCyan.black, this.custom);
return resolve();
});
});
}
const handle = (req, res, next) => {
customQuery(req)
.then(() => {
let flag = false;
if (this.custom !== null) {
flag = true;
req.query.filter = this.custom;
this.custom = null;
}
this
.findAndCountAll(req.query, req.options, flag)
.then(respond)
.catch(next);
});
function respond({
rows,
start,
end,
count
}) {
res.set('Content-Range', `${start}-${end}/${count}`);
if (count > end) {
res.status(206);
} else {
res.status(200);
}
const response = {
total: count,
resultado: rows
}
res.send(res.transform(response));
}
};
return [
raw,
handle
];
}
remove() {
const handle = (req, res, next) => {
this
.findOne(req.params)
.then(destroy)
.then(respond)
.catch(next);
function destroy(row) {
if (!row) {
throw new HttpStatusError(404, 'Not Found');
}
return row.destroy();
}
function respond() {
res.sendStatus(204);
}
};
return [
handle
];
}
update() {
const handle = (req, res, next) => {
console.log('[update] iniciando la modificacion ', req.params, req.body);
this
.findOne(req.params)
.then(updateAttributes)
.then(respond)
.catch(next);
function updateAttributes(row) {
console.log('[update] row', row);
if (!row) {
throw new HttpStatusError(404, 'Not Found');
}
// return row.updateAttributes(req.body);
return row.update(req.body);
}
function respond(row) {
res.send(res.transform(row));
}
};
return [
raw,
handle
];
}
findOne(params, options) {
if (params.hasOwnProperty('id')) {
params[`id_${this.name}`] = params.id;
delete params.id;
}
if (options && options.hasOwnProperty('id')) {
delete options.id;
delete options.audit_usuario;
}
options = _.merge(parse(params, this.model), options);
return this.model.findOne(options);
}
findAndCountAll(params, options, custom) {
let parsed = parse(params, this.model, custom);
options = _(parsed)
.defaults(this.defaults)
.merge(options)
.value();
if (custom) options.where["$or"] = params.filter;
if (params.page) {
options.offset = (params.page === 0 ? 0 : params.page - 1) * options.limit;
}
return this.model
.findAndCountAll(options)
.then(extract);
function extract({
count,
rows
}) {
const start = options.offset;
const end = Math.min(count, options.offset + options.limit);
return {
rows,
start,
end,
count
};
}
}
}
/**
Funcion que procesa una cadena, verifica si tiene el formato de una fecha.
@param {pCadena} Cadena de texto con formato de fecha.
@return Retorna:
EXITO -> un objeto de consulta con formato sequelize.
FALLO -> false.
*/
function procesarFecha(pCadena) {
var fecha = new Date(pCadena);
var anio = null,
inicio = null,
fin = null;
// Identifica el operador usando en la cadena para separar los datos.
var operador = pCadena.indexOf('-') > -1 ? '-' : pCadena.indexOf('/') > -1 ? '/' : null;
// Si existe un operador valido en la cadena.
if (operador != null) {
// Si la cadena no es valida como fecha, se la invierte.
if (fecha == 'Invalid Date') {
fecha = new Date(((pCadena.split(operador)).reverse()).join("-"));
}
// Obtine el año.
anio = fecha.getFullYear();
// Si existe el año.
if (anio != null) {
var vector = pCadena.split(operador)
// Si la longitud del vector es igual a 3.
if (vector.length == 3) {
var indice = vector.indexOf(anio.toString());
// Si el año existe dentro del vector de la cadena.
if (indice > -1) {
// Armado de la fecha inicio y fecha fin.
if (indice == 0) {
inicio = vector[0] + "-" + vector[1] + "-" + vector[2];
fin = vector[0] + "-" + vector[1] + "-" + (parseInt(vector[2]) + 1);
} else if (indice == 2) {
inicio = vector[2] + "-" + vector[1] + "-" + vector[0];
fin = vector[2] + "-" + vector[1] + "-" + (parseInt(vector[0]) + 1);
}
// Armado de la respuesta a retornar.
var respuesta = {
$gte: inicio,
$lt: fin
};
return respuesta;
} else return false; // Fin condicional indice.
} else return false; // Fin condicional longitud vector.
} else return false; // Fin condicional existencia año.
} else return false; // Fin condicional existencia operador.
}
module.exports = ModelHandler;