Skip to content

Commit dce7fcf

Browse files
authored
Merge pull request #10969 from marmelab/fix-use-get-many-aggregate
Fix `useGetManyAggregate` merge queries with different `meta`
2 parents 824cfb9 + 5f67a81 commit dce7fcf

File tree

2 files changed

+61
-16
lines changed

2 files changed

+61
-16
lines changed

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

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
import * as React from 'react';
22
import expect from 'expect';
33
import { render, waitFor } from '@testing-library/react';
4+
import { QueryClient } from '@tanstack/react-query';
45

56
import { CoreAdminContext } from '../core';
6-
import { useGetManyAggregate } from './useGetManyAggregate';
7+
import {
8+
useGetManyAggregate,
9+
type UseGetManyAggregateOptions,
10+
} from './useGetManyAggregate';
711
import { testDataProvider } from '../dataProvider';
8-
import { QueryClient } from '@tanstack/react-query';
912

1013
const UseGetManyAggregate = ({
1114
resource,
1215
ids,
16+
meta,
1317
options = {},
1418
callback = null,
19+
}: {
20+
resource: string;
21+
ids: (string | number)[];
22+
meta?: any;
23+
options?: UseGetManyAggregateOptions;
24+
callback?: (v: ReturnType<typeof useGetManyAggregate>) => void;
1525
}) => {
16-
const hookValue = useGetManyAggregate(resource, { ids }, options);
26+
const hookValue = useGetManyAggregate(resource, { ids, meta }, options);
1727
if (callback) callback(hookValue);
1828
return <div>hello</div>;
1929
};
@@ -290,6 +300,35 @@ describe('useGetManyAggregate', () => {
290300
});
291301
});
292302
});
303+
it('should not aggregate multiple calls for different meta', async () => {
304+
render(
305+
<CoreAdminContext dataProvider={dataProvider}>
306+
<UseGetManyAggregate
307+
resource="posts"
308+
ids={[1, 2]}
309+
meta={{ test: true }}
310+
/>
311+
<UseGetManyAggregate
312+
resource="posts"
313+
ids={[3, 4]}
314+
meta={{ test: true }}
315+
/>
316+
<UseGetManyAggregate resource="posts" ids={[5, 6]} />
317+
</CoreAdminContext>
318+
);
319+
await waitFor(() => {
320+
expect(dataProvider.getMany).toHaveBeenCalledTimes(2);
321+
expect(dataProvider.getMany).toHaveBeenCalledWith('posts', {
322+
ids: [1, 2, 3, 4],
323+
meta: { test: true },
324+
signal: undefined,
325+
});
326+
expect(dataProvider.getMany).toHaveBeenCalledWith('posts', {
327+
ids: [5, 6],
328+
signal: undefined,
329+
});
330+
});
331+
});
293332

294333
it('should deduplicated repeated ids', async () => {
295334
render(

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

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -246,31 +246,37 @@ const callGetManyQueries = batch((calls: GetManyCallArgs[]) => {
246246
const queryClient = calls[0].queryClient;
247247

248248
/**
249-
* Aggregate calls by resource
249+
* Aggregate calls by resource and meta
250250
*
251-
* callsByResource will look like:
251+
* callsByResourceAndMeta will look like:
252252
* {
253-
* posts: [{ resource, ids, resolve, reject, dataProvider, queryClient }, ...],
253+
* 'posts|{"test":true}': [{ resource, ids, resolve, reject, dataProvider, queryClient }, ...],
254+
* 'posts|{"test":false}': [{ resource, ids, resolve, reject, dataProvider, queryClient }, ...],
254255
* tags: [{ resource, ids, resolve, reject, dataProvider, queryClient }, ...],
255256
* }
256257
*/
257-
const callsByResource = calls.reduce(
258+
const callsByResourceAndMeta = calls.reduce(
258259
(acc, callArgs) => {
259-
if (!acc[callArgs.resource]) {
260-
acc[callArgs.resource] = [];
260+
const key = `${callArgs.resource}|${JSON.stringify(callArgs.meta)}`;
261+
if (!acc[key]) {
262+
acc[key] = [];
261263
}
262-
acc[callArgs.resource].push(callArgs);
264+
acc[key].push(callArgs);
263265
return acc;
264266
},
265267
{} as { [resource: string]: GetManyCallArgs[] }
266268
);
267269

268270
/**
269-
* For each resource, aggregate ids and call dataProvider.getMany() once
271+
* For each resource/meta association, aggregate ids and call dataProvider.getMany() once
270272
*/
271-
Object.keys(callsByResource).forEach(resource => {
272-
const callsForResource = callsByResource[resource];
273+
Object.keys(callsByResourceAndMeta).forEach(resource => {
274+
const callsForResource = callsByResourceAndMeta[resource];
273275

276+
const uniqueResource = callsForResource.reduce(
277+
(acc, { resource }) => resource || acc,
278+
'' as string // Should never happen as we always have a resource in callArgs but makes TS happy
279+
);
274280
/**
275281
* Extract ids from queries, aggregate and deduplicate them
276282
*
@@ -338,7 +344,7 @@ const callGetManyQueries = batch((calls: GetManyCallArgs[]) => {
338344
queryClient
339345
.fetchQuery<any[], Error, any[]>({
340346
queryKey: [
341-
resource,
347+
uniqueResource,
342348
'getMany',
343349
{
344350
ids: aggregatedIds.map(id => String(id)),
@@ -347,7 +353,7 @@ const callGetManyQueries = batch((calls: GetManyCallArgs[]) => {
347353
],
348354
queryFn: queryParams =>
349355
dataProvider
350-
.getMany<any>(resource, {
356+
.getMany<any>(uniqueResource, {
351357
ids: aggregatedIds,
352358
meta: uniqueMeta,
353359
signal:
@@ -377,7 +383,7 @@ const callGetManyQueries = batch((calls: GetManyCallArgs[]) => {
377383
const noop = () => undefined;
378384

379385
export type UseGetManyAggregateOptions<
380-
RecordType extends RaRecord,
386+
RecordType extends RaRecord = any,
381387
ErrorType = Error,
382388
> = Omit<UseQueryOptions<RecordType[], ErrorType>, 'queryKey' | 'queryFn'> & {
383389
onSuccess?: (data: RecordType[]) => void;

0 commit comments

Comments
 (0)