Admin API ProductVariant.stockLevels runs one query per variant
Describe the bug
The Admin API ProductVariant.stockLevels field resolver (packages/core/src/api/resolvers/entity/product-variant-entity.resolver.ts, stockLevels) calls StockLevelService.getStockLevelsForVariant, which builds a query joining stockLocation.channels and filtering on ctx.channelId, once per variant. Nothing batches it, so any list of variants that selects stockLevels costs one extra query per row.
#5224 removed the same per-variant stampede for stockOnHand / stockAllocated (the getAvailableStock path), but stockLevels still has it. The dashboard product-variants list and the variants table on the product detail page both select stockLevels for every row.
To Reproduce
- Enable query logging (
dbConnectionOptions.logging: ['query']) or attach a counting TypeORM logger. - Run this Admin API query against a catalog with a few dozen variants:
query { productVariants(options: { take: 40 }) { items { id stockLevels { id stockOnHand stockAllocated stockLocation { id name } } } } } - Count the
SELECT ... FROM "stock_level"statements.
On the core e2e fixture (34 variants) this issues 34 stock_level selects, one per variant, 48 queries for the request in total.
Expected behavior
A page of variants costs a bounded number of stock queries, as it does for stockOnHand / stockAllocated since #5224.
Actual behavior
One stock_level query per variant in the page. An ERP or WMS sync paging 100 variants pays 100 extra queries per page.
Environment
- @vendure/core version: 3.7.2 (master, includes #5224)
- Nodejs version:
- Database: reproduced on sqljs, Postgres 16, MySQL 8, MariaDB 11.5
- Operating System:
- Package manager:
Additional context
Same root cause as #5224, same fix shape: a per-request DataLoader with cache: false, so a write earlier in the request is not masked. PR to follow.
Source: vendurehq/vendure