@robohall/react-query-factory 1.1.0 → 2.0.0
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 +43 -21
- package/dist/index.d.mts +11 -6
- package/dist/index.d.ts +11 -6
- package/dist/index.js +25 -8
- package/dist/index.mjs +25 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# @robohall/react-query-factory
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@robohall/react-query-factory)
|
|
4
|
-
|
|
4
|
+

|
|
5
|
+

|
|
5
6
|
[](./LICENSE)
|
|
6
7
|
|
|
7
8
|
A factory function for TanStack Query configs. Instead of calling `useQuery` with ad-hoc options, you define a factory once and call it anywhere — getting consistent cache keys, automatic pagination crawling, and `useInfiniteQuery` support for free. TanStack's API stays fully exposed.
|
|
@@ -54,9 +55,9 @@ function InstanceList() {
|
|
|
54
55
|
|
|
55
56
|
## Crawling
|
|
56
57
|
|
|
57
|
-
`DescribeInstances` is paginated. If you have more than
|
|
58
|
+
`DescribeInstances` is paginated. If you have more than 20 instances, one call won't get them all. The standard approach — chaining `fetchNextPage` calls, accumulating results, checking `NextToken` — is correct but tedious to repeat everywhere.
|
|
58
59
|
|
|
59
|
-
Add `getNextPageParam` and `shouldFetchNextPage` to activate crawling — those two are the only required pieces. `initialPageParam` types `ctx.pageParam` in your `queryFn` (without it, `ctx.pageParam` is `never`). `reduce` folds crawled pages into a single value; without it the result is
|
|
60
|
+
Add `getNextPageParam` and `shouldFetchNextPage` to activate crawling — those two are the only required pieces. `initialPageParam` types `ctx.pageParam` in your `queryFn` (without it and without a `getNextPageParam` that provides inference, `ctx.pageParam` is `never`). `reduce` folds crawled pages into a single value; without it the result is an array of all fetched raw pages (`TData[]`). **`shouldFetchNextPage`** is called after each page — return `true` to keep fetching, `false` to stop. Use `() => true` to walk every page:
|
|
60
61
|
|
|
61
62
|
```typescript
|
|
62
63
|
import type { Instance, DescribeInstancesCommandInput } from '@aws-sdk/client-ec2';
|
|
@@ -79,7 +80,7 @@ const describeInstances = queryFactory({
|
|
|
79
80
|
|
|
80
81
|
function InstanceList() {
|
|
81
82
|
// one useQuery call; data is Instance[], not DescribeInstancesResponse[]
|
|
82
|
-
const { data } = useQuery(describeInstances({ MaxResults:
|
|
83
|
+
const { data } = useQuery(describeInstances({ MaxResults: 20 }));
|
|
83
84
|
}
|
|
84
85
|
```
|
|
85
86
|
|
|
@@ -94,11 +95,11 @@ const describeInstances = queryFactory({
|
|
|
94
95
|
});
|
|
95
96
|
|
|
96
97
|
// fetch all pages
|
|
97
|
-
const { data: all } = useQuery(describeInstances({ MaxResults:
|
|
98
|
+
const { data: all } = useQuery(describeInstances({ MaxResults: 20 }));
|
|
98
99
|
|
|
99
|
-
// stop after accumulating at least 50 instances
|
|
100
|
+
// stop after accumulating at least 50 instances (≥ 3 API calls)
|
|
100
101
|
const { data: partial } = useQuery(
|
|
101
|
-
describeInstances({ MaxResults:
|
|
102
|
+
describeInstances({ MaxResults: 20 }, { minResults: 50 })
|
|
102
103
|
);
|
|
103
104
|
```
|
|
104
105
|
|
|
@@ -117,9 +118,9 @@ const runningInstances = queryFactory(describeInstances, {
|
|
|
117
118
|
select: instances => instances.filter(i => i.State?.Name === 'running'),
|
|
118
119
|
});
|
|
119
120
|
|
|
120
|
-
// query key: ['ec2:DescribeInstances', { MaxResults:
|
|
121
|
+
// query key: ['ec2:DescribeInstances', { MaxResults: 20 }] (same cache entry as parent)
|
|
121
122
|
// data: Instance[] filtered to State.Name === 'running'
|
|
122
|
-
const { data } = useQuery(runningInstances({ MaxResults:
|
|
123
|
+
const { data } = useQuery(runningInstances({ MaxResults: 20 }));
|
|
123
124
|
```
|
|
124
125
|
|
|
125
126
|
Parent and child `select` functions compose automatically — if the parent already has a `select`, the child's `select` receives the parent's output, not the raw API response.
|
|
@@ -135,22 +136,41 @@ const findInstance = queryFactory(describeInstances, {
|
|
|
135
136
|
!instances.some(i => i.InstanceId === opts.instanceId),
|
|
136
137
|
});
|
|
137
138
|
|
|
138
|
-
// query key: ['ec2:DescribeInstances',
|
|
139
|
+
// query key: ['ec2:DescribeInstances', { MaxResults: 20 }, 'find', { instanceId: 'i-0abc123def456' }]
|
|
139
140
|
// crawls pages until the target instance appears, then stops
|
|
140
141
|
const { data } = useQuery(
|
|
141
|
-
findInstance({ MaxResults:
|
|
142
|
+
findInstance({ MaxResults: 20 }, { instanceId: 'i-0abc123def456' })
|
|
142
143
|
);
|
|
143
144
|
```
|
|
144
145
|
|
|
145
|
-
|
|
146
|
+
**Invalidation — broad and scoped:**
|
|
147
|
+
|
|
148
|
+
Child keys follow the ordering `[...parentNS, params, ...childSegments]`, which means the parent key for a given set of params is always a strict prefix of every child key for those same params:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
describeInstances({ MaxResults: 20 })
|
|
152
|
+
→ ['ec2:DescribeInstances', { MaxResults: 20 }]
|
|
153
|
+
|
|
154
|
+
runningInstances({ MaxResults: 20 }) // select child, no own segments
|
|
155
|
+
→ ['ec2:DescribeInstances', { MaxResults: 20 }] (same entry — select is not in the key)
|
|
156
|
+
|
|
157
|
+
findInstance({ MaxResults: 20 }, { instanceId: 'i-abc' })
|
|
158
|
+
→ ['ec2:DescribeInstances', { MaxResults: 20 }, 'find', { instanceId: 'i-abc' }]
|
|
159
|
+
// └── params ──────┘ └── own segs ──────────────────┘
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
This unlocks two invalidation granularities with no extra bookkeeping:
|
|
146
163
|
|
|
147
164
|
```typescript
|
|
148
|
-
//
|
|
149
|
-
// Calling the factory with no args produces just the namespace key; TanStack prefix-matches it
|
|
150
|
-
// against all entries, so describeInstances, runningInstances, and findInstance are all busted.
|
|
165
|
+
// Broad: zero-arg returns the namespace — busts every variant, every param set
|
|
151
166
|
await queryClient.invalidateQueries(describeInstances());
|
|
167
|
+
|
|
168
|
+
// Scoped: parent call with params — busts the parent and every child for those params only
|
|
169
|
+
await queryClient.invalidateQueries(describeInstances({ MaxResults: 20 }));
|
|
152
170
|
```
|
|
153
171
|
|
|
172
|
+
The scoped form is particularly useful after a targeted mutation: invalidate the one resource that changed without touching unrelated cache entries.
|
|
173
|
+
|
|
154
174
|
---
|
|
155
175
|
|
|
156
176
|
## Infinite queries
|
|
@@ -160,15 +180,17 @@ Every factory exposes a `.infinite()` method that returns `useInfiniteQuery`-com
|
|
|
160
180
|
```typescript
|
|
161
181
|
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery(
|
|
162
182
|
// load 50 instances per UI page, each backed by up to 5 DescribeInstances calls
|
|
163
|
-
describeInstances.infinite({ MaxResults:
|
|
183
|
+
describeInstances.infinite({ MaxResults: 20 }, { minResults: 50 })
|
|
164
184
|
);
|
|
165
185
|
|
|
166
186
|
// data.pages is Instance[][], one array per virtual page
|
|
167
187
|
```
|
|
168
188
|
|
|
169
189
|
The `.infinite()` key includes an `'infinite'` segment to keep it separate from the regular `useQuery` cache entry:
|
|
170
|
-
- `describeInstances({ MaxResults:
|
|
171
|
-
- `describeInstances.infinite({ MaxResults:
|
|
190
|
+
- `describeInstances({ MaxResults: 20 })` → `['ec2:DescribeInstances', { MaxResults: 20 }]`
|
|
191
|
+
- `describeInstances.infinite({ MaxResults: 20 })` → `['ec2:DescribeInstances', 'infinite', { MaxResults: 20 }]`
|
|
192
|
+
|
|
193
|
+
Child factories place `params` before their own key segments so that the parent key is always a prefix of the child key for the same params — enabling per-call-site scoped invalidation.
|
|
172
194
|
|
|
173
195
|
---
|
|
174
196
|
|
|
@@ -188,7 +210,7 @@ queryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions>(
|
|
|
188
210
|
|
|
189
211
|
Creates a child factory. Two overloads:
|
|
190
212
|
- **With a new `queryFn`** — inherits key namespace and standard options; crawling config must be re-declared if needed.
|
|
191
|
-
- **Without a `queryFn`** — inherits everything; accepts
|
|
213
|
+
- **Without a `queryFn`** — inherits everything; accepts `queryKey`, `select`, standard options, and any crawling fields (`shouldFetchNextPage`, `reduce`, `getNextPageParam`, `getPreviousPageParam`, `initialPageParam`) to override the parent's. `select` is composed with the parent's.
|
|
192
214
|
|
|
193
215
|
### `QueryFactoryConfig`
|
|
194
216
|
|
|
@@ -200,10 +222,10 @@ All fields except `reduce` and `shouldFetchNextPage` are the standard TanStack Q
|
|
|
200
222
|
| `queryFn` | `(params: TParams, ctx: QueryFunctionContext) => TData \| Promise<TData>` | Same as TanStack, with an extra leading `params` argument. |
|
|
201
223
|
| `select` | `(data: TData) => TSelected` | Exact TanStack API. Composed automatically on child factories. |
|
|
202
224
|
| `getNextPageParam` | `GetNextPageParamFunction<TPageParam, TData>` | Exact TanStack API. Required (with `shouldFetchNextPage`) to activate crawling. Required (with `initialPageParam`) for `.infinite()`. |
|
|
203
|
-
| `initialPageParam` | `TPageParam` | Exact TanStack API. Drives `TPageParam` inference — without it `ctx.pageParam` is typed `never`. Required for `.infinite()` to work at runtime. |
|
|
225
|
+
| `initialPageParam` | `TPageParam` | Exact TanStack API. Drives `TPageParam` inference — without it and without a `getNextPageParam` that provides inference, `ctx.pageParam` is typed `never`. Required for `.infinite()` to work at runtime. |
|
|
204
226
|
| `getPreviousPageParam` | `GetPreviousPageParamFunction<TPageParam, TData>` | Exact TanStack API. Passed through on `.infinite()`. |
|
|
205
227
|
| `shouldFetchNextPage` | `(combined: TSelected \| undefined, crawlOptions: TCrawlOptions) => boolean` | Library addition. **Required (with `getNextPageParam`) to activate crawling.** Called after each page — return `true` to keep fetching, `false` to stop. |
|
|
206
|
-
| `reduce` | `(acc: TSelected \| undefined, page: TData) => TSelected` | Library addition. Optional. Folds crawled pages into a single `TSelected` value; when omitted the result is
|
|
228
|
+
| `reduce` | `(acc: TSelected \| undefined, page: TData) => TSelected` | Library addition. Optional. Folds crawled pages into a single `TSelected` value; when omitted the result is an array of all fetched raw pages (`TData[]`). |
|
|
207
229
|
| + all `StandardQueryOptions` fields | | All options accepted by TanStack's `useQuery` / `useInfiniteQuery` except `queryKey`, `queryFn`, and `select` (which the factory owns). Includes `staleTime`, `gcTime`, `retry`, `retryOnMount`, `enabled`, `refetchOnWindowFocus`, `refetchOnReconnect`, `refetchOnMount`, `refetchInterval`, `refetchIntervalInBackground`, `networkMode`, `notifyOnChangeProps`, `throwOnError`, `structuralSharing`, `initialData`, `initialDataUpdatedAt`, `placeholderData`, `queryKeyHashFn`, `persister`, `meta`, `maxPages`, `experimental_prefetchInRender`. Function-form callbacks (e.g. `enabled: (query) => boolean`) are supported wherever TanStack accepts them. |
|
|
208
230
|
|
|
209
231
|
### `QueryFactory<TParams, TData, TError, TSelected, TPageParam, TCrawlOptions>`
|
package/dist/index.d.mts
CHANGED
|
@@ -62,15 +62,20 @@ type ResolvedQueryOptions<TData = unknown, TError = Error, TSelected = TData> =
|
|
|
62
62
|
/**
|
|
63
63
|
* What `factory.infinite(params)` returns — pass directly to `useInfiniteQuery()`.
|
|
64
64
|
*
|
|
65
|
-
* The `select` field
|
|
66
|
-
* guard making this type incompatible with `useQuery`.
|
|
65
|
+
* The `select` field input type (`InfiniteData<TData, TPageParam>`) is a structural
|
|
66
|
+
* guard making this type incompatible with `useQuery`, whose select expects `(data: TData)`.
|
|
67
|
+
*
|
|
68
|
+
* `TResult` is the concrete type that `useInfiniteQuery` will use as its `TData` — i.e.
|
|
69
|
+
* what `select` returns (or `InfiniteData<TData, TPageParam>` when no select is set).
|
|
70
|
+
* Carrying it explicitly avoids returning `any`, which would poison TResult inference
|
|
71
|
+
* in TypeScript 6 when callers spread this type and add their own `select`.
|
|
67
72
|
*/
|
|
68
|
-
type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unknown
|
|
73
|
+
type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unknown, TResult = InfiniteData<TData, TPageParam>> = Omit<StandardQueryOptions<TError, any>, 'persister'> & {
|
|
69
74
|
queryKey: QueryKey;
|
|
70
75
|
queryFn?: (context: QueryFunctionContext<QueryKey, TPageParam>) => TData | Promise<TData>;
|
|
71
|
-
/** Structural guard: the InfiniteData
|
|
76
|
+
/** Structural guard: the InfiniteData input type makes this incompatible with useQuery,
|
|
72
77
|
* whose select expects (data: TData) rather than (data: InfiniteData<TData, TPageParam>). */
|
|
73
|
-
select?: (data: InfiniteData<TData, TPageParam>) =>
|
|
78
|
+
select?: (data: InfiniteData<TData, TPageParam>) => TResult;
|
|
74
79
|
/** Required so this type satisfies useInfiniteQuery, which requires getNextPageParam. */
|
|
75
80
|
getNextPageParam: GetNextPageParamFunction<TPageParam, TData>;
|
|
76
81
|
getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
|
|
@@ -93,7 +98,7 @@ type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unkno
|
|
|
93
98
|
*/
|
|
94
99
|
interface QueryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, THasReduce extends boolean = boolean> {
|
|
95
100
|
(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedQueryOptions<TData, TError, TSelected>;
|
|
96
|
-
infinite(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedInfiniteOptions<TData, TError, TPageParam
|
|
101
|
+
infinite(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedInfiniteOptions<TData, TError, TPageParam, InfiniteData<TSelected, TPageParam>>;
|
|
97
102
|
}
|
|
98
103
|
/**
|
|
99
104
|
* Creates a standalone query factory with pagination and reduce. When `reduce` is
|
package/dist/index.d.ts
CHANGED
|
@@ -62,15 +62,20 @@ type ResolvedQueryOptions<TData = unknown, TError = Error, TSelected = TData> =
|
|
|
62
62
|
/**
|
|
63
63
|
* What `factory.infinite(params)` returns — pass directly to `useInfiniteQuery()`.
|
|
64
64
|
*
|
|
65
|
-
* The `select` field
|
|
66
|
-
* guard making this type incompatible with `useQuery`.
|
|
65
|
+
* The `select` field input type (`InfiniteData<TData, TPageParam>`) is a structural
|
|
66
|
+
* guard making this type incompatible with `useQuery`, whose select expects `(data: TData)`.
|
|
67
|
+
*
|
|
68
|
+
* `TResult` is the concrete type that `useInfiniteQuery` will use as its `TData` — i.e.
|
|
69
|
+
* what `select` returns (or `InfiniteData<TData, TPageParam>` when no select is set).
|
|
70
|
+
* Carrying it explicitly avoids returning `any`, which would poison TResult inference
|
|
71
|
+
* in TypeScript 6 when callers spread this type and add their own `select`.
|
|
67
72
|
*/
|
|
68
|
-
type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unknown
|
|
73
|
+
type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unknown, TResult = InfiniteData<TData, TPageParam>> = Omit<StandardQueryOptions<TError, any>, 'persister'> & {
|
|
69
74
|
queryKey: QueryKey;
|
|
70
75
|
queryFn?: (context: QueryFunctionContext<QueryKey, TPageParam>) => TData | Promise<TData>;
|
|
71
|
-
/** Structural guard: the InfiniteData
|
|
76
|
+
/** Structural guard: the InfiniteData input type makes this incompatible with useQuery,
|
|
72
77
|
* whose select expects (data: TData) rather than (data: InfiniteData<TData, TPageParam>). */
|
|
73
|
-
select?: (data: InfiniteData<TData, TPageParam>) =>
|
|
78
|
+
select?: (data: InfiniteData<TData, TPageParam>) => TResult;
|
|
74
79
|
/** Required so this type satisfies useInfiniteQuery, which requires getNextPageParam. */
|
|
75
80
|
getNextPageParam: GetNextPageParamFunction<TPageParam, TData>;
|
|
76
81
|
getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TData>;
|
|
@@ -93,7 +98,7 @@ type ResolvedInfiniteOptions<TData = unknown, TError = Error, TPageParam = unkno
|
|
|
93
98
|
*/
|
|
94
99
|
interface QueryFactory<TParams = void, TData = unknown, TError = Error, TSelected = TData, TPageParam = unknown, TCrawlOptions extends Record<string, unknown> = Record<string, unknown>, THasReduce extends boolean = boolean> {
|
|
95
100
|
(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedQueryOptions<TData, TError, TSelected>;
|
|
96
|
-
infinite(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedInfiniteOptions<TData, TError, TPageParam
|
|
101
|
+
infinite(params?: TParams, crawlOptions?: TCrawlOptions): ResolvedInfiniteOptions<TData, TError, TPageParam, InfiniteData<TSelected, TPageParam>>;
|
|
97
102
|
}
|
|
98
103
|
/**
|
|
99
104
|
* Creates a standalone query factory with pagination and reduce. When `reduce` is
|
package/dist/index.js
CHANGED
|
@@ -29,8 +29,7 @@ var FACTORY_CONFIG = /* @__PURE__ */ Symbol("factoryConfig");
|
|
|
29
29
|
var getEnvelopeNextPageParam = (envelope) => envelope.nextPageParam;
|
|
30
30
|
var noNextPage = () => void 0;
|
|
31
31
|
function resolveKey(namespace, params, crawlOptions) {
|
|
32
|
-
const
|
|
33
|
-
const withParams = params === void 0 ? base : [...base, params];
|
|
32
|
+
const withParams = params === void 0 ? namespace : [...namespace, params];
|
|
34
33
|
if (!crawlOptions) return withParams;
|
|
35
34
|
let defined;
|
|
36
35
|
for (const key in crawlOptions) {
|
|
@@ -40,9 +39,23 @@ function resolveKey(namespace, params, crawlOptions) {
|
|
|
40
39
|
}
|
|
41
40
|
return defined ? [...withParams, defined] : withParams;
|
|
42
41
|
}
|
|
43
|
-
function
|
|
42
|
+
function buildChildKey(parentKey, ownSegments, params, crawlOptions, infinite) {
|
|
43
|
+
let defined;
|
|
44
|
+
for (const key in crawlOptions) {
|
|
45
|
+
if (crawlOptions[key] !== void 0) {
|
|
46
|
+
(defined != null ? defined : defined = {})[key] = crawlOptions[key];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (params === void 0 && !defined) return [...parentKey];
|
|
50
|
+
const withParams = params !== void 0 ? [...parentKey, params] : [...parentKey];
|
|
51
|
+
const withOwn = [...withParams, ...ownSegments];
|
|
52
|
+
const withInfinite = infinite ? [...withOwn, "infinite"] : withOwn;
|
|
53
|
+
return defined ? [...withInfinite, defined] : withInfinite;
|
|
54
|
+
}
|
|
55
|
+
function wrapGetNextPageParam(getNextPageParam, shouldFetchNextPage, crawlOptions, select) {
|
|
44
56
|
return (lastPage, allPages, lastPageParam, allPageParams) => {
|
|
45
|
-
|
|
57
|
+
const combined = select ? select(lastPage) : lastPage;
|
|
58
|
+
if (!shouldFetchNextPage(combined, crawlOptions))
|
|
46
59
|
return void 0;
|
|
47
60
|
return getNextPageParam(lastPage, allPages, lastPageParam, allPageParams);
|
|
48
61
|
};
|
|
@@ -105,6 +118,7 @@ function buildInfiniteCrawlingQueryFn(queryFn, getNextPageParam, shouldFetchNext
|
|
|
105
118
|
function buildFactory(cfg) {
|
|
106
119
|
const {
|
|
107
120
|
queryKey: namespace,
|
|
121
|
+
parentKey,
|
|
108
122
|
queryFn: rawQueryFn,
|
|
109
123
|
select,
|
|
110
124
|
getNextPageParam,
|
|
@@ -114,6 +128,8 @@ function buildFactory(cfg) {
|
|
|
114
128
|
reduce,
|
|
115
129
|
standardOptions
|
|
116
130
|
} = cfg;
|
|
131
|
+
const ownSegments = parentKey !== void 0 ? namespace.slice(parentKey.length) : namespace;
|
|
132
|
+
const infiniteNamespace = [...namespace, "infinite"];
|
|
117
133
|
const hasCrawling = rawQueryFn !== void 0 && getNextPageParam !== void 0 && shouldFetchNextPage !== void 0;
|
|
118
134
|
const hasInfiniteCrawling = hasCrawling && reduce !== void 0;
|
|
119
135
|
const crawlingFn = hasCrawling ? buildCrawlingQueryFn(
|
|
@@ -129,7 +145,6 @@ function buildFactory(cfg) {
|
|
|
129
145
|
shouldFetchNextPage,
|
|
130
146
|
reduce
|
|
131
147
|
) : void 0;
|
|
132
|
-
const infiniteNamespace = [...resolveKey(namespace, void 0), "infinite"];
|
|
133
148
|
const envelopeSelect = infiniteCrawlingFn ? (data) => ({
|
|
134
149
|
...data,
|
|
135
150
|
pages: data.pages.map((e) => select ? select(e.data) : e.data)
|
|
@@ -139,7 +154,7 @@ function buildFactory(cfg) {
|
|
|
139
154
|
pages: data.pages.map(select)
|
|
140
155
|
}) : void 0;
|
|
141
156
|
const factory = function(params, crawlOptions = {}) {
|
|
142
|
-
const queryKey = resolveKey(namespace, params, crawlOptions);
|
|
157
|
+
const queryKey = parentKey !== void 0 ? buildChildKey(parentKey, ownSegments, params, crawlOptions) : resolveKey(namespace, params, crawlOptions);
|
|
143
158
|
const resolvedQueryFn = crawlingFn ? (ctx) => crawlingFn(params, crawlOptions, ctx) : rawQueryFn ? (ctx) => rawQueryFn(params, ctx) : void 0;
|
|
144
159
|
return {
|
|
145
160
|
...standardOptions,
|
|
@@ -150,7 +165,7 @@ function buildFactory(cfg) {
|
|
|
150
165
|
};
|
|
151
166
|
};
|
|
152
167
|
factory.infinite = function(params, crawlOptions = {}) {
|
|
153
|
-
const queryKey = resolveKey(infiniteNamespace, params, crawlOptions);
|
|
168
|
+
const queryKey = parentKey !== void 0 ? buildChildKey(parentKey, ownSegments, params, crawlOptions, true) : resolveKey(infiniteNamespace, params, crawlOptions);
|
|
154
169
|
if (infiniteCrawlingFn) {
|
|
155
170
|
return {
|
|
156
171
|
...standardOptions,
|
|
@@ -167,7 +182,8 @@ function buildFactory(cfg) {
|
|
|
167
182
|
const infiniteGetNextPageParam = getNextPageParam && shouldFetchNextPage ? wrapGetNextPageParam(
|
|
168
183
|
getNextPageParam,
|
|
169
184
|
shouldFetchNextPage,
|
|
170
|
-
crawlOptions
|
|
185
|
+
crawlOptions,
|
|
186
|
+
select
|
|
171
187
|
) : getNextPageParam != null ? getNextPageParam : noNextPage;
|
|
172
188
|
return {
|
|
173
189
|
...standardOptions,
|
|
@@ -234,6 +250,7 @@ function queryFactory(configOrParent, childConfig) {
|
|
|
234
250
|
} = childConfig;
|
|
235
251
|
return buildFactory({
|
|
236
252
|
queryKey: composedNamespace,
|
|
253
|
+
parentKey: parentCfg.queryKey,
|
|
237
254
|
queryFn: hasNewQueryFn ? childConfig.queryFn : parentCfg.queryFn,
|
|
238
255
|
select: resolvedSelect,
|
|
239
256
|
...crawling,
|
package/dist/index.mjs
CHANGED
|
@@ -3,8 +3,7 @@ var FACTORY_CONFIG = /* @__PURE__ */ Symbol("factoryConfig");
|
|
|
3
3
|
var getEnvelopeNextPageParam = (envelope) => envelope.nextPageParam;
|
|
4
4
|
var noNextPage = () => void 0;
|
|
5
5
|
function resolveKey(namespace, params, crawlOptions) {
|
|
6
|
-
const
|
|
7
|
-
const withParams = params === void 0 ? base : [...base, params];
|
|
6
|
+
const withParams = params === void 0 ? namespace : [...namespace, params];
|
|
8
7
|
if (!crawlOptions) return withParams;
|
|
9
8
|
let defined;
|
|
10
9
|
for (const key in crawlOptions) {
|
|
@@ -14,9 +13,23 @@ function resolveKey(namespace, params, crawlOptions) {
|
|
|
14
13
|
}
|
|
15
14
|
return defined ? [...withParams, defined] : withParams;
|
|
16
15
|
}
|
|
17
|
-
function
|
|
16
|
+
function buildChildKey(parentKey, ownSegments, params, crawlOptions, infinite) {
|
|
17
|
+
let defined;
|
|
18
|
+
for (const key in crawlOptions) {
|
|
19
|
+
if (crawlOptions[key] !== void 0) {
|
|
20
|
+
(defined != null ? defined : defined = {})[key] = crawlOptions[key];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (params === void 0 && !defined) return [...parentKey];
|
|
24
|
+
const withParams = params !== void 0 ? [...parentKey, params] : [...parentKey];
|
|
25
|
+
const withOwn = [...withParams, ...ownSegments];
|
|
26
|
+
const withInfinite = infinite ? [...withOwn, "infinite"] : withOwn;
|
|
27
|
+
return defined ? [...withInfinite, defined] : withInfinite;
|
|
28
|
+
}
|
|
29
|
+
function wrapGetNextPageParam(getNextPageParam, shouldFetchNextPage, crawlOptions, select) {
|
|
18
30
|
return (lastPage, allPages, lastPageParam, allPageParams) => {
|
|
19
|
-
|
|
31
|
+
const combined = select ? select(lastPage) : lastPage;
|
|
32
|
+
if (!shouldFetchNextPage(combined, crawlOptions))
|
|
20
33
|
return void 0;
|
|
21
34
|
return getNextPageParam(lastPage, allPages, lastPageParam, allPageParams);
|
|
22
35
|
};
|
|
@@ -79,6 +92,7 @@ function buildInfiniteCrawlingQueryFn(queryFn, getNextPageParam, shouldFetchNext
|
|
|
79
92
|
function buildFactory(cfg) {
|
|
80
93
|
const {
|
|
81
94
|
queryKey: namespace,
|
|
95
|
+
parentKey,
|
|
82
96
|
queryFn: rawQueryFn,
|
|
83
97
|
select,
|
|
84
98
|
getNextPageParam,
|
|
@@ -88,6 +102,8 @@ function buildFactory(cfg) {
|
|
|
88
102
|
reduce,
|
|
89
103
|
standardOptions
|
|
90
104
|
} = cfg;
|
|
105
|
+
const ownSegments = parentKey !== void 0 ? namespace.slice(parentKey.length) : namespace;
|
|
106
|
+
const infiniteNamespace = [...namespace, "infinite"];
|
|
91
107
|
const hasCrawling = rawQueryFn !== void 0 && getNextPageParam !== void 0 && shouldFetchNextPage !== void 0;
|
|
92
108
|
const hasInfiniteCrawling = hasCrawling && reduce !== void 0;
|
|
93
109
|
const crawlingFn = hasCrawling ? buildCrawlingQueryFn(
|
|
@@ -103,7 +119,6 @@ function buildFactory(cfg) {
|
|
|
103
119
|
shouldFetchNextPage,
|
|
104
120
|
reduce
|
|
105
121
|
) : void 0;
|
|
106
|
-
const infiniteNamespace = [...resolveKey(namespace, void 0), "infinite"];
|
|
107
122
|
const envelopeSelect = infiniteCrawlingFn ? (data) => ({
|
|
108
123
|
...data,
|
|
109
124
|
pages: data.pages.map((e) => select ? select(e.data) : e.data)
|
|
@@ -113,7 +128,7 @@ function buildFactory(cfg) {
|
|
|
113
128
|
pages: data.pages.map(select)
|
|
114
129
|
}) : void 0;
|
|
115
130
|
const factory = function(params, crawlOptions = {}) {
|
|
116
|
-
const queryKey = resolveKey(namespace, params, crawlOptions);
|
|
131
|
+
const queryKey = parentKey !== void 0 ? buildChildKey(parentKey, ownSegments, params, crawlOptions) : resolveKey(namespace, params, crawlOptions);
|
|
117
132
|
const resolvedQueryFn = crawlingFn ? (ctx) => crawlingFn(params, crawlOptions, ctx) : rawQueryFn ? (ctx) => rawQueryFn(params, ctx) : void 0;
|
|
118
133
|
return {
|
|
119
134
|
...standardOptions,
|
|
@@ -124,7 +139,7 @@ function buildFactory(cfg) {
|
|
|
124
139
|
};
|
|
125
140
|
};
|
|
126
141
|
factory.infinite = function(params, crawlOptions = {}) {
|
|
127
|
-
const queryKey = resolveKey(infiniteNamespace, params, crawlOptions);
|
|
142
|
+
const queryKey = parentKey !== void 0 ? buildChildKey(parentKey, ownSegments, params, crawlOptions, true) : resolveKey(infiniteNamespace, params, crawlOptions);
|
|
128
143
|
if (infiniteCrawlingFn) {
|
|
129
144
|
return {
|
|
130
145
|
...standardOptions,
|
|
@@ -141,7 +156,8 @@ function buildFactory(cfg) {
|
|
|
141
156
|
const infiniteGetNextPageParam = getNextPageParam && shouldFetchNextPage ? wrapGetNextPageParam(
|
|
142
157
|
getNextPageParam,
|
|
143
158
|
shouldFetchNextPage,
|
|
144
|
-
crawlOptions
|
|
159
|
+
crawlOptions,
|
|
160
|
+
select
|
|
145
161
|
) : getNextPageParam != null ? getNextPageParam : noNextPage;
|
|
146
162
|
return {
|
|
147
163
|
...standardOptions,
|
|
@@ -208,6 +224,7 @@ function queryFactory(configOrParent, childConfig) {
|
|
|
208
224
|
} = childConfig;
|
|
209
225
|
return buildFactory({
|
|
210
226
|
queryKey: composedNamespace,
|
|
227
|
+
parentKey: parentCfg.queryKey,
|
|
211
228
|
queryFn: hasNewQueryFn ? childConfig.queryFn : parentCfg.queryFn,
|
|
212
229
|
select: resolvedSelect,
|
|
213
230
|
...crawling,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robohall/react-query-factory",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
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",
|