From 03f53421231f1fcf1abdf7b738d288ac64cfaade Mon Sep 17 00:00:00 2001 From: Convly Date: Fri, 16 Oct 2020 11:30:51 +0200 Subject: [PATCH] Fix deepFiltering with draft & publish Signed-off-by: Convly --- .../lib/buildQuery.js | 31 +++++-- .../lib/utils/populate-queries.js | 4 +- .../lib/buildQuery.js | 90 ++++++++++++------- 3 files changed, 85 insertions(+), 40 deletions(-) diff --git a/packages/strapi-connector-bookshelf/lib/buildQuery.js b/packages/strapi-connector-bookshelf/lib/buildQuery.js index f0fef809e9..2627e76585 100644 --- a/packages/strapi-connector-bookshelf/lib/buildQuery.js +++ b/packages/strapi-connector-bookshelf/lib/buildQuery.js @@ -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} 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); }; /** diff --git a/packages/strapi-connector-bookshelf/lib/utils/populate-queries.js b/packages/strapi-connector-bookshelf/lib/utils/populate-queries.js index 6530de166e..8fe151484f 100644 --- a/packages/strapi-connector-bookshelf/lib/utils/populate-queries.js +++ b/packages/strapi-connector-bookshelf/lib/utils/populate-queries.js @@ -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, }, diff --git a/packages/strapi-connector-mongoose/lib/buildQuery.js b/packages/strapi-connector-mongoose/lib/buildQuery.js index 39803d96a2..e03fd6a1b0 100644 --- a/packages/strapi-connector-mongoose/lib/buildQuery.js +++ b/packages/strapi-connector-mongoose/lib/buildQuery.js @@ -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] } + ), }, }, },