282 lines
9.7 KiB
JavaScript
282 lines
9.7 KiB
JavaScript
const _ = require('lodash');
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
function foundModelAssociation(model, associationName) {
|
|
let result = false;
|
|
|
|
if (typeof model !== 'function' || typeof model.associations !== 'object') {
|
|
throw new Error("Model should be an object with the 'associations' property.");
|
|
};
|
|
|
|
Object.keys(model.associations).forEach((key) => {
|
|
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'],
|
|
}
|
|
}
|
|
})
|
|
return result;
|
|
}
|
|
|
|
const parseParamsToFindOptions = (params) => {
|
|
const result = {};
|
|
// Include All
|
|
result.include = (params.includeAll) ? [{ all: true }] : [];
|
|
|
|
// Query
|
|
if (params.query) {
|
|
result.query = params.query
|
|
}
|
|
|
|
// Params
|
|
result.where = {};
|
|
if (params.params) {
|
|
result.where = params.params
|
|
}
|
|
|
|
// Paginate
|
|
if (params.paginate) {
|
|
result.offset = params.paginate.limit * (params.paginate.page - 1);
|
|
result.limit = result.offset + params.paginate.limit;
|
|
}
|
|
|
|
// Order
|
|
result.order = [];
|
|
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;
|
|
}
|
|
|
|
function hasAssociation(params) {
|
|
return (params) ? ((params.params) ? ((params.params.association) ? params.params.association : false ) : false ) : false;
|
|
}
|
|
|
|
const defaultOptions = {};
|
|
|
|
const generateService = (model, extraMethods = {}, options = defaultOptions) => {
|
|
const defaultService = {
|
|
fetchAssociation: async(params, context) => {
|
|
const associationName = hasAssociation(params);
|
|
console.log('associationName => ', associationName);
|
|
delete params.params.association;
|
|
|
|
const associationInfo = foundModelAssociation(model, associationName);
|
|
if (associationInfo) {
|
|
const master = await defaultService.fetchOne(params, context);
|
|
const details = {
|
|
rows: await master[associationInfo.getFunc](),
|
|
count: await master[associationInfo.countFunc]()
|
|
}
|
|
return details;
|
|
} else {
|
|
return {
|
|
rows: ["Association not exists"],
|
|
count: 0
|
|
};
|
|
}
|
|
},
|
|
|
|
fetchAll: async (params, context) => {
|
|
if (hasAssociation(params)) {
|
|
return defaultService.fetchAssociation(params, context)
|
|
} else {
|
|
const findOptions = parseParamsToFindOptions(params);
|
|
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
|
|
console.log(findOptions);
|
|
const result = await model.findAndCountAll(findOptions);
|
|
console.log(result);
|
|
return result;
|
|
}
|
|
},
|
|
|
|
fetchOne: async (params, context) => {
|
|
const findOptions = parseParamsToFindOptions(params);
|
|
console.log(findOptions);
|
|
return await model.findOne({
|
|
where: findOptions.where,
|
|
include: findOptions.include
|
|
});
|
|
},
|
|
|
|
count: async (params, context) => {
|
|
const findOptions = parseParamsToFindOptions(params);
|
|
return await model.count(findOptions);
|
|
},
|
|
|
|
create: async (values, context) => {
|
|
return await model.create(values);
|
|
},
|
|
|
|
update: async (params, values, context) => {
|
|
const findOptions = parseParamsToFindOptions(params);
|
|
return await model.update(values, findOptions)
|
|
},
|
|
|
|
delete: async (params, context) => {
|
|
const findOptions = parseParamsToFindOptions(params);
|
|
const numAffectedRows = await model.destroy(findOptions);
|
|
return (numAffectedRows > 0);
|
|
},
|
|
|
|
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 = {
|
|
_debugModelInfo,
|
|
generateService,
|
|
parseParamsToFindOptions,
|
|
defaultOptions
|
|
} |