Skip to content

Commit 798124d

Browse files
slax57TkDodo
andauthored
fix(codemod): add support for useMutation (#7187)
* fix(codemod): add support for useMutation * fix(codemod): add missing empty line to test fixture file --------- Co-authored-by: Dominik Dorfmeister <[email protected]>
1 parent eaf4af6 commit 798124d

File tree

4 files changed

+113
-13
lines changed

4 files changed

+113
-13
lines changed

packages/query-codemods/src/v5/remove-overloads/__testfixtures__/bug-reports.input.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,32 @@ export function useWhatever({ thing }: { thing: string }) {
2525
{ enabled: Boolean(thing) },
2626
);
2727
}
28+
29+
// From: https://github.com/TanStack/query/issues/6548
30+
export function useDeleteSomething(): any {
31+
return useMutation(({ groupId }: { groupId: string }) => {
32+
return fetch(`/api/groups/${groupId}`, {
33+
method: 'DELETE',
34+
});
35+
});
36+
}
37+
38+
// From: https://github.com/TanStack/query/issues/6548
39+
export function useDeleteSomethingWithOnError(): any {
40+
return useMutation(
41+
({ groupId }: { groupId: string }) => {
42+
return fetch(`/api/groups/${groupId}`, {
43+
method: 'DELETE',
44+
});
45+
},
46+
{
47+
onError: (_error, _variables, context) => {
48+
// An error happened!
49+
console.log(
50+
`rolling back optimistic delete with id ${context.id}`
51+
);
52+
},
53+
}
54+
);
55+
}
56+

packages/query-codemods/src/v5/remove-overloads/__testfixtures__/bug-reports.output.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,32 @@ export function useWhatever({ thing }: { thing: string }) {
3232
});
3333
}
3434

35+
// From: https://github.com/TanStack/query/issues/6548
36+
export function useDeleteSomething(): any {
37+
return useMutation({
38+
mutationFn: ({ groupId }: { groupId: string }) => {
39+
return fetch(`/api/groups/${groupId}`, {
40+
method: 'DELETE',
41+
});
42+
}
43+
});
44+
}
45+
46+
// From: https://github.com/TanStack/query/issues/6548
47+
export function useDeleteSomethingWithOnError(): any {
48+
return useMutation({
49+
mutationFn: ({ groupId }: { groupId: string }) => {
50+
return fetch(`/api/groups/${groupId}`, {
51+
method: 'DELETE',
52+
});
53+
},
54+
55+
onError: (_error, _variables, context) => {
56+
// An error happened!
57+
console.log(
58+
`rolling back optimistic delete with id ${context.id}`
59+
);
60+
}
61+
});
62+
}
63+

packages/query-codemods/src/v5/remove-overloads/remove-overloads.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module.exports = (file, api) => {
1717
...dependencies,
1818
config: {
1919
keyName: 'queryKey',
20+
fnName: 'queryFn',
2021
queryClientMethods: [
2122
'cancelQueries',
2223
'getQueriesData',
@@ -35,8 +36,9 @@ module.exports = (file, api) => {
3536
...dependencies,
3637
config: {
3738
keyName: 'mutationKey',
39+
fnName: 'mutationFn',
3840
queryClientMethods: [],
39-
hooks: ['useIsMutating'],
41+
hooks: ['useIsMutating', 'useMutation'],
4042
},
4143
})
4244

packages/query-codemods/src/v5/remove-overloads/transformers/filter-aware-usage-transformer.js

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const createUseQueryLikeTransformer = require('../../../utils/transformers/use-q
1414
* @param {Object} utils
1515
* @param {import('jscodeshift').Collection} root
1616
* @param {string} filePath
17-
* @param {{keyName: "mutationKey"|"queryKey", queryClientMethods: ReadonlyArray<string>, hooks: ReadonlyArray<string>}} config
17+
* @param {{keyName: "mutationKey"|"queryKey", fnName: "mutationFn"|"queryFn", queryClientMethods: ReadonlyArray<string>, hooks: ReadonlyArray<string>}} config
1818
*/
1919
const transformFilterAwareUsages = ({
2020
jscodeshift,
@@ -28,15 +28,18 @@ const transformFilterAwareUsages = ({
2828
/**
2929
* @param {import('jscodeshift').CallExpression} node
3030
* @param {"mutationKey"|"queryKey"} keyName
31+
* @param {"mutationFn"|"queryFn"} fnName
3132
* @returns {boolean}
3233
*/
33-
const canSkipReplacement = (node, keyName) => {
34+
const canSkipReplacement = (node, keyName, fnName) => {
3435
const callArguments = node.arguments
3536

36-
const hasKeyProperty = () =>
37+
const hasKeyOrFnProperty = () =>
3738
callArguments[0].properties.some(
3839
(property) =>
39-
utils.isObjectProperty(property) && property.key.name !== keyName,
40+
utils.isObjectProperty(property) &&
41+
property.key.name !== keyName &&
42+
property.key.name !== fnName,
4043
)
4144

4245
/**
@@ -46,7 +49,7 @@ const transformFilterAwareUsages = ({
4649
return (
4750
callArguments.length > 0 &&
4851
utils.isObjectExpression(callArguments[0]) &&
49-
hasKeyProperty()
52+
hasKeyOrFnProperty()
5053
)
5154
}
5255

@@ -92,13 +95,50 @@ const transformFilterAwareUsages = ({
9295

9396
try {
9497
// If the given method/function call matches certain criteria, the node doesn't need to be replaced, this step can be skipped.
95-
if (canSkipReplacement(node, config.keyName)) {
98+
if (canSkipReplacement(node, config.keyName, config.fnName)) {
9699
return node
97100
}
98101

99102
/**
100-
* Here we attempt to determine the first parameter of the function call. If it's an array expression or an
101-
* identifier that references an array expression then we create an object property from it.
103+
* Here we attempt to determine the first parameter of the function call.
104+
* If it's a function definition, we can create an object property from it (the mutation fn).
105+
*/
106+
const firstArgument = node.arguments[0]
107+
if (isFunctionDefinition(firstArgument)) {
108+
const objectExpression = jscodeshift.objectExpression([
109+
jscodeshift.property(
110+
'init',
111+
jscodeshift.identifier(config.fnName),
112+
firstArgument,
113+
),
114+
])
115+
116+
const secondArgument = node.arguments[1]
117+
118+
if (secondArgument) {
119+
// If it's an object expression, we can copy the properties from it to the newly created object expression.
120+
if (utils.isObjectExpression(secondArgument)) {
121+
v5Utils.copyPropertiesFromSource(
122+
secondArgument,
123+
objectExpression,
124+
predicate,
125+
)
126+
} else {
127+
// Otherwise, we simply spread the second argument in the newly created object expression.
128+
objectExpression.properties.push(
129+
jscodeshift.spreadElement(secondArgument),
130+
)
131+
}
132+
}
133+
134+
return jscodeshift.callExpression(node.original.callee, [
135+
objectExpression,
136+
])
137+
}
138+
139+
/**
140+
* If, instead, the first parameter is an array expression or an identifier that references
141+
* an array expression, then we create an object property from it (the query or mutation key).
102142
*
103143
* @type {import('jscodeshift').Property|undefined}
104144
*/
@@ -126,12 +166,12 @@ const transformFilterAwareUsages = ({
126166
const firstArgument = jscodeshift.objectExpression([
127167
jscodeshift.property(
128168
'init',
129-
jscodeshift.identifier('queryKey'),
169+
jscodeshift.identifier(config.keyName),
130170
originalArguments[0],
131171
),
132172
jscodeshift.property(
133173
'init',
134-
jscodeshift.identifier('queryFn'),
174+
jscodeshift.identifier(config.fnName),
135175
secondArgument,
136176
),
137177
])
@@ -153,12 +193,12 @@ const transformFilterAwareUsages = ({
153193
const objectExpression = jscodeshift.objectExpression([
154194
jscodeshift.property(
155195
'init',
156-
jscodeshift.identifier('queryKey'),
196+
jscodeshift.identifier(config.keyName),
157197
node.arguments[0],
158198
),
159199
jscodeshift.property(
160200
'init',
161-
jscodeshift.identifier('queryFn'),
201+
jscodeshift.identifier(config.fnName),
162202
secondParameter,
163203
),
164204
])

0 commit comments

Comments
 (0)