Skip to content

Commit 587167c

Browse files
committed
feat: Support dc mutation factory fn
1 parent 271834e commit 587167c

File tree

3 files changed

+123
-9
lines changed

3 files changed

+123
-9
lines changed

packages/react/src/data-connect/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ export type FlattenedMutationResult<Data, Variables> = Omit<
1818
// Helper function to determine if a key is a QueryKey.
1919
export function isQueryKey(key: unknown): key is QueryKey {
2020
return Array.isArray(key) && key.length > 0;
21-
}
21+
}

packages/react/src/data-connect/useDataConnectMutation.test.tsx

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,48 @@ describe("useDataConnectMutation", () => {
473473
);
474474
});
475475

476+
test("invalidates queries specified in the invalidate option as a QueryKey", async () => {
477+
const movieData = {
478+
title: "tanstack query firebase",
479+
genre: "library",
480+
imageUrl: "https://invertase.io/",
481+
};
482+
483+
const createdMovie = await createMovie(movieData);
484+
485+
const movieId = createdMovie?.data?.movie_insert?.id;
486+
487+
const { result } = renderHook(
488+
() =>
489+
useDataConnectMutation(createMovieRef, {
490+
invalidate: [["GetMovieById", { id: movieId }]],
491+
}),
492+
{
493+
wrapper,
494+
},
495+
);
496+
const movie = {
497+
title: "TanStack Query Firebase",
498+
genre: "invalidate_option_test",
499+
imageUrl: "https://test-image-url.com/",
500+
};
501+
502+
await act(async () => {
503+
await result.current.mutateAsync(movie);
504+
});
505+
506+
await waitFor(() => {
507+
expect(result.current.status).toBe("success");
508+
});
509+
510+
expect(invalidateQueriesSpy.mock.calls).toHaveLength(1);
511+
expect(invalidateQueriesSpy).toHaveBeenCalledWith(
512+
expect.objectContaining({
513+
queryKey: ["GetMovieById", { id: movieId }],
514+
}),
515+
);
516+
});
517+
476518
test("invalidates queries specified in the invalidate option for create mutations with both variable and non-variable refs", async () => {
477519
const movieData = {
478520
title: "tanstack query firebase",
@@ -1015,4 +1057,65 @@ describe("useDataConnectMutation", () => {
10151057
expect(deleteMutationResult.current.data?.movie_delete?.id).toBe(movieId);
10161058
});
10171059
});
1060+
1061+
test("executes mutation successfully with function ref", async () => {
1062+
const movie = {
1063+
title: "TanStack Query Firebase",
1064+
genre: "library",
1065+
imageUrl: "https://test-image-url.com/",
1066+
};
1067+
1068+
const { result } = renderHook(
1069+
() => useDataConnectMutation(() => createMovieRef(movie)),
1070+
{
1071+
wrapper,
1072+
},
1073+
);
1074+
1075+
await act(async () => {
1076+
await result.current.mutateAsync();
1077+
});
1078+
1079+
await waitFor(() => {
1080+
expect(result.current.isSuccess).toBe(true);
1081+
expect(result.current.data).toHaveProperty("movie_insert");
1082+
expect(result.current.data?.movie_insert).toMatchObject({
1083+
title: movie.title,
1084+
genre: movie.genre,
1085+
imageUrl: movie.imageUrl,
1086+
});
1087+
});
1088+
});
1089+
1090+
test("executes mutation successfully with function ref that accepts variables", async () => {
1091+
const { result } = renderHook(
1092+
() =>
1093+
useDataConnectMutation((title: string) =>
1094+
createMovieRef({
1095+
title,
1096+
genre: "library",
1097+
imageUrl: "https://test-image-url.com/",
1098+
}),
1099+
),
1100+
{
1101+
wrapper,
1102+
},
1103+
);
1104+
1105+
const movieTitle = "TanStack Query Firebase";
1106+
1107+
await act(async () => {
1108+
await result.current.mutateAsync(movieTitle);
1109+
});
1110+
1111+
await waitFor(() => {
1112+
expect(result.current.isSuccess).toBe(true);
1113+
expect(result.current.data).toHaveProperty("movie_insert");
1114+
expect(result.current.data?.movie_insert).toMatchObject({
1115+
title: movieTitle,
1116+
genre: "library",
1117+
imageUrl: "https://test-image-url.com/",
1118+
});
1119+
});
1120+
});
10181121
});

packages/react/src/data-connect/useDataConnectMutation.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,25 @@ export type useDataConnectMutationOptions<
2424
};
2525

2626
export function useDataConnectMutation<
27-
Fn extends (...args: any[]) => MutationRef<any, any>,
28-
Data = ReturnType<Fn> extends MutationRef<infer D, any> ? D : never,
29-
Variables = Fn extends (
30-
dc: DataConnect,
31-
vars: infer V
32-
) => MutationRef<any, any>
33-
? V
27+
Fn extends
28+
| (() => MutationRef<any, any>)
29+
| ((vars: any) => MutationRef<any, any>)
30+
| ((...args: any[]) => MutationRef<any, any>),
31+
Data = ReturnType<
32+
Fn extends (() => MutationRef<infer D, any>)
33+
? () => MutationRef<D, any>
34+
: Fn extends (vars: any) => MutationRef<infer D, any>
35+
? (vars: any) => MutationRef<D, any>
36+
: Fn
37+
> extends MutationRef<infer D, any>
38+
? D
39+
: never,
40+
Variables = Fn extends () => MutationRef<any, any>
41+
? void
3442
: Fn extends (vars: infer V) => MutationRef<any, any>
3543
? V
44+
: Fn extends (dc: DataConnect, vars: infer V) => MutationRef<any, any>
45+
? V
3646
: never
3747
>(
3848
ref: Fn,
@@ -73,7 +83,8 @@ export function useDataConnectMutation<
7383
options?.onSuccess?.(...args);
7484
},
7585
mutationFn: async (variables) => {
76-
const response = await executeMutation<Data, Variables>(ref(variables));
86+
const mutationRef = typeof ref === "function" ? ref(variables) : ref;
87+
const response = await executeMutation<Data, Variables>(mutationRef);
7788

7889
return {
7990
...response.data,

0 commit comments

Comments
 (0)