app2-api/helpers/service.helper.js

325 lines
11 KiB
JavaScript
Raw Normal View History

2019-05-09 16:23:54 +00:00
const _ = require('lodash');
2019-05-23 09:40:50 +00:00
function _debugModelInfo(model) {
if (!model.name)
return;
console.log("\n\n----------------------------------\n",
model.name,
"\n----------------------------------");
console.log("\nAttributes");
if (model.rawAttributes) {
for (let attr of Object.keys(model.rawAttributes)) {
console.log(model.name + '.' + attr);
}
}
console.log("\nAssociations");
if (model.associations) {
for (let assoc of Object.keys(model.associations)) {
console.log('as: ', model.associations[assoc].as, 'type: ', model.associations[assoc].associationType);
for (let accessor of Object.keys(model.associations[assoc].accessors)) {
console.log(accessor);
console.log(model.name + '.' + model.associations[assoc].accessors[accessor] + '()');
}
}
}
if (model.Instance && model.Instance.super_) {
console.log("\nCommon");
for (let func of Object.keys(model.Instance.super_.prototype)) {
if (func === 'constructor' || func === 'sequelize')
continue;
console.log(model.name + '.' + func + '()');
}
}
console.log("\n\n----------------------------------\n",
"END",
"\n----------------------------------");
return;
}
2019-07-09 20:13:41 +00:00
function foundModelAssociation(model, associationName) {
let result = false;
2019-05-23 09:40:50 +00:00
2019-07-09 20:13:41 +00:00
if (typeof model !== 'function' || typeof model.associations !== 'object') {
2019-05-23 09:40:50 +00:00
throw new Error("Model should be an object with the 'associations' property.");
2019-07-09 20:13:41 +00:00
};
2019-05-23 09:40:50 +00:00
Object.keys(model.associations).forEach((key) => {
2019-07-09 20:13:41 +00:00
const nameAs = model.associations[key].as;
if (nameAs.toUpperCase() == associationName.toUpperCase()) {
const item = model.associations[key];
const accessors = item.accessors;
result = {
name: item.as,
type: item.associationType,
accessors: accessors,
countFunc: accessors['count'],
getFunc: accessors['get'],
}
}
})
2019-05-23 09:40:50 +00:00
return result;
}
2019-05-09 16:23:54 +00:00
const parseParamsToFindOptions = (params) => {
const result = {};
2019-08-05 17:44:16 +00:00
2019-05-23 09:40:50 +00:00
// Include All
result.include = (params.includeAll) ? [{ all: true }] : [];
2019-05-09 16:23:54 +00:00
2019-08-05 17:44:16 +00:00
// Query & params
result.where = {};
2019-05-09 16:23:54 +00:00
if (params.query) {
2019-08-05 17:44:16 +00:00
result.where = params.query;
2019-05-09 16:23:54 +00:00
}
if (params.params) {
2019-08-05 17:44:16 +00:00
result.where = Object.assign(result.where, params.params);
2019-05-09 16:23:54 +00:00
}
// Paginate
if (params.paginate) {
result.offset = params.paginate.limit * (params.paginate.page - 1);
2019-07-31 13:36:57 +00:00
result.limit = params.paginate.limit; // result.offset + params.paginate.limit;
2019-05-09 16:23:54 +00:00
}
// Order
2019-07-09 16:56:22 +00:00
result.order = [];
2019-05-09 16:23:54 +00:00
if (params.sort) {
Object.keys(params.sort).forEach(key => {
let dir = params.sort[key] ? 'ASC' : 'DESC';
result.order.push([key, dir])
});
}
// Attributes
if (params.fields) {
if (params.fields.validFields) {
result.attributes = params.fields.validFields
}
if (params.fields.invalidFields && Array.isArray(params.fields.invalidFields)) {
result.attributes = {
...result.attributes,
exclude: params.fields.invalidFields
}
}
}
return result;
}
2019-07-09 20:13:41 +00:00
function hasAssociation(params) {
return (params) ? ((params.params) ? ((params.params.association) ? params.params.association : false ) : false ) : false;
}
2019-05-09 16:23:54 +00:00
const defaultOptions = {};
const generateService = (model, extraMethods = {}, options = defaultOptions) => {
2019-07-17 12:07:35 +00:00
2019-05-09 16:23:54 +00:00
const defaultService = {
2019-07-09 20:13:41 +00:00
fetchAssociation: async(params, context) => {
2019-08-05 10:55:24 +00:00
const _fetchOne = async (params, context) => {
const findOptions = parseParamsToFindOptions(params);
return await model.scope(context.scopes).findOne(findOptions);
};
2019-07-09 20:13:41 +00:00
const associationName = hasAssociation(params);
2019-07-09 20:20:59 +00:00
console.log('associationName => ', associationName);
2019-07-09 20:13:41 +00:00
delete params.params.association;
const associationInfo = foundModelAssociation(model, associationName);
if (associationInfo) {
2019-08-14 19:42:40 +00:00
console.log(associationInfo);
2019-08-14 19:42:23 +00:00
const master = await _fetchOne({ params: params.params }, context);
2019-08-14 19:42:40 +00:00
console.log(master);
2019-08-05 10:55:24 +00:00
const detailRows = await master[associationInfo.getFunc]();
2019-07-09 20:13:41 +00:00
const details = {
2019-08-05 10:55:24 +00:00
rows: detailRows,
count: detailRows.length
2019-07-09 20:13:41 +00:00
}
2019-08-14 19:42:23 +00:00
console.log(details);
2019-07-09 20:13:41 +00:00
return details;
} else {
2019-07-09 20:20:59 +00:00
return {
rows: ["Association not exists"],
count: 0
};
2019-07-09 20:13:41 +00:00
}
},
2019-05-09 16:23:54 +00:00
fetchAll: async (params, context) => {
2019-07-09 20:13:41 +00:00
if (hasAssociation(params)) {
return defaultService.fetchAssociation(params, context)
} else {
const findOptions = parseParamsToFindOptions(params);
2019-07-31 10:40:36 +00:00
// Necesario para el cálculo del count
2019-08-20 15:37:59 +00:00
// https://github.com/sequelize/sequelize/issues/10557
2019-07-31 10:40:36 +00:00
findOptions.distinct = true;
2019-08-20 12:10:49 +00:00
2019-07-17 12:07:35 +00:00
const result = await model.scope(context.scopes).findAndCountAll(findOptions);
if (extraMethods.afterFetchAll) {
return extraMethods.afterFetchAll(result, params, context);
} else {
return result;
}
2019-07-09 20:13:41 +00:00
}
2019-05-09 16:23:54 +00:00
},
fetchOne: async (params, context) => {
2019-05-23 09:40:50 +00:00
const findOptions = parseParamsToFindOptions(params);
2019-07-18 18:13:07 +00:00
const result = await model.scope(context.scopes).findOne(findOptions);
2019-07-17 12:07:35 +00:00
if (extraMethods.afterFetchOne) {
return extraMethods.afterFetchOne(result, params, context);
} else {
return result;
}
2019-05-09 16:23:54 +00:00
},
count: async (params, context) => {
2019-05-23 09:40:50 +00:00
const findOptions = parseParamsToFindOptions(params);
2019-07-17 12:07:35 +00:00
const result = await model.scope(context.scopes).count(findOptions);
if (extraMethods.afterCount) {
return extraMethods.afterCount(result, params, context);
} else {
return result;
2019-08-05 17:44:16 +00:00
}
2019-05-09 16:23:54 +00:00
},
create: async (values, context) => {
2019-08-16 14:39:26 +00:00
if (extraMethods.beforeCreate) {
values = extraMethods.beforeCreate(values, context);
}
2019-08-16 16:37:13 +00:00
var result = await model.scope(context.scopes).create(values);
if (extraMethods.afterCreate) {
result = extraMethods.beforeCreate(result, context);
}
return result;
2019-05-09 16:23:54 +00:00
},
update: async (params, values, context) => {
2019-05-23 09:40:50 +00:00
const findOptions = parseParamsToFindOptions(params);
2019-08-06 17:23:56 +00:00
if (extraMethods.beforeUpdate) {
values = extraMethods.beforeUpdate(values, findOptions, context);
}
2019-08-18 21:15:34 +00:00
console.log(values, findOptions);
2019-07-17 12:07:35 +00:00
return await model.scope(context.scopes).update(values, findOptions)
2019-05-09 16:23:54 +00:00
},
delete: async (params, context) => {
2019-05-23 09:40:50 +00:00
const findOptions = parseParamsToFindOptions(params);
2019-07-17 12:07:35 +00:00
const numAffectedRows = await model.scope(context.scopes).destroy(findOptions);
2019-08-16 16:37:13 +00:00
var result = (numAffectedRows > 0);
if (extraMethods.afterDelete) {
extraMethods.afterDelete(values, findOptions, context);
}
return result;
2019-05-09 16:23:54 +00:00
},
search: async (params, context) => {
// Convert `params` object to filters compatible with Bookshelf.
const filters = strapi.utils.models.convertParams('post', params);
// Select field to populate.
const populate = Post.associations
.filter(ast => ast.autoPopulate !== false)
.map(ast => ast.alias);
const associations = Post.associations.map(x => x.alias);
const searchText = Object.keys(Post._attributes)
.filter(attribute => attribute !== Post.primaryKey && !associations.includes(attribute))
.filter(attribute => ['string', 'text'].includes(Post._attributes[attribute].type));
const searchNoText = Object.keys(Post._attributes)
.filter(attribute => attribute !== Post.primaryKey && !associations.includes(attribute))
.filter(attribute => !['string', 'text', 'boolean', 'integer', 'decimal', 'float'].includes(Post._attributes[attribute].type));
const searchInt = Object.keys(Post._attributes)
.filter(attribute => attribute !== Post.primaryKey && !associations.includes(attribute))
.filter(attribute => ['integer', 'decimal', 'float'].includes(Post._attributes[attribute].type));
const searchBool = Object.keys(Post._attributes)
.filter(attribute => attribute !== Post.primaryKey && !associations.includes(attribute))
.filter(attribute => ['boolean'].includes(Post._attributes[attribute].type));
const query = (params._q || '').replace(/[^a-zA-Z0-9.-\s]+/g, '');
return Post.query(qb => {
// Search in columns which are not text value.
searchNoText.forEach(attribute => {
qb.orWhereRaw(`LOWER(${attribute}) LIKE '%${_.toLower(query)}%'`);
});
if (!_.isNaN(_.toNumber(query))) {
searchInt.forEach(attribute => {
qb.orWhereRaw(`${attribute} = ${_.toNumber(query)}`);
});
}
if (query === 'true' || query === 'false') {
searchBool.forEach(attribute => {
qb.orWhereRaw(`${attribute} = ${_.toNumber(query === 'true')}`);
});
}
// Search in columns with text using index.
switch (Post.client) {
case 'mysql':
qb.orWhereRaw(`MATCH(${searchText.join(',')}) AGAINST(? IN BOOLEAN MODE)`, `*${query}*`);
break;
case 'pg':
{
const searchQuery = searchText.map(attribute =>
_.toLower(attribute) === attribute ?
`to_tsvector(${attribute})` :
`to_tsvector('${attribute}')`
);
qb.orWhereRaw(`${searchQuery.join(' || ')} @@ to_tsquery(?)`, query);
break;
}
}
if (filters.sort) {
qb.orderBy(filters.sort.key, filters.sort.order);
}
if (filters.skip) {
qb.offset(_.toNumber(filters.skip));
}
if (filters.limit) {
qb.limit(_.toNumber(filters.limit));
}
}).fetchAll({
withRelated: populate
});
}
}
return {
...defaultService,
//...associationControllers
...extraMethods
}
}
module.exports = {
2019-05-23 09:40:50 +00:00
_debugModelInfo,
2019-05-09 16:23:54 +00:00
generateService,
parseParamsToFindOptions,
defaultOptions
}