@robohall/react-query-factory 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -3
- package/dist/index.js +6 -3
- package/dist/index.mjs +6 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<a href="https://roberth26.github.io/react-query-factory/"><strong>Visit the Sandbox</strong></a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
-
TanStack Query handles caching, syncing, and invalidation. What it doesn't do is crawl paginated APIs for you. This library adds that — a factory function that wraps your `queryFn` with a configurable crawl loop so `useQuery` can return accumulated results instead of a single page. The same factory produces `useInfiniteQuery` options, composes into child factories that share the cache, and exposes scope-aware invalidation keys. TanStack's API stays fully exposed at every call site.
|
|
12
|
+
TanStack Query handles caching, syncing, and invalidation. What it doesn't do is crawl paginated APIs for you. This library adds that — a factory function that wraps your `queryFn` with a configurable crawl loop so `useQuery` can return accumulated results instead of a single page. The `queryFn` can be a plain async function or an async iterable (e.g. an AWS SDK paginator), with no cursor wiring required in the latter case. The same factory produces `useInfiniteQuery` options, composes into child factories that share the cache, and exposes scope-aware invalidation keys. TanStack's API stays fully exposed at every call site.
|
|
13
13
|
|
|
14
14
|
Zero runtime dependencies.
|
|
15
15
|
|
|
@@ -30,7 +30,30 @@ function useInstances(params: DescribeInstancesCommandInput) {
|
|
|
30
30
|
}
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Works,
|
|
33
|
+
Works, until requirements grow. You need a `select` option — so the hook grows a generic. You need a `useInfiniteQuery` variant — so you write a second hook with a key differentiator to avoid a cache collision. You need to prefetch in a route loader — but the key is trapped inside the hook.
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
function useInstances<TSelected = Instance[]>(
|
|
37
|
+
params: DescribeInstancesCommandInput,
|
|
38
|
+
options?: { select?: (data: Instance[]) => TSelected },
|
|
39
|
+
) {
|
|
40
|
+
return useQuery({
|
|
41
|
+
queryKey: ['instances', params],
|
|
42
|
+
queryFn: () => fetchInstances(params),
|
|
43
|
+
select: options?.select,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// separate hook, duplicated key and queryFn, must stay in sync manually
|
|
48
|
+
function useInstancesInfinite(params: DescribeInstancesCommandInput) {
|
|
49
|
+
return useInfiniteQuery({
|
|
50
|
+
queryKey: ['instances', 'infinite', params],
|
|
51
|
+
// ...
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The generics multiply with every new transform. The key is still trapped — prefetching and invalidation still can't reach it from outside.
|
|
34
57
|
|
|
35
58
|
### Step 2 — `queryOptions` for colocation
|
|
36
59
|
|
|
@@ -126,7 +149,7 @@ Now you have two separate factories that duplicate the key and queryFn and need
|
|
|
126
149
|
### What's missing
|
|
127
150
|
|
|
128
151
|
- Define the query **once**: key, queryFn, pagination config
|
|
129
|
-
- Let each **call site** decide how much to crawl (e.g. 50 records
|
|
152
|
+
- Let each **call site** decide how much to crawl (e.g. 50 records, all of them, or none)
|
|
130
153
|
- Optionally have `useQuery` crawl and return the **accumulated result** instead of a single page
|
|
131
154
|
- Use **async iterables** as `queryFn` — pass a paginator function directly, no cursor wiring required
|
|
132
155
|
- Have `.infinite()` available on the **same factory**, no duplication
|
package/dist/index.js
CHANGED
|
@@ -122,13 +122,16 @@ function buildInfiniteCrawlingQueryFn(queryFn, getNextPageParam, shouldFetchNext
|
|
|
122
122
|
const initialResult = queryFn(params, ctx);
|
|
123
123
|
if (isAsyncIterable(initialResult)) {
|
|
124
124
|
const pages2 = [];
|
|
125
|
+
const startParam = context.pageParam;
|
|
125
126
|
let acc2 = void 0;
|
|
126
127
|
let nextBatchParam2 = null;
|
|
127
128
|
for await (const page of initialResult) {
|
|
128
129
|
if ((_b = context.signal) == null ? void 0 : _b.aborted) break;
|
|
129
130
|
pages2.push(page);
|
|
130
131
|
acc2 = reduce(acc2, page);
|
|
131
|
-
const nextParam = getNextPageParam(page, pages2,
|
|
132
|
+
const nextParam = getNextPageParam(page, pages2, startParam, [
|
|
133
|
+
startParam
|
|
134
|
+
]);
|
|
132
135
|
nextBatchParam2 = nextParam != null ? nextParam : null;
|
|
133
136
|
if (nextParam == null) break;
|
|
134
137
|
if (!shouldFetchNextPage(acc2, crawlOptions)) break;
|
|
@@ -147,9 +150,9 @@ function buildInfiniteCrawlingQueryFn(queryFn, getNextPageParam, shouldFetchNext
|
|
|
147
150
|
pages.push(page);
|
|
148
151
|
pageParams.push(currentParam);
|
|
149
152
|
acc = reduce(acc, page);
|
|
150
|
-
if ((_c = context.signal) == null ? void 0 : _c.aborted) break;
|
|
151
153
|
const nextParam = getNextPageParam(page, pages, currentParam, pageParams);
|
|
152
154
|
nextBatchParam = nextParam != null ? nextParam : null;
|
|
155
|
+
if ((_c = context.signal) == null ? void 0 : _c.aborted) break;
|
|
153
156
|
if (nextParam == null) break;
|
|
154
157
|
if (!shouldFetchNextPage(acc, crawlOptions)) break;
|
|
155
158
|
currentParam = nextParam;
|
|
@@ -279,7 +282,7 @@ function queryFactory(configOrParent, childConfig) {
|
|
|
279
282
|
} : {
|
|
280
283
|
getNextPageParam: (_b = childConfig.getNextPageParam) != null ? _b : parentCfg.getNextPageParam,
|
|
281
284
|
getPreviousPageParam: (_c = childConfig.getPreviousPageParam) != null ? _c : parentCfg.getPreviousPageParam,
|
|
282
|
-
initialPageParam:
|
|
285
|
+
initialPageParam: "initialPageParam" in childConfig ? childConfig.initialPageParam : parentCfg.initialPageParam,
|
|
283
286
|
shouldFetchNextPage: (_d = childConfig.shouldFetchNextPage) != null ? _d : parentCfg.shouldFetchNextPage,
|
|
284
287
|
reduce: (_e = childConfig.reduce) != null ? _e : parentCfg.reduce
|
|
285
288
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -96,13 +96,16 @@ function buildInfiniteCrawlingQueryFn(queryFn, getNextPageParam, shouldFetchNext
|
|
|
96
96
|
const initialResult = queryFn(params, ctx);
|
|
97
97
|
if (isAsyncIterable(initialResult)) {
|
|
98
98
|
const pages2 = [];
|
|
99
|
+
const startParam = context.pageParam;
|
|
99
100
|
let acc2 = void 0;
|
|
100
101
|
let nextBatchParam2 = null;
|
|
101
102
|
for await (const page of initialResult) {
|
|
102
103
|
if ((_b = context.signal) == null ? void 0 : _b.aborted) break;
|
|
103
104
|
pages2.push(page);
|
|
104
105
|
acc2 = reduce(acc2, page);
|
|
105
|
-
const nextParam = getNextPageParam(page, pages2,
|
|
106
|
+
const nextParam = getNextPageParam(page, pages2, startParam, [
|
|
107
|
+
startParam
|
|
108
|
+
]);
|
|
106
109
|
nextBatchParam2 = nextParam != null ? nextParam : null;
|
|
107
110
|
if (nextParam == null) break;
|
|
108
111
|
if (!shouldFetchNextPage(acc2, crawlOptions)) break;
|
|
@@ -121,9 +124,9 @@ function buildInfiniteCrawlingQueryFn(queryFn, getNextPageParam, shouldFetchNext
|
|
|
121
124
|
pages.push(page);
|
|
122
125
|
pageParams.push(currentParam);
|
|
123
126
|
acc = reduce(acc, page);
|
|
124
|
-
if ((_c = context.signal) == null ? void 0 : _c.aborted) break;
|
|
125
127
|
const nextParam = getNextPageParam(page, pages, currentParam, pageParams);
|
|
126
128
|
nextBatchParam = nextParam != null ? nextParam : null;
|
|
129
|
+
if ((_c = context.signal) == null ? void 0 : _c.aborted) break;
|
|
127
130
|
if (nextParam == null) break;
|
|
128
131
|
if (!shouldFetchNextPage(acc, crawlOptions)) break;
|
|
129
132
|
currentParam = nextParam;
|
|
@@ -253,7 +256,7 @@ function queryFactory(configOrParent, childConfig) {
|
|
|
253
256
|
} : {
|
|
254
257
|
getNextPageParam: (_b = childConfig.getNextPageParam) != null ? _b : parentCfg.getNextPageParam,
|
|
255
258
|
getPreviousPageParam: (_c = childConfig.getPreviousPageParam) != null ? _c : parentCfg.getPreviousPageParam,
|
|
256
|
-
initialPageParam:
|
|
259
|
+
initialPageParam: "initialPageParam" in childConfig ? childConfig.initialPageParam : parentCfg.initialPageParam,
|
|
257
260
|
shouldFetchNextPage: (_d = childConfig.shouldFetchNextPage) != null ? _d : parentCfg.shouldFetchNextPage,
|
|
258
261
|
reduce: (_e = childConfig.reduce) != null ? _e : parentCfg.reduce
|
|
259
262
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robohall/react-query-factory",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "A factory abstraction for TanStack Query (React Query) with composable keys, crawling support, and automatic infinite query generation",
|
|
5
5
|
"author": "Robert Hall",
|
|
6
6
|
"license": "MIT",
|