Skip to content

Commit 085e3de

Browse files
committed
feat(tanstack-react-query): clean up useQueries
1 parent 6d63019 commit 085e3de

File tree

1 file changed

+67
-61
lines changed

1 file changed

+67
-61
lines changed

packages/tanstack-react-query/src/hooks/useQueries.ts

Lines changed: 67 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
import { type CompilableQuery, parseQuery } from '@powersync/common';
22
import { usePowerSync } from '@powersync/react';
33
import * as Tanstack from '@tanstack/react-query';
4-
import { useEffect, useMemo, useState } from 'react';
4+
import { useEffect, useMemo, useState, useCallback } from 'react';
55

66
export type PowerSyncQueryOptions<T> = {
77
query?: string | CompilableQuery<T>;
88
parameters?: any[];
99
};
1010

11-
export type UseBaseQueryOptions<TQueryOptions> = TQueryOptions & PowerSyncQueryOptions<any>;
12-
13-
export type PowerSyncQueriesOptions<T extends any[]> = {
14-
[K in keyof T]: Tanstack.UseQueryOptions<T[K], any> & PowerSyncQueryOptions<T[K]>;
15-
};
16-
1711
type PowerSyncQueryOption<T = any> = Tanstack.UseQueryOptions<T[], any> & PowerSyncQueryOptions<T>;
1812

1913
type InferQueryResults<TQueries extends readonly any[]> = {
@@ -75,8 +69,10 @@ export function useQueries<TQueries extends readonly PowerSyncQueryOption[]>(
7569
// Implementation
7670
export function useQueries(
7771
options: {
78-
queries: readonly (Tanstack.UseQueryOptions<any, any> & PowerSyncQueryOptions<any>)[];
79-
combine?: (results: (Tanstack.UseQueryResult<any, any> & { queryKey: Tanstack.QueryKey })[]) => any;
72+
queries: readonly (Tanstack.UseQueryOptions & PowerSyncQueryOptions<unknown>)[];
73+
combine?: (
74+
results: (Tanstack.UseQueryResult<unknown, Tanstack.DefaultError> & { queryKey: Tanstack.QueryKey })[]
75+
) => unknown;
8076
},
8177
queryClient: Tanstack.QueryClient = Tanstack.useQueryClient()
8278
) {
@@ -85,24 +81,56 @@ export function useQueries(
8581
const [tablesArr, setTablesArr] = useState<string[][]>(() => queriesInput.map(() => []));
8682
const [errorsArr, setErrorsArr] = useState<(Error | undefined)[]>(() => queriesInput.map(() => undefined));
8783

88-
const parsedQueries = useMemo(() => {
89-
return queriesInput.map((queryOptions: Tanstack.UseQueryOptions<any, any> & PowerSyncQueryOptions<any>) => {
90-
const { query, parameters = [], ...rest } = queryOptions;
91-
let sqlStatement = '';
92-
let queryParameters: any[] = [];
93-
let error: Error | undefined = undefined;
94-
if (query) {
95-
try {
96-
const parsedQuery = parseQuery(query, parameters);
97-
sqlStatement = parsedQuery.sqlStatement;
98-
queryParameters = parsedQuery.parameters;
99-
} catch (e) {
100-
error = e as Error;
101-
}
102-
}
103-
return { query, parameters, rest, sqlStatement, queryParameters, error };
84+
const updateTablesArr = useCallback((tables: string[], idx: number) => {
85+
setTablesArr((prev) => {
86+
if (JSON.stringify(prev[idx]) === JSON.stringify(tables)) return prev;
87+
const next = [...prev];
88+
next[idx] = tables;
89+
return next;
90+
});
91+
}, []);
92+
93+
const updateErrorsArr = useCallback((error: Error, idx: number) => {
94+
setErrorsArr((prev) => {
95+
if (prev[idx]?.message === error.message) return prev;
96+
const next = [...prev];
97+
next[idx] = error;
98+
return next;
10499
});
105-
}, [queriesInput]);
100+
}, []);
101+
102+
const parsedQueries = useMemo(() => queriesInput.map((queryOptions: Tanstack.UseQueryOptions<any, any> & PowerSyncQueryOptions<any>) => {
103+
const { query, parameters = [], ...rest } = queryOptions;
104+
const parsed = (() => {
105+
if (!query) {
106+
return { sqlStatement: '', queryParameters: [], error: undefined };
107+
}
108+
109+
try {
110+
const parsedQuery = parseQuery(query, parameters);
111+
return {
112+
sqlStatement: parsedQuery.sqlStatement,
113+
queryParameters: parsedQuery.parameters,
114+
error: undefined
115+
};
116+
} catch (e) {
117+
return {
118+
sqlStatement: '',
119+
queryParameters: [],
120+
error: e as Error
121+
};
122+
}
123+
})();
124+
125+
return { query, parameters, rest, ...parsed };
126+
}), [queriesInput]);
127+
128+
const stringifiedQueriesDeps = JSON.stringify(
129+
parsedQueries.map(q => ({
130+
sql: q.sqlStatement,
131+
params: q.queryParameters,
132+
}))
133+
);
106134

107135
useEffect(() => {
108136
const listeners: (undefined | (() => void))[] = [];
@@ -111,39 +139,19 @@ export function useQueries(
111139
(async () => {
112140
try {
113141
const t = await powerSync.resolveTables(q.sqlStatement, q.queryParameters);
114-
setTablesArr((prev) => {
115-
if (JSON.stringify(prev[idx]) === JSON.stringify(t)) return prev;
116-
const next = prev.slice();
117-
next[idx] = t;
118-
return next;
119-
});
142+
updateTablesArr(t, idx);
120143
} catch (e) {
121-
setErrorsArr((prev) => {
122-
if (prev[idx]?.message === (e as Error).message) return prev;
123-
const next = prev.slice();
124-
next[idx] = e as Error;
125-
return next;
126-
});
144+
updateErrorsArr(e, idx);
127145
}
128146
})();
129147
const l = powerSync.registerListener({
130148
schemaChanged: async () => {
131149
try {
132150
const t = await powerSync.resolveTables(q.sqlStatement, q.queryParameters);
133-
setTablesArr((prev) => {
134-
if (JSON.stringify(prev[idx]) === JSON.stringify(t)) return prev;
135-
const next = prev.slice();
136-
next[idx] = t;
137-
return next;
138-
});
151+
updateTablesArr(t, idx);
139152
queryClient.invalidateQueries({ queryKey: q.rest.queryKey });
140153
} catch (e) {
141-
setErrorsArr((prev) => {
142-
if (prev[idx]?.message === (e as Error).message) return prev;
143-
const next = prev.slice();
144-
next[idx] = e as Error;
145-
return next;
146-
});
154+
updateErrorsArr(e, idx);
147155
}
148156
},
149157
});
@@ -153,7 +161,9 @@ export function useQueries(
153161
return () => {
154162
listeners.forEach((l) => l?.());
155163
};
156-
}, [powerSync, parsedQueries, queryClient]);
164+
}, [powerSync, queryClient, stringifiedQueriesDeps, updateErrorsArr, updateTablesArr]);
165+
166+
const stringifiedQueryKeys = JSON.stringify(parsedQueries.map((q) => q.rest.queryKey));
157167

158168
useEffect(() => {
159169
const aborts: AbortController[] = [];
@@ -167,12 +177,7 @@ export function useQueries(
167177
queryClient.invalidateQueries({ queryKey: q.rest.queryKey });
168178
},
169179
onError: (e) => {
170-
setErrorsArr((prev) => {
171-
if (prev[idx]?.message === (e as Error).message) return prev;
172-
const next = prev.slice();
173-
next[idx] = e as Error;
174-
return next;
175-
});
180+
updateErrorsArr(e, idx);
176181
},
177182
},
178183
{
@@ -182,13 +187,14 @@ export function useQueries(
182187
);
183188
});
184189
return () => aborts.forEach((a) => a?.abort());
185-
}, [powerSync, parsedQueries, queryClient, tablesArr]);
190+
}, [powerSync, queryClient, tablesArr, updateErrorsArr, stringifiedQueryKeys]);
186191

187192
const queries = useMemo(() => {
188193
return parsedQueries.map((q, idx) => {
189194
const error = q.error || errorsArr[idx];
190195
const queryFn = async () => {
191196
if (error) throw error;
197+
192198
try {
193199
return typeof q.query === 'string'
194200
? powerSync.getAll(q.sqlStatement, q.queryParameters)
@@ -203,19 +209,19 @@ export function useQueries(
203209
queryKey: q.rest.queryKey,
204210
};
205211
});
206-
}, [parsedQueries, errorsArr, powerSync]);
212+
}, [stringifiedQueriesDeps, errorsArr]);
207213

208214
return Tanstack.useQueries(
209215
{
210216
queries: queries as Tanstack.QueriesOptions<any>,
211217
combine: options.combine
212218
? (results) => {
213-
const enhancedResults = results.map((result, index) => ({
219+
const enhancedResultsWithQueryKey = results.map((result, index) => ({
214220
...result,
215221
queryKey: queries[index].queryKey,
216222
}));
217223

218-
return options.combine?.(enhancedResults);
224+
return options.combine?.(enhancedResultsWithQueryKey as any);
219225
}
220226
: undefined,
221227
},

0 commit comments

Comments
 (0)