diff --git a/packages/core/database/lib/query/helpers/populate/apply.js b/packages/core/database/lib/query/helpers/populate/apply.js index 130f2aa093..1138bab261 100644 --- a/packages/core/database/lib/query/helpers/populate/apply.js +++ b/packages/core/database/lib/query/helpers/populate/apply.js @@ -446,6 +446,11 @@ const morphToMany = async (input, ctx) => { .where({ [joinColumn.name]: referencedValues, ...(joinTable.on || {}), + // If the populateValue contains an "on" property, + // only populate the types defined in it + ...('on' in populateValue + ? { [morphColumn.typeColumn.name]: Object.keys(populateValue.on) } + : {}), }) .orderBy([joinColumn.name, 'order']) .execute({ mapResults: false }); @@ -482,14 +487,10 @@ const morphToMany = async (input, ctx) => { continue; } - if (on && on[type]) { - Object.assign(typePopulate, on[type]); - } - const qb = db.entityManager.createQueryBuilder(type); const rows = await qb - .init(typePopulate) + .init(on && type in on ? on[type] : typePopulate) .addSelect(`${qb.alias}.${idColumn.referencedColumn}`) .where({ [idColumn.referencedColumn]: ids }) .execute({ mapResults: false }); @@ -546,6 +547,8 @@ const morphToOne = async (input, ctx) => { }, {}); const map = {}; + const { on, ...typePopulate } = populateValue; + for (const type of Object.keys(idsByType)) { const ids = idsByType[type]; @@ -558,7 +561,7 @@ const morphToOne = async (input, ctx) => { const qb = db.entityManager.createQueryBuilder(type); const rows = await qb - .init(populateValue) + .init(on && type in on ? on[type] : typePopulate) .addSelect(`${qb.alias}.${idColumn.referencedColumn}`) .where({ [idColumn.referencedColumn]: ids }) .execute({ mapResults: false }); diff --git a/packages/core/utils/lib/convert-query-params.js b/packages/core/utils/lib/convert-query-params.js index 4c11510375..a6b6cadb26 100644 --- a/packages/core/utils/lib/convert-query-params.js +++ b/packages/core/utils/lib/convert-query-params.js @@ -17,6 +17,7 @@ const { isPlainObject, cloneDeep, get, + mergeAll, } = require('lodash/fp'); const _ = require('lodash'); const parseType = require('./parse-type'); @@ -185,14 +186,13 @@ const convertPopulateObject = (populate, schema) => { return acc; } - if (subPopulate && subPopulate.on) { + if (subPopulate && 'on' in subPopulate) { return { ...acc, [key]: { - ...subPopulate, on: Object.entries(subPopulate.on).reduce( - (newTypeSubPopulate, [type, typeSubPopulate]) => ({ - ...newTypeSubPopulate, + (acc, [type, typeSubPopulate]) => ({ + ...acc, [type]: convertNestedPopulate(typeSubPopulate, strapi.getModel(type)), }), {} @@ -201,6 +201,25 @@ const convertPopulateObject = (populate, schema) => { }; } + // TODO: Deprecated way of handling dynamic zone populate queries. It's kept as is, + // as removing it could break existing user queries but should be removed in V5. + if (attribute.type === 'dynamiczone') { + const populates = attribute.components + .map((uid) => strapi.getModel(uid)) + .map((schema) => convertNestedPopulate(subPopulate, schema)) + .map((populate) => (populate === true ? {} : populate)) // cast boolean to empty object to avoid merging issues + .filter((populate) => populate !== false); + + if (isEmpty(populates)) { + return acc; + } + + return { + ...acc, + [key]: mergeAll(populates), + }; + } + // NOTE: Retrieve the target schema UID. // Only handles basic relations, medias and component since it's not possible // to populate with options for a dynamic zone or a polymorphic relation