Fix deepFiltering with draft & publish

Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu>
This commit is contained in:
Convly 2020-10-16 11:30:51 +02:00
parent fad9fda318
commit 03f5342123
3 changed files with 85 additions and 40 deletions

View File

@ -13,7 +13,7 @@ const BOOLEAN_OPERATORS = ['or'];
const buildQuery = ({ model, filters }) => qb => {
if (_.has(filters, 'where') && Array.isArray(filters.where) && filters.where.length > 0) {
qb.distinct();
buildJoinsAndFilter(qb, model, filters.where);
buildJoinsAndFilter(qb, model, filters);
}
if (_.has(filters, 'sort')) {
@ -45,9 +45,11 @@ const buildQuery = ({ model, filters }) => qb => {
* Add joins and where filters
* @param {Object} qb - knex query builder
* @param {Object} model - Bookshelf model
* @param {Array<Object>} whereClauses - an array of where clause
* @param {Object} filters - The query filters
*/
const buildJoinsAndFilter = (qb, model, whereClauses) => {
const buildJoinsAndFilter = (qb, model, filters) => {
const { where: whereClauses } = filters;
/**
* Returns an alias for a name (simple incremental alias name)
* @param {string} name - name to alias
@ -210,12 +212,29 @@ const buildJoinsAndFilter = (qb, model, whereClauses) => {
});
};
const aliasedWhereClauses = buildWhereClauses(whereClauses, { model });
/**
* Add queries on tree's joins (deep search) based on given filters
* @param tree - joins tree
*/
const addFiltersQueriesToJoinTree = tree => {
_.each(tree.joins, value => {
const { alias, model } = value;
buildJoinsFromTree(qb, tree);
runPopulateQueries(
toQueries({
publicationState: { query: filters.publicationState, model, alias },
}),
qb
);
addFiltersQueriesToJoinTree(value);
});
};
const aliasedWhereClauses = buildWhereClauses(whereClauses, { model });
aliasedWhereClauses.forEach(w => buildWhereClause({ qb, ...w }));
return;
buildJoinsFromTree(qb, tree);
addFiltersQueriesToJoinTree(tree);
};
/**

View File

@ -11,9 +11,9 @@ const {
const optionsMap = {
publicationState: {
queries: {
[DP_PUB_STATE_LIVE]: ({ model }) => qb => {
[DP_PUB_STATE_LIVE]: ({ model, alias }) => qb => {
const { collectionName } = model;
qb.whereNotNull(`${collectionName}.${PUBLISHED_AT_ATTRIBUTE}`);
qb.whereNotNull(`${alias || collectionName}.${PUBLISHED_AT_ATTRIBUTE}`);
},
[DP_PUB_STATE_PREVIEW]: () => null,
},

View File

@ -6,7 +6,10 @@ const utils = require('./utils')();
const populateQueries = require('./utils/populate-queries');
const {
hasDeepFilters,
contentTypes: { hasDraftAndPublish },
contentTypes: {
constants: { DP_PUB_STATES },
hasDraftAndPublish,
},
} = require('strapi-utils');
const combineSearchAndWhere = (search = [], wheres = []) => {
@ -139,7 +142,7 @@ const buildDeepQuery = ({ model, filters, search, populate }) => {
// Init the query
let query = model
.aggregate(
buildQueryAggregate(model, {
buildQueryAggregate(model, filters, {
paths: _.merge({}, populatePaths, wherePaths),
})
)
@ -292,7 +295,7 @@ const recursiveCastedWherePaths = (whereClauses, { model }) => {
* Builds an object based on paths:
* [
* 'articles',
* 'articles.tags.cateogry',
* 'articles.tags.category',
* 'articles.tags.label',
* ] => {
* articles: {
@ -307,14 +310,15 @@ const recursiveCastedWherePaths = (whereClauses, { model }) => {
const pathsToTree = paths => paths.reduce((acc, path) => _.merge(acc, _.set({}, path, {})), {});
/**
* Builds the aggregations pipeling of the query
* Builds the aggregations pipeline of the query
* @param {Object} model - Queried model
* @param {Object} filters - The query filters
* @param {Object} options - Options
* @param {Object} options.paths - A tree of paths to aggregate e.g { article : { tags : { label: {}}}}
*/
const buildQueryAggregate = (model, { paths } = {}) => {
const buildQueryAggregate = (model, filters, { paths } = {}) => {
return Object.keys(paths).reduce((acc, key) => {
return acc.concat(buildLookup({ model, key, paths: paths[key] }));
return acc.concat(buildLookup({ model, key, paths: paths[key], filters }));
}, []);
};
@ -325,7 +329,7 @@ const buildQueryAggregate = (model, { paths } = {}) => {
* @param {string} options.key - The attribute name to lookup on the model
* @param {Object} options.paths - A tree of paths to aggregate inside the current lookup e.g { { tags : { label: {}}}
*/
const buildLookup = ({ model, key, paths }) => {
const buildLookup = ({ model, key, paths, filters }) => {
const assoc = model.associations.find(a => a.alias === key);
const assocModel = strapi.db.getModelByAssoc(assoc);
@ -341,8 +345,8 @@ const buildLookup = ({ model, key, paths }) => {
localAlias: `$${assoc.alias}`,
},
pipeline: []
.concat(buildLookupMatch({ assoc }))
.concat(buildQueryAggregate(assocModel, { paths })),
.concat(buildLookupMatch({ assoc, assocModel, filters }))
.concat(buildQueryAggregate(assocModel, filters, { paths })),
},
},
];
@ -351,17 +355,29 @@ const buildLookup = ({ model, key, paths }) => {
/**
* Build a lookup match expression (equivalent to a SQL join condition)
* @param {Object} options - Options
* @param {Object} options.assoc - The association on which is based the ematching xpression
* @param {Object} options.assoc - The association on which is based the matching expression
*/
const buildLookupMatch = ({ assoc }) => {
const buildLookupMatch = ({ assoc, assocModel, filters = {} }) => {
const defaultMatches = [];
if (hasDraftAndPublish(assocModel) && DP_PUB_STATES.includes(filters.publicationState)) {
const dpQuery = populateQueries.publicationState[filters.publicationState];
if (_.isObject(dpQuery)) {
defaultMatches.push(dpQuery);
}
}
switch (assoc.nature) {
case 'oneToOne': {
return [
{
$match: {
$expr: {
$eq: [`$${assoc.via}`, '$$localId'],
},
$and: defaultMatches.concat({
$expr: {
$eq: [`$${assoc.via}`, '$$localId'],
},
}),
},
},
];
@ -369,9 +385,11 @@ const buildLookupMatch = ({ assoc }) => {
case 'oneToMany': {
return {
$match: {
$expr: {
$eq: [`$${assoc.via}`, '$$localId'],
},
$and: defaultMatches.concat({
$expr: {
$eq: [`$${assoc.via}`, '$$localId'],
},
}),
},
};
}
@ -379,18 +397,22 @@ const buildLookupMatch = ({ assoc }) => {
case 'manyToOne': {
return {
$match: {
$expr: {
$eq: ['$$localAlias', '$_id'],
},
$and: defaultMatches.concat({
$expr: {
$eq: ['$$localAlias', '$_id'],
},
}),
},
};
}
case 'manyWay': {
return {
$match: {
$expr: {
$in: ['$_id', '$$localAlias'],
},
$and: defaultMatches.concat({
$expr: {
$in: ['$_id', '$$localAlias'],
},
}),
},
};
}
@ -398,18 +420,22 @@ const buildLookupMatch = ({ assoc }) => {
if (assoc.dominant === true) {
return {
$match: {
$expr: {
$in: ['$_id', '$$localAlias'],
},
$and: defaultMatches.concat({
$expr: {
$in: ['$_id', '$$localAlias'],
},
}),
},
};
}
return {
$match: {
$expr: {
$in: ['$$localId', `$${assoc.via}`],
},
$and: defaultMatches.concat({
$expr: {
$in: ['$$localId', `$${assoc.via}`],
},
}),
},
};
}
@ -422,10 +448,10 @@ const buildLookupMatch = ({ assoc }) => {
{
$match: {
$expr: {
$and: [
$and: defaultMatches.concat(
{ $eq: [`$${assoc.via}.ref`, '$$localId'] },
{ $eq: [`$${assoc.via}.${assoc.filter}`, assoc.alias] },
],
{ $eq: [`$${assoc.via}.${assoc.filter}`, assoc.alias] }
),
},
},
},