mirror of
https://github.com/strapi/strapi.git
synced 2025-09-22 14:59:07 +00:00

When doing an 'IN' query it looks like this will incorrectly loop over the values and put them into multiple where clauses. This additional check on the symbol should leave the array untouched and pass it on into the orm for processing.
243 lines
7.2 KiB
Plaintext
243 lines
7.2 KiB
Plaintext
'use strict';
|
|
|
|
/**
|
|
* <%= filename %> service
|
|
*
|
|
* @description: A set of functions similar to controller's actions to avoid code duplication.
|
|
*/
|
|
|
|
// Public dependencies.
|
|
const _ = require('lodash');
|
|
|
|
// Strapi utilities.
|
|
const utils = require('strapi-hook-bookshelf/lib/utils/');
|
|
|
|
module.exports = {
|
|
|
|
/**
|
|
* Promise to fetch all <%= idPluralized %>.
|
|
*
|
|
* @return {Promise}
|
|
*/
|
|
|
|
fetchAll: (params) => {
|
|
// Convert `params` object to filters compatible with Bookshelf.
|
|
const filters = strapi.utils.models.convertParams('<%= globalID.toLowerCase() %>', params);
|
|
// Select field to populate.
|
|
const populate = <%= globalID %>.associations
|
|
.filter(ast => ast.autoPopulate !== false)
|
|
.map(ast => ast.alias);
|
|
|
|
return <%= globalID %>.query(function(qb) {
|
|
_.forEach(filters.where, (where, key) => {
|
|
if (_.isArray(where.value) && where.symbol !== 'IN') {
|
|
for (const value in where.value) {
|
|
qb[value ? 'where' : 'orWhere'](key, where.symbol, where.value[value])
|
|
}
|
|
} else {
|
|
qb.where(key, where.symbol, where.value);
|
|
}
|
|
});
|
|
|
|
if (filters.sort) {
|
|
qb.orderBy(filters.sort.key, filters.sort.order);
|
|
}
|
|
|
|
qb.offset(filters.start);
|
|
qb.limit(filters.limit);
|
|
}).fetchAll({
|
|
withRelated: populate
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Promise to fetch a/an <%= id %>.
|
|
*
|
|
* @return {Promise}
|
|
*/
|
|
|
|
fetch: (params) => {
|
|
// Select field to populate.
|
|
const populate = <%= globalID %>.associations
|
|
.filter(ast => ast.autoPopulate !== false)
|
|
.map(ast => ast.alias);
|
|
|
|
return <%= globalID %>.forge(_.pick(params, 'id')).fetch({
|
|
withRelated: populate
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Promise to count a/an <%= id %>.
|
|
*
|
|
* @return {Promise}
|
|
*/
|
|
|
|
count: (params) => {
|
|
// Convert `params` object to filters compatible with Bookshelf.
|
|
const filters = strapi.utils.models.convertParams('<%= globalID.toLowerCase() %>', params);
|
|
|
|
return <%= globalID %>.query(function(qb) {
|
|
_.forEach(filters.where, (where, key) => {
|
|
if (_.isArray(where.value)) {
|
|
for (const value in where.value) {
|
|
qb[value ? 'where' : 'orWhere'](key, where.symbol, where.value[value])
|
|
}
|
|
} else {
|
|
qb.where(key, where.symbol, where.value);
|
|
}
|
|
});
|
|
}).count();
|
|
},
|
|
|
|
/**
|
|
* Promise to add a/an <%= id %>.
|
|
*
|
|
* @return {Promise}
|
|
*/
|
|
|
|
add: async (values) => {
|
|
// Extract values related to relational data.
|
|
const relations = _.pick(values, <%= globalID %>.associations.map(ast => ast.alias));
|
|
const data = _.omit(values, <%= globalID %>.associations.map(ast => ast.alias));
|
|
|
|
// Create entry with no-relational data.
|
|
const entry = await <%= globalID %>.forge(data).save();
|
|
|
|
// Create relational data and return the entry.
|
|
return <%= globalID %>.updateRelations({ id: entry.id , values: relations });
|
|
},
|
|
|
|
/**
|
|
* Promise to edit a/an <%= id %>.
|
|
*
|
|
* @return {Promise}
|
|
*/
|
|
|
|
edit: async (params, values) => {
|
|
// Extract values related to relational data.
|
|
const relations = _.pick(values, <%= globalID %>.associations.map(ast => ast.alias));
|
|
const data = _.omit(values, <%= globalID %>.associations.map(ast => ast.alias));
|
|
|
|
// Create entry with no-relational data.
|
|
const entry = <%= globalID %>.forge(params).save(data);
|
|
|
|
// Create relational data and return the entry.
|
|
return <%= globalID %>.updateRelations(Object.assign(params, { values: relations }));
|
|
},
|
|
|
|
/**
|
|
* Promise to remove a/an <%= id %>.
|
|
*
|
|
* @return {Promise}
|
|
*/
|
|
|
|
remove: async (params) => {
|
|
params.values = {};
|
|
<%= globalID %>.associations.map(association => {
|
|
switch (association.nature) {
|
|
case 'oneWay':
|
|
case 'oneToOne':
|
|
case 'manyToOne':
|
|
case 'oneToManyMorph':
|
|
params.values[association.alias] = null;
|
|
break;
|
|
case 'oneToMany':
|
|
case 'manyToMany':
|
|
case 'manyToManyMorph':
|
|
params.values[association.alias] = [];
|
|
break;
|
|
default:
|
|
}
|
|
});
|
|
|
|
await <%= globalID %>.updateRelations(params);
|
|
|
|
return <%= globalID %>.forge(params).destroy();
|
|
},
|
|
|
|
/**
|
|
* Promise to search a/an <%= id %>.
|
|
*
|
|
* @return {Promise}
|
|
*/
|
|
|
|
search: async (params) => {
|
|
// Convert `params` object to filters compatible with Bookshelf.
|
|
const filters = strapi.utils.models.convertParams('<%= globalID.toLowerCase() %>', params);
|
|
// Select field to populate.
|
|
const populate = <%= globalID %>.associations
|
|
.filter(ast => ast.autoPopulate !== false)
|
|
.map(ast => ast.alias);
|
|
|
|
const associations = <%= globalID %>.associations.map(x => x.alias);
|
|
const searchText = Object.keys(<%= globalID %>._attributes)
|
|
.filter(attribute => attribute !== <%= globalID %>.primaryKey && !associations.includes(attribute))
|
|
.filter(attribute => ['string', 'text'].includes(<%= globalID %>._attributes[attribute].type));
|
|
|
|
const searchNoText = Object.keys(<%= globalID %>._attributes)
|
|
.filter(attribute => attribute !== <%= globalID %>.primaryKey && !associations.includes(attribute))
|
|
.filter(attribute => !['string', 'text', 'boolean', 'integer', 'decimal', 'float'].includes(<%= globalID %>._attributes[attribute].type));
|
|
|
|
const searchInt = Object.keys(<%= globalID %>._attributes)
|
|
.filter(attribute => attribute !== <%= globalID %>.primaryKey && !associations.includes(attribute))
|
|
.filter(attribute => ['integer', 'decimal', 'float'].includes(<%= globalID %>._attributes[attribute].type));
|
|
|
|
const searchBool = Object.keys(<%= globalID %>._attributes)
|
|
.filter(attribute => attribute !== <%= globalID %>.primaryKey && !associations.includes(attribute))
|
|
.filter(attribute => ['boolean'].includes(<%= globalID %>._attributes[attribute].type));
|
|
|
|
const query = (params._q || '').replace(/[^a-zA-Z0-9.-\s]+/g, '');
|
|
|
|
return <%= globalID %>.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 (<%= globalID %>.client) {
|
|
case 'pg': {
|
|
const searchQuery = searchText.map(attribute =>
|
|
_.toLower(attribute) === attribute
|
|
? `to_tsvector(${attribute})`
|
|
: `to_tsvector('${attribute}')`
|
|
);
|
|
|
|
qb.orWhereRaw(`${searchQuery.join(' || ')} @@ to_tsquery(?)`, query);
|
|
break;
|
|
}
|
|
default:
|
|
qb.orWhereRaw(`MATCH(${searchText.join(',')}) AGAINST(? IN BOOLEAN MODE)`, `*${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({
|
|
width: populate
|
|
});
|
|
}
|
|
};
|