feat(stock-info): implement request batching with BatchingResource

- Add BatchingResource base class for automatic API request batching
- Refactor StockInfoComponent to use StockInfoResource with batching
- Remove redundant StockResource provider from RewardShoppingCartItemComponent
- Update tests to match new BatchingResourceRef API
- Add comprehensive documentation for BatchingResource pattern

The BatchingResource pattern optimizes multiple simultaneous stock info
requests by collecting params within a 250ms window and making a single
batched API call, significantly reducing network overhead.
This commit is contained in:
Lorenz Hilpert
2025-10-15 20:58:46 +02:00
parent 57302b4536
commit b96d889da5
3 changed files with 109 additions and 82 deletions

View File

@@ -34,7 +34,6 @@ export type BatchingResourceRef<TResourceValue> = {
reload: () => void;
};
/**
* Generic batching resource for optimizing multiple API requests.
* Collects params from multiple components, waits for a batching window,
@@ -82,7 +81,11 @@ export type BatchingResourceRef<TResourceValue> = {
* const stockInfo = stockResource.resource(itemId);
* const inStock = computed(() => stockInfo.value()?.inStock ?? 0);
*/
export abstract class BatchingResource<TParams, TResourceParams, TResourceValue> {
export abstract class BatchingResource<
TParams,
TResourceParams,
TResourceValue,
> {
readonly #batchWindowMs: number;
/**
@@ -147,7 +150,9 @@ export abstract class BatchingResource<TParams, TResourceParams, TResourceValue>
* Extract the params from a result item.
* Implement this method to match results back to requested params.
*/
protected abstract getKeyFromResult(result: TResourceValue): TParams | undefined;
protected abstract getKeyFromResult(
result: TResourceValue,
): TParams | undefined;
/**
* Generate a cache key from params.
@@ -189,7 +194,9 @@ export abstract class BatchingResource<TParams, TResourceParams, TResourceValue>
const cached = this.#cachedResults();
// Filter out params that are already cached
const uncachedCacheKeys = cacheKeys.filter((cacheKey) => !cached.has(cacheKey));
const uncachedCacheKeys = cacheKeys.filter(
(cacheKey) => !cached.has(cacheKey),
);
// Convert cache keys back to original params for buildParams
return uncachedCacheKeys.length > 0
@@ -247,7 +254,10 @@ export abstract class BatchingResource<TParams, TResourceParams, TResourceValue>
paramsList.forEach((itemParams) => {
const hasResult = results.some((r) => {
const resultKey = this.getKeyFromResult(r);
return resultKey !== undefined && this.getCacheKey(resultKey) === this.getCacheKey(itemParams);
return (
resultKey !== undefined &&
this.getCacheKey(resultKey) === this.getCacheKey(itemParams)
);
});
if (!hasResult) {
const cacheKey = this.getCacheKey(itemParams);