Skip to content

feat: add cartLoader to batch User.cart resolution#697

Closed
pozylon wants to merge 1 commit into
masterfrom
pozylon/cart-loader
Closed

feat: add cartLoader to batch User.cart resolution#697
pozylon wants to merge 1 commit into
masterfrom
pozylon/cart-loader

Conversation

@pozylon
Copy link
Copy Markdown
Member

@pozylon pozylon commented May 29, 2026

Problem

The cart query in core-orders (configureOrdersModule-queries.ts) used a plain findOne with no batching. Resolving the cart field across multiple users in a single GraphQL request (e.g. admin users { cart { ... } }) issued one DB query per user.

Change

Adds a request-scoped DataLoader for carts, keyed by { userId, countryCode } (plus orderNumber), following the existing loader conventions in packages/api/src/loaders.

  • core-orders: extract a shared buildCartSelector helper and add a batched findCarts({ userIds, ... }) query (userId: { $in }, sorted updated: -1). cart now reuses the helper (behavior unchanged — every caller already supplies countryCode). The loader lives in the API layer and can't query MongoDB directly (layer boundary), and findOrders/buildFindSelector only support a single userId, so a dedicated batched method was needed.
  • cartLoader.ts (new): batches all keys into one findCarts({ userIds }) query, then resolves each key in JS by matching userId + countryCode + orderNumber against the most-recently-updated-first list — mirroring modules.orders.cart semantics.
  • User.cart resolver: now calls loaders.cartLoader.load(...), covering me { cart }, user(userId) { cart }, and users { cart }.

Intentionally left on the direct modules.orders.cart call

  • Core services (nextUserCart, migrateOrderCart) and platform/worker — no request-scoped loaders there.
  • signPaymentProviderForCheckout mutation — avoids loader-cache staleness in the write path.
  • getUserCart MCP tool — single read, no batching benefit.

Verification

  • npm run build (full typecheck) passes; ESLint clean on changed files.
  • 88 integration tests pass: heartbeat, cart-products, cart-migrate, auth-admin (all select me/cross-user cart), plus cart-checkout, cart-delivery-payment, cart-discounts, cart-quotations (exercise the refactored cart/findCarts path via checkout services).

The cart query in core-orders used a plain findOne with no batching, so
resolving carts for multiple users in one request (e.g. admin `users { cart }`)
issued N queries.

- Add a batched `findCarts({ userIds })` query plus a shared `buildCartSelector`
  helper in configureOrdersModule-queries (cart now reuses it).
- Add `cartLoader` keyed by `{ userId, countryCode, orderNumber }`, batching all
  keys into one `findCarts` query and resolving each via most-recent-first match,
  mirroring `modules.orders.cart` semantics.
- Use the loader in the `User.cart` resolver (covers me/user/users).

Mutations, MCP tools and core services keep the direct module call.
@pozylon
Copy link
Copy Markdown
Member Author

pozylon commented May 29, 2026

Closing — this change should target the v4.8.x branch, not master. Re-doing it on a branch based off v4.8.x.

@pozylon pozylon closed this May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant