mirror of
https://github.com/strapi/strapi.git
synced 2025-07-27 02:44:13 +00:00
177 lines
4.8 KiB
JavaScript
177 lines
4.8 KiB
JavaScript
const _ = require('lodash');
|
|
|
|
const buildQuery = ({ model, filters }) => qb => {
|
|
if (_.has(filters, 'where') && Array.isArray(filters.where)) {
|
|
// build joins
|
|
buildQueryJoins(qb)(model, filters.where);
|
|
|
|
// apply filters
|
|
filters.where.forEach(whereClause => {
|
|
const { association, model: fieldModel, attributeKey } = getAssociationFromFieldKey(
|
|
model,
|
|
whereClause.field
|
|
);
|
|
|
|
let fieldKey = `${fieldModel.collectionName}.${attributeKey}`;
|
|
|
|
if (association && attributeKey === whereClause.field) {
|
|
fieldKey = `${fieldModel.collectionName}.${fieldModel.primaryKey}`;
|
|
}
|
|
|
|
buildWhereClause(qb)({
|
|
...whereClause,
|
|
field: fieldKey,
|
|
});
|
|
});
|
|
}
|
|
|
|
if (_.has(filters, 'sort')) {
|
|
qb.orderBy(
|
|
filters.sort.map(({ field, order }) => ({
|
|
column: field,
|
|
order,
|
|
}))
|
|
);
|
|
}
|
|
|
|
if (_.has(filters, 'start')) {
|
|
qb.offset(filters.start);
|
|
}
|
|
|
|
if (_.has(filters, 'limit') && filters.limit >= 0) {
|
|
qb.limit(filters.limit);
|
|
}
|
|
};
|
|
|
|
const buildWhereClause = qb => ({ field, operator, value }) => {
|
|
switch (operator) {
|
|
case 'eq':
|
|
return qb.where(field, value);
|
|
case 'ne':
|
|
return qb.where(field, '!=', value);
|
|
case 'lt':
|
|
return qb.where(field, '<', value);
|
|
case 'lte':
|
|
return qb.where(field, '<=', value);
|
|
case 'gt':
|
|
return qb.where(field, '>', value);
|
|
case 'gte':
|
|
return qb.where(field, '>=', value);
|
|
case 'in':
|
|
return qb.whereIn(field, Array.isArray(value) ? value : [value]);
|
|
case 'nin':
|
|
return qb.whereNotIn(field, 'NOT IN', Array.isArray(value) ? value : [value]);
|
|
case 'contains': {
|
|
return qb.whereRaw('LOWER(??) LIKE LOWER(?)', [field, `%${value}%`]);
|
|
}
|
|
case 'ncontains':
|
|
return qb.whereRaw('LOWER(??) NOT LIKE LOWER(?)', [field, `%${value}%`]);
|
|
case 'containss':
|
|
return qb.where(field, 'like', `%${value}%`);
|
|
case 'ncontainss':
|
|
return qb.whereNot(field, 'like', `%${value}%`);
|
|
|
|
default:
|
|
throw new Error(`Unhandled whereClause : ${fullField} ${operator} ${value}`);
|
|
}
|
|
};
|
|
|
|
const buildQueryJoins = qb => {
|
|
return (strapiModel, where) => {
|
|
const relationToPopulate = extractRelationsFromWhere(where);
|
|
|
|
relationToPopulate.forEach(fieldPath => {
|
|
const associationParts = fieldPath.split('.');
|
|
|
|
let currentModel = strapiModel;
|
|
associationParts.forEach(astPart => {
|
|
const { association, model } = getAssociationFromFieldKey(currentModel, astPart);
|
|
|
|
if (association) {
|
|
buildSingleJoin(qb)(currentModel, model, association);
|
|
currentModel = model;
|
|
}
|
|
});
|
|
});
|
|
};
|
|
};
|
|
|
|
const extractRelationsFromWhere = where => {
|
|
return where
|
|
.map(({ field }) => {
|
|
const parts = field.split('.');
|
|
return parts.length === 1 ? field : _.initial(parts).join('.');
|
|
})
|
|
.sort()
|
|
.reverse()
|
|
.reduce((acc, currentValue) => {
|
|
const alreadyPopulated = _.some(acc, item => _.startsWith(item, currentValue));
|
|
if (!alreadyPopulated) {
|
|
acc.push(currentValue);
|
|
}
|
|
return acc;
|
|
}, []);
|
|
};
|
|
|
|
const getAssociationFromFieldKey = (strapiModel, fieldKey) => {
|
|
let model = strapiModel;
|
|
let association;
|
|
let attributeKey;
|
|
|
|
const parts = fieldKey.split('.');
|
|
|
|
for (let key of parts) {
|
|
attributeKey = key;
|
|
association = model.associations.find(ast => ast.alias === key);
|
|
if (association) {
|
|
const { models } = strapi.plugins[association.plugin] || strapi;
|
|
model = models[association.model || association.collection];
|
|
}
|
|
}
|
|
|
|
return {
|
|
association,
|
|
model,
|
|
attributeKey,
|
|
};
|
|
};
|
|
|
|
const buildSingleJoin = qb => {
|
|
return (strapiModel, astModel, association) => {
|
|
const relationTable = astModel.collectionName;
|
|
|
|
qb.distinct();
|
|
|
|
if (association.nature === 'manyToMany') {
|
|
// Join on both ends
|
|
qb.innerJoin(
|
|
association.tableCollectionName,
|
|
`${association.tableCollectionName}.${strapiModel.info.name}_${strapiModel.primaryKey}`,
|
|
`${strapiModel.collectionName}.${strapiModel.primaryKey}`
|
|
);
|
|
|
|
qb.innerJoin(
|
|
relationTable,
|
|
`${association.tableCollectionName}.${
|
|
strapiModel.attributes[association.alias].attribute
|
|
}_${strapiModel.attributes[association.alias].column}`,
|
|
`${relationTable}.${astModel.primaryKey}`
|
|
);
|
|
} else {
|
|
const externalKey =
|
|
association.type === 'collection'
|
|
? `${relationTable}.${association.via}`
|
|
: `${relationTable}.${astModel.primaryKey}`;
|
|
|
|
const internalKey =
|
|
association.type === 'collection'
|
|
? `${strapiModel.collectionName}.${strapiModel.primaryKey}`
|
|
: `${strapiModel.collectionName}.${association.alias}`;
|
|
|
|
qb.innerJoin(relationTable, externalKey, internalKey);
|
|
}
|
|
};
|
|
};
|
|
|
|
module.exports = buildQuery;
|