mirror of
https://github.com/strapi/strapi.git
synced 2025-10-11 16:13:12 +00:00
Merge pull request #1520 from strapi/api-search
Add search in generated API
This commit is contained in:
commit
b48dced09d
@ -15,7 +15,11 @@ module.exports = {
|
||||
*/
|
||||
|
||||
find: async (ctx) => {
|
||||
return strapi.services.<%= id %>.fetchAll(ctx.query);
|
||||
if (ctx.query._q) {
|
||||
return strapi.services.<%= id %>.search(ctx.query);
|
||||
} else {
|
||||
return strapi.services.<%= id %>.fetchAll(ctx.query);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -154,5 +154,89 @@ module.exports = {
|
||||
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
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -15,7 +15,11 @@ module.exports = {
|
||||
*/
|
||||
|
||||
find: async (ctx) => {
|
||||
return strapi.services.<%= id %>.fetchAll(ctx.query);
|
||||
if (ctx.query._q) {
|
||||
return strapi.services.<%= id %>.search(ctx.query);
|
||||
} else {
|
||||
return strapi.services.<%= id %>.fetchAll(ctx.query);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -142,5 +142,53 @@ module.exports = {
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Promise to search a/an <%= id %>.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
|
||||
search: async (params) => {
|
||||
// Convert `params` object to filters compatible with Mongo.
|
||||
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)
|
||||
.join(' ');
|
||||
|
||||
const $or = Object.keys(<%= globalID %>.attributes).reduce((acc, curr) => {
|
||||
switch (<%= globalID %>.attributes[curr].type) {
|
||||
case 'integer':
|
||||
case 'float':
|
||||
case 'decimal':
|
||||
if (!_.isNaN(_.toNumber(params._q))) {
|
||||
return acc.concat({ [curr]: params._q });
|
||||
}
|
||||
|
||||
return acc;
|
||||
case 'string':
|
||||
case 'text':
|
||||
case 'password':
|
||||
return acc.concat({ [curr]: { $regex: params._q, $options: 'i' } });
|
||||
case 'boolean':
|
||||
if (params._q === 'true' || params._q === 'false') {
|
||||
return acc.concat({ [curr]: params._q === 'true' });
|
||||
}
|
||||
|
||||
return acc;
|
||||
default:
|
||||
return acc;
|
||||
}
|
||||
}, []);
|
||||
|
||||
return <%= globalID %>
|
||||
.find({ $or })
|
||||
.sort(filters.sort)
|
||||
.skip(filters.start)
|
||||
.limit(filters.limit)
|
||||
.populate(populate);
|
||||
}
|
||||
};
|
||||
|
@ -48,7 +48,9 @@ module.exports = function (options, cb) {
|
||||
}
|
||||
|
||||
try {
|
||||
const compiled = _.template(contents);
|
||||
const compiled = _.template(contents, {
|
||||
interpolate: /<%=([\s\S]+?)%>/g
|
||||
});
|
||||
contents = compiled(options);
|
||||
|
||||
// With Lodash templates, HTML entities are escaped by default.
|
||||
|
Loading…
x
Reference in New Issue
Block a user