Skip to content

Commit 2152c80

Browse files
committed
add withPagination with separate options
1 parent 4f7a66c commit 2152c80

File tree

8 files changed

+58
-37
lines changed

8 files changed

+58
-37
lines changed

examples/vite/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const postsQuery = builder
3333
.withData<PostData[]>()
3434
.withSearch<{ page?: number }>()
3535
.withPagination({
36-
getInitialPageParam: { search: { page: 0 } },
36+
initialPageParam: { search: { page: 0 } },
3737
getNextPageParam: (prev, __, lastVars) => (!prev?.length ? null : { search: { page: (lastVars?.search?.page || 0) + 1 } }),
3838
});
3939

@@ -92,7 +92,7 @@ function AppCore() {
9292
const [enablePrefetch, setEnablePrefetch] = useState(false);
9393
const [postId, setPostId] = useState<number | null>(null);
9494

95-
const posts = postsQuery.useInfiniteQuery({}, { enabled: postId != null });
95+
const posts = postsQuery.useInfiniteQuery({}, { enabled: postId == null });
9696
const reset = resetMutation.useMutation();
9797

9898
const deleteErrors = deletePostMutation.useMutationState(undefined, { status: 'error' }, (x) => x.state.variables?.params.id);

packages/react-query-builder/src/builder/HttpQueryBuilder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class HttpQueryBuilder<
8383
) => HttpQueryBuilder<TParam, TSearch, TBody, THeader, TMeta, TData, TError, TTags, TFlags | 'withClient', TKey>;
8484

8585
declare withPagination: (
86-
paginationConfig: BuilderPaginationOptions<HttpBuilderVars<TParam, TSearch, TBody, THeader, TMeta>, TData, TError, TKey>,
86+
paginationOptions: BuilderPaginationOptions<HttpBuilderVars<TParam, TSearch, TBody, THeader, TMeta>, TData, TError, TKey>,
8787
) => HttpQueryBuilder<TParam, TSearch, TBody, THeader, TMeta, TData, TError, TTags, TFlags | 'withPagination', TKey>;
8888

8989
withTagTypes<TTag extends string, T = unknown>(): HttpQueryBuilder<

packages/react-query-builder/src/builder/QueryBuilder.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ export class QueryBuilder<
102102
}
103103

104104
withPagination(
105-
paginationConfig: BuilderPaginationOptions<TVars, TData, TError, TKey>,
105+
paginationOptions: BuilderPaginationOptions<TVars, TData, TError, TKey>,
106106
): QueryBuilder<TVars, TData, TError, TKey, TTags, TFlags | 'withPagination'> {
107-
return this.withConfig({ options: paginationConfig }) as any;
107+
return this.withConfig({ paginationOptions }) as any;
108108
}
109109

110110
freeze(): QueryBuilderFrozen<TVars, TData, TError, TKey, TTags, TFlags> {

packages/react-query-builder/src/builder/QueryBuilderClient.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@ export class QueryBuilderClient<
2121
TFilters = QueryFilters<TData, TError, TData, TKey>,
2222
> {
2323
private declare _options: BuilderConfig<TVars, TData, TError, TKey>['options'];
24+
private declare _pgOptions: BuilderConfig<TVars, TData, TError, TKey>['paginationOptions'];
2425
constructor(private builder: QueryBuilderFrozen<TVars, TData, TError, TKey, TTags, any>) {}
2526

2627
readonly ensureData = (vars: TVars, opts?: typeof this._options) =>
2728
this.builder.config.queryClient?.ensureQueryData(this.builder.getQueryOptions(vars, opts));
2829

29-
readonly ensureInfiniteData = (vars: TVars, opts?: typeof this._options) =>
30+
readonly ensureInfiniteData = (vars: TVars, opts?: typeof this._pgOptions) =>
3031
this.builder.config.queryClient?.ensureInfiniteQueryData(this.builder.getInfiniteQueryOptions(vars, opts));
3132

3233
readonly refetch = (vars: TVars, filters?: TFilters, opts?: RefetchOptions) =>
@@ -35,7 +36,7 @@ export class QueryBuilderClient<
3536
readonly fetch = (vars: TVars, opts?: typeof this._options) =>
3637
this.builder.config.queryClient?.fetchQuery(this.builder.getQueryOptions(vars, opts));
3738

38-
readonly fetchInfinite = (vars: TVars, opts?: typeof this._options) =>
39+
readonly fetchInfinite = (vars: TVars, opts?: typeof this._pgOptions) =>
3940
this.builder.config.queryClient?.fetchInfiniteQuery(this.builder.getInfiniteQueryOptions(vars, opts));
4041

4142
readonly isFetching = (vars: TVars, filters?: TFilters) =>
@@ -44,7 +45,7 @@ export class QueryBuilderClient<
4445
readonly prefetch = (vars: TVars, opts?: typeof this._options) =>
4546
this.builder.config.queryClient?.prefetchQuery(this.builder.getQueryOptions(vars, opts));
4647

47-
readonly prefetchInfinite = (vars: TVars, opts?: typeof this._options) =>
48+
readonly prefetchInfinite = (vars: TVars, opts?: typeof this._pgOptions) =>
4849
this.builder.config.queryClient?.prefetchInfiniteQuery(this.builder.getInfiniteQueryOptions(vars, opts));
4950

5051
readonly reset = (vars: TVars, filters?: TFilters, opts?: ResetOptions) =>

packages/react-query-builder/src/builder/QueryBuilderFrozen.ts

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
QueryClient,
99
QueryFilters,
1010
QueryFunction,
11-
UseInfiniteQueryOptions,
1211
UseInfiniteQueryResult,
1312
UseMutationOptions,
1413
UseQueryResult,
@@ -28,10 +27,10 @@ import {
2827
useSuspenseQueries,
2928
useSuspenseQuery,
3029
} from '@tanstack/react-query';
31-
import type { FunctionType, TODO, WithRequired } from '../type-utils';
30+
import type { TODO, WithRequired } from '../type-utils';
3231
import { QueryBuilderClient } from './QueryBuilderClient';
3332
import { QueryBuilderTagsManager } from './QueryBuilderTagsManager';
34-
import { type BuilderOptions, mergeBuilderOptions } from './options';
33+
import { type BuilderOptions, BuilderPaginationOptions, mergeBuilderOptions, mergeBuilderPaginationOptions } from './options';
3534
import type { BuilderConfig, BuilderFlags, BuilderQueriesResult, HasClient, HasPagination } from './types';
3635
import { areKeysEqual, getRandomKey, mergeMutationOptions, mergeVars } from './utils';
3736

@@ -44,6 +43,7 @@ export class QueryBuilderFrozen<
4443
TFlags extends BuilderFlags = '',
4544
> {
4645
protected declare _options: BuilderOptions<TVars, TData, TError, TKey>;
46+
protected declare _pgOptions: Partial<BuilderPaginationOptions<TVars, TData, TError, TKey>>;
4747

4848
constructor(public readonly config: BuilderConfig<TVars, TData, TError, TKey>) {}
4949

@@ -53,6 +53,7 @@ export class QueryBuilderFrozen<
5353
...other,
5454
vars: mergeVars([config.vars, other.vars], other.mergeVars || config.mergeVars),
5555
options: mergeBuilderOptions([config.options, other.options]),
56+
paginationOptions: mergeBuilderPaginationOptions([config.paginationOptions, other.paginationOptions]),
5657
};
5758
};
5859

@@ -179,13 +180,12 @@ export class QueryBuilderFrozen<
179180
//#region InfiniteQuery
180181

181182
getInfiniteQueryOptions = ((vars, opts) => {
182-
// TODO: eventually allow these options as well
183+
// Remove incompatible options from the base query options
183184
const {
184185
enabled,
185186
staleTime,
186187
initialData,
187188
placeholderData,
188-
getInitialPageParam,
189189
refetchInterval,
190190
refetchOnWindowFocus,
191191
refetchOnReconnect,
@@ -194,38 +194,42 @@ export class QueryBuilderFrozen<
194194
persister,
195195
behavior,
196196
...options
197-
} = this.getQueryOptions(vars, opts, 'infiniteQuery');
198-
return {
199-
...options,
200-
initialPageParam: typeof getInitialPageParam === 'function' ? getInitialPageParam() : getInitialPageParam!,
201-
getNextPageParam: options.getNextPageParam!,
202-
};
197+
} = this.config.options || {};
198+
199+
return mergeBuilderPaginationOptions([
200+
{
201+
queryFn: this.getQueryFn('infiniteQuery'),
202+
queryKeyHashFn: this.getQueryKeyHashFn(),
203+
queryKey: this.getQueryKey(vars),
204+
},
205+
options,
206+
this.config.paginationOptions,
207+
opts,
208+
]);
203209
}) as HasPagination<
204210
TFlags,
205211
(
206212
vars: TVars,
207-
opts?: typeof this._options,
208-
) => UseInfiniteQueryOptions<TData, TError, InfiniteData<TData, Partial<TVars>>, TData, TKey, Partial<TVars>> & {
209-
queryFn: FunctionType;
210-
}
213+
opts?: typeof this._pgOptions,
214+
) => WithRequired<BuilderPaginationOptions<TVars, TData, TError, TKey>, 'queryFn' | 'queryKey' | 'initialPageParam'>
211215
>;
212216

213217
useInfiniteQuery = ((vars, opts) => {
214218
return useInfiniteQuery(this.getInfiniteQueryOptions(vars, opts), this.config.queryClient);
215219
}) as HasPagination<
216220
TFlags,
217-
(vars: TVars, opts?: typeof this._options) => UseInfiniteQueryResult<InfiniteData<TData, Partial<TVars>>, TError>
221+
(vars: TVars, opts?: typeof this._pgOptions) => UseInfiniteQueryResult<InfiniteData<TData, Partial<TVars>>, TError>
218222
>;
219223

220224
usePrefetchInfiniteQuery = ((vars, opts) => {
221225
return usePrefetchInfiniteQuery(this.getInfiniteQueryOptions(vars, opts), this.config.queryClient);
222-
}) as HasPagination<TFlags, (vars: TVars, opts?: typeof this._options) => void>;
226+
}) as HasPagination<TFlags, (vars: TVars, opts?: typeof this._pgOptions) => void>;
223227

224228
useSuspenseInfiniteQuery = ((vars, opts) => {
225229
return useSuspenseInfiniteQuery(this.getInfiniteQueryOptions(vars, opts), this.config.queryClient);
226230
}) as HasPagination<
227231
TFlags,
228-
(vars: TVars, opts?: typeof this._options) => UseSuspenseInfiniteQueryResult<InfiniteData<TData, Partial<TVars>>, TError>
232+
(vars: TVars, opts?: typeof this._pgOptions) => UseSuspenseInfiniteQueryResult<InfiniteData<TData, Partial<TVars>>, TError>
229233
>;
230234

231235
//#endregion

packages/react-query-builder/src/builder/QueryBuilderTagsManager.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import type { QueryTagContext, QueryUpdateTag, TagOperationOptions } from '../ta
44
import { updateTags } from '../tags/updateTags';
55
import type { WithOptional } from '../type-utils';
66
import type { QueryBuilderFrozen } from './QueryBuilderFrozen';
7-
import type { BuilderConfig } from './types';
87

98
export class QueryBuilderTagsManager<TVars, TData, TError, TKey extends unknown[], TTags extends Record<string, unknown>> {
10-
private declare _options: BuilderConfig<TVars, TData, TError, TKey>['options'];
119
constructor(private builder: QueryBuilderFrozen<TVars, TData, TError, TKey, TTags>) {}
1210

1311
/**

packages/react-query-builder/src/builder/options.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
1-
import type { GetNextPageParamFunction, GetPreviousPageParamFunction, UseMutationOptions, UseQueryOptions } from '@tanstack/react-query';
1+
import type { InfiniteData, UseInfiniteQueryOptions, UseMutationOptions, UseQueryOptions } from '@tanstack/react-query';
22
import type { FunctionType, WithOptional } from '../type-utils';
33
import { mergeQueryEnabled } from './utils';
44

5-
export type BuilderPaginationOptions<TVars, TData, TError, TKey extends unknown[]> = {
6-
getNextPageParam: GetNextPageParamFunction<Partial<TVars>, TData>;
7-
getPreviousPageParam?: GetPreviousPageParamFunction<Partial<TVars>, TData>;
8-
getInitialPageParam?: Partial<TVars> | (() => Partial<TVars>);
9-
};
5+
export type BuilderPaginationOptions<TVars, TData, TError, TKey extends unknown[]> = WithOptional<
6+
UseInfiniteQueryOptions<TData, TError, InfiniteData<TData, Partial<TVars>>, TData, TKey, Partial<TVars>>,
7+
'queryFn' | 'queryKey' | 'initialPageParam'
8+
> & { queryFn?: FunctionType };
109

1110
export type BuilderOptions<TVars, TData, TError, TKey extends unknown[]> = WithOptional<
1211
UseQueryOptions<TData, TError, TData, TKey>,
1312
'queryFn' | 'queryKey'
14-
> & { queryFn?: FunctionType } & Partial<BuilderPaginationOptions<TVars, TData, TError, TKey>> &
15-
Pick<
13+
> & { queryFn?: FunctionType } & Pick<
1614
UseMutationOptions<TData, TError, TVars>,
1715
'onError' | 'onMutate' | 'onSettled' | 'onSuccess' | 'gcTime' | 'mutationKey' | 'networkMode' | 'retry' | 'retryDelay' | 'throwOnError'
1816
>;
@@ -35,3 +33,22 @@ export function mergeBuilderOptions<TVars, TData, TError, TKey extends unknown[]
3533

3634
return opts;
3735
}
36+
37+
export function mergeBuilderPaginationOptions<TVars, TData, TError, TKey extends unknown[]>(
38+
optsList: (Partial<BuilderPaginationOptions<TVars, TData, TError, TKey>> | undefined | null)[],
39+
): BuilderPaginationOptions<TVars, TData, TError, TKey> {
40+
type TOpt = BuilderPaginationOptions<TVars, TData, TError, TKey>;
41+
const filtered = optsList.filter(Boolean) as TOpt[];
42+
43+
if (filtered.length === 1) return filtered[0];
44+
45+
const opts = {} as TOpt;
46+
47+
for (const { enabled, meta, ...opt } of filtered) {
48+
Object.assign(opts, opt);
49+
opts.enabled = mergeQueryEnabled([opts.enabled, enabled]) as TOpt['enabled'];
50+
opts.meta = { ...opts.meta, ...meta };
51+
}
52+
53+
return opts;
54+
}

packages/react-query-builder/src/builder/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { QueryClient, QueryFunctionContext, QueryKey, UseQueryResult } from '@tanstack/react-query';
22
import type { HttpRequestOptions } from '../http/types';
33
import type { HasFlag, Prettify } from '../type-utils';
4-
import type { BuilderOptions } from './options';
4+
import type { BuilderOptions, BuilderPaginationOptions } from './options';
55

66
export type BuilderConfig<TVars, TData, TError, TKey extends unknown[]> = {
77
queryFn: BuilderQueryFn<TVars, TData, TError, TKey>;
@@ -12,6 +12,7 @@ export type BuilderConfig<TVars, TData, TError, TKey extends unknown[]> = {
1212
syncChannel?: BroadcastChannel;
1313
preprocessorFn?: (vars: TVars) => TKey[0];
1414
options?: BuilderOptions<TVars, TData, TError, TKey>;
15+
paginationOptions?: BuilderPaginationOptions<TVars, TData, TError, TKey>;
1516
};
1617

1718
export type HttpBaseHeaders = Record<string, string | string[]>;

0 commit comments

Comments
 (0)