@tanstack/solid-query 5.0.0-beta.18 → 5.0.0-beta.21
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.
- package/build/dev.cjs +176 -80
- package/build/dev.js +178 -82
- package/build/index.cjs +176 -80
- package/build/index.d.cts +9 -5
- package/build/index.d.ts +9 -5
- package/build/index.js +178 -82
- package/package.json +2 -2
- package/src/QueryClientProvider.tsx +14 -7
- package/src/__tests__/createInfiniteQuery.test.tsx +36 -29
- package/src/__tests__/createMutation.test.tsx +4 -4
- package/src/__tests__/createQueries.test.tsx +31 -29
- package/src/__tests__/createQuery.test.tsx +81 -86
- package/src/__tests__/suspense.test.tsx +4 -4
- package/src/__tests__/transition.test.tsx +1 -2
- package/src/__tests__/useIsFetching.test.tsx +2 -2
- package/src/__tests__/useIsMutating.test.tsx +3 -3
- package/src/__tests__/utils.tsx +1 -1
- package/src/createBaseQuery.ts +95 -61
- package/src/createMutation.ts +3 -3
- package/src/createQueries.ts +156 -52
- package/src/index.ts +1 -0
- package/src/isRestoring.ts +6 -0
- package/src/utils.ts +1 -1
|
@@ -28,7 +28,7 @@ describe("useQuery's in Suspense mode", () => {
|
|
|
28
28
|
|
|
29
29
|
it('should render the correct amount of times in Suspense mode', async () => {
|
|
30
30
|
const key = queryKey()
|
|
31
|
-
const states: CreateQueryResult<number
|
|
31
|
+
const states: Array<CreateQueryResult<number>> = []
|
|
32
32
|
|
|
33
33
|
let count = 0
|
|
34
34
|
let renders = 0
|
|
@@ -84,7 +84,7 @@ describe("useQuery's in Suspense mode", () => {
|
|
|
84
84
|
|
|
85
85
|
it('should return the correct states for a successful infinite query', async () => {
|
|
86
86
|
const key = queryKey()
|
|
87
|
-
const states: CreateInfiniteQueryResult<InfiniteData<number
|
|
87
|
+
const states: Array<CreateInfiniteQueryResult<InfiniteData<number>>> = []
|
|
88
88
|
|
|
89
89
|
function Page() {
|
|
90
90
|
const [multiplier, setMultiplier] = createSignal(1)
|
|
@@ -143,7 +143,7 @@ describe("useQuery's in Suspense mode", () => {
|
|
|
143
143
|
it('should not call the queryFn twice when used in Suspense mode', async () => {
|
|
144
144
|
const key = queryKey()
|
|
145
145
|
|
|
146
|
-
const queryFn = vi.fn<unknown
|
|
146
|
+
const queryFn = vi.fn<Array<unknown>, string>()
|
|
147
147
|
queryFn.mockImplementation(() => {
|
|
148
148
|
sleep(10)
|
|
149
149
|
return 'data'
|
|
@@ -663,7 +663,7 @@ describe("useQuery's in Suspense mode", () => {
|
|
|
663
663
|
it('should not call the queryFn when not enabled', async () => {
|
|
664
664
|
const key = queryKey()
|
|
665
665
|
|
|
666
|
-
const queryFn = vi.fn<unknown
|
|
666
|
+
const queryFn = vi.fn<Array<unknown>, Promise<string>>()
|
|
667
667
|
queryFn.mockImplementation(async () => {
|
|
668
668
|
await sleep(10)
|
|
669
669
|
return '23'
|
|
@@ -4,7 +4,7 @@ import { Show, Suspense, createSignal, startTransition } from 'solid-js'
|
|
|
4
4
|
import { QueryCache, QueryClientProvider, createQuery } from '..'
|
|
5
5
|
import { createQueryClient, queryKey, sleep } from './utils'
|
|
6
6
|
|
|
7
|
-
describe("
|
|
7
|
+
describe("createQuery's in Suspense mode with transitions", () => {
|
|
8
8
|
const queryCache = new QueryCache()
|
|
9
9
|
const queryClient = createQueryClient({ queryCache })
|
|
10
10
|
|
|
@@ -19,7 +19,6 @@ describe("useQuery's in Suspense mode with transitions", () => {
|
|
|
19
19
|
return true
|
|
20
20
|
},
|
|
21
21
|
}))
|
|
22
|
-
|
|
23
22
|
return <Show when={state.data}>Message</Show>
|
|
24
23
|
}
|
|
25
24
|
|
|
@@ -59,7 +59,7 @@ describe('useIsFetching', () => {
|
|
|
59
59
|
const key1 = queryKey()
|
|
60
60
|
const key2 = queryKey()
|
|
61
61
|
|
|
62
|
-
const isFetchings: number
|
|
62
|
+
const isFetchings: Array<number> = []
|
|
63
63
|
|
|
64
64
|
function IsFetching() {
|
|
65
65
|
const isFetching = useIsFetching()
|
|
@@ -125,7 +125,7 @@ describe('useIsFetching', () => {
|
|
|
125
125
|
const key1 = queryKey()
|
|
126
126
|
const key2 = queryKey()
|
|
127
127
|
|
|
128
|
-
const isFetchings: number
|
|
128
|
+
const isFetchings: Array<number> = []
|
|
129
129
|
|
|
130
130
|
function One() {
|
|
131
131
|
createQuery(() => ({
|
|
@@ -8,7 +8,7 @@ import { createQueryClient, setActTimeout, sleep } from './utils'
|
|
|
8
8
|
|
|
9
9
|
describe('useIsMutating', () => {
|
|
10
10
|
it('should return the number of fetching mutations', async () => {
|
|
11
|
-
const isMutatings: number
|
|
11
|
+
const isMutatings: Array<number> = []
|
|
12
12
|
const queryClient = createQueryClient()
|
|
13
13
|
|
|
14
14
|
function IsMutating() {
|
|
@@ -63,7 +63,7 @@ describe('useIsMutating', () => {
|
|
|
63
63
|
})
|
|
64
64
|
|
|
65
65
|
it('should filter correctly by mutationKey', async () => {
|
|
66
|
-
const isMutatings: number
|
|
66
|
+
const isMutatings: Array<number> = []
|
|
67
67
|
const queryClient = createQueryClient()
|
|
68
68
|
|
|
69
69
|
function IsMutating() {
|
|
@@ -108,7 +108,7 @@ describe('useIsMutating', () => {
|
|
|
108
108
|
})
|
|
109
109
|
|
|
110
110
|
it('should filter correctly by predicate', async () => {
|
|
111
|
-
const isMutatings: number
|
|
111
|
+
const isMutatings: Array<number> = []
|
|
112
112
|
const queryClient = createQueryClient()
|
|
113
113
|
|
|
114
114
|
function IsMutating() {
|
package/src/__tests__/utils.tsx
CHANGED
package/src/createBaseQuery.ts
CHANGED
|
@@ -8,12 +8,16 @@ import {
|
|
|
8
8
|
createComputed,
|
|
9
9
|
createMemo,
|
|
10
10
|
createResource,
|
|
11
|
+
createSignal,
|
|
12
|
+
mergeProps,
|
|
11
13
|
on,
|
|
12
14
|
onCleanup,
|
|
15
|
+
untrack,
|
|
13
16
|
} from 'solid-js'
|
|
14
17
|
import { createStore, reconcile, unwrap } from 'solid-js/store'
|
|
15
18
|
import { useQueryClient } from './QueryClientProvider'
|
|
16
19
|
import { shouldThrowError } from './utils'
|
|
20
|
+
import { useIsRestoring } from './isRestoring'
|
|
17
21
|
import type { CreateBaseQueryOptions } from './types'
|
|
18
22
|
import type { Accessor } from 'solid-js'
|
|
19
23
|
import type { QueryClient } from './QueryClient'
|
|
@@ -104,18 +108,31 @@ export function createBaseQuery<
|
|
|
104
108
|
| QueryObserverResult<TData, TError>
|
|
105
109
|
|
|
106
110
|
const client = createMemo(() => useQueryClient(queryClient?.()))
|
|
111
|
+
const isRestoring = useIsRestoring()
|
|
107
112
|
|
|
108
|
-
const defaultedOptions =
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
const defaultedOptions = createMemo(() =>
|
|
114
|
+
mergeProps(client().defaultQueryOptions(options()), {
|
|
115
|
+
get _optimisticResults() {
|
|
116
|
+
return isRestoring() ? 'isRestoring' : 'optimistic'
|
|
117
|
+
},
|
|
118
|
+
structuralSharing: false,
|
|
119
|
+
...(isServer && { retry: false, throwOnError: true }),
|
|
120
|
+
}),
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
const [observer, setObserver] = createSignal(
|
|
124
|
+
new Observer(client(), untrack(defaultedOptions)),
|
|
125
|
+
)
|
|
126
|
+
// we set the value in a computed because `createMemo`
|
|
127
|
+
// returns undefined during transitions
|
|
128
|
+
createComputed(
|
|
129
|
+
on(client, (c) => setObserver(new Observer(c, defaultedOptions())), {
|
|
130
|
+
defer: true,
|
|
131
|
+
}),
|
|
132
|
+
)
|
|
116
133
|
|
|
117
134
|
const [state, setState] = createStore<QueryObserverResult<TData, TError>>(
|
|
118
|
-
observer.getOptimisticResult(defaultedOptions),
|
|
135
|
+
observer().getOptimisticResult(defaultedOptions()),
|
|
119
136
|
)
|
|
120
137
|
|
|
121
138
|
const createServerSubscriber = (
|
|
@@ -124,9 +141,9 @@ export function createBaseQuery<
|
|
|
124
141
|
) => void,
|
|
125
142
|
reject: (reason?: any) => void,
|
|
126
143
|
) => {
|
|
127
|
-
return observer.subscribe((result) => {
|
|
144
|
+
return observer().subscribe((result) => {
|
|
128
145
|
notifyManager.batchCalls(() => {
|
|
129
|
-
const query = observer.getCurrentQuery()
|
|
146
|
+
const query = observer().getCurrentQuery()
|
|
130
147
|
const unwrappedResult = hydrateableObserverResult(query, result)
|
|
131
148
|
|
|
132
149
|
if (unwrappedResult.isError) {
|
|
@@ -139,32 +156,30 @@ export function createBaseQuery<
|
|
|
139
156
|
}
|
|
140
157
|
|
|
141
158
|
const createClientSubscriber = () => {
|
|
142
|
-
|
|
159
|
+
const obs = observer()
|
|
160
|
+
return obs.subscribe((result) => {
|
|
143
161
|
notifyManager.batchCalls(() => {
|
|
144
162
|
// @ts-expect-error - This will error because the reconcile option does not
|
|
145
163
|
// exist on the query-core QueryObserverResult type
|
|
146
|
-
const reconcileOptions =
|
|
164
|
+
const reconcileOptions = obs.options.reconcile
|
|
165
|
+
|
|
166
|
+
setState((store) => {
|
|
167
|
+
return reconcileFn(
|
|
168
|
+
store,
|
|
169
|
+
result,
|
|
170
|
+
reconcileOptions === undefined ? 'id' : reconcileOptions,
|
|
171
|
+
)
|
|
172
|
+
})
|
|
147
173
|
// If the query has data we dont suspend but instead mutate the resource
|
|
148
174
|
// This could happen when placeholderData/initialData is defined
|
|
149
|
-
if (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
)
|
|
156
|
-
})
|
|
175
|
+
if (
|
|
176
|
+
queryResource()?.data &&
|
|
177
|
+
result.data &&
|
|
178
|
+
!queryResource.loading &&
|
|
179
|
+
isRestoring()
|
|
180
|
+
)
|
|
157
181
|
mutate(state)
|
|
158
|
-
|
|
159
|
-
setState((store) => {
|
|
160
|
-
return reconcileFn(
|
|
161
|
-
store,
|
|
162
|
-
result,
|
|
163
|
-
reconcileOptions === undefined ? 'id' : reconcileOptions,
|
|
164
|
-
)
|
|
165
|
-
})
|
|
166
|
-
refetch()
|
|
167
|
-
}
|
|
182
|
+
else refetch()
|
|
168
183
|
})()
|
|
169
184
|
})
|
|
170
185
|
}
|
|
@@ -178,17 +193,16 @@ export function createBaseQuery<
|
|
|
178
193
|
ResourceData | undefined
|
|
179
194
|
>(
|
|
180
195
|
() => {
|
|
196
|
+
const obs = observer()
|
|
181
197
|
return new Promise((resolve, reject) => {
|
|
182
|
-
if (isServer)
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
}
|
|
198
|
+
if (isServer) unsubscribe = createServerSubscriber(resolve, reject)
|
|
199
|
+
else if (!unsubscribe && !isRestoring())
|
|
200
|
+
unsubscribe = createClientSubscriber()
|
|
201
|
+
|
|
202
|
+
obs.updateResult()
|
|
189
203
|
|
|
190
|
-
if (!state.isLoading) {
|
|
191
|
-
const query =
|
|
204
|
+
if (!state.isLoading && !isRestoring()) {
|
|
205
|
+
const query = obs.getCurrentQuery()
|
|
192
206
|
resolve(hydrateableObserverResult(query, state))
|
|
193
207
|
}
|
|
194
208
|
})
|
|
@@ -197,7 +211,9 @@ export function createBaseQuery<
|
|
|
197
211
|
initialValue: state,
|
|
198
212
|
|
|
199
213
|
// If initialData is provided, we resolve the resource immediately
|
|
200
|
-
ssrLoadFrom
|
|
214
|
+
get ssrLoadFrom() {
|
|
215
|
+
return options().initialData ? 'initial' : 'server'
|
|
216
|
+
},
|
|
201
217
|
|
|
202
218
|
get deferStream() {
|
|
203
219
|
return options().deferStream
|
|
@@ -212,37 +228,50 @@ export function createBaseQuery<
|
|
|
212
228
|
* Note that this is only invoked on the client, for queries that were originally run on the server.
|
|
213
229
|
*/
|
|
214
230
|
onHydrated(_k, info) {
|
|
231
|
+
const defaultOptions = defaultedOptions()
|
|
215
232
|
if (info.value) {
|
|
216
233
|
hydrate(client(), {
|
|
217
234
|
queries: [
|
|
218
235
|
{
|
|
219
|
-
queryKey:
|
|
220
|
-
queryHash:
|
|
236
|
+
queryKey: defaultOptions.queryKey,
|
|
237
|
+
queryHash: defaultOptions.queryHash,
|
|
221
238
|
state: info.value,
|
|
222
239
|
},
|
|
223
240
|
],
|
|
224
241
|
})
|
|
225
242
|
}
|
|
226
243
|
|
|
227
|
-
if (
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
// Setting the options as an immutable object to prevent
|
|
237
|
-
// wonky behavior with observer subscriptions
|
|
238
|
-
observer.setOptions(newOptions)
|
|
239
|
-
setState(observer.getOptimisticResult(newOptions))
|
|
240
|
-
unsubscribe = createClientSubscriber()
|
|
244
|
+
if (unsubscribe) return
|
|
245
|
+
/**
|
|
246
|
+
* Do not refetch query on mount if query was fetched on server,
|
|
247
|
+
* even if `staleTime` is not set.
|
|
248
|
+
*/
|
|
249
|
+
const newOptions = { ...defaultOptions }
|
|
250
|
+
if (defaultOptions.staleTime || !defaultOptions.initialData) {
|
|
251
|
+
newOptions.refetchOnMount = false
|
|
241
252
|
}
|
|
253
|
+
// Setting the options as an immutable object to prevent
|
|
254
|
+
// wonky behavior with observer subscriptions
|
|
255
|
+
observer().setOptions(newOptions)
|
|
256
|
+
setState(observer().getOptimisticResult(newOptions))
|
|
257
|
+
unsubscribe = createClientSubscriber()
|
|
242
258
|
},
|
|
243
259
|
},
|
|
244
260
|
)
|
|
245
261
|
|
|
262
|
+
createComputed(
|
|
263
|
+
on(
|
|
264
|
+
[isRestoring, observer],
|
|
265
|
+
([restoring]) => {
|
|
266
|
+
const unsub = unsubscribe
|
|
267
|
+
queueMicrotask(() => unsub?.())
|
|
268
|
+
unsubscribe = null
|
|
269
|
+
if (!restoring) refetch()
|
|
270
|
+
},
|
|
271
|
+
{ defer: true },
|
|
272
|
+
),
|
|
273
|
+
)
|
|
274
|
+
|
|
246
275
|
onCleanup(() => {
|
|
247
276
|
if (unsubscribe) {
|
|
248
277
|
unsubscribe()
|
|
@@ -252,8 +281,11 @@ export function createBaseQuery<
|
|
|
252
281
|
|
|
253
282
|
createComputed(
|
|
254
283
|
on(
|
|
255
|
-
|
|
256
|
-
() =>
|
|
284
|
+
[observer, defaultedOptions],
|
|
285
|
+
([obs, opts]) => {
|
|
286
|
+
obs.setOptions(opts)
|
|
287
|
+
setState(obs.getOptimisticResult(opts))
|
|
288
|
+
},
|
|
257
289
|
{
|
|
258
290
|
// Defer because we don't need to trigger on first render
|
|
259
291
|
// This only cares about changes to options after the observer is created
|
|
@@ -266,12 +298,14 @@ export function createBaseQuery<
|
|
|
266
298
|
on(
|
|
267
299
|
() => state.status,
|
|
268
300
|
() => {
|
|
301
|
+
const obs = observer()
|
|
269
302
|
if (
|
|
270
303
|
state.isError &&
|
|
271
304
|
!state.isFetching &&
|
|
272
|
-
|
|
305
|
+
!isRestoring() &&
|
|
306
|
+
shouldThrowError(obs.options.throwOnError, [
|
|
273
307
|
state.error,
|
|
274
|
-
|
|
308
|
+
obs.getCurrentQuery(),
|
|
275
309
|
])
|
|
276
310
|
) {
|
|
277
311
|
throw state.error
|
package/src/createMutation.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MutationObserver } from '@tanstack/query-core'
|
|
2
|
-
import { createComputed, on, onCleanup } from 'solid-js'
|
|
2
|
+
import { createComputed, createMemo, on, onCleanup } from 'solid-js'
|
|
3
3
|
import { createStore } from 'solid-js/store'
|
|
4
4
|
import { useQueryClient } from './QueryClientProvider'
|
|
5
5
|
import { shouldThrowError } from './utils'
|
|
@@ -22,10 +22,10 @@ export function createMutation<
|
|
|
22
22
|
options: CreateMutationOptions<TData, TError, TVariables, TContext>,
|
|
23
23
|
queryClient?: Accessor<QueryClient>,
|
|
24
24
|
): CreateMutationResult<TData, TError, TVariables, TContext> {
|
|
25
|
-
const client = useQueryClient(queryClient?.())
|
|
25
|
+
const client = createMemo(() => useQueryClient(queryClient?.()))
|
|
26
26
|
|
|
27
27
|
const observer = new MutationObserver<TData, TError, TVariables, TContext>(
|
|
28
|
-
client,
|
|
28
|
+
client(),
|
|
29
29
|
options(),
|
|
30
30
|
)
|
|
31
31
|
|
package/src/createQueries.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import { QueriesObserver
|
|
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
|
|
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
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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 =
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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'
|