fix: Prevent promotion filtering to exceed psql limits (#13540)

* fix(): Prevent promotion filtering to exceed psql limits

* Create sour-rockets-grin.md
This commit is contained in:
Adrien de Peretti authored and GitHub committed 2025-09-18 17:50:10 +02:00
1 parent aa7ea4d9a6
commit 4736c58da5
4 files changed
+43 -6

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/promotion": patch
---
fix(): Prevent promotion filtering to exceed psql limits
@@ -353,7 +353,7 @@ moduleIntegrationTestRunner({
value: 100, value: 100,
target_rules: [ target_rules: [
{ {
attribute: "product.id", attribute: "items.product.id",
operator: "eq", operator: "eq",
values: ["prod_tshirt0"], // Only applies to product 0 values: ["prod_tshirt0"], // Only applies to product 0
}, },
@@ -466,7 +466,10 @@ export default class PromotionModuleService
if (!preventAutoPromotions) { if (!preventAutoPromotions) {
const rulePrefilteringFilters = const rulePrefilteringFilters =
buildPromotionRuleQueryFilterFromContext(applicationContext) await buildPromotionRuleQueryFilterFromContext(
applicationContext,
sharedContext
)
let prefilteredAutomaticPromotionIds: string[] = [] let prefilteredAutomaticPromotionIds: string[] = []
@@ -2,11 +2,12 @@ import {
ComputeActionContext, ComputeActionContext,
ComputeActionItemLine, ComputeActionItemLine,
ComputeActionShippingLine, ComputeActionShippingLine,
Context,
DAL, DAL,
PromotionTypes, PromotionTypes,
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
import { flattenObjectToKeyValuePairs } from "@medusajs/framework/utils" import { flattenObjectToKeyValuePairs } from "@medusajs/framework/utils"
import { raw } from "@mikro-orm/postgresql" import { raw, SqlEntityManager } from "@mikro-orm/postgresql"
/** /**
* Builds a query filter for promotion rules based on the context. * Builds a query filter for promotion rules based on the context.
@@ -17,9 +18,10 @@ import { raw } from "@mikro-orm/postgresql"
* @param context * @param context
* @returns * @returns
*/ */
export function buildPromotionRuleQueryFilterFromContext( export async function buildPromotionRuleQueryFilterFromContext(
context: PromotionTypes.ComputeActionContext context: PromotionTypes.ComputeActionContext,
): DAL.FilterQuery<any> | null { sharedContext: Context
): Promise<DAL.FilterQuery<any> | null> {
const { const {
items = [], items = [],
shipping_methods: shippingMethods = [], shipping_methods: shippingMethods = [],
@@ -67,6 +69,33 @@ export function buildPromotionRuleQueryFilterFromContext(
}) })
}) })
// count the number of attributes in the map
const numberOfAttributes = attributeValueMap.size
if (numberOfAttributes > 10) {
const manager = (sharedContext.transactionManager ??
sharedContext.manager) as SqlEntityManager
const knex = manager.getKnex()
const { rows } = await knex.raw(
`
SELECT DISTINCT attribute
FROM promotion_rule
WHERE deleted_at IS NULL
`
)
const dbAvailableAttributes = new Set(
rows.map(({ attribute }) => attribute)
)
// update the attribute in the map to remove the one that are not in the db
attributeValueMap.forEach((valueSet, attribute) => {
if (!dbAvailableAttributes.has(attribute)) {
attributeValueMap.delete(attribute)
}
})
}
// Build conditions for a NOT EXISTS subquery to exclude promotions with unsatisfiable rules // Build conditions for a NOT EXISTS subquery to exclude promotions with unsatisfiable rules
const sqlConditions: string[] = [] const sqlConditions: string[] = []