|
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