Skip to content

Commit a623f89

Browse files
committed
refactor(web): graphql-batching-and-optimisations
1 parent 47e2cd6 commit a623f89

12 files changed

+54
-19
lines changed

web/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@
7878
},
7979
"dependencies": {
8080
"@cyntler/react-doc-viewer": "^1.17.0",
81+
"@graphql-tools/batch-execute": "^9.0.11",
82+
"@graphql-tools/utils": "^10.7.2",
8183
"@kleros/kleros-app": "workspace:^",
8284
"@kleros/kleros-sdk": "workspace:^",
8385
"@kleros/kleros-v2-contracts": "workspace:^",

web/src/consts/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export { ArbitratorTypes };
77
export const ONE_BASIS_POINT = 10000n;
88

99
export const REFETCH_INTERVAL = 5000;
10+
export const STALE_TIME = 1000;
1011

1112
export const IPFS_GATEWAY = import.meta.env.REACT_APP_IPFS_GATEWAY || "https://cdn.kleros.link";
1213
export const HERMES_TELEGRAM_BOT_URL =
@@ -20,7 +21,7 @@ export const GIT_URL = `https://github.com/kleros/kleros-v2/tree/${gitCommitHash
2021
export const RELEASE_VERSION = version;
2122

2223
// https://www.w3.org/TR/2012/WD-html-markup-20120329/input.email.html#input.email.attrs.value.single
23-
// eslint-disable-next-line security/detect-unsafe-regex
24+
2425
export const EMAIL_REGEX =
2526
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
2627
export const TELEGRAM_REGEX = /^@\w{5,32}$/;

web/src/context/GraphqlBatcher.tsx

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import React, { useMemo, createContext, useContext } from "react";
22

3+
import { createBatchingExecutor } from "@graphql-tools/batch-execute";
4+
import { AsyncExecutor, ExecutionResult } from "@graphql-tools/utils";
35
import { TypedDocumentNode } from "@graphql-typed-document-node/core";
46
import { create, windowedFiniteBatchScheduler, Batcher } from "@yornaath/batshit";
57
import { request } from "graphql-request";
68

79
import { debounceErrorToast } from "utils/debounceErrorToast";
810
import { getGraphqlUrl } from "utils/getGraphqlUrl";
9-
1011
interface IGraphqlBatcher {
1112
graphqlBatcher: Batcher<any, IQuery>;
1213
}
@@ -21,19 +22,37 @@ interface IQuery {
2122

2223
const Context = createContext<IGraphqlBatcher | undefined>(undefined);
2324

25+
const executor: AsyncExecutor = async ({ document, variables, extensions }) => {
26+
console.log({ url: extensions.url });
27+
28+
try {
29+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
30+
//@ts-ignore
31+
const result = request(extensions.url, document, variables).then((res) => ({
32+
data: res,
33+
})) as Promise<ExecutionResult>;
34+
35+
return result;
36+
} catch (error) {
37+
console.error("Graph error: ", { error });
38+
debounceErrorToast("Graph query error: failed to fetch data.");
39+
return { data: {} };
40+
}
41+
};
42+
43+
const myBatchExec = createBatchingExecutor(executor);
44+
2445
const fetcher = async (queries: IQuery[]) => {
25-
const promises = queries.map(async ({ id, document, variables, isDisputeTemplate, chainId }) => {
26-
const url = getGraphqlUrl(isDisputeTemplate ?? false, chainId);
27-
try {
28-
return request(url, document, variables).then((result) => ({ id, result }));
29-
} catch (error) {
30-
console.error("Graph error: ", { error });
31-
debounceErrorToast("Graph query error: failed to fetch data.");
32-
return { id, result: {} };
33-
}
34-
});
35-
const data = await Promise.all(promises);
36-
return data;
46+
const batchdata = await Promise.all(
47+
queries.map(({ document, variables, isDisputeTemplate, chainId }) =>
48+
myBatchExec({ document, variables, extensions: { url: getGraphqlUrl(isDisputeTemplate ?? false, chainId) } })
49+
)
50+
);
51+
52+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
53+
//@ts-ignore
54+
const processedData = batchdata.map((data, index) => ({ id: queries[index].id, result: data.data }));
55+
return processedData;
3756
};
3857

3958
const GraphqlBatcherProvider: React.FC<{ children?: React.ReactNode }> = ({ children }) => {

web/src/hooks/queries/useAllCasesQuery.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query";
22

33
import { useGraphqlBatcher } from "context/GraphqlBatcher";
44

5+
import { STALE_TIME } from "src/consts";
56
import { graphql } from "src/graphql";
67
import { AllCasesQuery } from "src/graphql/graphql";
78

@@ -20,6 +21,7 @@ export const useAllCasesQuery = () => {
2021
const { graphqlBatcher } = useGraphqlBatcher();
2122
return useQuery({
2223
queryKey: [`allCasesQuery`],
24+
staleTime: STALE_TIME,
2325
queryFn: async () =>
2426
await graphqlBatcher.fetch({ id: crypto.randomUUID(), document: allCasesQuery, variables: {} }),
2527
});

web/src/hooks/queries/useClassicAppealQuery.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useQuery } from "@tanstack/react-query";
22

3-
import { REFETCH_INTERVAL } from "consts/index";
3+
import { REFETCH_INTERVAL, STALE_TIME } from "consts/index";
44
import { useGraphqlBatcher } from "context/GraphqlBatcher";
55

66
import { graphql } from "src/graphql";
@@ -44,6 +44,7 @@ export const useClassicAppealQuery = (id?: string | number) => {
4444
queryKey: [`classicAppealQuery${id}`],
4545
enabled: isEnabled,
4646
refetchInterval: REFETCH_INTERVAL,
47+
staleTime: STALE_TIME,
4748
queryFn: async () =>
4849
isEnabled
4950
? await graphqlBatcher.fetch({

web/src/hooks/queries/useCourtDetails.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useQuery } from "@tanstack/react-query";
22

3-
import { REFETCH_INTERVAL } from "consts/index";
3+
import { REFETCH_INTERVAL, STALE_TIME } from "consts/index";
44
import { useGraphqlBatcher } from "context/GraphqlBatcher";
55

66
import { graphql } from "src/graphql";
@@ -36,6 +36,7 @@ export const useCourtDetails = (id?: string) => {
3636
queryKey: [`courtDetails${id}`],
3737
enabled: isEnabled,
3838
refetchInterval: REFETCH_INTERVAL,
39+
staleTime: STALE_TIME,
3940
queryFn: async () =>
4041
await graphqlBatcher.fetch({ id: crypto.randomUUID(), document: courtDetailsQuery, variables: { id } }),
4142
});

web/src/hooks/queries/useCourtTree.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query";
22

33
import { useGraphqlBatcher } from "context/GraphqlBatcher";
44

5+
import { STALE_TIME } from "src/consts";
56
import { graphql } from "src/graphql";
67
import { CourtTreeQuery } from "src/graphql/graphql";
78
export type { CourtTreeQuery };
@@ -39,6 +40,7 @@ export const useCourtTree = () => {
3940
const { graphqlBatcher } = useGraphqlBatcher();
4041
return useQuery<CourtTreeQuery>({
4142
queryKey: ["courtTreeQuery"],
43+
staleTime: STALE_TIME,
4244
queryFn: async () =>
4345
await graphqlBatcher.fetch({ id: crypto.randomUUID(), document: courtTreeQuery, variables: {} }),
4446
});

web/src/hooks/queries/useDisputeDetailsQuery.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useQuery } from "@tanstack/react-query";
22

3-
import { REFETCH_INTERVAL } from "consts/index";
3+
import { REFETCH_INTERVAL, STALE_TIME } from "consts/index";
44
import { useGraphqlBatcher } from "context/GraphqlBatcher";
55

66
import { graphql } from "src/graphql";
@@ -48,6 +48,7 @@ export const useDisputeDetailsQuery = (id?: string | number) => {
4848
queryKey: [`disputeDetailsQuery${id}`],
4949
enabled: isEnabled,
5050
refetchInterval: REFETCH_INTERVAL,
51+
staleTime: STALE_TIME,
5152
queryFn: async () =>
5253
await graphqlBatcher.fetch({
5354
id: crypto.randomUUID(),

web/src/hooks/queries/useDisputeMaintenanceQuery.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query";
22

33
import { useGraphqlBatcher } from "context/GraphqlBatcher";
44

5+
import { STALE_TIME } from "src/consts";
56
import { graphql } from "src/graphql";
67
import { DisputeMaintenanceQuery } from "src/graphql/graphql";
78
import { isUndefined } from "src/utils";
@@ -40,6 +41,7 @@ const useDisputeMaintenanceQuery = (id?: string) => {
4041
return useQuery<DisputeMaintenanceQuery>({
4142
queryKey: [`disputeMaintenanceQuery-${id}`],
4243
enabled: isEnabled,
44+
staleTime: STALE_TIME,
4345
queryFn: async () =>
4446
await graphqlBatcher.fetch({
4547
id: crypto.randomUUID(),

web/src/hooks/queries/useJurorStakeDetailsQuery.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useQuery } from "@tanstack/react-query";
22

3-
import { REFETCH_INTERVAL } from "consts/index";
3+
import { REFETCH_INTERVAL, STALE_TIME } from "consts/index";
44
import { useGraphqlBatcher } from "context/GraphqlBatcher";
55

66
import { graphql } from "src/graphql";
@@ -29,6 +29,7 @@ export const useJurorStakeDetailsQuery = (userId?: string) => {
2929
queryKey: [`jurorStakeDetails${userId}`],
3030
enabled: isEnabled,
3131
refetchInterval: REFETCH_INTERVAL,
32+
staleTime: STALE_TIME,
3233
queryFn: async () =>
3334
await graphqlBatcher.fetch({ id: crypto.randomUUID(), document: jurorStakeDetailsQuery, variables: { userId } }),
3435
});

web/src/hooks/queries/useUser.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Address } from "viem";
33

44
import { useGraphqlBatcher } from "context/GraphqlBatcher";
55

6+
import { STALE_TIME } from "src/consts";
67
import { graphql } from "src/graphql";
78
import { UserQuery, Dispute_Filter, UserDisputeFilterQuery, UserDetailsFragment } from "src/graphql/graphql";
89
export type { UserQuery, UserDetailsFragment };
@@ -58,6 +59,7 @@ export const useUserQuery = (address?: Address, where?: Dispute_Filter) => {
5859
return useQuery<UserQuery | UserDisputeFilterQuery>({
5960
queryKey: [`userQuery${address?.toLowerCase()}`],
6061
enabled: isEnabled,
62+
staleTime: STALE_TIME,
6163
queryFn: async () =>
6264
await graphqlBatcher.fetch({
6365
id: crypto.randomUUID(),

web/src/hooks/queries/useVotingHistory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useQuery } from "@tanstack/react-query";
22

3-
import { REFETCH_INTERVAL } from "consts/index";
3+
import { REFETCH_INTERVAL, STALE_TIME } from "consts/index";
44
import { useGraphqlBatcher } from "context/GraphqlBatcher";
55

66
import { graphql } from "src/graphql";
@@ -59,6 +59,7 @@ export const useVotingHistory = (disputeID?: string) => {
5959
queryKey: [`VotingHistory${disputeID}`],
6060
enabled: isEnabled,
6161
refetchInterval: REFETCH_INTERVAL,
62+
staleTime: STALE_TIME,
6263
queryFn: async () =>
6364
await graphqlBatcher.fetch({ id: crypto.randomUUID(), document: votingHistoryQuery, variables: { disputeID } }),
6465
});

0 commit comments

Comments
 (0)