alphascript-server
Version:
CRUD operations for mongo and other functionalities to get started quickly in any CMS project
379 lines (343 loc) • 11.8 kB
JavaScript
var api = require('../../../');
var moment = require('moment');
var objectPath = require("object-path");
var PdfTable = require('voilab-pdf-table');
var PdfDocument = require('pdfkit');
module.exports = {
getMetadata: function (reportKey) {
var report = api.reportMap[reportKey];
return function (req, res) {
res.json({
title: report.title,
fields: report.fields
});
};
},
getReport: function (reportKey) {
var report = api.reportMap[reportKey];
return function (req, res) {
var params = {},
invokes = [],
i, field;
//SELECT
var project = {},
requires = [],
toRemove = [];
if (typeof req.query.select !== 'undefined') params.select = req.query.select instanceof Array ? req.query.select : [req.query.select];
else return res.status(400).send("Deve incluir pelo menos 1 campo no relatório");
for (i = 0; i < params.select.length; i++) {
field = report.fields[parseInt(params.select[i])];
if (typeof field.name !== 'undefined') {
params.select[i] = field.name;
continue;
}
invokes.push(field.invoke);
field.requires.forEach(function (require) {
if (requires.indexOf(require) !== -1) return;
requires.push(require);
});
params.select.splice(i, 1);
i--;
}
requires.forEach(function (require) {
if (params.select.indexOf(require) !== -1) return;
params.select.push(require);
toRemove.push(require);
});
params.select.forEach(function (subselect) {
project[subselect] = 1;
});
//SORT
var sort = undefined;
try {
params.sort = JSON.parse(req.query.sort);
if (typeof params.sort.field !== 'undefined' && typeof params.sort.type !== 'undefined') {
field = report.fields[parseInt(params.sort.field)];
if (typeof field.name === 'undefined') {
sort = function (a, b) {
if (a[field.invoke] < b[field.invoke])
return -1;
if (a[field.invoke] > b[field.invoke])
return 1;
return 0;
};
} else {
sort = {};
sort[field.name] = params.sort.type;
}
}
} catch (err) {
//api.error.log(err);
}
//AGGREGATING OPERATOR
params.aggregator = "$and";
try {
var aggregator = JSON.parse(req.query.aggregator);
params.aggregator = aggregator.value;
} catch (err) {
//api.error.log(err);
}
//QUERY
if (typeof req.query.query !== 'undefined') params.query = req.query.query instanceof Array ? req.query.query : [req.query.query];
var query = {};
query[params.aggregator] = [];
var invokeQuery = [];
for (i = 0; i < (params.query || []).length; i++) {
var subquery = params.query[i];
try {
subquery = JSON.parse(subquery);
} catch (err) {
api.error.log(err);
return res.status(400).send("Não foi possível formular a sua busca com os dados fornecidos");
}
if (subquery.field && subquery.field.type === 'Boolean') subquery.operator = "equals";
if (typeof subquery.field === 'undefined' || typeof subquery.operator === 'undefined') {
return res.status(400).send("Erro num dos filtros definidos");
}
var assembledSubquery = assembleQuery(subquery.field, subquery.operator, subquery.value);
if (typeof subquery.field.name === 'undefined') {
invokeQuery.push(assembledSubquery);
} else {
query[params.aggregator].push(assembledSubquery);
}
}
//ASSEMBLE AGGREGATE STAGES
var aggregate = [];
report.aggregate.forEach(function (stage) {
aggregate.push(stage);
});
if (query[params.aggregator].length > 0) aggregate.push({ $match: query });
aggregate.push({ $project: project });
if (typeof sort === 'object') aggregate.push({ $sort: sort });
//GET DATA FROM DB
var db = typeof report.db === 'function' ? report.db(req) : report.db;
db[report.model].aggregate(aggregate).allowDiskUse(true)/*.cursor({ batchSize: 1000, async: true })*/.exec(function (err, items) {
if (err) {
if (err.code === 16389) return res.status(500).send("Listagem solicitada excede o tamanho máximo permitido, deve filtrar os seus dados");
api.error.log(err);
return res.status(500).send(api.error.DB_GENERIC);
}
//ASSEMBLE ITEMS
items = items.filter(function (item) {
//SET DYNAMIC FIELDS
if (invokes.length > 0 || invokeQuery.length > 0) {
invokes.forEach(function (invoke) {
item[invoke] = report.invoke[invoke](item, items);
});
var invalid = invokeQuery.some(function (subquery) {
return !subquery.invoke(item[subquery.field]);
});
if (invalid) return false;
}
//CLEANUP
toRemove.forEach(function (key) {
objectPath.del(item, key);
});
return true;
});
//SET DYNAMIC SORT
if (typeof sort === 'function') items.sort(sort);
//ASSEMBLE RESPONSE
if (req.query.xls) {
//on excel
var xls = { sheets: [] };
var xlsHeader = {};
//headers
invokes.forEach(function (invoke) {
params.select.push(invoke);
});
params.select.forEach(function (select) {
if (toRemove.indexOf(select) !== -1) return;
var field = report.fields.find(function (field) {
return field.name === select || field.invoke === select;
});
var key = typeof field.name === 'undefined' ? field.invoke : field.name;
xlsHeader[key] = field.caption;
});
var filename = report.title + '_' + moment().format('YYYY-MM-DD') + '.xlsx';
xls.sheets.push({ header: xlsHeader, sheetName: 'listagem', items: items });
res.setHeader('Content-Type', 'application/vnd.openxmlformats');
res.setHeader("Content-Disposition", "attachment; filename=" + filename);
res.send(api.xlsx.fromJson(xls));
} else if (req.query.pdf) {
//on pdf
var pdf = new PdfDocument({
autoFirstPage: false,
size: [842, 595],
bufferPages: true,
});
pdf.fontSize(8);
//headers
invokes.forEach(function (invoke) {
params.select.push(invoke);
});
var cols = params.select.filter(function (select) {
return toRemove.indexOf(select) === -1;
});
cols = cols.map(function (select) {
var field = report.fields.find(function (field) {
return field.name === select || field.invoke === select;
});
var key = typeof field.name === 'undefined' ? field.invoke : field.name;
return {
field: key,
title: field.caption,
width: (842 - 130) / cols.length
};
});
var table = new PdfTable(pdf, { bottomMargin: 30 });
table.setColumnsDefaults({
headerBorder: 'LTBR',
align: 'left'
}).addColumns(cols).onPageAdded(function (tb) {
tb.addHeader();
});
pdf.addPage();
items = items.map(function (item) {
var _item = {};
cols.forEach(function (col) {
_item[col.field] = objectPath.get(item, col.field);
});
return _item;
});
table.addBody(items);
pdf.pipe(res);
return pdf.end();
} else {
//on screen
res.json(items);
}
});
};
}
};
function assembleQuery(field, operator, value) {
//assert if field is dynamic
var mongo, fieldPointer;
if (typeof field.name === 'undefined') {
fieldPointer = field.invoke;
mongo = false;
} else {
fieldPointer = field.name;
mongo = true;
}
//parse value data type
if (field.type === 'Date') value = value ? new Date(value) : undefined;
else if (field.type === 'Number') value = value ? parseFloat(value) : undefined;
var parts = fieldPointer.split('.'),
subquery = {},
criteriaMain, criteriaNull;
if (mongo) {
var key;
switch (operator) {
case "greaterThan":
key = "$gt";
subquery[fieldPointer] = {};
subquery[fieldPointer][key] = value;
break;
case "greaterThanOrEquals":
key = "$gte";
subquery[fieldPointer] = {};
subquery[fieldPointer][key] = value;
break;
case "lesserThan":
key = "$lt";
subquery[fieldPointer] = {};
subquery[fieldPointer][key] = value;
break;
case "lesserThanOrEquals":
key = "$lte";
subquery[fieldPointer] = {};
subquery[fieldPointer][key] = value;
break;
case "notEquals":
key = "$ne";
subquery[fieldPointer] = {};
subquery[fieldPointer][key] = value;
break;
default:
break;
}
if (!key) {
switch (operator) {
case "contains":
subquery[fieldPointer] = new RegExp('.*' + value + '.*', 'i');
break;
case "startsWith":
subquery[fieldPointer] = new RegExp('^' + value + '.*', 'i');
break;
case "endsWith":
subquery[fieldPointer] = new RegExp('.*' + value + '$', 'i');
break;
case "notExists":
subquery[fieldPointer] = { $exists: false };
break;
default:
subquery[fieldPointer] = value;
break;
}
}
} else {
subquery.field = fieldPointer;
switch (operator) {
case "greaterThan":
subquery.invoke = function (thisValue) {
return thisValue > value;
};
break;
case "greaterThanOrEquals":
subquery.invoke = function (thisValue) {
return thisValue >= value;
};
break;
case "lesserThan":
subquery.invoke = function (thisValue) {
return thisValue < value;
};
break;
case "lesserThanOrEquals":
subquery.invoke = function (thisValue) {
return thisValue <= value;
};
break;
case "notEquals":
subquery.invoke = function (thisValue) {
return thisValue !== value;
};
break;
case "equals":
subquery.invoke = function (thisValue) {
return thisValue === value;
};
break;
case "contains":
subquery.invoke = function (thisValue) {
return new RegExp('.*' + value + '.*', 'i').test(thisValue);
};
break;
case "startsWith":
subquery.invoke = function (thisValue) {
return new RegExp('^' + value + '.*', 'i').test(thisValue);
};
break;
case "endsWith":
subquery.invoke = function (thisValue) {
return new RegExp('.*' + value + '$', 'i').test(thisValue);
};
break;
case "notExists":
subquery.invoke = function (thisValue) {
return typeof thisValue === 'undefined';
};
break;
case "exists":
subquery.invoke = function (thisValue) {
return typeof thisValue !== 'undefined';
};
break;
default:
console.log('unknown operator: ' + operator);
}
}
return subquery;
}