@tanstack/solid-query 5.0.0-beta.9 → 5.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,19 @@
1
- import { QueriesObserver, notifyManager } from '@tanstack/query-core'
2
- import { createComputed, onCleanup } from 'solid-js'
1
+ import { QueriesObserver } from '@tanstack/query-core'
3
2
  import { createStore, unwrap } from 'solid-js/store'
3
+ import {
4
+ batch,
5
+ createComputed,
6
+ createMemo,
7
+ createRenderEffect,
8
+ createResource,
9
+ mergeProps,
10
+ on,
11
+ onCleanup,
12
+ onMount,
13
+ } from 'solid-js'
4
14
  import { useQueryClient } from './QueryClientProvider'
15
+ import { useIsRestoring } from './isRestoring'
16
+ import type { CreateQueryResult, SolidQueryOptions } from './types'
5
17
  import type { Accessor } from 'solid-js'
6
18
  import type { QueryClient } from './QueryClient'
7
19
  import type {
@@ -10,8 +22,8 @@ import type {
10
22
  QueriesPlaceholderDataFunction,
11
23
  QueryFunction,
12
24
  QueryKey,
25
+ QueryObserverResult,
13
26
  } from '@tanstack/query-core'
14
- import type { CreateQueryResult, SolidQueryOptions } from './types'
15
27
 
16
28
  // This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
17
29
  // `placeholderData` function does not have a parameter
@@ -95,63 +107,71 @@ type GetResults<T> =
95
107
  * QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
96
108
  */
97
109
  export type QueriesOptions<
98
- T extends any[],
99
- Result extends any[] = [],
110
+ T extends Array<any>,
111
+ Result extends Array<any> = [],
100
112
  Depth extends ReadonlyArray<number> = [],
101
113
  > = Depth['length'] extends MAXIMUM_DEPTH
102
- ? CreateQueryOptionsForCreateQueries[]
114
+ ? Array<CreateQueryOptionsForCreateQueries>
103
115
  : T extends []
104
116
  ? []
105
117
  : T extends [infer Head]
106
118
  ? [...Result, GetOptions<Head>]
107
119
  : T extends [infer Head, ...infer Tail]
108
120
  ? QueriesOptions<[...Tail], [...Result, GetOptions<Head>], [...Depth, 1]>
109
- : unknown[] extends T
121
+ : Array<unknown> extends T
110
122
  ? T
111
123
  : // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!
112
124
  // use this to infer the param types in the case of Array.map() argument
113
- T extends CreateQueryOptionsForCreateQueries<
114
- infer TQueryFnData,
115
- infer TError,
116
- infer TData,
117
- infer TQueryKey
118
- >[]
119
- ? CreateQueryOptionsForCreateQueries<TQueryFnData, TError, TData, TQueryKey>[]
125
+ T extends Array<
126
+ CreateQueryOptionsForCreateQueries<
127
+ infer TQueryFnData,
128
+ infer TError,
129
+ infer TData,
130
+ infer TQueryKey
131
+ >
132
+ >
133
+ ? Array<
134
+ CreateQueryOptionsForCreateQueries<TQueryFnData, TError, TData, TQueryKey>
135
+ >
120
136
  : // Fallback
121
- CreateQueryOptionsForCreateQueries[]
137
+ Array<CreateQueryOptionsForCreateQueries>
122
138
 
123
139
  /**
124
140
  * QueriesResults reducer recursively maps type param to results
125
141
  */
126
142
  export type QueriesResults<
127
- T extends any[],
128
- Result extends any[] = [],
143
+ T extends Array<any>,
144
+ Result extends Array<any> = [],
129
145
  Depth extends ReadonlyArray<number> = [],
130
146
  > = Depth['length'] extends MAXIMUM_DEPTH
131
- ? CreateQueryResult[]
147
+ ? Array<CreateQueryResult>
132
148
  : T extends []
133
149
  ? []
134
150
  : T extends [infer Head]
135
151
  ? [...Result, GetResults<Head>]
136
152
  : T extends [infer Head, ...infer Tail]
137
153
  ? QueriesResults<[...Tail], [...Result, GetResults<Head>], [...Depth, 1]>
138
- : T extends CreateQueryOptionsForCreateQueries<
139
- infer TQueryFnData,
140
- infer TError,
141
- infer TData,
142
- any
143
- >[]
154
+ : T extends Array<
155
+ CreateQueryOptionsForCreateQueries<
156
+ infer TQueryFnData,
157
+ infer TError,
158
+ infer TData,
159
+ any
160
+ >
161
+ >
144
162
  ? // Dynamic-size (homogenous) UseQueryOptions array: map directly to array of results
145
- CreateQueryResult<
146
- unknown extends TData ? TQueryFnData : TData,
147
- unknown extends TError ? DefaultError : TError
148
- >[]
163
+ Array<
164
+ CreateQueryResult<
165
+ unknown extends TData ? TQueryFnData : TData,
166
+ unknown extends TError ? DefaultError : TError
167
+ >
168
+ >
149
169
  : // Fallback
150
- CreateQueryResult[]
170
+ Array<CreateQueryResult>
151
171
 
152
172
  export function createQueries<
153
- T extends any[],
154
- TCombinedResult = QueriesResults<T>,
173
+ T extends Array<any>,
174
+ TCombinedResult extends QueriesResults<T> = QueriesResults<T>,
155
175
  >(
156
176
  queriesOptions: Accessor<{
157
177
  queries: readonly [...QueriesOptions<T>]
@@ -159,17 +179,22 @@ export function createQueries<
159
179
  }>,
160
180
  queryClient?: Accessor<QueryClient>,
161
181
  ): TCombinedResult {
162
- const client = useQueryClient(queryClient?.())
182
+ const client = createMemo(() => useQueryClient(queryClient?.()))
183
+ const isRestoring = useIsRestoring()
163
184
 
164
- const defaultedQueries = queriesOptions().queries.map((options) => {
165
- const defaultedOptions = client.defaultQueryOptions(options)
166
- defaultedOptions._optimisticResults = 'optimistic'
167
- return defaultedOptions
168
- })
185
+ const defaultedQueries = createMemo(() =>
186
+ queriesOptions().queries.map((options) =>
187
+ mergeProps(client().defaultQueryOptions(options), {
188
+ get _optimisticResults() {
189
+ return isRestoring() ? 'isRestoring' : 'optimistic'
190
+ },
191
+ }),
192
+ ),
193
+ )
169
194
 
170
195
  const observer = new QueriesObserver(
171
- client,
172
- defaultedQueries,
196
+ client(),
197
+ defaultedQueries(),
173
198
  queriesOptions().combine
174
199
  ? ({
175
200
  combine: queriesOptions().combine,
@@ -177,27 +202,89 @@ export function createQueries<
177
202
  : undefined,
178
203
  )
179
204
 
180
- // @ts-expect-error - Types issue with solid-js createStore
181
205
  const [state, setState] = createStore<TCombinedResult>(
182
- observer.getOptimisticResult(defaultedQueries)[1](),
206
+ observer.getOptimisticResult(defaultedQueries())[1](),
207
+ )
208
+
209
+ createRenderEffect(
210
+ on(
211
+ () => queriesOptions().queries.length,
212
+ () => setState(observer.getOptimisticResult(defaultedQueries())[1]()),
213
+ ),
214
+ )
215
+
216
+ const dataResources = createMemo(
217
+ on(
218
+ () => state.length,
219
+ () =>
220
+ state.map((queryRes) => {
221
+ const dataPromise = () =>
222
+ new Promise((resolve) => {
223
+ if (queryRes.isFetching && queryRes.isLoading) return
224
+ resolve(unwrap(queryRes.data))
225
+ })
226
+ return createResource(dataPromise)
227
+ }),
228
+ ),
183
229
  )
184
230
 
185
- const unsubscribe = observer.subscribe((result) => {
186
- notifyManager.batchCalls(() => {
187
- setState(unwrap(result) as unknown as TCombinedResult)
188
- })()
231
+ batch(() => {
232
+ const dataResources_ = dataResources()
233
+ for (let index = 0; index < dataResources_.length; index++) {
234
+ const dataResource = dataResources_[index]!
235
+ dataResource[1].mutate(() => unwrap(state[index]!.data))
236
+ dataResource[1].refetch()
237
+ }
189
238
  })
190
239
 
240
+ let taskQueue: Array<() => void> = []
241
+ const subscribeToObserver = () =>
242
+ observer.subscribe((result) => {
243
+ taskQueue.push(() => {
244
+ batch(() => {
245
+ const dataResources_ = dataResources()
246
+ for (let index = 0; index < dataResources_.length; index++) {
247
+ const dataResource = dataResources_[index]!
248
+ const unwrappedResult = { ...unwrap(result[index]!) }
249
+ // @ts-expect-error typescript pedantry regarding the possible range of index
250
+ setState(index, unwrap(unwrappedResult))
251
+ dataResource[1].mutate(() => unwrap(state[index]!.data))
252
+ dataResource[1].refetch()
253
+ }
254
+ })
255
+ })
256
+
257
+ queueMicrotask(() => {
258
+ const taskToRun = taskQueue.pop()
259
+ if (taskToRun) taskToRun()
260
+ taskQueue = []
261
+ })
262
+ })
263
+
264
+ let unsubscribe: () => void = () => undefined
265
+ createComputed<() => void>((cleanup) => {
266
+ cleanup?.()
267
+ unsubscribe = isRestoring() ? () => undefined : subscribeToObserver()
268
+ // cleanup needs to be scheduled after synchronous effects take place
269
+ return () => queueMicrotask(unsubscribe)
270
+ })
191
271
  onCleanup(unsubscribe)
192
272
 
273
+ onMount(() => {
274
+ observer.setQueries(
275
+ defaultedQueries(),
276
+ queriesOptions().combine
277
+ ? ({
278
+ combine: queriesOptions().combine,
279
+ } as QueriesObserverOptions<TCombinedResult>)
280
+ : undefined,
281
+ { listeners: false },
282
+ )
283
+ })
284
+
193
285
  createComputed(() => {
194
- const updatedQueries = queriesOptions().queries.map((options) => {
195
- const defaultedOptions = client.defaultQueryOptions(options)
196
- defaultedOptions._optimisticResults = 'optimistic'
197
- return defaultedOptions
198
- })
199
286
  observer.setQueries(
200
- updatedQueries,
287
+ defaultedQueries(),
201
288
  queriesOptions().combine
202
289
  ? ({
203
290
  combine: queriesOptions().combine,
@@ -207,5 +294,22 @@ export function createQueries<
207
294
  )
208
295
  })
209
296
 
210
- return state
297
+ const handler = (index: number) => ({
298
+ get(target: QueryObserverResult, prop: keyof QueryObserverResult): any {
299
+ if (prop === 'data') {
300
+ return dataResources()[index]![0]()
301
+ }
302
+ return Reflect.get(target, prop)
303
+ },
304
+ })
305
+
306
+ const getProxies = () =>
307
+ state.map((s, index) => {
308
+ return new Proxy(s, handler(index))
309
+ })
310
+
311
+ const [proxifiedState, setProxifiedState] = createStore(getProxies())
312
+ createRenderEffect(() => setProxifiedState(getProxies()))
313
+
314
+ return proxifiedState as TCombinedResult
211
315
  }
package/src/index.ts CHANGED
@@ -27,3 +27,4 @@ export { createInfiniteQuery } from './createInfiniteQuery'
27
27
  export { createMutation } from './createMutation'
28
28
  export { useIsMutating } from './useIsMutating'
29
29
  export { createQueries } from './createQueries'
30
+ export { useIsRestoring, IsRestoringProvider } from './isRestoring'
@@ -0,0 +1,6 @@
1
+ import { type Accessor, createContext, useContext } from 'solid-js'
2
+
3
+ const IsRestoringContext = createContext<Accessor<boolean>>(() => false)
4
+
5
+ export const useIsRestoring = () => useContext(IsRestoringContext)
6
+ export const IsRestoringProvider = IsRestoringContext.Provider
package/src/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- export function shouldThrowError<T extends (...args: any[]) => boolean>(
1
+ export function shouldThrowError<T extends (...args: Array<any>) => boolean>(
2
2
  throwError: boolean | T | undefined,
3
3
  params: Parameters<T>,
4
4
  ): boolean {