|
1 |
| -import { type CompilableQuery, parseQuery } from '@powersync/common'; |
| 1 | +import { type CompilableQuery } from '@powersync/common'; |
2 | 2 | import { usePowerSync } from '@powersync/react';
|
3 | 3 | import * as Tanstack from '@tanstack/react-query';
|
4 |
| -import { useEffect, useMemo, useState, useCallback } from 'react'; |
| 4 | +import { useMemo } from 'react'; |
| 5 | +import { usePowerSyncQueries } from './usePowerSyncQueries'; |
5 | 6 |
|
6 | 7 | export type PowerSyncQueryOptions<T> = {
|
7 | 8 | query?: string | CompilableQuery<T>;
|
@@ -75,145 +76,37 @@ export function useQueries(
|
75 | 76 | queryClient: Tanstack.QueryClient = Tanstack.useQueryClient()
|
76 | 77 | ) {
|
77 | 78 | const powerSync = usePowerSync();
|
78 |
| - const queriesInput = options.queries; |
79 |
| - const [tablesArr, setTablesArr] = useState<string[][]>(() => queriesInput.map(() => [])); |
80 |
| - const [errorsArr, setErrorsArr] = useState<(Error | undefined)[]>(() => queriesInput.map(() => undefined)); |
81 |
| - |
82 |
| - const updateTablesArr = useCallback((tables: string[], idx: number) => { |
83 |
| - setTablesArr((prev) => { |
84 |
| - if (JSON.stringify(prev[idx]) === JSON.stringify(tables)) return prev; |
85 |
| - const next = [...prev]; |
86 |
| - next[idx] = tables; |
87 |
| - return next; |
88 |
| - }); |
89 |
| - }, []); |
90 |
| - |
91 |
| - const updateErrorsArr = useCallback((error: Error, idx: number) => { |
92 |
| - setErrorsArr((prev) => { |
93 |
| - if (prev[idx]?.message === error.message) return prev; |
94 |
| - const next = [...prev]; |
95 |
| - next[idx] = error; |
96 |
| - return next; |
97 |
| - }); |
98 |
| - }, []); |
99 | 79 |
|
100 |
| - const parsedQueries = useMemo( |
101 |
| - () => |
102 |
| - queriesInput.map((queryOptions) => { |
103 |
| - const { query, parameters = [], ...rest } = queryOptions; |
104 |
| - const parsed = (() => { |
105 |
| - if (!query) { |
106 |
| - return { sqlStatement: '', queryParameters: [], error: undefined }; |
107 |
| - } |
| 80 | + if (!powerSync) { |
| 81 | + throw new Error('PowerSync is not available'); |
| 82 | + } |
108 | 83 |
|
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 |
| - })(); |
| 84 | + const queriesInput = options.queries; |
124 | 85 |
|
125 |
| - return { query, parameters, rest, ...parsed }; |
126 |
| - }), |
| 86 | + const powerSyncQueriesInput = useMemo( |
| 87 | + () => |
| 88 | + queriesInput.map((queryOptions) => ({ |
| 89 | + query: queryOptions.query, |
| 90 | + parameters: queryOptions.parameters, |
| 91 | + queryKey: queryOptions.queryKey |
| 92 | + })), |
127 | 93 | [queriesInput]
|
128 | 94 | );
|
129 | 95 |
|
130 |
| - const stringifiedQueriesDeps = JSON.stringify( |
131 |
| - parsedQueries.map((q) => ({ |
132 |
| - sql: q.sqlStatement, |
133 |
| - params: q.queryParameters |
134 |
| - })) |
135 |
| - ); |
136 |
| - |
137 |
| - useEffect(() => { |
138 |
| - const listeners = parsedQueries.map((q, idx) => { |
139 |
| - if (q.error || !q.query) { |
140 |
| - return null; |
141 |
| - } |
142 |
| - |
143 |
| - (async () => { |
144 |
| - try { |
145 |
| - const t = await powerSync.resolveTables(q.sqlStatement, q.queryParameters); |
146 |
| - updateTablesArr(t, idx); |
147 |
| - } catch (e) { |
148 |
| - updateErrorsArr(e, idx); |
149 |
| - } |
150 |
| - })(); |
151 |
| - return powerSync.registerListener({ |
152 |
| - schemaChanged: async () => { |
153 |
| - try { |
154 |
| - const t = await powerSync.resolveTables(q.sqlStatement, q.queryParameters); |
155 |
| - updateTablesArr(t, idx); |
156 |
| - queryClient.invalidateQueries({ queryKey: q.rest.queryKey }); |
157 |
| - } catch (e) { |
158 |
| - updateErrorsArr(e, idx); |
159 |
| - } |
160 |
| - } |
161 |
| - }); |
162 |
| - }); |
163 |
| - |
164 |
| - return () => { |
165 |
| - listeners.forEach((l) => l?.()); |
166 |
| - }; |
167 |
| - }, [powerSync, queryClient, stringifiedQueriesDeps, updateErrorsArr, updateTablesArr]); |
168 |
| - |
169 |
| - const stringifiedQueryKeys = JSON.stringify(parsedQueries.map((q) => q.rest.queryKey)); |
170 |
| - |
171 |
| - useEffect(() => { |
172 |
| - const aborts = parsedQueries.map((q, idx) => { |
173 |
| - if (q.error || !q.query) { |
174 |
| - return null; |
175 |
| - } |
176 |
| - |
177 |
| - const abort = new AbortController(); |
178 |
| - |
179 |
| - powerSync.onChangeWithCallback( |
180 |
| - { |
181 |
| - onChange: () => { |
182 |
| - queryClient.invalidateQueries({ queryKey: q.rest.queryKey }); |
183 |
| - }, |
184 |
| - onError: (e) => { |
185 |
| - updateErrorsArr(e, idx); |
186 |
| - } |
187 |
| - }, |
188 |
| - { |
189 |
| - tables: tablesArr[idx], |
190 |
| - signal: abort.signal |
191 |
| - } |
192 |
| - ); |
193 |
| - return abort; |
194 |
| - }); |
195 |
| - return () => aborts.forEach((a) => a?.abort()); |
196 |
| - }, [powerSync, queryClient, tablesArr, updateErrorsArr, stringifiedQueryKeys]); |
| 96 | + const states = usePowerSyncQueries(powerSyncQueriesInput, queryClient); |
197 | 97 |
|
198 | 98 | const queries = useMemo(() => {
|
199 |
| - return parsedQueries.map((q, idx) => { |
200 |
| - const error = q.error || errorsArr[idx]; |
201 |
| - const queryFn = async () => { |
202 |
| - if (error) throw error; |
203 |
| - |
204 |
| - try { |
205 |
| - return typeof q.query === 'string' ? powerSync.getAll(q.sqlStatement, q.queryParameters) : q.query?.execute(); |
206 |
| - } catch (e) { |
207 |
| - throw e; |
208 |
| - } |
209 |
| - }; |
| 99 | + return queriesInput.map((queryOptions, idx) => { |
| 100 | + const { query, parameters, ...rest } = queryOptions; |
| 101 | + const state = states[idx]; |
| 102 | + |
210 | 103 | return {
|
211 |
| - ...q.rest, |
212 |
| - queryFn: q.query ? queryFn : q.rest.queryFn, |
213 |
| - queryKey: q.rest.queryKey |
| 104 | + ...rest, |
| 105 | + queryFn: query ? state.queryFn : rest.queryFn, |
| 106 | + queryKey: rest.queryKey |
214 | 107 | };
|
215 | 108 | });
|
216 |
| - }, [stringifiedQueriesDeps, errorsArr]); |
| 109 | + }, [queriesInput, states]); |
217 | 110 |
|
218 | 111 | return Tanstack.useQueries(
|
219 | 112 | {
|
|
0 commit comments