Skip to content

Commit 4772050

Browse files
authored
Merge pull request #10851 from marmelab/offline-support-mutations-keys
Add `mutationKey` to all mutations
2 parents 0d1be4c + 45528e2 commit 4772050

File tree

10 files changed

+234
-6
lines changed

10 files changed

+234
-6
lines changed

packages/ra-core/src/dataProvider/useCreate.spec.tsx

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
WithMiddlewaresSuccess as WithMiddlewaresSuccessUndoable,
2626
WithMiddlewaresError as WithMiddlewaresErrorUndoable,
2727
} from './useCreate.undoable.stories';
28+
import { QueryClient, useMutationState } from '@tanstack/react-query';
2829

2930
describe('useCreate', () => {
3031
it('returns a callback that can be used with create arguments', async () => {
@@ -99,7 +100,7 @@ describe('useCreate', () => {
99100
});
100101
});
101102

102-
it('accepts a meta paramater', async () => {
103+
it('accepts a meta parameter', async () => {
103104
const dataProvider = testDataProvider({
104105
create: jest.fn(() => Promise.resolve({ data: { id: 1 } } as any)),
105106
});
@@ -124,6 +125,47 @@ describe('useCreate', () => {
124125
});
125126
});
126127

128+
it('sets the mutationKey', async () => {
129+
const queryClient = new QueryClient();
130+
queryClient.setMutationDefaults(['foo', 'create'], {
131+
meta: { hello: 'world' },
132+
});
133+
134+
const dataProvider = testDataProvider({
135+
create: jest.fn(() => Promise.resolve({ data: { id: 1 } } as any)),
136+
});
137+
let localCreate;
138+
const Dummy = () => {
139+
const [create] = useCreate('foo');
140+
localCreate = create;
141+
return <span />;
142+
};
143+
const Observe = () => {
144+
const mutation = useMutationState({
145+
filters: {
146+
mutationKey: ['foo', 'create'],
147+
},
148+
});
149+
150+
return <span>mutations: {mutation.length}</span>;
151+
};
152+
153+
render(
154+
<CoreAdminContext dataProvider={dataProvider}>
155+
<Dummy />
156+
<Observe />
157+
</CoreAdminContext>
158+
);
159+
localCreate('foo', { data: { bar: 'baz' }, meta: { hello: 'world' } });
160+
await waitFor(() => {
161+
expect(dataProvider.create).toHaveBeenCalledWith('foo', {
162+
data: { bar: 'baz' },
163+
meta: { hello: 'world' },
164+
});
165+
});
166+
await screen.findByText('mutations: 1');
167+
});
168+
127169
it('returns a state typed based on the parametric type', async () => {
128170
interface Product extends RaRecord {
129171
sku: string;

packages/ra-core/src/dataProvider/useCreate.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ export const useCreate = <
152152
MutationError,
153153
Partial<UseCreateMutateParams<RecordType>>
154154
>({
155+
mutationKey: [resource, 'create', params],
155156
mutationFn: ({
156157
resource: callTimeResource = resource,
157158
data: callTimeData = paramsRef.current.data,

packages/ra-core/src/dataProvider/useDelete.spec.tsx

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
ErrorCase as ErrorCaseUndoable,
2020
SuccessCase as SuccessCaseUndoable,
2121
} from './useDelete.undoable.stories';
22-
import { QueryClient } from '@tanstack/react-query';
22+
import { QueryClient, useMutationState } from '@tanstack/react-query';
2323

2424
describe('useDelete', () => {
2525
it('returns a callback that can be used with deleteOne arguments', async () => {
@@ -136,6 +136,47 @@ describe('useDelete', () => {
136136
});
137137
});
138138

139+
it('sets the mutationKey', async () => {
140+
const dataProvider = testDataProvider({
141+
delete: jest.fn(() => Promise.resolve({ data: { id: 1 } } as any)),
142+
});
143+
let localDeleteOne;
144+
const Dummy = () => {
145+
const [deleteOne] = useDelete('foo');
146+
localDeleteOne = deleteOne;
147+
return <span />;
148+
};
149+
const Observe = () => {
150+
const mutation = useMutationState({
151+
filters: {
152+
mutationKey: ['foo', 'delete'],
153+
},
154+
});
155+
156+
return <span>mutations: {mutation.length}</span>;
157+
};
158+
159+
render(
160+
<CoreAdminContext dataProvider={dataProvider}>
161+
<Dummy />
162+
<Observe />
163+
</CoreAdminContext>
164+
);
165+
localDeleteOne('foo', {
166+
id: 1,
167+
previousData: { id: 1, bar: 'bar' },
168+
meta: { hello: 'world' },
169+
});
170+
await waitFor(() => {
171+
expect(dataProvider.delete).toHaveBeenCalledWith('foo', {
172+
id: 1,
173+
previousData: { id: 1, bar: 'bar' },
174+
meta: { hello: 'world' },
175+
});
176+
});
177+
await screen.findByText('mutations: 1');
178+
});
179+
139180
it('returns data typed based on the parametric type', async () => {
140181
interface Product extends RaRecord {
141182
sku: string;

packages/ra-core/src/dataProvider/useDelete.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ export const useDelete = <
194194
MutationError,
195195
Partial<UseDeleteMutateParams<RecordType>>
196196
>({
197+
mutationKey: [resource, 'delete', params],
197198
mutationFn: ({
198199
resource: callTimeResource = resource,
199200
id: callTimeId = paramsRef.current.id,

packages/ra-core/src/dataProvider/useDeleteMany.spec.tsx

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as React from 'react';
2-
import { waitFor, render } from '@testing-library/react';
2+
import { waitFor, render, screen } from '@testing-library/react';
33
import expect from 'expect';
44

55
import { CoreAdminContext } from '../core';
66
import { testDataProvider } from './testDataProvider';
77
import { useDeleteMany } from './useDeleteMany';
8-
import { QueryClient } from '@tanstack/react-query';
8+
import { QueryClient, useMutationState } from '@tanstack/react-query';
99

1010
describe('useDeleteMany', () => {
1111
it('returns a callback that can be used with update arguments', async () => {
@@ -80,6 +80,64 @@ describe('useDeleteMany', () => {
8080
});
8181
});
8282

83+
it('accepts a meta parameter', async () => {
84+
const dataProvider = testDataProvider({
85+
deleteMany: jest.fn(() => Promise.resolve({ data: [1, 2] } as any)),
86+
});
87+
let localDeleteMany;
88+
const Dummy = () => {
89+
const [deleteMany] = useDeleteMany();
90+
localDeleteMany = deleteMany;
91+
return <span />;
92+
};
93+
94+
render(
95+
<CoreAdminContext dataProvider={dataProvider}>
96+
<Dummy />
97+
</CoreAdminContext>
98+
);
99+
localDeleteMany('foo', { ids: [1, 2], meta: { hello: 'world' } });
100+
await waitFor(() => {
101+
expect(dataProvider.deleteMany).toHaveBeenCalledWith('foo', {
102+
ids: [1, 2],
103+
meta: { hello: 'world' },
104+
});
105+
});
106+
});
107+
it('sets the mutationKey', async () => {
108+
const dataProvider = testDataProvider({
109+
deleteMany: jest.fn(() => Promise.resolve({ data: [1, 2] } as any)),
110+
});
111+
let localDeleteMany;
112+
const Dummy = () => {
113+
const [deleteMany] = useDeleteMany('foo');
114+
localDeleteMany = deleteMany;
115+
return <span />;
116+
};
117+
const Observe = () => {
118+
const mutation = useMutationState({
119+
filters: {
120+
mutationKey: ['foo', 'deleteMany'],
121+
},
122+
});
123+
124+
return <span>mutations: {mutation.length}</span>;
125+
};
126+
127+
render(
128+
<CoreAdminContext dataProvider={dataProvider}>
129+
<Dummy />
130+
<Observe />
131+
</CoreAdminContext>
132+
);
133+
localDeleteMany('foo', { ids: [1, 2] });
134+
await waitFor(() => {
135+
expect(dataProvider.deleteMany).toHaveBeenCalledWith('foo', {
136+
ids: [1, 2],
137+
});
138+
});
139+
await screen.findByText('mutations: 1');
140+
});
83141
it('accepts a meta parameter', async () => {
84142
const dataProvider = testDataProvider({
85143
deleteMany: jest.fn(() => Promise.resolve({ data: [1, 2] } as any)),

packages/ra-core/src/dataProvider/useDeleteMany.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ export const useDeleteMany = <
220220
MutationError,
221221
Partial<UseDeleteManyMutateParams<RecordType>>
222222
>({
223+
mutationKey: [resource, 'deleteMany', params],
223224
mutationFn: ({
224225
resource: callTimeResource = resource,
225226
ids: callTimeIds = paramsRef.current.ids,

packages/ra-core/src/dataProvider/useUpdate.spec.tsx

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
WithMiddlewaresSuccess as WithMiddlewaresSuccessUndoable,
2525
WithMiddlewaresError as WithMiddlewaresErrorUndoable,
2626
} from './useUpdate.undoable.stories';
27-
import { QueryClient } from '@tanstack/react-query';
27+
import { QueryClient, useMutationState } from '@tanstack/react-query';
2828

2929
describe('useUpdate', () => {
3030
describe('mutate', () => {
@@ -190,6 +190,48 @@ describe('useUpdate', () => {
190190
});
191191
});
192192
});
193+
it('sets the mutationKey', async () => {
194+
const dataProvider = {
195+
update: jest.fn(() => Promise.resolve({ data: { id: 1 } } as any)),
196+
} as any;
197+
let localUpdate;
198+
const Dummy = () => {
199+
const [update] = useUpdate('foo');
200+
localUpdate = update;
201+
return <span />;
202+
};
203+
const Observe = () => {
204+
const mutation = useMutationState({
205+
filters: {
206+
mutationKey: ['foo', 'update'],
207+
},
208+
});
209+
210+
return <span>mutations: {mutation.length}</span>;
211+
};
212+
213+
render(
214+
<CoreAdminContext dataProvider={dataProvider}>
215+
<Dummy />
216+
<Observe />
217+
</CoreAdminContext>
218+
);
219+
localUpdate('foo', {
220+
id: 1,
221+
data: { bar: 'baz' },
222+
previousData: { id: 1, bar: 'bar' },
223+
meta: { hello: 'world' },
224+
});
225+
await waitFor(() => {
226+
expect(dataProvider.update).toHaveBeenCalledWith('foo', {
227+
id: 1,
228+
data: { bar: 'baz' },
229+
previousData: { id: 1, bar: 'bar' },
230+
meta: { hello: 'world' },
231+
});
232+
});
233+
await screen.findByText('mutations: 1');
234+
});
193235
describe('data', () => {
194236
it('returns a data typed based on the parametric type', async () => {
195237
interface Product extends RaRecord {

packages/ra-core/src/dataProvider/useUpdate.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ export const useUpdate = <RecordType extends RaRecord = any, ErrorType = Error>(
196196
ErrorType,
197197
Partial<UseUpdateMutateParams<RecordType>>
198198
>({
199+
mutationKey: [resource, 'update', params],
199200
mutationFn: ({
200201
resource: callTimeResource = resource,
201202
id: callTimeId = paramsRef.current.id,

packages/ra-core/src/dataProvider/useUpdateMany.spec.tsx

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { screen, render, waitFor, act } from '@testing-library/react';
3-
import { QueryClient } from '@tanstack/react-query';
3+
import { QueryClient, useMutationState } from '@tanstack/react-query';
44
import expect from 'expect';
55

66
import { testDataProvider } from './testDataProvider';
@@ -117,6 +117,46 @@ describe('useUpdateMany', () => {
117117
});
118118
});
119119

120+
it('sets the mutationKey', async () => {
121+
const dataProvider = testDataProvider({
122+
updateMany: jest.fn(() => Promise.resolve({ data: [1, 2] } as any)),
123+
});
124+
let localUpdateMany;
125+
const Dummy = () => {
126+
const [updateMany] = useUpdateMany('foo');
127+
localUpdateMany = updateMany;
128+
return <span />;
129+
};
130+
const Observe = () => {
131+
const mutation = useMutationState({
132+
filters: {
133+
mutationKey: ['foo', 'updateMany'],
134+
},
135+
});
136+
137+
return <span>mutations: {mutation.length}</span>;
138+
};
139+
render(
140+
<CoreAdminContext dataProvider={dataProvider}>
141+
<Dummy />
142+
<Observe />
143+
</CoreAdminContext>
144+
);
145+
localUpdateMany('foo', {
146+
ids: [1, 2],
147+
data: { bar: 'baz' },
148+
meta: { hello: 'world' },
149+
});
150+
await waitFor(() => {
151+
expect(dataProvider.updateMany).toHaveBeenCalledWith('foo', {
152+
ids: [1, 2],
153+
data: { bar: 'baz' },
154+
meta: { hello: 'world' },
155+
});
156+
});
157+
await screen.findByText('mutations: 1');
158+
});
159+
120160
describe('query cache', () => {
121161
it('updates getList query cache when dataProvider promise resolves', async () => {
122162
const queryClient = new QueryClient();

packages/ra-core/src/dataProvider/useUpdateMany.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ export const useUpdateMany = <
199199
MutationError,
200200
Partial<UseUpdateManyMutateParams<RecordType>>
201201
>({
202+
mutationKey: [resource, 'updateMany', params],
202203
mutationFn: ({
203204
resource: callTimeResource = resource,
204205
ids: callTimeIds = paramsRef.current.ids,

0 commit comments

Comments
 (0)