@tanstack/lit-query 0.0.1 → 0.2.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.
- package/LICENSE +21 -0
- package/README.md +125 -43
- package/dist/QueryClientProvider.d.ts +85 -0
- package/dist/QueryClientProvider.d.ts.map +1 -0
- package/dist/QueryClientProvider.js +137 -0
- package/dist/QueryClientProvider.js.map +1 -0
- package/dist/accessor.d.ts +32 -0
- package/dist/accessor.d.ts.map +1 -0
- package/dist/accessor.js +12 -0
- package/dist/accessor.js.map +1 -0
- package/dist/context.d.ts +59 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +100 -0
- package/dist/context.js.map +1 -0
- package/dist/controllers/BaseController.d.ts +38 -0
- package/dist/controllers/BaseController.d.ts.map +1 -0
- package/dist/controllers/BaseController.js +204 -0
- package/dist/controllers/BaseController.js.map +1 -0
- package/dist/createInfiniteQueryController.d.ts +76 -0
- package/dist/createInfiniteQueryController.d.ts.map +1 -0
- package/dist/createInfiniteQueryController.js +221 -0
- package/dist/createInfiniteQueryController.js.map +1 -0
- package/dist/createMutationController.d.ts +79 -0
- package/dist/createMutationController.d.ts.map +1 -0
- package/dist/createMutationController.js +193 -0
- package/dist/createMutationController.js.map +1 -0
- package/dist/createQueriesController.d.ts +145 -0
- package/dist/createQueriesController.d.ts.map +1 -0
- package/dist/createQueriesController.js +302 -0
- package/dist/createQueriesController.js.map +1 -0
- package/dist/createQueryController.d.ts +67 -0
- package/dist/createQueryController.d.ts.map +1 -0
- package/dist/createQueryController.js +211 -0
- package/dist/createQueryController.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/infiniteQueryOptions.d.ts +21 -0
- package/dist/infiniteQueryOptions.d.ts.map +1 -0
- package/dist/infiniteQueryOptions.js +22 -0
- package/dist/infiniteQueryOptions.js.map +1 -0
- package/dist/mutationOptions.d.ts +19 -0
- package/dist/mutationOptions.d.ts.map +1 -0
- package/dist/mutationOptions.js +20 -0
- package/dist/mutationOptions.js.map +1 -0
- package/dist/queryOptions.d.ts +62 -0
- package/dist/queryOptions.d.ts.map +1 -0
- package/dist/queryOptions.js +4 -0
- package/dist/queryOptions.js.map +1 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/useIsFetching.d.ts +45 -0
- package/dist/useIsFetching.d.ts.map +1 -0
- package/dist/useIsFetching.js +116 -0
- package/dist/useIsFetching.js.map +1 -0
- package/dist/useIsMutating.d.ts +45 -0
- package/dist/useIsMutating.d.ts.map +1 -0
- package/dist/useIsMutating.js +116 -0
- package/dist/useIsMutating.js.map +1 -0
- package/dist/useMutationState.d.ts +57 -0
- package/dist/useMutationState.d.ts.map +1 -0
- package/dist/useMutationState.js +132 -0
- package/dist/useMutationState.js.map +1 -0
- package/dist-cjs/QueryClientProvider.d.cts +84 -0
- package/dist-cjs/QueryClientProvider.js +141 -0
- package/dist-cjs/QueryClientProvider.js.map +1 -0
- package/dist-cjs/accessor.d.cts +31 -0
- package/dist-cjs/accessor.js +16 -0
- package/dist-cjs/accessor.js.map +1 -0
- package/dist-cjs/context.d.cts +58 -0
- package/dist-cjs/context.js +109 -0
- package/dist-cjs/context.js.map +1 -0
- package/dist-cjs/controllers/BaseController.d.cts +37 -0
- package/dist-cjs/controllers/BaseController.js +208 -0
- package/dist-cjs/controllers/BaseController.js.map +1 -0
- package/dist-cjs/createInfiniteQueryController.d.cts +75 -0
- package/dist-cjs/createInfiniteQueryController.js +224 -0
- package/dist-cjs/createInfiniteQueryController.js.map +1 -0
- package/dist-cjs/createMutationController.d.cts +78 -0
- package/dist-cjs/createMutationController.js +196 -0
- package/dist-cjs/createMutationController.js.map +1 -0
- package/dist-cjs/createQueriesController.d.cts +144 -0
- package/dist-cjs/createQueriesController.js +305 -0
- package/dist-cjs/createQueriesController.js.map +1 -0
- package/dist-cjs/createQueryController.d.cts +66 -0
- package/dist-cjs/createQueryController.js +214 -0
- package/dist-cjs/createQueryController.js.map +1 -0
- package/dist-cjs/index.d.cts +23 -0
- package/dist-cjs/index.js +49 -0
- package/dist-cjs/index.js.map +1 -0
- package/dist-cjs/infiniteQueryOptions.d.cts +20 -0
- package/dist-cjs/infiniteQueryOptions.js +25 -0
- package/dist-cjs/infiniteQueryOptions.js.map +1 -0
- package/dist-cjs/mutationOptions.d.cts +18 -0
- package/dist-cjs/mutationOptions.js +23 -0
- package/dist-cjs/mutationOptions.js.map +1 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/queryOptions.d.cts +61 -0
- package/dist-cjs/queryOptions.js +7 -0
- package/dist-cjs/queryOptions.js.map +1 -0
- package/dist-cjs/types.d.cts +30 -0
- package/dist-cjs/types.js +3 -0
- package/dist-cjs/types.js.map +1 -0
- package/dist-cjs/useIsFetching.d.cts +44 -0
- package/dist-cjs/useIsFetching.js +119 -0
- package/dist-cjs/useIsFetching.js.map +1 -0
- package/dist-cjs/useIsMutating.d.cts +44 -0
- package/dist-cjs/useIsMutating.js +119 -0
- package/dist-cjs/useIsMutating.js.map +1 -0
- package/dist-cjs/useMutationState.d.cts +56 -0
- package/dist-cjs/useMutationState.js +135 -0
- package/dist-cjs/useMutationState.js.map +1 -0
- package/package.json +73 -8
- package/src/QueryClientProvider.ts +174 -0
- package/src/accessor.ts +43 -0
- package/src/context.ts +120 -0
- package/src/controllers/BaseController.ts +284 -0
- package/src/createInfiniteQueryController.ts +394 -0
- package/src/createMutationController.ts +361 -0
- package/src/createQueriesController.ts +633 -0
- package/src/createQueryController.ts +342 -0
- package/src/index.ts +72 -0
- package/src/infiniteQueryOptions.ts +48 -0
- package/src/mutationOptions.ts +31 -0
- package/src/queryOptions.ts +143 -0
- package/src/types.ts +77 -0
- package/src/useIsFetching.ts +159 -0
- package/src/useIsMutating.ts +159 -0
- package/src/useMutationState.ts +201 -0
|
@@ -0,0 +1,633 @@
|
|
|
1
|
+
import {
|
|
2
|
+
QueriesObserver,
|
|
3
|
+
type DefaultError,
|
|
4
|
+
type DefinedQueryObserverResult,
|
|
5
|
+
type OmitKeyof,
|
|
6
|
+
type QueriesObserverOptions,
|
|
7
|
+
type QueryFunction,
|
|
8
|
+
type QueryKey,
|
|
9
|
+
type QueryObserverOptions,
|
|
10
|
+
type QueryObserverResult,
|
|
11
|
+
type ThrowOnError,
|
|
12
|
+
} from '@tanstack/query-core'
|
|
13
|
+
import type { QueryClient } from '@tanstack/query-core'
|
|
14
|
+
import type { ReactiveControllerHost } from 'lit'
|
|
15
|
+
import {
|
|
16
|
+
createValueAccessor,
|
|
17
|
+
readAccessor,
|
|
18
|
+
type Accessor,
|
|
19
|
+
type ValueAccessor,
|
|
20
|
+
} from './accessor.js'
|
|
21
|
+
import { createMissingQueryClientError } from './context.js'
|
|
22
|
+
import { BaseController } from './controllers/BaseController.js'
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Options for one query inside `createQueriesController`.
|
|
26
|
+
*
|
|
27
|
+
* This mirrors `QueryObserverOptions` and is used by the tuple inference that
|
|
28
|
+
* maps each input query to its corresponding result.
|
|
29
|
+
*/
|
|
30
|
+
export type CreateQueriesInput<
|
|
31
|
+
TQueryFnData = unknown,
|
|
32
|
+
TError = DefaultError,
|
|
33
|
+
TData = TQueryFnData,
|
|
34
|
+
TQueryKey extends QueryKey = QueryKey,
|
|
35
|
+
> = QueryObserverOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>
|
|
36
|
+
|
|
37
|
+
type CreateQueriesInputForController<
|
|
38
|
+
TQueryFnData = unknown,
|
|
39
|
+
TError = DefaultError,
|
|
40
|
+
TData = TQueryFnData,
|
|
41
|
+
TQueryKey extends QueryKey = QueryKey,
|
|
42
|
+
> = OmitKeyof<CreateQueriesInput<TQueryFnData, TError, TData, TQueryKey>, never>
|
|
43
|
+
|
|
44
|
+
type MAXIMUM_DEPTH = 20
|
|
45
|
+
|
|
46
|
+
type SkipTokenForCreateQueries = symbol
|
|
47
|
+
|
|
48
|
+
type GetCreateQueriesInput<T> = T extends {
|
|
49
|
+
queryFnData: infer TQueryFnData
|
|
50
|
+
error?: infer TError
|
|
51
|
+
data: infer TData
|
|
52
|
+
}
|
|
53
|
+
? CreateQueriesInputForController<TQueryFnData, TError, TData>
|
|
54
|
+
: T extends { queryFnData: infer TQueryFnData; error?: infer TError }
|
|
55
|
+
? CreateQueriesInputForController<TQueryFnData, TError>
|
|
56
|
+
: T extends { data: infer TData; error?: infer TError }
|
|
57
|
+
? CreateQueriesInputForController<unknown, TError, TData>
|
|
58
|
+
: T extends [infer TQueryFnData, infer TError, infer TData]
|
|
59
|
+
? CreateQueriesInputForController<TQueryFnData, TError, TData>
|
|
60
|
+
: T extends [infer TQueryFnData, infer TError]
|
|
61
|
+
? CreateQueriesInputForController<TQueryFnData, TError>
|
|
62
|
+
: T extends [infer TQueryFnData]
|
|
63
|
+
? CreateQueriesInputForController<TQueryFnData>
|
|
64
|
+
: T extends {
|
|
65
|
+
queryFn?:
|
|
66
|
+
| QueryFunction<infer TQueryFnData, infer TQueryKey>
|
|
67
|
+
| SkipTokenForCreateQueries
|
|
68
|
+
select?: (data: any) => infer TData
|
|
69
|
+
throwOnError?: ThrowOnError<any, infer TError, any, any>
|
|
70
|
+
}
|
|
71
|
+
? CreateQueriesInputForController<
|
|
72
|
+
TQueryFnData,
|
|
73
|
+
unknown extends TError ? DefaultError : TError,
|
|
74
|
+
unknown extends TData ? TQueryFnData : TData,
|
|
75
|
+
TQueryKey
|
|
76
|
+
>
|
|
77
|
+
: CreateQueriesInputForController
|
|
78
|
+
|
|
79
|
+
type GetDefinedOrUndefinedCreateQueriesResult<
|
|
80
|
+
T,
|
|
81
|
+
TData,
|
|
82
|
+
TError = unknown,
|
|
83
|
+
> = T extends {
|
|
84
|
+
initialData?: infer TInitialData
|
|
85
|
+
}
|
|
86
|
+
? unknown extends TInitialData
|
|
87
|
+
? QueryObserverResult<TData, TError>
|
|
88
|
+
: TInitialData extends TData
|
|
89
|
+
? DefinedQueryObserverResult<TData, TError>
|
|
90
|
+
: TInitialData extends () => infer TInitialDataResult
|
|
91
|
+
? unknown extends TInitialDataResult
|
|
92
|
+
? QueryObserverResult<TData, TError>
|
|
93
|
+
: TInitialDataResult extends TData
|
|
94
|
+
? DefinedQueryObserverResult<TData, TError>
|
|
95
|
+
: QueryObserverResult<TData, TError>
|
|
96
|
+
: QueryObserverResult<TData, TError>
|
|
97
|
+
: QueryObserverResult<TData, TError>
|
|
98
|
+
|
|
99
|
+
type GetCreateQueriesResult<T> = T extends {
|
|
100
|
+
queryFnData: any
|
|
101
|
+
error?: infer TError
|
|
102
|
+
data: infer TData
|
|
103
|
+
}
|
|
104
|
+
? GetDefinedOrUndefinedCreateQueriesResult<T, TData, TError>
|
|
105
|
+
: T extends { queryFnData: infer TQueryFnData; error?: infer TError }
|
|
106
|
+
? GetDefinedOrUndefinedCreateQueriesResult<T, TQueryFnData, TError>
|
|
107
|
+
: T extends { data: infer TData; error?: infer TError }
|
|
108
|
+
? GetDefinedOrUndefinedCreateQueriesResult<T, TData, TError>
|
|
109
|
+
: T extends [any, infer TError, infer TData]
|
|
110
|
+
? GetDefinedOrUndefinedCreateQueriesResult<T, TData, TError>
|
|
111
|
+
: T extends [infer TQueryFnData, infer TError]
|
|
112
|
+
? GetDefinedOrUndefinedCreateQueriesResult<T, TQueryFnData, TError>
|
|
113
|
+
: T extends [infer TQueryFnData]
|
|
114
|
+
? GetDefinedOrUndefinedCreateQueriesResult<T, TQueryFnData>
|
|
115
|
+
: T extends {
|
|
116
|
+
queryFn?:
|
|
117
|
+
| QueryFunction<infer TQueryFnData, any>
|
|
118
|
+
| SkipTokenForCreateQueries
|
|
119
|
+
select?: (data: any) => infer TData
|
|
120
|
+
throwOnError?: ThrowOnError<any, infer TError, any, any>
|
|
121
|
+
}
|
|
122
|
+
? GetDefinedOrUndefinedCreateQueriesResult<
|
|
123
|
+
T,
|
|
124
|
+
unknown extends TData ? TQueryFnData : TData,
|
|
125
|
+
unknown extends TError ? DefaultError : TError
|
|
126
|
+
>
|
|
127
|
+
: QueryObserverResult
|
|
128
|
+
|
|
129
|
+
export type CreateQueriesOptions<
|
|
130
|
+
T extends Array<any>,
|
|
131
|
+
TResults extends Array<any> = [],
|
|
132
|
+
TDepth extends ReadonlyArray<number> = [],
|
|
133
|
+
> = TDepth['length'] extends MAXIMUM_DEPTH
|
|
134
|
+
? Array<CreateQueriesInputForController>
|
|
135
|
+
: T extends []
|
|
136
|
+
? []
|
|
137
|
+
: T extends [infer Head]
|
|
138
|
+
? [...TResults, GetCreateQueriesInput<Head>]
|
|
139
|
+
: T extends [infer Head, ...infer Tails]
|
|
140
|
+
? CreateQueriesOptions<
|
|
141
|
+
[...Tails],
|
|
142
|
+
[...TResults, GetCreateQueriesInput<Head>],
|
|
143
|
+
[...TDepth, 1]
|
|
144
|
+
>
|
|
145
|
+
: ReadonlyArray<unknown> extends T
|
|
146
|
+
? T
|
|
147
|
+
: T extends Array<
|
|
148
|
+
CreateQueriesInputForController<
|
|
149
|
+
infer TQueryFnData,
|
|
150
|
+
infer TError,
|
|
151
|
+
infer TData,
|
|
152
|
+
infer TQueryKey
|
|
153
|
+
>
|
|
154
|
+
>
|
|
155
|
+
? Array<
|
|
156
|
+
CreateQueriesInputForController<
|
|
157
|
+
TQueryFnData,
|
|
158
|
+
TError,
|
|
159
|
+
TData,
|
|
160
|
+
TQueryKey
|
|
161
|
+
>
|
|
162
|
+
>
|
|
163
|
+
: Array<CreateQueriesInputForController>
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Tuple of query results inferred from the query inputs passed to
|
|
167
|
+
* `createQueriesController`.
|
|
168
|
+
*/
|
|
169
|
+
export type CreateQueriesResults<
|
|
170
|
+
T extends Array<any>,
|
|
171
|
+
TResults extends Array<any> = [],
|
|
172
|
+
TDepth extends ReadonlyArray<number> = [],
|
|
173
|
+
> = TDepth['length'] extends MAXIMUM_DEPTH
|
|
174
|
+
? Array<QueryObserverResult>
|
|
175
|
+
: T extends []
|
|
176
|
+
? []
|
|
177
|
+
: T extends [infer Head]
|
|
178
|
+
? [...TResults, GetCreateQueriesResult<Head>]
|
|
179
|
+
: T extends [infer Head, ...infer Tails]
|
|
180
|
+
? CreateQueriesResults<
|
|
181
|
+
[...Tails],
|
|
182
|
+
[...TResults, GetCreateQueriesResult<Head>],
|
|
183
|
+
[...TDepth, 1]
|
|
184
|
+
>
|
|
185
|
+
: { [K in keyof T]: GetCreateQueriesResult<T[K]> }
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Options accepted by `createQueriesController`.
|
|
189
|
+
*
|
|
190
|
+
* `queries` can be a static list or a getter that returns the current list.
|
|
191
|
+
* `combine` can reshape the array of query results into a single value for the
|
|
192
|
+
* returned accessor.
|
|
193
|
+
*/
|
|
194
|
+
export type CreateQueriesControllerOptions<
|
|
195
|
+
TQueryOptions extends Array<any> = Array<any>,
|
|
196
|
+
TCombinedResult = CreateQueriesResults<TQueryOptions>,
|
|
197
|
+
> = {
|
|
198
|
+
/** Query options to observe, or a getter that returns the current options. */
|
|
199
|
+
queries: Accessor<
|
|
200
|
+
| readonly [...CreateQueriesOptions<TQueryOptions>]
|
|
201
|
+
| readonly [
|
|
202
|
+
...{
|
|
203
|
+
[K in keyof TQueryOptions]: GetCreateQueriesInput<TQueryOptions[K]>
|
|
204
|
+
},
|
|
205
|
+
]
|
|
206
|
+
>
|
|
207
|
+
/** Optional function that combines the query result array into one value. */
|
|
208
|
+
combine?: (result: CreateQueriesResults<TQueryOptions>) => TCombinedResult
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Accessor returned by `createQueriesController`.
|
|
213
|
+
*
|
|
214
|
+
* Call the accessor or read its `current` property to get the latest combined
|
|
215
|
+
* value.
|
|
216
|
+
*/
|
|
217
|
+
export type QueriesResultAccessor<TCombinedResult> =
|
|
218
|
+
ValueAccessor<TCombinedResult> & {
|
|
219
|
+
/** Removes the controller from its Lit host and unsubscribes observers. */
|
|
220
|
+
destroy: () => void
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function createPendingQueryObserverResult(): QueryObserverResult {
|
|
224
|
+
return {
|
|
225
|
+
data: undefined,
|
|
226
|
+
dataUpdatedAt: 0,
|
|
227
|
+
error: null,
|
|
228
|
+
errorUpdatedAt: 0,
|
|
229
|
+
failureCount: 0,
|
|
230
|
+
failureReason: null,
|
|
231
|
+
errorUpdateCount: 0,
|
|
232
|
+
isError: false,
|
|
233
|
+
isFetched: false,
|
|
234
|
+
isFetchedAfterMount: false,
|
|
235
|
+
isFetching: false,
|
|
236
|
+
isInitialLoading: false,
|
|
237
|
+
isLoading: false,
|
|
238
|
+
isLoadingError: false,
|
|
239
|
+
isPaused: false,
|
|
240
|
+
isPending: true,
|
|
241
|
+
isPlaceholderData: false,
|
|
242
|
+
isRefetchError: false,
|
|
243
|
+
isRefetching: false,
|
|
244
|
+
isStale: true,
|
|
245
|
+
isEnabled: true,
|
|
246
|
+
isSuccess: false,
|
|
247
|
+
fetchStatus: 'idle',
|
|
248
|
+
status: 'pending',
|
|
249
|
+
refetch: (() =>
|
|
250
|
+
Promise.reject(
|
|
251
|
+
createMissingQueryClientError(),
|
|
252
|
+
)) as QueryObserverResult['refetch'],
|
|
253
|
+
promise: Promise.resolve(undefined as never),
|
|
254
|
+
} as unknown as QueryObserverResult
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function createPlaceholderQueryObserverResult(
|
|
258
|
+
query: QueryObserverOptions,
|
|
259
|
+
): QueryObserverResult {
|
|
260
|
+
const initialData =
|
|
261
|
+
typeof query.initialData === 'function'
|
|
262
|
+
? query.initialData()
|
|
263
|
+
: query.initialData
|
|
264
|
+
|
|
265
|
+
if (initialData === undefined) {
|
|
266
|
+
return createPendingQueryObserverResult()
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const data = query.select ? query.select(initialData) : initialData
|
|
270
|
+
const initialDataUpdatedAt =
|
|
271
|
+
typeof query.initialDataUpdatedAt === 'function'
|
|
272
|
+
? query.initialDataUpdatedAt()
|
|
273
|
+
: query.initialDataUpdatedAt
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
...createPendingQueryObserverResult(),
|
|
277
|
+
data,
|
|
278
|
+
dataUpdatedAt: initialDataUpdatedAt ?? Date.now(),
|
|
279
|
+
isPending: false,
|
|
280
|
+
isInitialLoading: false,
|
|
281
|
+
isLoading: false,
|
|
282
|
+
isSuccess: true,
|
|
283
|
+
status: 'success',
|
|
284
|
+
promise: Promise.resolve(data as never),
|
|
285
|
+
} as QueryObserverResult
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function resolveQueriesOptions<TCombinedResult>(
|
|
289
|
+
optionsAccessor: Accessor<
|
|
290
|
+
CreateQueriesControllerOptions<any, TCombinedResult>
|
|
291
|
+
>,
|
|
292
|
+
client: QueryClient,
|
|
293
|
+
): {
|
|
294
|
+
queries: Array<QueryObserverOptions>
|
|
295
|
+
combine: QueriesObserverOptions<TCombinedResult>['combine']
|
|
296
|
+
} {
|
|
297
|
+
const resolvedOptions = readAccessor(optionsAccessor)
|
|
298
|
+
const resolvedQueries = readAccessor(resolvedOptions.queries)
|
|
299
|
+
const combine =
|
|
300
|
+
resolvedOptions.combine as QueriesObserverOptions<TCombinedResult>['combine']
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
queries: resolvedQueries.map((query) => {
|
|
304
|
+
const defaulted = client.defaultQueryOptions(
|
|
305
|
+
query as QueryObserverOptions,
|
|
306
|
+
)
|
|
307
|
+
;(defaulted as { _optimisticResults?: 'optimistic' })._optimisticResults =
|
|
308
|
+
'optimistic'
|
|
309
|
+
return defaulted
|
|
310
|
+
}),
|
|
311
|
+
combine,
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
class QueriesController<
|
|
316
|
+
TQueryOptions extends Array<any>,
|
|
317
|
+
TCombinedResult,
|
|
318
|
+
> extends BaseController<TCombinedResult> {
|
|
319
|
+
private readonly options: Accessor<
|
|
320
|
+
CreateQueriesControllerOptions<TQueryOptions, TCombinedResult>
|
|
321
|
+
>
|
|
322
|
+
private observer: QueriesObserver<TCombinedResult> | undefined
|
|
323
|
+
private unsubscribe: (() => void) | undefined
|
|
324
|
+
private queryClient: QueryClient | undefined
|
|
325
|
+
private explicitInitializationError: unknown | undefined
|
|
326
|
+
private placeholderInitialized = false
|
|
327
|
+
private placeholderRetryableFailure = true
|
|
328
|
+
|
|
329
|
+
constructor(
|
|
330
|
+
host: ReactiveControllerHost,
|
|
331
|
+
options: Accessor<
|
|
332
|
+
CreateQueriesControllerOptions<TQueryOptions, TCombinedResult>
|
|
333
|
+
>,
|
|
334
|
+
queryClient?: QueryClient,
|
|
335
|
+
) {
|
|
336
|
+
super(host, [] as unknown as TCombinedResult, queryClient)
|
|
337
|
+
this.options = options
|
|
338
|
+
|
|
339
|
+
queueMicrotask(() => {
|
|
340
|
+
this.placeholderRetryableFailure = false
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
if (!queryClient) {
|
|
344
|
+
return
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (this.shouldRefreshOnHostUpdate()) {
|
|
348
|
+
return
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
this.tryInitializeExplicitClient(queryClient)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
protected onConnected(): void {
|
|
355
|
+
if (!this.syncClient()) {
|
|
356
|
+
return
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
this.refreshOptions()
|
|
360
|
+
this.subscribe()
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
protected onDisconnected(): void {
|
|
364
|
+
this.unsubscribeObserver()
|
|
365
|
+
this.syncClient()
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
protected onHostUpdate(): void {
|
|
369
|
+
if (!this.shouldRefreshOnHostUpdate()) {
|
|
370
|
+
return
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (!this.refreshOptions()) {
|
|
374
|
+
this.setPlaceholderResult()
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
protected onQueryClientChanged(): void {
|
|
379
|
+
if (!this.syncClient() || !this.connectedState) {
|
|
380
|
+
return
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
this.refreshOptions()
|
|
384
|
+
this.subscribe()
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private subscribe(): void {
|
|
388
|
+
if (!this.observer) {
|
|
389
|
+
return
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (this.unsubscribe) {
|
|
393
|
+
return
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
this.unsubscribe = this.observer.subscribe((next) => {
|
|
397
|
+
const { combine } = this.readResolvedOptions()
|
|
398
|
+
this.setResult(this.computeResult(next, combine))
|
|
399
|
+
})
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
private tryInitializeExplicitClient(queryClient: QueryClient): boolean {
|
|
403
|
+
try {
|
|
404
|
+
const { queries, combine } = resolveQueriesOptions(
|
|
405
|
+
this.options,
|
|
406
|
+
queryClient,
|
|
407
|
+
)
|
|
408
|
+
const observer = new QueriesObserver(queryClient, queries, {
|
|
409
|
+
combine,
|
|
410
|
+
} as QueriesObserverOptions<TCombinedResult>)
|
|
411
|
+
this.queryClient = queryClient
|
|
412
|
+
this.observer = observer
|
|
413
|
+
this.result = this.computeResult(observer.getCurrentResult(), combine)
|
|
414
|
+
this.explicitInitializationError = undefined
|
|
415
|
+
this.placeholderInitialized = true
|
|
416
|
+
return true
|
|
417
|
+
} catch (error) {
|
|
418
|
+
// Retry after construction completes so late host fields used by
|
|
419
|
+
// static queries/combine callbacks can finish initializing first.
|
|
420
|
+
this.explicitInitializationError = error
|
|
421
|
+
this.queryClient = undefined
|
|
422
|
+
this.observer = undefined
|
|
423
|
+
return false
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
private retryExplicitInitializationIfNeeded(): boolean {
|
|
428
|
+
if (!this.explicitInitializationError || this.shouldRefreshOnHostUpdate()) {
|
|
429
|
+
return false
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const explicitClient = this.tryGetQueryClient()
|
|
433
|
+
if (!explicitClient) {
|
|
434
|
+
return false
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return this.tryInitializeExplicitClient(explicitClient)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
private unsubscribeObserver(): void {
|
|
441
|
+
this.unsubscribe?.()
|
|
442
|
+
this.unsubscribe = undefined
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
private syncClient(): boolean {
|
|
446
|
+
const nextClient = this.tryGetQueryClient()
|
|
447
|
+
if (!nextClient) {
|
|
448
|
+
this.unsubscribeObserver()
|
|
449
|
+
this.queryClient = undefined
|
|
450
|
+
this.observer = undefined
|
|
451
|
+
this.setPlaceholderResult()
|
|
452
|
+
return false
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (nextClient === this.queryClient) {
|
|
456
|
+
return true
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
this.unsubscribeObserver()
|
|
460
|
+
this.queryClient = nextClient
|
|
461
|
+
const { queries, combine } = this.readResolvedOptions()
|
|
462
|
+
this.observer = new QueriesObserver(this.queryClient, queries, {
|
|
463
|
+
combine,
|
|
464
|
+
} as QueriesObserverOptions<TCombinedResult>)
|
|
465
|
+
this.setResult(
|
|
466
|
+
this.computeResult(this.observer.getCurrentResult(), combine),
|
|
467
|
+
)
|
|
468
|
+
this.placeholderInitialized = true
|
|
469
|
+
return true
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
private refreshOptions(): boolean {
|
|
473
|
+
if (!this.syncClient() || !this.observer) {
|
|
474
|
+
return false
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const { queries, combine } = this.readResolvedOptions()
|
|
478
|
+
|
|
479
|
+
this.observer.setQueries(queries, {
|
|
480
|
+
combine,
|
|
481
|
+
} as QueriesObserverOptions<TCombinedResult>)
|
|
482
|
+
|
|
483
|
+
const [rawResult, getCombinedResult] = this.observer.getOptimisticResult(
|
|
484
|
+
queries,
|
|
485
|
+
combine,
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
this.setResult(getCombinedResult(rawResult))
|
|
489
|
+
return true
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
private readResolvedOptions(client = this.queryClient): {
|
|
493
|
+
queries: Array<QueryObserverOptions>
|
|
494
|
+
combine: QueriesObserverOptions<TCombinedResult>['combine']
|
|
495
|
+
} {
|
|
496
|
+
if (!client) {
|
|
497
|
+
throw createMissingQueryClientError()
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return resolveQueriesOptions(
|
|
501
|
+
this.options as Accessor<
|
|
502
|
+
CreateQueriesControllerOptions<any, TCombinedResult>
|
|
503
|
+
>,
|
|
504
|
+
client,
|
|
505
|
+
)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
private shouldRefreshOnHostUpdate(): boolean {
|
|
509
|
+
if (typeof this.options === 'function') {
|
|
510
|
+
return true
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return typeof this.options.queries === 'function'
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
private computeResult(
|
|
517
|
+
rawResult: Array<QueryObserverResult>,
|
|
518
|
+
combine: QueriesObserverOptions<TCombinedResult>['combine'],
|
|
519
|
+
): TCombinedResult {
|
|
520
|
+
return (combine ? combine(rawResult) : rawResult) as TCombinedResult
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
private static createPlaceholderResult<TCombinedResult>(
|
|
524
|
+
optionsAccessor: Accessor<
|
|
525
|
+
CreateQueriesControllerOptions<any, TCombinedResult>
|
|
526
|
+
>,
|
|
527
|
+
): TCombinedResult {
|
|
528
|
+
const resolvedOptions = readAccessor(optionsAccessor)
|
|
529
|
+
const queries = readAccessor(resolvedOptions.queries)
|
|
530
|
+
const placeholders = queries.map((query) =>
|
|
531
|
+
createPlaceholderQueryObserverResult(query as QueryObserverOptions),
|
|
532
|
+
)
|
|
533
|
+
return (
|
|
534
|
+
resolvedOptions.combine
|
|
535
|
+
? resolvedOptions.combine(placeholders as never)
|
|
536
|
+
: placeholders
|
|
537
|
+
) as TCombinedResult
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
readCurrent(): TCombinedResult {
|
|
541
|
+
if (this.retryExplicitInitializationIfNeeded()) {
|
|
542
|
+
return this.current
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (this.explicitInitializationError && !this.placeholderRetryableFailure) {
|
|
546
|
+
throw this.explicitInitializationError
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (!this.queryClient && !this.observer && !this.placeholderInitialized) {
|
|
550
|
+
try {
|
|
551
|
+
// Early reads can happen during class-field initialization, before
|
|
552
|
+
// accessors referenced by queries/combine are ready. Retry normally
|
|
553
|
+
// after construction finishes and only surface errors after that point.
|
|
554
|
+
this.setPlaceholderResult()
|
|
555
|
+
} catch (error) {
|
|
556
|
+
if (!this.placeholderRetryableFailure) {
|
|
557
|
+
throw error
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return this.current
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
private setPlaceholderResult(): void {
|
|
566
|
+
this.result = QueriesController.createPlaceholderResult(this.options)
|
|
567
|
+
this.placeholderInitialized = true
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Creates a Lit reactive controller that subscribes the host to multiple
|
|
573
|
+
* queries.
|
|
574
|
+
*
|
|
575
|
+
* The returned accessor is callable and also exposes `current` and `destroy`.
|
|
576
|
+
* When `options` or `options.queries` is a function, it is re-read during host
|
|
577
|
+
* updates so the query list can follow reactive host state.
|
|
578
|
+
*
|
|
579
|
+
* If `queryClient` is omitted, the controller resolves the client from the
|
|
580
|
+
* nearest connected `QueryClientProvider`.
|
|
581
|
+
*
|
|
582
|
+
* @param host - The Lit reactive controller host that owns the queries
|
|
583
|
+
* subscription.
|
|
584
|
+
* @param options - Queries controller options, or a getter that returns options.
|
|
585
|
+
* @param queryClient - Optional explicit query client. Provide this for
|
|
586
|
+
* controllers that should not resolve a client from Lit context.
|
|
587
|
+
* @returns An accessor for the latest query results, or the value returned by
|
|
588
|
+
* `combine`.
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* ```ts
|
|
592
|
+
* import { LitElement, html } from 'lit'
|
|
593
|
+
* import { createQueriesController } from '@tanstack/lit-query'
|
|
594
|
+
*
|
|
595
|
+
* class DashboardView extends LitElement {
|
|
596
|
+
* private readonly dashboard = createQueriesController(this, {
|
|
597
|
+
* queries: [
|
|
598
|
+
* { queryKey: ['stats'], queryFn: fetchStats },
|
|
599
|
+
* { queryKey: ['projects'], queryFn: fetchProjects },
|
|
600
|
+
* ],
|
|
601
|
+
* combine: ([stats, projects]) => ({
|
|
602
|
+
* stats: stats.data,
|
|
603
|
+
* projects: projects.data ?? [],
|
|
604
|
+
* isPending: stats.isPending || projects.isPending,
|
|
605
|
+
* }),
|
|
606
|
+
* })
|
|
607
|
+
*
|
|
608
|
+
* render() {
|
|
609
|
+
* const dashboard = this.dashboard()
|
|
610
|
+
* return html`<p>Projects: ${dashboard.projects.length}</p>`
|
|
611
|
+
* }
|
|
612
|
+
* }
|
|
613
|
+
* ```
|
|
614
|
+
*/
|
|
615
|
+
export function createQueriesController<
|
|
616
|
+
TQueryOptions extends Array<any>,
|
|
617
|
+
TCombinedResult = CreateQueriesResults<TQueryOptions>,
|
|
618
|
+
>(
|
|
619
|
+
host: ReactiveControllerHost,
|
|
620
|
+
options: Accessor<
|
|
621
|
+
CreateQueriesControllerOptions<TQueryOptions, TCombinedResult>
|
|
622
|
+
>,
|
|
623
|
+
queryClient?: QueryClient,
|
|
624
|
+
): QueriesResultAccessor<TCombinedResult> {
|
|
625
|
+
const controller = new QueriesController(host, options, queryClient)
|
|
626
|
+
|
|
627
|
+
return Object.assign(
|
|
628
|
+
createValueAccessor(() => controller.readCurrent()),
|
|
629
|
+
{
|
|
630
|
+
destroy: () => controller.destroy(),
|
|
631
|
+
},
|
|
632
|
+
)
|
|
633
|
+
}
|