2017-09-18 18:20:33 +02:00
|
|
|
const _ = require('lodash');
|
2019-03-13 19:27:18 +01:00
|
|
|
const { convertRestQueryParams, buildQuery } = require('strapi-utils');
|
2017-09-18 18:20:33 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
module.exports = ({ model }) => ({
|
|
|
|
find(params, populate, raw = false) {
|
2019-03-13 19:27:18 +01:00
|
|
|
const filters = convertRestQueryParams(params);
|
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
return model
|
|
|
|
.query(buildQuery({ model, filters }))
|
2019-03-13 19:27:18 +01:00
|
|
|
.fetchAll({
|
2019-04-11 16:19:15 +02:00
|
|
|
withRelated: populate || model.associations.map(x => x.alias),
|
2019-03-13 19:27:18 +01:00
|
|
|
})
|
2019-03-29 16:53:25 +01:00
|
|
|
.then(data => (raw ? data.toJSON() : data));
|
2017-06-17 17:01:50 +02:00
|
|
|
},
|
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
count(params = {}) {
|
2019-03-13 19:27:18 +01:00
|
|
|
const { where } = convertRestQueryParams(params);
|
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
return model.query(buildQuery({ model, filters: { where } })).count();
|
2017-06-17 17:01:50 +02:00
|
|
|
},
|
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
search(params, populate, raw = false) {
|
|
|
|
const associations = model.associations.map(x => x.alias);
|
|
|
|
const searchText = Object.keys(model._attributes)
|
|
|
|
.filter(
|
|
|
|
attribute =>
|
|
|
|
attribute !== model.primaryKey && !associations.includes(attribute)
|
|
|
|
)
|
|
|
|
.filter(attribute =>
|
|
|
|
['string', 'text'].includes(model._attributes[attribute].type)
|
|
|
|
);
|
2018-06-07 16:14:04 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
const searchInt = Object.keys(model._attributes)
|
|
|
|
.filter(
|
|
|
|
attribute =>
|
|
|
|
attribute !== model.primaryKey && !associations.includes(attribute)
|
|
|
|
)
|
2019-03-13 19:27:18 +01:00
|
|
|
.filter(attribute =>
|
2019-04-11 16:19:15 +02:00
|
|
|
['integer', 'biginteger', 'decimal', 'float'].includes(
|
|
|
|
model._attributes[attribute].type
|
|
|
|
)
|
2019-03-13 19:27:18 +01:00
|
|
|
);
|
2018-06-12 11:32:13 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
const searchBool = Object.keys(model._attributes)
|
|
|
|
.filter(
|
|
|
|
attribute =>
|
|
|
|
attribute !== model.primaryKey && !associations.includes(attribute)
|
|
|
|
)
|
|
|
|
.filter(attribute =>
|
|
|
|
['boolean'].includes(model._attributes[attribute].type)
|
|
|
|
);
|
2018-06-12 11:32:13 +02:00
|
|
|
|
|
|
|
const query = (params.search || '').replace(/[^a-zA-Z0-9.-\s]+/g, '');
|
2018-06-07 16:14:04 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
return model
|
|
|
|
.query(qb => {
|
|
|
|
if (!_.isNaN(_.toNumber(query))) {
|
|
|
|
searchInt.forEach(attribute => {
|
|
|
|
qb.orWhereRaw(`${attribute} = ${_.toNumber(query)}`);
|
|
|
|
});
|
|
|
|
}
|
2018-06-12 11:32:13 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
if (query === 'true' || query === 'false') {
|
|
|
|
searchBool.forEach(attribute => {
|
|
|
|
qb.orWhereRaw(`${attribute} = ${_.toNumber(query === 'true')}`);
|
|
|
|
});
|
|
|
|
}
|
2018-06-12 11:32:13 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
// Search in columns with text using index.
|
|
|
|
switch (model.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;
|
|
|
|
}
|
|
|
|
case 'sqlite3':
|
|
|
|
searchText.map(attribute => {
|
|
|
|
qb.orWhere(`${attribute}`, 'LIKE', `%${query}%`);
|
|
|
|
});
|
2018-06-07 17:24:09 +02:00
|
|
|
}
|
2018-06-07 16:14:04 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
if (params.sort) {
|
|
|
|
qb.orderBy(params.sort.key, params.sort.order);
|
|
|
|
}
|
2018-06-07 16:14:04 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
if (params.skip) {
|
|
|
|
qb.offset(_.toNumber(params.skip));
|
|
|
|
}
|
2018-06-07 16:14:04 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
if (params.limit) {
|
|
|
|
qb.limit(_.toNumber(params.limit));
|
|
|
|
}
|
|
|
|
})
|
2019-03-13 19:27:18 +01:00
|
|
|
.fetchAll({
|
|
|
|
withRelated: populate || associations,
|
|
|
|
})
|
|
|
|
.then(data => (raw ? data.toJSON() : data));
|
2018-06-07 14:35:09 +02:00
|
|
|
},
|
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
countSearch(params = {}) {
|
|
|
|
const associations = model.associations.map(x => x.alias);
|
|
|
|
const searchText = Object.keys(model._attributes)
|
|
|
|
.filter(
|
|
|
|
attribute =>
|
|
|
|
attribute !== model.primaryKey && !associations.includes(attribute)
|
|
|
|
)
|
|
|
|
.filter(attribute =>
|
|
|
|
['string', 'text'].includes(model._attributes[attribute].type)
|
|
|
|
);
|
2018-06-07 17:24:09 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
const searchInt = Object.keys(model._attributes)
|
|
|
|
.filter(
|
|
|
|
attribute =>
|
|
|
|
attribute !== model.primaryKey && !associations.includes(attribute)
|
|
|
|
)
|
2019-03-13 19:27:18 +01:00
|
|
|
.filter(attribute =>
|
2019-04-11 16:19:15 +02:00
|
|
|
['integer', 'biginteger', 'decimal', 'float'].includes(
|
|
|
|
model._attributes[attribute].type
|
|
|
|
)
|
2019-03-13 19:27:18 +01:00
|
|
|
);
|
2018-06-12 11:32:13 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
const searchBool = Object.keys(model._attributes)
|
|
|
|
.filter(
|
|
|
|
attribute =>
|
|
|
|
attribute !== model.primaryKey && !associations.includes(attribute)
|
|
|
|
)
|
|
|
|
.filter(attribute =>
|
|
|
|
['boolean'].includes(model._attributes[attribute].type)
|
|
|
|
);
|
2018-06-12 11:32:13 +02:00
|
|
|
|
|
|
|
const query = (params.search || '').replace(/[^a-zA-Z0-9.-\s]+/g, '');
|
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
return model
|
|
|
|
.query(qb => {
|
|
|
|
if (!_.isNaN(_.toNumber(query))) {
|
|
|
|
searchInt.forEach(attribute => {
|
|
|
|
qb.orWhereRaw(`${attribute} = ${_.toNumber(query)}`);
|
|
|
|
});
|
|
|
|
}
|
2018-06-12 11:32:13 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
if (query === 'true' || query === 'false') {
|
|
|
|
searchBool.forEach(attribute => {
|
|
|
|
qb.orWhereRaw(`${attribute} = ${_.toNumber(query === 'true')}`);
|
|
|
|
});
|
|
|
|
}
|
2018-06-12 11:32:13 +02:00
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
// Search in columns with text using index.
|
|
|
|
switch (model.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;
|
|
|
|
}
|
|
|
|
case 'mysql':
|
|
|
|
qb.orWhereRaw(
|
|
|
|
`MATCH(${searchText.join(',')}) AGAINST(? IN BOOLEAN MODE)`,
|
|
|
|
`*${query}*`
|
|
|
|
);
|
|
|
|
break;
|
2018-06-07 17:24:09 +02:00
|
|
|
}
|
2019-04-11 16:19:15 +02:00
|
|
|
})
|
|
|
|
.count();
|
2018-06-07 14:35:09 +02:00
|
|
|
},
|
|
|
|
|
2019-03-13 19:27:18 +01:00
|
|
|
findOne: async function(params, populate) {
|
2019-04-11 16:19:15 +02:00
|
|
|
const record = await model
|
|
|
|
.forge({
|
|
|
|
[model.primaryKey]: params[model.primaryKey],
|
|
|
|
})
|
|
|
|
.fetch({
|
|
|
|
withRelated: populate || model.associations.map(x => x.alias),
|
|
|
|
});
|
2017-09-14 18:47:10 +02:00
|
|
|
|
2018-11-01 12:46:20 +01:00
|
|
|
const data = _.get(record, 'toJSON()', record);
|
2018-04-11 12:53:07 +02:00
|
|
|
|
|
|
|
// Retrieve data manually.
|
|
|
|
if (_.isEmpty(populate)) {
|
2019-04-11 16:19:15 +02:00
|
|
|
const arrayOfPromises = model.associations
|
|
|
|
.filter(association =>
|
|
|
|
['manyMorphToOne', 'manyMorphToMany'].includes(association.nature)
|
|
|
|
)
|
2019-03-22 12:16:09 +01:00
|
|
|
.map(() => {
|
2019-04-11 16:19:15 +02:00
|
|
|
return model.morph
|
2019-03-13 19:27:18 +01:00
|
|
|
.forge()
|
2018-04-11 12:53:07 +02:00
|
|
|
.where({
|
2019-04-11 16:19:15 +02:00
|
|
|
[`${model.collectionName}_id`]: params[model.primaryKey],
|
2018-04-11 12:53:07 +02:00
|
|
|
})
|
2018-04-30 16:32:48 +02:00
|
|
|
.fetchAll();
|
2018-04-11 12:53:07 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
const related = await Promise.all(arrayOfPromises);
|
|
|
|
|
|
|
|
related.forEach((value, index) => {
|
2019-04-11 16:19:15 +02:00
|
|
|
data[model.associations[index].alias] = value ? value.toJSON() : value;
|
2018-04-11 12:53:07 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
2017-06-17 17:01:50 +02:00
|
|
|
},
|
|
|
|
|
2019-03-13 19:27:18 +01:00
|
|
|
create: async function(params) {
|
2018-03-01 17:39:31 +01:00
|
|
|
// Exclude relationships.
|
|
|
|
const values = Object.keys(params.values).reduce((acc, current) => {
|
2019-04-11 16:19:15 +02:00
|
|
|
if (model._attributes[current] && model._attributes[current].type) {
|
2017-09-19 11:17:04 +02:00
|
|
|
acc[current] = params.values[current];
|
|
|
|
}
|
|
|
|
|
|
|
|
return acc;
|
2018-03-01 17:39:31 +01:00
|
|
|
}, {});
|
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
const request = await model
|
|
|
|
.forge(values)
|
2018-01-23 18:54:17 +01:00
|
|
|
.save()
|
2019-03-13 19:27:18 +01:00
|
|
|
.catch(err => {
|
2018-04-30 16:32:48 +02:00
|
|
|
if (err.detail) {
|
2018-03-01 17:39:31 +01:00
|
|
|
const field = _.last(_.words(err.detail.split('=')[0]));
|
|
|
|
err = { message: `This ${field} is already taken`, field };
|
|
|
|
}
|
2017-12-06 15:58:20 +01:00
|
|
|
|
2018-03-01 17:39:31 +01:00
|
|
|
throw err;
|
|
|
|
});
|
2017-09-19 11:17:04 +02:00
|
|
|
|
2018-04-26 14:10:17 +02:00
|
|
|
const entry = request.toJSON ? request.toJSON() : request;
|
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
const relations = model.associations.reduce((acc, association) => {
|
2018-05-02 15:39:12 +02:00
|
|
|
acc[association.alias] = params.values[association.alias];
|
|
|
|
return acc;
|
|
|
|
}, {});
|
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
return this.update({
|
|
|
|
[model.primaryKey]: entry[model.primaryKey],
|
2019-03-13 19:27:18 +01:00
|
|
|
values: _.assign(
|
|
|
|
{
|
2019-04-11 16:19:15 +02:00
|
|
|
id: entry[model.primaryKey],
|
2019-03-13 19:27:18 +01:00
|
|
|
},
|
|
|
|
relations
|
|
|
|
),
|
2017-09-19 11:17:04 +02:00
|
|
|
});
|
2017-06-17 17:01:50 +02:00
|
|
|
},
|
|
|
|
|
2019-04-11 16:19:15 +02:00
|
|
|
update(params) {
|
2018-05-09 16:57:16 +02:00
|
|
|
// Call the business logic located in the hook.
|
|
|
|
// This function updates no-relational and relational data.
|
2019-04-11 16:19:15 +02:00
|
|
|
return model.updateRelations(params);
|
2017-06-17 17:01:50 +02:00
|
|
|
},
|
|
|
|
|
2019-03-13 19:27:18 +01:00
|
|
|
delete: async function(params) {
|
2019-04-11 16:19:15 +02:00
|
|
|
return await model
|
|
|
|
.forge({
|
|
|
|
[model.primaryKey]: params.id,
|
|
|
|
})
|
|
|
|
.destroy();
|
2018-06-06 12:47:29 +02:00
|
|
|
},
|
|
|
|
|
2019-03-13 19:27:18 +01:00
|
|
|
deleteMany: async function(params) {
|
2019-04-11 16:19:15 +02:00
|
|
|
return await model
|
|
|
|
.query(function(qb) {
|
|
|
|
return qb.whereIn('id', params.id);
|
|
|
|
})
|
|
|
|
.destroy();
|
2019-03-13 19:27:18 +01:00
|
|
|
},
|
2019-04-11 16:19:15 +02:00
|
|
|
});
|