Skip to content

Commit 6e5a84e

Browse files
committed
add withPostprocessor
1 parent 987b3b2 commit 6e5a84e

File tree

6 files changed

+53
-13
lines changed

6 files changed

+53
-13
lines changed

examples/vite/src/examples/main/example.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@ export const { useQuery: useArticle, ...articleQuery } = builder
2525
.withTags((ctx) => ({ type: 'article', id: ctx.data.id }))
2626
.withPath('/articles/:id')
2727
.withPreprocessor<{ id: number }>((vars) => ({ ...vars, params: { id: vars.id } }))
28-
.withMiddleware(async (ctx, next) => {
29-
const res = await next(ctx);
30-
return { ...res, titleUppercase: res.title.toUpperCase() };
31-
})
28+
.withPostprocessor((data) => ({ ...data, titleUppercase: data.title.toUpperCase() }))
3229
.asBound();
3330

3431
export const commentsQuery = builder

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

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { InferDataFromQueryTagOption, QueryTagObject, QueryTagOption, Query
44
import { TODO } from '../type-utils';
55
import { QueryBuilderFrozen } from './QueryBuilderFrozen';
66
import { type MiddlewareFn, createMiddlewareFunction } from './createMiddlewareFunction';
7+
import { PostprocessorFn } from './createMiddlewareFunction';
78
import { type PreprocessorFn, createPreprocessorFunction, identityPreprocessor } from './createPreprocessorFunction';
89
import { createTagMiddleware } from './createTagMiddleware';
910
import { createUpdateMiddleware } from './createUpdateMiddleware';
@@ -65,8 +66,8 @@ export class QueryBuilder<
6566
withPreprocessor(preprocessor: PreprocessorFn<TVars, TVars>): this;
6667

6768
/**
68-
* Adds a preprocessor function to the query with a different type of input variables.
69-
* The preprocessor function is called before the query function is called.
69+
* Adds a pre-processor function to the query with a different type of input variables.
70+
* The pre-processor function is called before the query function is called.
7071
*/
7172
withPreprocessor<TVars$ = TVars>(preprocessor: PreprocessorFn<TVars$, TVars>): QueryBuilder<TVars$, TData, TError, TKey, TTags, TFlags>;
7273

@@ -78,24 +79,35 @@ export class QueryBuilder<
7879
});
7980
}
8081

82+
/**
83+
* Adds a post-processor function to the query.
84+
* The post-processor function is called after the query function is successfully called.
85+
* It can be used to modify the output data.
86+
*/
87+
withPostprocessor<TData$ = TData>(
88+
postprocessor: PostprocessorFn<TData, TData$>,
89+
): QueryBuilder<TVars, TData$, TError, TKey, TTags, TFlags> {
90+
return this.withMiddleware(async (ctx, next) => postprocessor(await next(ctx)));
91+
}
92+
8193
/**
8294
* Adds a middleware function to the query.
8395
* The middleware function wraps the query function and
8496
* can be used to modify the input variables, the output data, or the error.
8597
*/
86-
withMiddleware(middleware: MiddlewareFn<TVars, TData, TError, TKey>): this;
98+
withMiddleware(middleware: MiddlewareFn<TVars, TData, TError, TKey, TData>): this;
8799

88100
/**
89101
* Adds a middleware function to the query with overloaded types.
90102
* The middleware function wraps the query function and
91103
* can be used to modify the input variables, the output data, or the error.
92104
*/
93105
withMiddleware<TVars$ = TVars, TData$ = TData, TError$ = TError>(
94-
middleware: MiddlewareFn<TVars$, TData$, TError$, TKey>,
106+
middleware: MiddlewareFn<TVars$, TData$, TError$, TKey, TData>,
95107
): QueryBuilder<TVars$, TData$, TError$, TKey, TTags, TFlags>;
96108

97109
withMiddleware<TVars$ = TVars, TData$ = TData, TError$ = TError>(
98-
middleware: MiddlewareFn<TVars$, TData$, TError$, TKey>,
110+
middleware: MiddlewareFn<TVars$, TData$, TError$, TKey, TData>,
99111
config?: Partial<BuilderConfig<TVars$, TData$, TError$, TKey>>,
100112
): QueryBuilder<TVars$, TData$, TError$, TKey, TTags, TFlags> {
101113
const newBuilder = this as unknown as QueryBuilder<TVars$, TData$, TError$, TKey, TTags, TFlags>;

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ export class QueryBuilderFrozen<
7878
TTags extends Record<string, unknown> = Record<string, unknown>,
7979
TFlags extends BuilderFlags = '',
8080
> {
81+
get types(): {
82+
vars: TVars;
83+
data: TData;
84+
error: TError;
85+
key: TKey;
86+
tagMap: TTags;
87+
flags: TFlags;
88+
} {
89+
throw new Error('Types should not be used in runtime. They are only for type inference.');
90+
}
91+
8192
constructor(public readonly config: BuilderConfig<TVars, TData, TError, TKey>) {
8293
if (config.bound) bindMethods(this, methodsToBind);
8394
this.client = new QueryBuilderClient(this) as typeof this.client;

packages/tanstack-query-builder/src/builder/createMiddlewareFunction.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { BuilderConfig } from './types';
22
import type { BuilderQueryContext, BuilderQueryFn } from './types';
33

4-
export type MiddlewareFn<TVars, TData, TError, TKey extends unknown[]> = (
4+
export type MiddlewareFn<TVars, TData, TError, TKey extends unknown[], TNextData> = (
55
context: MiddlewareContext<TKey>,
6-
next: MiddlewareNextFn<any, any, any, any>,
6+
next: MiddlewareNextFn<any, TNextData, any, TKey>,
77
config: BuilderConfig<TVars, TData, TError, TKey>,
88
) => TData | Promise<TData>;
99

@@ -22,11 +22,15 @@ const createMiddlewareContext = <TKey extends unknown[]>(context: BuilderQueryCo
2222
};
2323
};
2424

25-
export const createMiddlewareFunction = <TVars, TData, TError, TKey extends unknown[]>(
25+
export const createMiddlewareFunction = <TVars, TData, TError, TKey extends unknown[], TNextData>(
2626
originalFn: BuilderQueryFn<any, any, any, any>,
27-
middleware: MiddlewareFn<TVars, TData, TError, TKey>,
27+
middleware: MiddlewareFn<TVars, TData, TError, TKey, TNextData>,
2828
config: BuilderConfig<TVars, TData, TError, TKey>,
2929
): BuilderQueryFn<TVars, TData, TError, TKey> => {
3030
return async (context) =>
3131
middleware(createMiddlewareContext<TKey>(context), async (ctx) => originalFn({ ...context, queryKey: [ctx.vars] }), config);
3232
};
33+
34+
export type PostprocessorFn<TData, TModifiedData> = (data: TData) => TModifiedData;
35+
36+
export const identityPostprocessor = <TData = unknown, TOut = TData>(data: TData): TOut => data as unknown as TOut;

packages/tanstack-query-builder/src/http/HttpQueryBuilder.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { QueryClient } from '@tanstack/react-query';
22
import { QueryBuilder } from '../builder/QueryBuilder';
3+
import { PostprocessorFn } from '../builder/createMiddlewareFunction';
34
import type { BuilderPaginationOptions } from '../builder/options';
45
import type { BuilderConfig, BuilderFlags } from '../builder/types';
56
import type { RequestError } from '../http/errors';
@@ -144,6 +145,10 @@ export class HttpQueryBuilder<
144145
? HttpQueryBuilder<TParam, TSearch, TBody, THeader, TMeta, InferDataFromQueryTagOption<TTagOpt, TTags>, TError, TTags, TFlags, TKey>
145146
: this;
146147

148+
declare withPostprocessor: <TData$ = TData>(
149+
postprocessor: PostprocessorFn<TData, TData$>,
150+
) => HttpQueryBuilder<TParam, TSearch, TBody, THeader, TMeta, TData$, TError, TTags, TFlags, TKey>;
151+
147152
withTagTypes<TTag extends string, T = unknown>(): HttpQueryBuilder<
148153
TParam,
149154
TSearch,

website/docs/api/builder.mdx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ withPreprocessor(preprocessor): this
4040
Adds a preprocessor function to the query.
4141
The preprocessor function is called before the query function is called.
4242

43+
### withPostprocessor
44+
45+
```ts
46+
withPostprocessor(postprocessor): this
47+
```
48+
49+
Adds a postprocessor function to the query.
50+
The preprocessor function is called after the query function is called successfully.
51+
The postprocessor function can be used to modify the output data or the error.
52+
Note that this is a specific case of the middleware function and middleware functions can be used to handle more advanced use cases.
53+
4354
### withMiddleware
4455

4556
```ts

0 commit comments

Comments
 (0)