chore(): Improve product list when there is a single sales channel (#14082)

FIXES https://github.com/medusajs/medusa/issues/13976

**What**
Before applying the sales channel link filter, check if there is a single sales channel or many, if will add a bit of overhead but marginal compare to the improvement for big catalog with single sales channel


---

> [!NOTE]
> Optimizes store products listing by conditionally skipping sales channel link filtering when the index can be used or only one sales channel exists.
> 
> - **Store API – `products`** (`packages/medusa/src/api/store/products/middlewares.ts`):
>   - Adds `applyMaybeLinkFilterIfNecessary` middleware:
>     - Skips link filtering when `IndexEngine` is enabled and no tag/category filters are present.
>     - Queries `sales_channels` count; if only one exists, removes `sales_channel_id` filter and proceeds.
>   - Integrates this middleware into `GET /store/products` before default filters; `GET /store/products/:id` remains unchanged with `maybeApplyLinkFilter`.
> - **Release**:
>   - Adds patch changeset for `@medusajs/medusa`.
> 
> <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8a0b024ea1bc9696f350f34fa77df321e5ecf553. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup>
This commit is contained in:
Adrien de Peretti
2025-11-25 11:45:38 +01:00
committed by GitHub
parent 5725837ba8
commit 1cfc88ee55
2 changed files with 46 additions and 18 deletions

View File

@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---
chore(): Improve product list when there is a single sales channel

View File

@@ -5,9 +5,13 @@ import {
authenticate,
clearFiltersByKey,
maybeApplyLinkFilter,
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
MiddlewareRoute,
} from "@medusajs/framework/http"
import {
ContainerRegistrationKeys,
FeatureFlag,
isPresent,
ProductStatus,
@@ -22,6 +26,42 @@ import {
import * as QueryConfig from "./query-config"
import { StoreGetProductsParams } from "./validators"
async function applyMaybeLinkFilterIfNecessary(
req: MedusaRequest,
res: MedusaResponse,
next: MedusaNextFunction
) {
const canUseIndex = !(
isPresent(req.filterableFields.tags) ||
isPresent(req.filterableFields.categories)
)
if (FeatureFlag.isFeatureEnabled(IndexEngineFeatureFlag.key) && canUseIndex) {
return next()
}
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const salesChannelsQueryRes = await query.graph({
entity: "sales_channels",
fields: ["id"],
pagination: {
skip: 0,
take: 1,
},
})
const salesChannelCount = salesChannelsQueryRes.metadata?.count ?? 0
if (!(salesChannelCount > 1)) {
delete req.filterableFields.sales_channel_id
return next()
}
return maybeApplyLinkFilter({
entryPoint: "product_sales_channel",
resourceId: "product_id",
filterableField: "sales_channel_id",
})(req, res, next)
}
export const storeProductRoutesMiddlewares: MiddlewareRoute[] = [
{
method: ["GET"],
@@ -35,24 +75,7 @@ export const storeProductRoutesMiddlewares: MiddlewareRoute[] = [
QueryConfig.listProductQueryConfig
),
filterByValidSalesChannels(),
(req, res, next) => {
const canUseIndex = !(
isPresent(req.filterableFields.tags) ||
isPresent(req.filterableFields.categories)
)
if (
FeatureFlag.isFeatureEnabled(IndexEngineFeatureFlag.key) &&
canUseIndex
) {
return next()
}
return maybeApplyLinkFilter({
entryPoint: "product_sales_channel",
resourceId: "product_id",
filterableField: "sales_channel_id",
})(req, res, next)
},
applyMaybeLinkFilterIfNecessary,
applyDefaultFilters({
status: ProductStatus.PUBLISHED,
// TODO: the type here seems off and the implementation does not take into account $and and $or possible filters. Might be worth re working (original type used here was StoreGetProductsParamsType)