@wisemen/vue-core-api-utils 1.0.0-beta.0 → 1.0.0-beta.2
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/dist/index.d.mts +565 -50
- package/dist/index.mjs +501 -25
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,52 +1,115 @@
|
|
|
1
|
+
import { Result } from "neverthrow";
|
|
2
|
+
import { QueryClient } from "@tanstack/vue-query";
|
|
1
3
|
import * as vue0 from "vue";
|
|
2
4
|
import { ComputedRef, MaybeRef, Ref, UnwrapRef } from "vue";
|
|
3
|
-
import { Result } from "neverthrow";
|
|
4
5
|
|
|
5
|
-
//#region src/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
params: TParams;
|
|
16
|
-
};
|
|
17
|
-
interface UseMutationOptions<TParams, TReqData, TResData> {
|
|
6
|
+
//#region src/async-result/asyncResult.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* Base class for AsyncResult - internal use only.
|
|
9
|
+
* Use AsyncResult<T, E> as the public type.
|
|
10
|
+
*/
|
|
11
|
+
declare abstract class AsyncResultBase<T, E> {
|
|
12
|
+
protected readonly _error: E | undefined;
|
|
13
|
+
protected readonly _status: 'err' | 'loading' | 'ok';
|
|
14
|
+
protected readonly _value: T | undefined;
|
|
15
|
+
protected constructor(status: 'err' | 'loading' | 'ok', value?: T, error?: E);
|
|
18
16
|
/**
|
|
19
|
-
*
|
|
17
|
+
* Check if the result is an error (type predicate for narrowing)
|
|
20
18
|
*/
|
|
21
|
-
|
|
19
|
+
isErr(): this is AsyncResultErr<T, E>;
|
|
22
20
|
/**
|
|
23
|
-
*
|
|
24
|
-
* @param options - Parameters and body for the mutation
|
|
25
|
-
* @returns Promise with the response data
|
|
21
|
+
* Check if the result is in loading state (type predicate for narrowing)
|
|
26
22
|
*/
|
|
27
|
-
|
|
23
|
+
isLoading(): this is AsyncResultLoading<T, E>;
|
|
28
24
|
/**
|
|
29
|
-
*
|
|
25
|
+
* Check if the result is a success (type predicate for narrowing)
|
|
30
26
|
*/
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
interface UseMutationReturnType<TReqData, TResData, TParams = void> {
|
|
27
|
+
isOk(): this is AsyncResultOk<T, E>;
|
|
34
28
|
/**
|
|
35
|
-
*
|
|
29
|
+
* Map the success value to a new value
|
|
36
30
|
*/
|
|
37
|
-
|
|
31
|
+
map<U>(fn: (value: T) => U): AsyncResult<U, E>;
|
|
38
32
|
/**
|
|
39
|
-
*
|
|
33
|
+
* Map the error to a new error
|
|
40
34
|
*/
|
|
41
|
-
|
|
35
|
+
mapErr<F>(fn: (error: E) => F): AsyncResult<T, F>;
|
|
42
36
|
/**
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
* Pattern match on all three states
|
|
38
|
+
*/
|
|
39
|
+
match<U>(handlers: {
|
|
40
|
+
err: (error: E) => U;
|
|
41
|
+
loading: () => U;
|
|
42
|
+
ok: (value: T) => U;
|
|
43
|
+
}): U;
|
|
44
|
+
/**
|
|
45
|
+
* Get the success value, or return null if loading or error.
|
|
46
|
+
* Returns T | null when null is passed as the default value.
|
|
47
|
+
*/
|
|
48
|
+
unwrapOr(defaultValue: null): T | null;
|
|
49
|
+
/**
|
|
50
|
+
* Get the success value, or return the default value of type T if loading or error.
|
|
51
|
+
* Returns T when a value of type T is passed as the default value.
|
|
46
52
|
*/
|
|
47
|
-
|
|
53
|
+
unwrapOr(defaultValue: T): T;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* AsyncResult representing an error state
|
|
57
|
+
*/
|
|
58
|
+
declare class AsyncResultErr<T, E> extends AsyncResultBase<T, E> {
|
|
59
|
+
private constructor();
|
|
60
|
+
/** @internal */
|
|
61
|
+
static _create<T, E>(error: E): AsyncResultErr<T, E>;
|
|
62
|
+
/** Get the error value - only available after isErr() check */
|
|
63
|
+
getError(): E;
|
|
64
|
+
getResult(): Result<T, E>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* AsyncResult representing a loading state
|
|
68
|
+
*/
|
|
69
|
+
declare class AsyncResultLoading<T, E> extends AsyncResultBase<T, E> {
|
|
70
|
+
private constructor();
|
|
71
|
+
/** @internal */
|
|
72
|
+
static _create<T, E>(): AsyncResultLoading<T, E>;
|
|
73
|
+
getResult(): null;
|
|
48
74
|
}
|
|
49
|
-
|
|
75
|
+
/**
|
|
76
|
+
* AsyncResult representing a success state
|
|
77
|
+
*/
|
|
78
|
+
declare class AsyncResultOk<T, E> extends AsyncResultBase<T, E> {
|
|
79
|
+
private constructor();
|
|
80
|
+
/** @internal */
|
|
81
|
+
static _create<T, E>(value: T): AsyncResultOk<T, E>;
|
|
82
|
+
getResult(): Result<T, E>;
|
|
83
|
+
/** Get the success value - only available after isOk() check */
|
|
84
|
+
getValue(): T;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Union type of all AsyncResult states.
|
|
88
|
+
* Use isOk(), isErr(), or isLoading() to narrow to specific state.
|
|
89
|
+
*/
|
|
90
|
+
type AsyncResult<T, E> = AsyncResultErr<T, E> | AsyncResultLoading<T, E> | AsyncResultOk<T, E>;
|
|
91
|
+
/**
|
|
92
|
+
* Static factory methods for creating AsyncResult instances.
|
|
93
|
+
* This pattern (same name for type and value) is intentional for ergonomic API.
|
|
94
|
+
*/
|
|
95
|
+
declare const AsyncResult: {
|
|
96
|
+
/**
|
|
97
|
+
* Create a failed AsyncResult with error
|
|
98
|
+
*/
|
|
99
|
+
readonly err: <T, E>(error: E) => AsyncResultErr<T, E>;
|
|
100
|
+
/**
|
|
101
|
+
* Create an AsyncResult from an existing neverthrow Result
|
|
102
|
+
*/
|
|
103
|
+
readonly fromResult: <T, E>(result: Result<T, E>) => AsyncResult<T, E>;
|
|
104
|
+
/**
|
|
105
|
+
* Create a loading AsyncResult
|
|
106
|
+
*/
|
|
107
|
+
readonly loading: <T, E>() => AsyncResultLoading<T, E>;
|
|
108
|
+
/**
|
|
109
|
+
* Create a successful AsyncResult with data
|
|
110
|
+
*/
|
|
111
|
+
readonly ok: <T, E>(value: T) => AsyncResultOk<T, E>;
|
|
112
|
+
};
|
|
50
113
|
//#endregion
|
|
51
114
|
//#region src/types/apiError.type.d.ts
|
|
52
115
|
interface ApiErrorCodes {}
|
|
@@ -75,11 +138,73 @@ type ApiUnexpectedError = Error;
|
|
|
75
138
|
type ApiError = ApiExpectedError | ApiUnexpectedError;
|
|
76
139
|
type ApiResult<T> = Result<T, ApiError>;
|
|
77
140
|
//#endregion
|
|
141
|
+
//#region src/composables/mutation/mutation.composable.d.ts
|
|
142
|
+
type RequestParams$1<TReqData, TParams> = TReqData extends void ? TParams extends void ? void : {
|
|
143
|
+
params: TParams;
|
|
144
|
+
} : TParams extends void ? {
|
|
145
|
+
body: TReqData;
|
|
146
|
+
} : {
|
|
147
|
+
body: TReqData;
|
|
148
|
+
params: TParams;
|
|
149
|
+
};
|
|
150
|
+
interface UseMutationOptions<TReqData, TResData, TParams = void> {
|
|
151
|
+
/**
|
|
152
|
+
* Whether to enable debug mode
|
|
153
|
+
*/
|
|
154
|
+
isDebug?: boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Function that will be called to perform the mutation
|
|
157
|
+
* @param options - Parameters and body for the mutation
|
|
158
|
+
* @returns Promise with ApiResult containing either the response data or an error
|
|
159
|
+
*/
|
|
160
|
+
queryFn: (options: RequestParams$1<TReqData, TParams>) => Promise<ApiResult<TResData>>;
|
|
161
|
+
/**
|
|
162
|
+
* Object where each key is a query key to invalidate after mutation succeeds.
|
|
163
|
+
* Each query key can optionally have nested parameter extractors.
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* queryKeysToInvalidate: {
|
|
167
|
+
* contactDetail: {
|
|
168
|
+
* contactUuid: (params, result) => params.contactUuid,
|
|
169
|
+
* },
|
|
170
|
+
* contactIndex: {},
|
|
171
|
+
* }
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
queryKeysToInvalidate?: Record<string, Record<string, (params: TParams, data: TResData) => any> | undefined>;
|
|
175
|
+
}
|
|
176
|
+
interface UseMutationReturnType<TReqData, TResData, TParams = void> {
|
|
177
|
+
/**
|
|
178
|
+
* Whether mutation is loading
|
|
179
|
+
*/
|
|
180
|
+
isLoading: ComputedRef<boolean>;
|
|
181
|
+
/**
|
|
182
|
+
* Response data from the mutation
|
|
183
|
+
* @deprecated - use `result.value.getValue()` instead
|
|
184
|
+
*/
|
|
185
|
+
data: ComputedRef<TResData | null>;
|
|
186
|
+
/**
|
|
187
|
+
* Function to execute the mutation
|
|
188
|
+
* @param data - Parameters and body for the mutation
|
|
189
|
+
* @returns Promise with ApiResult containing either the response data or an error
|
|
190
|
+
*/
|
|
191
|
+
execute: (data: RequestParams$1<TReqData, TParams>) => Promise<ApiResult<TResData>>;
|
|
192
|
+
/**
|
|
193
|
+
* Computed result of the mutation
|
|
194
|
+
* Returns an AsyncResult with three states:
|
|
195
|
+
* - loading: use `result.value.isLoading()`
|
|
196
|
+
* - ok: use `result.value.isOk()` and `result.value.getValue()`
|
|
197
|
+
* - err: use `result.value.isErr()` and `result.value.getError()`
|
|
198
|
+
*/
|
|
199
|
+
result: ComputedRef<AsyncResult<TResData, ApiError>>;
|
|
200
|
+
}
|
|
201
|
+
declare function useMutation<TReqData = void, TResData = void, TParams = void>(options: UseMutationOptions<TReqData, TResData, TParams>): UseMutationReturnType<TReqData, TResData, TParams>;
|
|
202
|
+
//#endregion
|
|
78
203
|
//#region src/types/sort.type.d.ts
|
|
79
204
|
type SortDirection = 'asc' | 'desc';
|
|
80
|
-
interface Sort<TKey extends string = string> {
|
|
205
|
+
interface Sort<TKey$1 extends string = string> {
|
|
81
206
|
direction: SortDirection;
|
|
82
|
-
key: TKey;
|
|
207
|
+
key: TKey$1;
|
|
83
208
|
}
|
|
84
209
|
//#endregion
|
|
85
210
|
//#region src/types/query.type.d.ts
|
|
@@ -141,8 +266,85 @@ interface PaginatedDataDto<TSchema> {
|
|
|
141
266
|
};
|
|
142
267
|
}
|
|
143
268
|
//#endregion
|
|
269
|
+
//#region src/types/queryKeys.type.d.ts
|
|
270
|
+
/**
|
|
271
|
+
* Base interface for defining query keys with their associated entities
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```typescript
|
|
275
|
+
* declare module '@wisemen/vue-core-api-utils' {
|
|
276
|
+
* interface QueryKeys {
|
|
277
|
+
* userDetail: {
|
|
278
|
+
* params: { userUuid: ComputedRef<UserUuid> }
|
|
279
|
+
* entity: User
|
|
280
|
+
* }
|
|
281
|
+
* productList: {
|
|
282
|
+
* params: { category: ComputedRef<string> }
|
|
283
|
+
* entity: Product[]
|
|
284
|
+
* }
|
|
285
|
+
* }
|
|
286
|
+
* }
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
289
|
+
interface QueryKeys {}
|
|
290
|
+
/**
|
|
291
|
+
* Generic helper types for libraries/factories that want to infer query key typing
|
|
292
|
+
* from a user-provided config object (instead of relying on module augmentation).
|
|
293
|
+
*/
|
|
294
|
+
/**
|
|
295
|
+
* Extract the entity type from a query-keys config for a specific key.
|
|
296
|
+
*/
|
|
297
|
+
type QueryKeyEntityFromConfig<TQueryKeys extends object, TKey$1 extends PropertyKey> = TKey$1 extends keyof TQueryKeys ? TQueryKeys[TKey$1] extends {
|
|
298
|
+
entity: infer E;
|
|
299
|
+
} ? E : never : never;
|
|
300
|
+
/**
|
|
301
|
+
* Extract the params type from a query-keys config for a specific key.
|
|
302
|
+
* Automatically wraps each param in Ref for reactivity.
|
|
303
|
+
*/
|
|
304
|
+
type QueryKeyParamsFromConfig<TQueryKeys extends object, TKey$1 extends PropertyKey> = TKey$1 extends keyof TQueryKeys ? TQueryKeys[TKey$1] extends {
|
|
305
|
+
params: infer P;
|
|
306
|
+
} ? { [K in keyof P]: Ref<P[K]> } : void : never;
|
|
307
|
+
/**
|
|
308
|
+
* Extract the raw params type from a query-keys config for a specific key (unwrapped from Computed).
|
|
309
|
+
* Used for optimistic updates which accept plain values.
|
|
310
|
+
*/
|
|
311
|
+
type QueryKeyRawParamsFromConfig<TQueryKeys extends object, TKey$1 extends PropertyKey> = TKey$1 extends keyof TQueryKeys ? TQueryKeys[TKey$1] extends {
|
|
312
|
+
params: infer P;
|
|
313
|
+
} ? P : void : never;
|
|
314
|
+
/**
|
|
315
|
+
* Get all keys that have an associated entity in a query-keys config.
|
|
316
|
+
*/
|
|
317
|
+
type QueryKeysWithEntityFromConfig<TQueryKeys extends object> = ({ [K in keyof TQueryKeys]: TQueryKeys[K] extends {
|
|
318
|
+
entity: any;
|
|
319
|
+
} ? K : never }[keyof TQueryKeys]) & string;
|
|
320
|
+
/**
|
|
321
|
+
* Extract the parameters object from a query key definition
|
|
322
|
+
*/
|
|
323
|
+
type QueryKeyParams<TKey$1 extends keyof QueryKeys> = QueryKeys[TKey$1] extends {
|
|
324
|
+
params: infer P;
|
|
325
|
+
} ? Ref<P> : QueryKeys[TKey$1];
|
|
326
|
+
/**
|
|
327
|
+
* Extract the entity type from a query key definition
|
|
328
|
+
*/
|
|
329
|
+
type QueryKeyEntity<TKey$1 extends keyof QueryKeys> = QueryKeys[TKey$1] extends {
|
|
330
|
+
entity: infer E;
|
|
331
|
+
} ? E : never;
|
|
332
|
+
/**
|
|
333
|
+
* Check if a query key has an associated entity
|
|
334
|
+
*/
|
|
335
|
+
type HasEntity<TKey$1 extends keyof QueryKeys> = QueryKeys[TKey$1] extends {
|
|
336
|
+
entity: any;
|
|
337
|
+
} ? TKey$1 : never;
|
|
338
|
+
/**
|
|
339
|
+
* Get all query keys that have an associated entity
|
|
340
|
+
*/
|
|
341
|
+
type QueryKeysWithEntity = { [K in keyof QueryKeys]: HasEntity<K> }[keyof QueryKeys];
|
|
342
|
+
//#endregion
|
|
144
343
|
//#region src/composables/query/keysetInfiniteQuery.composable.d.ts
|
|
145
344
|
type NonOptionalKeys$2<T> = { [K in keyof T]-?: T[K] };
|
|
345
|
+
type ExtractParams$2<T> = T extends {
|
|
346
|
+
params: infer P;
|
|
347
|
+
} ? P : T;
|
|
146
348
|
interface KeysetInfiniteQueryOptions<TData> {
|
|
147
349
|
/**
|
|
148
350
|
* The time in milliseconds after which the query will be considered stale
|
|
@@ -169,7 +371,7 @@ interface KeysetInfiniteQueryOptions<TData> {
|
|
|
169
371
|
/**
|
|
170
372
|
* Query key associated with the query
|
|
171
373
|
*/
|
|
172
|
-
queryKey: { [TQueryKey in keyof QueryKeys]?: { [TQueryKeyParam in keyof NonOptionalKeys$2<QueryKeys[TQueryKey]
|
|
374
|
+
queryKey: { [TQueryKey in keyof QueryKeys]?: { [TQueryKeyParam in keyof NonOptionalKeys$2<ExtractParams$2<QueryKeys[TQueryKey]>>]: MaybeRef<ExtractParams$2<QueryKeys[TQueryKey]>[TQueryKeyParam]> } };
|
|
173
375
|
}
|
|
174
376
|
declare function useKeysetInfiniteQuery<TData>(options: KeysetInfiniteQueryOptions<TData>): {
|
|
175
377
|
hasNextPage: vue0.ComputedRef<boolean>;
|
|
@@ -180,11 +382,14 @@ declare function useKeysetInfiniteQuery<TData>(options: KeysetInfiniteQueryOptio
|
|
|
180
382
|
isSuccess: vue0.ComputedRef<boolean>;
|
|
181
383
|
fetchNextPage: () => Promise<void>;
|
|
182
384
|
refetch: () => Promise<void>;
|
|
183
|
-
result: vue0.ComputedRef<
|
|
385
|
+
result: vue0.ComputedRef<AsyncResult<KeysetPaginationResponse<TData>, ApiError>>;
|
|
184
386
|
};
|
|
185
387
|
//#endregion
|
|
186
388
|
//#region src/composables/query/offsetInfiniteQuery.composable.d.ts
|
|
187
389
|
type NonOptionalKeys$1<T> = { [K in keyof T]-?: T[K] };
|
|
390
|
+
type ExtractParams$1<T> = T extends {
|
|
391
|
+
params: infer P;
|
|
392
|
+
} ? P : T;
|
|
188
393
|
interface OffsetInfiniteQueryOptions<TData> {
|
|
189
394
|
/**
|
|
190
395
|
* The time in milliseconds after which the query will be considered stale
|
|
@@ -211,7 +416,7 @@ interface OffsetInfiniteQueryOptions<TData> {
|
|
|
211
416
|
/**
|
|
212
417
|
* Query key associated with the query
|
|
213
418
|
*/
|
|
214
|
-
queryKey: { [TQueryKey in keyof QueryKeys]?: { [TQueryKeyParam in keyof NonOptionalKeys$1<QueryKeys[TQueryKey]
|
|
419
|
+
queryKey: { [TQueryKey in keyof QueryKeys]?: { [TQueryKeyParam in keyof NonOptionalKeys$1<ExtractParams$1<QueryKeys[TQueryKey]>>]: MaybeRef<ExtractParams$1<QueryKeys[TQueryKey]>[TQueryKeyParam]> } };
|
|
215
420
|
}
|
|
216
421
|
declare function useOffsetInfiniteQuery<TData>(options: OffsetInfiniteQueryOptions<TData>): {
|
|
217
422
|
hasNextPage: vue0.ComputedRef<boolean>;
|
|
@@ -222,11 +427,14 @@ declare function useOffsetInfiniteQuery<TData>(options: OffsetInfiniteQueryOptio
|
|
|
222
427
|
isSuccess: vue0.ComputedRef<boolean>;
|
|
223
428
|
fetchNextPage: () => Promise<void>;
|
|
224
429
|
refetch: () => Promise<void>;
|
|
225
|
-
result: vue0.ComputedRef<
|
|
430
|
+
result: vue0.ComputedRef<AsyncResult<OffsetPaginationResponse<TData>, ApiError>>;
|
|
226
431
|
};
|
|
227
432
|
//#endregion
|
|
228
433
|
//#region src/composables/query/query.composable.d.ts
|
|
229
434
|
type NonOptionalKeys<T> = { [K in keyof T]-?: T[K] };
|
|
435
|
+
type ExtractParams<T> = T extends {
|
|
436
|
+
params: infer P;
|
|
437
|
+
} ? P : T;
|
|
230
438
|
interface UseQueryOptions<TResData> {
|
|
231
439
|
/**
|
|
232
440
|
* The time in milliseconds after which the query will be considered stale
|
|
@@ -254,28 +462,26 @@ interface UseQueryOptions<TResData> {
|
|
|
254
462
|
/**
|
|
255
463
|
* Query key associated with the query
|
|
256
464
|
*/
|
|
257
|
-
queryKey: { [TQueryKey in keyof QueryKeys]?: { [TQueryKeyParam in keyof NonOptionalKeys<QueryKeys[TQueryKey]
|
|
465
|
+
queryKey: { [TQueryKey in keyof QueryKeys]?: { [TQueryKeyParam in keyof NonOptionalKeys<ExtractParams<QueryKeys[TQueryKey]>>]: MaybeRef<ExtractParams<QueryKeys[TQueryKey]>[TQueryKeyParam]> } };
|
|
258
466
|
}
|
|
259
467
|
interface UseQueryReturnType<TResData> {
|
|
260
|
-
/**
|
|
261
|
-
* Response data
|
|
262
|
-
*/
|
|
263
468
|
/**
|
|
264
469
|
* Whether query has errored at least once
|
|
265
|
-
* @deprecated - use `result.isErr()` instead
|
|
470
|
+
* @deprecated - use `result.value.isErr()` instead
|
|
266
471
|
*/
|
|
267
472
|
isError: ComputedRef<boolean>;
|
|
268
473
|
/**
|
|
269
|
-
* Whether query is currently
|
|
474
|
+
* Whether query is currently fetching data, regardless of cache status
|
|
270
475
|
*/
|
|
271
476
|
isFetching: ComputedRef<boolean>;
|
|
272
477
|
/**
|
|
273
478
|
* Whether query is initially loading
|
|
479
|
+
* @deprecated - use `result.value.isLoading()` instead
|
|
274
480
|
*/
|
|
275
481
|
isLoading: ComputedRef<boolean>;
|
|
276
482
|
/**
|
|
277
483
|
* Whether query has been executed successfully
|
|
278
|
-
* @deprecated - use `result.isOk()` instead
|
|
484
|
+
* @deprecated - use `result.value.isOk()` instead
|
|
279
485
|
*/
|
|
280
486
|
isSuccess: ComputedRef<boolean>;
|
|
281
487
|
/**
|
|
@@ -284,10 +490,14 @@ interface UseQueryReturnType<TResData> {
|
|
|
284
490
|
refetch: () => Promise<void>;
|
|
285
491
|
/**
|
|
286
492
|
* Computed result of the query
|
|
287
|
-
*
|
|
288
|
-
*
|
|
493
|
+
* Returns an AsyncResult with three states:
|
|
494
|
+
* - loading: use `result.value.isLoading()`
|
|
495
|
+
* - ok: use `result.value.isOk()` and `result.value.getValue()`
|
|
496
|
+
* - err: use `result.value.isErr()` and `result.value.getError()`
|
|
497
|
+
*
|
|
498
|
+
* Use `result.value.match({ loading, ok, err })` for exhaustive handling
|
|
289
499
|
*/
|
|
290
|
-
result: ComputedRef<
|
|
500
|
+
result: ComputedRef<AsyncResult<TResData, ApiError>>;
|
|
291
501
|
}
|
|
292
502
|
declare function useQuery<TResData>(options: UseQueryOptions<TResData>): UseQueryReturnType<TResData>;
|
|
293
503
|
//#endregion
|
|
@@ -303,4 +513,309 @@ interface QueryConfig {
|
|
|
303
513
|
}
|
|
304
514
|
declare function setQueryConfig(config: Partial<QueryConfig>): void;
|
|
305
515
|
//#endregion
|
|
306
|
-
|
|
516
|
+
//#region src/factory/createApiUtils.types.d.ts
|
|
517
|
+
interface CreateApiUtilsOptions {
|
|
518
|
+
queryClient: QueryClient;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Helper type to build the invalidation config for a specific query key
|
|
522
|
+
* Maps the query key's params to optional parameter extractors
|
|
523
|
+
*/
|
|
524
|
+
type QueryKeyInvalidationConfig<TQueryKeys extends object, TKey$1 extends keyof TQueryKeys, TParams, TResData> = QueryKeyRawParamsFromConfig<TQueryKeys, TKey$1 & string> extends void ? {} : QueryKeyRawParamsFromConfig<TQueryKeys, TKey$1 & string> extends object ? { [ParamKey in keyof QueryKeyRawParamsFromConfig<TQueryKeys, TKey$1 & string>]?: (params: TParams, data: TResData) => QueryKeyRawParamsFromConfig<TQueryKeys, TKey$1 & string>[ParamKey] } : {};
|
|
525
|
+
type QueryKeysWithArrayEntityFromConfig<TQueryKeys extends object> = ({ [K in keyof TQueryKeys]: TQueryKeys[K] extends {
|
|
526
|
+
entity: any[];
|
|
527
|
+
} ? K : never }[keyof TQueryKeys]) & string;
|
|
528
|
+
type QueryKeyArrayItemFromConfig<TQueryKeys extends object, TKey$1 extends PropertyKey> = QueryKeyEntityFromConfig<TQueryKeys, TKey$1> extends (infer TItem)[] ? TItem : never;
|
|
529
|
+
type ApiUseQueryOptions<TQueryKeys extends object, TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>> = {
|
|
530
|
+
staleTime?: number;
|
|
531
|
+
isDebug?: boolean;
|
|
532
|
+
isEnabled?: MaybeRef<boolean>;
|
|
533
|
+
queryFn: () => Promise<ApiResult<QueryKeyEntityFromConfig<TQueryKeys, TKey$1>>>;
|
|
534
|
+
} & (QueryKeyParamsFromConfig<TQueryKeys, TKey$1> extends void ? {
|
|
535
|
+
params?: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
536
|
+
} : {
|
|
537
|
+
params: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
538
|
+
});
|
|
539
|
+
type ApiUsePrefetchQueryOptions<TQueryKeys extends object, TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>> = {
|
|
540
|
+
staleTime?: number;
|
|
541
|
+
queryFn: () => Promise<ApiResult<QueryKeyEntityFromConfig<TQueryKeys, TKey$1>>>;
|
|
542
|
+
} & (QueryKeyParamsFromConfig<TQueryKeys, TKey$1> extends void ? {
|
|
543
|
+
params?: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
544
|
+
} : {
|
|
545
|
+
params: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
546
|
+
});
|
|
547
|
+
type ApiUseOffsetInfiniteQueryOptions<TQueryKeys extends object, TKey$1 extends QueryKeysWithArrayEntityFromConfig<TQueryKeys>> = {
|
|
548
|
+
staleTime?: number;
|
|
549
|
+
isEnabled?: MaybeRef<boolean>;
|
|
550
|
+
limit?: number;
|
|
551
|
+
queryFn: (paginationParams: OffsetPaginationParams) => Promise<OffsetPaginationResult<QueryKeyArrayItemFromConfig<TQueryKeys, TKey$1>>>;
|
|
552
|
+
} & (QueryKeyParamsFromConfig<TQueryKeys, TKey$1> extends void ? {
|
|
553
|
+
params?: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
554
|
+
} : {
|
|
555
|
+
params: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
556
|
+
});
|
|
557
|
+
type ApiUseOffsetInfinitePrefetchQueryOptions<TQueryKeys extends object, TKey$1 extends QueryKeysWithArrayEntityFromConfig<TQueryKeys>> = {
|
|
558
|
+
staleTime?: number;
|
|
559
|
+
limit?: number;
|
|
560
|
+
queryFn: (paginationParams: OffsetPaginationParams) => Promise<OffsetPaginationResult<QueryKeyArrayItemFromConfig<TQueryKeys, TKey$1>>>;
|
|
561
|
+
} & (QueryKeyParamsFromConfig<TQueryKeys, TKey$1> extends void ? {
|
|
562
|
+
params?: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
563
|
+
} : {
|
|
564
|
+
params: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
565
|
+
});
|
|
566
|
+
type ApiUseKeysetInfiniteQueryOptions<TQueryKeys extends object, TKey$1 extends QueryKeysWithArrayEntityFromConfig<TQueryKeys>> = {
|
|
567
|
+
staleTime?: number;
|
|
568
|
+
isEnabled?: MaybeRef<boolean>;
|
|
569
|
+
limit?: number;
|
|
570
|
+
queryFn: (paginationParams: KeysetPaginationParams) => Promise<KeysetPaginationResult<QueryKeyArrayItemFromConfig<TQueryKeys, TKey$1>>>;
|
|
571
|
+
} & (QueryKeyParamsFromConfig<TQueryKeys, TKey$1> extends void ? {
|
|
572
|
+
params?: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
573
|
+
} : {
|
|
574
|
+
params: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
575
|
+
});
|
|
576
|
+
type ApiUseKeysetInfinitePrefetchQueryOptions<TQueryKeys extends object, TKey$1 extends QueryKeysWithArrayEntityFromConfig<TQueryKeys>> = {
|
|
577
|
+
staleTime?: number;
|
|
578
|
+
limit?: number;
|
|
579
|
+
queryFn: (paginationParams: KeysetPaginationParams) => Promise<KeysetPaginationResult<QueryKeyArrayItemFromConfig<TQueryKeys, TKey$1>>>;
|
|
580
|
+
} & (QueryKeyParamsFromConfig<TQueryKeys, TKey$1> extends void ? {
|
|
581
|
+
params?: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
582
|
+
} : {
|
|
583
|
+
params: QueryKeyParamsFromConfig<TQueryKeys, TKey$1>;
|
|
584
|
+
});
|
|
585
|
+
type RequestParams<TReqData, TParams> = TReqData extends void ? TParams extends void ? void : {
|
|
586
|
+
params: TParams;
|
|
587
|
+
} : TParams extends void ? {
|
|
588
|
+
body: TReqData;
|
|
589
|
+
} : {
|
|
590
|
+
body: TReqData;
|
|
591
|
+
params: TParams;
|
|
592
|
+
};
|
|
593
|
+
interface ApiUseMutationOptions<TQueryKeys extends object, TReqData, TResData, TParams = void> {
|
|
594
|
+
/**
|
|
595
|
+
* Whether to enable debug mode
|
|
596
|
+
*/
|
|
597
|
+
isDebug?: boolean;
|
|
598
|
+
/**
|
|
599
|
+
* Function that will be called to perform the mutation
|
|
600
|
+
* @param options - Parameters and body for the mutation
|
|
601
|
+
* @returns Promise with ApiResult containing either the response data or an error
|
|
602
|
+
*/
|
|
603
|
+
queryFn: (options: RequestParams<TReqData, TParams>) => Promise<ApiResult<TResData>>;
|
|
604
|
+
/**
|
|
605
|
+
* Query keys which should be invalidated after mutation is successful
|
|
606
|
+
* Each key is optional and maps to the query key's specific parameters
|
|
607
|
+
* @example
|
|
608
|
+
* ```typescript
|
|
609
|
+
* queryKeysToInvalidate: {
|
|
610
|
+
* userDetail: {
|
|
611
|
+
* userUuid: (params, result) => params.userUuid,
|
|
612
|
+
* },
|
|
613
|
+
* userList: {},
|
|
614
|
+
* }
|
|
615
|
+
* ```
|
|
616
|
+
*/
|
|
617
|
+
queryKeysToInvalidate?: { [TKey in keyof TQueryKeys]?: QueryKeyInvalidationConfig<TQueryKeys, TKey, TParams, TResData> };
|
|
618
|
+
}
|
|
619
|
+
interface CreateApiMutationUtilsReturnType<TQueryKeys extends object> {
|
|
620
|
+
useMutation: <TReqData = void, TResData = void, TParams = void>(options: ApiUseMutationOptions<TQueryKeys, TReqData, TResData, TParams>) => UseMutationReturnType<TReqData, TResData, TParams>;
|
|
621
|
+
}
|
|
622
|
+
//#endregion
|
|
623
|
+
//#region src/factory/createApiInfiniteQueryUtils.d.ts
|
|
624
|
+
interface CreateApiInfiniteQueryUtilsReturnType<TQueryKeys extends object> {
|
|
625
|
+
useKeysetInfiniteQuery: <TKey$1 extends QueryKeysWithArrayEntityFromConfig<TQueryKeys>>(key: TKey$1, queryOptions: ApiUseKeysetInfiniteQueryOptions<TQueryKeys, TKey$1>) => ReturnType<typeof useKeysetInfiniteQuery<QueryKeyArrayItemFromConfig<TQueryKeys, TKey$1>>>;
|
|
626
|
+
useOffsetInfiniteQuery: <TKey$1 extends QueryKeysWithArrayEntityFromConfig<TQueryKeys>>(key: TKey$1, queryOptions: ApiUseOffsetInfiniteQueryOptions<TQueryKeys, TKey$1>) => ReturnType<typeof useOffsetInfiniteQuery<QueryKeyArrayItemFromConfig<TQueryKeys, TKey$1>>>;
|
|
627
|
+
}
|
|
628
|
+
declare function createApiInfiniteQueryUtils<TQueryKeys extends object>(): CreateApiInfiniteQueryUtilsReturnType<TQueryKeys>;
|
|
629
|
+
//#endregion
|
|
630
|
+
//#region src/factory/createApiMutationUtils.d.ts
|
|
631
|
+
declare function createApiMutationUtils<TQueryKeys extends object>(): CreateApiMutationUtilsReturnType<TQueryKeys>;
|
|
632
|
+
//#endregion
|
|
633
|
+
//#region src/utils/optimisticUpdates.d.ts
|
|
634
|
+
/**
|
|
635
|
+
* Predicate function type that takes an entity and returns boolean
|
|
636
|
+
*/
|
|
637
|
+
type PredicateFn<TEntity> = TEntity extends any[] ? (item: TEntity[number]) => boolean : (item: TEntity) => boolean;
|
|
638
|
+
/**
|
|
639
|
+
* Type for matching by key-value pair
|
|
640
|
+
*/
|
|
641
|
+
type EntityItem<TEntity> = TEntity extends any[] ? TEntity[number] : TEntity;
|
|
642
|
+
type MatchByKeyValue<TEntity> = Partial<{ [K in keyof EntityItem<TEntity>]: MaybeRef<UnwrapRef<EntityItem<TEntity>[K]>> }>;
|
|
643
|
+
/**
|
|
644
|
+
* Options for the "by" parameter - can be a predicate function or key-value object
|
|
645
|
+
*/
|
|
646
|
+
type ByOption<TEntity> = MatchByKeyValue<TEntity> | PredicateFn<TEntity> | null | undefined;
|
|
647
|
+
/**
|
|
648
|
+
* Options for optimistic update
|
|
649
|
+
*/
|
|
650
|
+
interface OptimisticUpdateOptions<TEntity> {
|
|
651
|
+
/**
|
|
652
|
+
* How to match the entity to update:
|
|
653
|
+
* - function: a predicate that returns true for the entity to update
|
|
654
|
+
* - object: key-value pairs to match (e.g., { id: '123' } or { uuid: 'abc' })
|
|
655
|
+
* - undefined: defaults to matching by 'id' from the value
|
|
656
|
+
*/
|
|
657
|
+
by?: ByOption<TEntity>;
|
|
658
|
+
/**
|
|
659
|
+
* The new value to set (for single entities) or merge (for arrays)
|
|
660
|
+
*/
|
|
661
|
+
value: TEntity extends any[] ? Partial<TEntity[number]> : Partial<TEntity>;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* OptimisticUpdates utility class for type-safe optimistic updates
|
|
665
|
+
*/
|
|
666
|
+
declare class OptimisticUpdates<TQueryKeys extends object = QueryKeys> {
|
|
667
|
+
private readonly queryClient;
|
|
668
|
+
constructor(queryClient: QueryClient);
|
|
669
|
+
/**
|
|
670
|
+
* Extract the raw entity from AsyncResult data
|
|
671
|
+
*/
|
|
672
|
+
private extractEntityFromAsyncResult;
|
|
673
|
+
private isInfiniteDataLike;
|
|
674
|
+
/**
|
|
675
|
+
* Determine if an item should be updated
|
|
676
|
+
*/
|
|
677
|
+
private shouldUpdateItem;
|
|
678
|
+
/**
|
|
679
|
+
* Internal method to update entity based on the "by" option
|
|
680
|
+
*/
|
|
681
|
+
private updateEntity;
|
|
682
|
+
/**
|
|
683
|
+
* Wrap a raw entity in an AsyncResult (preserving ok state)
|
|
684
|
+
*/
|
|
685
|
+
private wrapEntityInAsyncResult;
|
|
686
|
+
/**
|
|
687
|
+
* Get raw entity data from the query cache
|
|
688
|
+
* Automatically extracts the entity from AsyncResult wrapper
|
|
689
|
+
*
|
|
690
|
+
* When using just a key string:
|
|
691
|
+
* - By default (isExact=false), returns ALL queries with that key as first element
|
|
692
|
+
* - With isExact=true, returns only the query stored as [key]
|
|
693
|
+
*
|
|
694
|
+
* @example
|
|
695
|
+
* ```typescript
|
|
696
|
+
* // Get all userDetail queries (returns array)
|
|
697
|
+
* const allUsers = optimisticUpdates.get('userDetail')
|
|
698
|
+
*
|
|
699
|
+
* // Get exact query stored as ['userDetail']
|
|
700
|
+
* const exactUser = optimisticUpdates.get('userDetail', { isExact: true })
|
|
701
|
+
*
|
|
702
|
+
* // Get specific userDetail query with params
|
|
703
|
+
* const user = optimisticUpdates.get(['userDetail', { userUuid: '123' }] as const)
|
|
704
|
+
* ```
|
|
705
|
+
*/
|
|
706
|
+
get<TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>>(queryKey: TKey$1, options?: {
|
|
707
|
+
isExact?: false;
|
|
708
|
+
}): QueryKeyEntityFromConfig<TQueryKeys, TKey$1>[];
|
|
709
|
+
get<TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>>(queryKey: TKey$1, options: {
|
|
710
|
+
isExact: true;
|
|
711
|
+
}): QueryKeyEntityFromConfig<TQueryKeys, TKey$1> | null;
|
|
712
|
+
get<TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>>(queryKey: readonly [TKey$1, Partial<QueryKeyRawParamsFromConfig<TQueryKeys, TKey$1>>]): QueryKeyEntityFromConfig<TQueryKeys, TKey$1> | null;
|
|
713
|
+
/**
|
|
714
|
+
* Invalidate queries to trigger a refetch
|
|
715
|
+
*
|
|
716
|
+
* When using just the key, invalidates ALL queries with that key
|
|
717
|
+
* When using key + params tuple, invalidates SPECIFIC query
|
|
718
|
+
*
|
|
719
|
+
* @example
|
|
720
|
+
* ```typescript
|
|
721
|
+
* // Invalidate all userDetail queries
|
|
722
|
+
* await optimisticUpdates.invalidate('userDetail')
|
|
723
|
+
*
|
|
724
|
+
* // Invalidate specific query
|
|
725
|
+
* await optimisticUpdates.invalidate(['userDetail', { userUuid: '123' }] as const)
|
|
726
|
+
* ```
|
|
727
|
+
*/
|
|
728
|
+
invalidate<TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>>(key: TKey$1): Promise<void>;
|
|
729
|
+
invalidate<TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>>(keyTuple: readonly [TKey$1, Partial<QueryKeyRawParamsFromConfig<TQueryKeys, TKey$1>>]): Promise<void>;
|
|
730
|
+
/**
|
|
731
|
+
* Set raw entity data in the query cache for a specific query
|
|
732
|
+
* Automatically wraps the entity in AsyncResult
|
|
733
|
+
*
|
|
734
|
+
* Both formats set a single query - just with different key representations:
|
|
735
|
+
* - 'userDetail' sets the query with key ['userDetail']
|
|
736
|
+
* - ['userDetail', { userUuid: '123' }] sets the query with that exact key
|
|
737
|
+
*
|
|
738
|
+
* @example
|
|
739
|
+
* ```typescript
|
|
740
|
+
* // Set query with just the key
|
|
741
|
+
* optimisticUpdates.set('userDetail', userData)
|
|
742
|
+
*
|
|
743
|
+
* // Set query with key + params
|
|
744
|
+
* optimisticUpdates.set(['userDetail', { userUuid: '123' }] as const, userData)
|
|
745
|
+
* ```
|
|
746
|
+
*/
|
|
747
|
+
set<TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>>(queryKey: TKey$1, entity: QueryKeyEntityFromConfig<TQueryKeys, TKey$1>): void;
|
|
748
|
+
set<TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>>(queryKey: readonly [TKey$1, Partial<QueryKeyRawParamsFromConfig<TQueryKeys, TKey$1>>], entity: QueryKeyEntityFromConfig<TQueryKeys, TKey$1>): void;
|
|
749
|
+
/**
|
|
750
|
+
* Update entity data in the query cache optimistically
|
|
751
|
+
*
|
|
752
|
+
* When using just the key, updates ALL queries with that key
|
|
753
|
+
* When using key + params tuple, updates SPECIFIC query
|
|
754
|
+
*
|
|
755
|
+
* @example
|
|
756
|
+
* ```typescript
|
|
757
|
+
* // Update all userDetail queries by id
|
|
758
|
+
* optimisticUpdates.update('userDetail', {
|
|
759
|
+
* value: { id: '123', name: 'John Doe' }
|
|
760
|
+
* })
|
|
761
|
+
*
|
|
762
|
+
* // Update specific query by key + params
|
|
763
|
+
* optimisticUpdates.update(['userDetail', { userUuid: '123' }] as const, {
|
|
764
|
+
* value: { name: 'John Doe' }
|
|
765
|
+
* })
|
|
766
|
+
*
|
|
767
|
+
* // Update using predicates
|
|
768
|
+
* optimisticUpdates.update('userList', {
|
|
769
|
+
* value: { isActive: false },
|
|
770
|
+
* by: (user) => user.email === 'john@example.com'
|
|
771
|
+
* })
|
|
772
|
+
* ```
|
|
773
|
+
*/
|
|
774
|
+
update<TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>, TEntity extends QueryKeyEntityFromConfig<TQueryKeys, TKey$1> = QueryKeyEntityFromConfig<TQueryKeys, TKey$1>>(key: TKey$1, options: OptimisticUpdateOptions<TEntity>): void;
|
|
775
|
+
update<TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>, TEntity extends QueryKeyEntityFromConfig<TQueryKeys, TKey$1> = QueryKeyEntityFromConfig<TQueryKeys, TKey$1>>(keyTuple: readonly [TKey$1, Partial<QueryKeyRawParamsFromConfig<TQueryKeys, TKey$1>>], options: OptimisticUpdateOptions<TEntity>): void;
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Create an OptimisticUpdates instance
|
|
779
|
+
*/
|
|
780
|
+
declare function createOptimisticUpdates(queryClient: QueryClient): OptimisticUpdates;
|
|
781
|
+
//#endregion
|
|
782
|
+
//#region src/factory/createApiOptimisticUpdatesUtils.d.ts
|
|
783
|
+
interface CreateApiOptimisticUpdatesUtilsReturnType<TQueryKeys extends object> {
|
|
784
|
+
useOptimisticUpdates: () => OptimisticUpdates<TQueryKeys>;
|
|
785
|
+
}
|
|
786
|
+
declare function createApiOptimisticUpdatesUtils<TQueryKeys extends object>(options: CreateApiUtilsOptions): CreateApiOptimisticUpdatesUtilsReturnType<TQueryKeys>;
|
|
787
|
+
//#endregion
|
|
788
|
+
//#region src/factory/createApiPrefetchInfiniteQueryUtils.d.ts
|
|
789
|
+
interface CreateApiPrefetchInfiniteQueryUtilsReturnType<TQueryKeys extends object> {
|
|
790
|
+
usePrefetchKeysetInfiniteQuery: <TKey$1 extends QueryKeysWithArrayEntityFromConfig<TQueryKeys>>(key: TKey$1, queryOptions: ApiUseKeysetInfinitePrefetchQueryOptions<TQueryKeys, TKey$1>) => {
|
|
791
|
+
execute: () => Promise<void>;
|
|
792
|
+
};
|
|
793
|
+
usePrefetchOffsetInfiniteQuery: <TKey$1 extends QueryKeysWithArrayEntityFromConfig<TQueryKeys>>(key: TKey$1, queryOptions: ApiUseOffsetInfinitePrefetchQueryOptions<TQueryKeys, TKey$1>) => {
|
|
794
|
+
execute: () => Promise<void>;
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
declare function createApiPrefetchInfiniteQueryUtils<TQueryKeys extends object>(options: CreateApiUtilsOptions): CreateApiPrefetchInfiniteQueryUtilsReturnType<TQueryKeys>;
|
|
798
|
+
//#endregion
|
|
799
|
+
//#region src/factory/createApiPrefetchQueryUtils.d.ts
|
|
800
|
+
interface CreateApiPrefetchQueryUtilsReturnType<TQueryKeys extends object> {
|
|
801
|
+
usePrefetchQuery: <TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>>(key: TKey$1, queryOptions: ApiUsePrefetchQueryOptions<TQueryKeys, TKey$1>) => {
|
|
802
|
+
execute: () => Promise<void>;
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
declare function createApiPrefetchQueryUtils<TQueryKeys extends object>(options: CreateApiUtilsOptions): CreateApiPrefetchQueryUtilsReturnType<TQueryKeys>;
|
|
806
|
+
//#endregion
|
|
807
|
+
//#region src/factory/createApiQueryUtils.d.ts
|
|
808
|
+
interface CreateApiQueryUtilsReturnType<TQueryKeys extends object> {
|
|
809
|
+
useQuery: <TKey$1 extends QueryKeysWithEntityFromConfig<TQueryKeys>>(key: TKey$1, queryOptions: ApiUseQueryOptions<TQueryKeys, TKey$1>) => UseQueryReturnType<QueryKeyEntityFromConfig<TQueryKeys, TKey$1>>;
|
|
810
|
+
}
|
|
811
|
+
declare function createApiQueryUtils<TQueryKeys extends object>(): CreateApiQueryUtilsReturnType<TQueryKeys>;
|
|
812
|
+
//#endregion
|
|
813
|
+
//#region src/factory/createApiUtils.d.ts
|
|
814
|
+
type CreateApiUtilsReturnType<TQueryKeys extends object> = ReturnType<typeof createApiQueryUtils<TQueryKeys>> & ReturnType<typeof createApiPrefetchQueryUtils<TQueryKeys>> & ReturnType<typeof createApiInfiniteQueryUtils<TQueryKeys>> & ReturnType<typeof createApiPrefetchInfiniteQueryUtils<TQueryKeys>> & ReturnType<typeof createApiMutationUtils<TQueryKeys>> & ReturnType<typeof createApiOptimisticUpdatesUtils<TQueryKeys>>;
|
|
815
|
+
/**
|
|
816
|
+
* Factory that creates typed composables based on a user-provided query-keys config.
|
|
817
|
+
* This is an alternative to module augmentation of `QueryKeys`.
|
|
818
|
+
*/
|
|
819
|
+
declare function createApiUtils<TQueryKeys extends object>(options: CreateApiUtilsOptions): CreateApiUtilsReturnType<TQueryKeys>;
|
|
820
|
+
//#endregion
|
|
821
|
+
export { ApiError, ApiErrorCode, ApiErrorCodes, ApiErrorObject, ApiExpectedError, ApiKnownErrorObject, ApiResult, ApiUnexpectedError, ApiUnknownErrorObject, ApiUseKeysetInfinitePrefetchQueryOptions, ApiUseKeysetInfiniteQueryOptions, ApiUseMutationOptions, ApiUseOffsetInfinitePrefetchQueryOptions, ApiUseOffsetInfiniteQueryOptions, ApiUsePrefetchQueryOptions, ApiUseQueryOptions, AsyncResult, AsyncResultErr, AsyncResultLoading, AsyncResultOk, type CreateApiInfiniteQueryUtilsReturnType, type CreateApiMutationUtilsReturnType, type CreateApiOptimisticUpdatesUtilsReturnType, type CreateApiPrefetchInfiniteQueryUtilsReturnType, type CreateApiPrefetchQueryUtilsReturnType, type CreateApiQueryUtilsReturnType, type CreateApiUtilsOptions, CreateApiUtilsReturnType, HasEntity, InfiniteQueryOptions, KeysetInfiniteQueryOptions, KeysetPagination, KeysetPaginationParams, KeysetPaginationResponse, KeysetPaginationResult, OffsetInfiniteQueryOptions, OffsetPagination, OffsetPaginationParams, OffsetPaginationResponse, OffsetPaginationResult, OptimisticUpdateOptions, OptimisticUpdates, PaginatedDataDto, type QueryConfig, QueryKeyArrayItemFromConfig, QueryKeyEntity, QueryKeyEntityFromConfig, QueryKeyParams, QueryKeyParamsFromConfig, QueryKeyRawParamsFromConfig, QueryKeys, QueryKeysWithArrayEntityFromConfig, QueryKeysWithEntity, QueryKeysWithEntityFromConfig, QueryParams, Sort, SortDirection, UseMutationReturnType, UseQueryOptions, UseQueryReturnType, WithFilterQuery, WithSearchQuery, WithSortQuery, createApiInfiniteQueryUtils, createApiMutationUtils, createApiOptimisticUpdatesUtils, createApiPrefetchInfiniteQueryUtils, createApiPrefetchQueryUtils, createApiQueryUtils, createApiUtils, createOptimisticUpdates, setQueryConfig, useKeysetInfiniteQuery, useMutation, useOffsetInfiniteQuery, usePrefetchQuery, useQuery };
|
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,162 @@
|
|
|
1
|
-
import { useInfiniteQuery, useMutation as useMutation$1, useQuery as useQuery$1, useQueryClient } from "@tanstack/vue-query";
|
|
2
|
-
import { computed } from "vue";
|
|
3
1
|
import { err, ok } from "neverthrow";
|
|
2
|
+
import { useInfiniteQuery, useMutation as useMutation$1, useQuery as useQuery$1, useQueryClient } from "@tanstack/vue-query";
|
|
3
|
+
import { computed, unref } from "vue";
|
|
4
|
+
|
|
5
|
+
//#region src/async-result/asyncResult.ts
|
|
6
|
+
/**
|
|
7
|
+
* Base class for AsyncResult - internal use only.
|
|
8
|
+
* Use AsyncResult<T, E> as the public type.
|
|
9
|
+
*/
|
|
10
|
+
var AsyncResultBase = class {
|
|
11
|
+
_error;
|
|
12
|
+
_status;
|
|
13
|
+
_value;
|
|
14
|
+
constructor(status, value, error) {
|
|
15
|
+
this._status = status;
|
|
16
|
+
this._value = value;
|
|
17
|
+
this._error = error;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check if the result is an error (type predicate for narrowing)
|
|
21
|
+
*/
|
|
22
|
+
isErr() {
|
|
23
|
+
return this._status === "err";
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check if the result is in loading state (type predicate for narrowing)
|
|
27
|
+
*/
|
|
28
|
+
isLoading() {
|
|
29
|
+
return this._status === "loading";
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if the result is a success (type predicate for narrowing)
|
|
33
|
+
*/
|
|
34
|
+
isOk() {
|
|
35
|
+
return this._status === "ok";
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Map the success value to a new value
|
|
39
|
+
*/
|
|
40
|
+
map(fn) {
|
|
41
|
+
if (this._status === "loading") return AsyncResult.loading();
|
|
42
|
+
if (this._status === "ok") return AsyncResult.ok(fn(this._value));
|
|
43
|
+
return AsyncResult.err(this._error);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Map the error to a new error
|
|
47
|
+
*/
|
|
48
|
+
mapErr(fn) {
|
|
49
|
+
if (this._status === "loading") return AsyncResult.loading();
|
|
50
|
+
if (this._status === "err") return AsyncResult.err(fn(this._error));
|
|
51
|
+
return AsyncResult.ok(this._value);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Pattern match on all three states
|
|
55
|
+
*/
|
|
56
|
+
match(handlers) {
|
|
57
|
+
if (this._status === "loading") return handlers.loading();
|
|
58
|
+
if (this._status === "ok") return handlers.ok(this._value);
|
|
59
|
+
return handlers.err(this._error);
|
|
60
|
+
}
|
|
61
|
+
unwrapOr(defaultValue) {
|
|
62
|
+
if (this._status === "ok") return this._value;
|
|
63
|
+
return defaultValue;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* AsyncResult representing an error state
|
|
68
|
+
*/
|
|
69
|
+
var AsyncResultErr = class AsyncResultErr extends AsyncResultBase {
|
|
70
|
+
constructor(error) {
|
|
71
|
+
super("err", void 0, error);
|
|
72
|
+
}
|
|
73
|
+
/** @internal */
|
|
74
|
+
static _create(error) {
|
|
75
|
+
return new AsyncResultErr(error);
|
|
76
|
+
}
|
|
77
|
+
/** Get the error value - only available after isErr() check */
|
|
78
|
+
getError() {
|
|
79
|
+
return this._error;
|
|
80
|
+
}
|
|
81
|
+
getResult() {
|
|
82
|
+
return err(this._error);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* AsyncResult representing a loading state
|
|
87
|
+
*/
|
|
88
|
+
var AsyncResultLoading = class AsyncResultLoading extends AsyncResultBase {
|
|
89
|
+
constructor() {
|
|
90
|
+
super("loading");
|
|
91
|
+
}
|
|
92
|
+
/** @internal */
|
|
93
|
+
static _create() {
|
|
94
|
+
return new AsyncResultLoading();
|
|
95
|
+
}
|
|
96
|
+
getResult() {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* AsyncResult representing a success state
|
|
102
|
+
*/
|
|
103
|
+
var AsyncResultOk = class AsyncResultOk extends AsyncResultBase {
|
|
104
|
+
constructor(value) {
|
|
105
|
+
super("ok", value);
|
|
106
|
+
}
|
|
107
|
+
/** @internal */
|
|
108
|
+
static _create(value) {
|
|
109
|
+
return new AsyncResultOk(value);
|
|
110
|
+
}
|
|
111
|
+
getResult() {
|
|
112
|
+
return ok(this._value);
|
|
113
|
+
}
|
|
114
|
+
/** Get the success value - only available after isOk() check */
|
|
115
|
+
getValue() {
|
|
116
|
+
return this._value;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Static factory methods for creating AsyncResult instances.
|
|
121
|
+
* This pattern (same name for type and value) is intentional for ergonomic API.
|
|
122
|
+
*/
|
|
123
|
+
const AsyncResult = {
|
|
124
|
+
err(error) {
|
|
125
|
+
return AsyncResultErr._create(error);
|
|
126
|
+
},
|
|
127
|
+
fromResult(result) {
|
|
128
|
+
if (result.isOk()) return AsyncResult.ok(result.value);
|
|
129
|
+
return AsyncResult.err(result.error);
|
|
130
|
+
},
|
|
131
|
+
loading() {
|
|
132
|
+
return AsyncResultLoading._create();
|
|
133
|
+
},
|
|
134
|
+
ok(value) {
|
|
135
|
+
return AsyncResultOk._create(value);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
4
138
|
|
|
139
|
+
//#endregion
|
|
5
140
|
//#region src/composables/mutation/mutation.composable.ts
|
|
6
141
|
function useMutation(options) {
|
|
7
142
|
const isDebug = options.isDebug ?? false;
|
|
8
143
|
const queryClient = useQueryClient();
|
|
9
144
|
async function onSuccess(responseData, params) {
|
|
145
|
+
if (!options.queryKeysToInvalidate) return;
|
|
10
146
|
await Promise.all(Object.entries(options.queryKeysToInvalidate).map(async ([queryKey, queryKeyParams]) => {
|
|
147
|
+
if (!queryKeyParams) {
|
|
148
|
+
if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`);
|
|
149
|
+
await queryClient.invalidateQueries({ queryKey: [queryKey] });
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
11
152
|
const qkp = queryKeyParams;
|
|
12
|
-
const
|
|
153
|
+
const paramEntries = Object.entries(qkp);
|
|
154
|
+
if (paramEntries.length === 0) {
|
|
155
|
+
if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`);
|
|
156
|
+
await queryClient.invalidateQueries({ queryKey: [queryKey] });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const paramsWithValues = paramEntries.reduce((acc, [key, value]) => {
|
|
13
160
|
acc[key] = value(params, responseData);
|
|
14
161
|
return acc;
|
|
15
162
|
}, {});
|
|
@@ -22,7 +169,9 @@ function useMutation(options) {
|
|
|
22
169
|
}
|
|
23
170
|
const mutation = useMutation$1({
|
|
24
171
|
mutationFn: options.queryFn,
|
|
25
|
-
onSuccess: async (
|
|
172
|
+
onSuccess: async (result$1, variables) => {
|
|
173
|
+
if (!result$1.isOk()) return;
|
|
174
|
+
const data = result$1.value;
|
|
26
175
|
if (variables !== void 0 && "params" in variables) {
|
|
27
176
|
await onSuccess(data, variables.params);
|
|
28
177
|
return;
|
|
@@ -33,20 +182,34 @@ function useMutation(options) {
|
|
|
33
182
|
async function execute(data) {
|
|
34
183
|
return await mutation.mutateAsync(data);
|
|
35
184
|
}
|
|
185
|
+
const result = computed(() => {
|
|
186
|
+
if (mutation.isPending.value) return AsyncResult.loading();
|
|
187
|
+
if (mutation.isError.value && mutation.error.value) return AsyncResult.err(mutation.error.value);
|
|
188
|
+
if (mutation.isSuccess.value && mutation.data.value !== void 0) {
|
|
189
|
+
const apiResult = mutation.data.value;
|
|
190
|
+
if (apiResult.isOk()) return AsyncResult.ok(apiResult.value);
|
|
191
|
+
if (apiResult.isErr()) return AsyncResult.err(apiResult.error);
|
|
192
|
+
}
|
|
193
|
+
return AsyncResult.loading();
|
|
194
|
+
});
|
|
36
195
|
return {
|
|
37
196
|
isLoading: computed(() => mutation.isPending.value),
|
|
38
|
-
data: computed(() =>
|
|
39
|
-
|
|
197
|
+
data: computed(() => {
|
|
198
|
+
if (mutation.data.value?.isOk()) return mutation.data.value.value;
|
|
199
|
+
return null;
|
|
200
|
+
}),
|
|
201
|
+
execute,
|
|
202
|
+
result
|
|
40
203
|
};
|
|
41
204
|
}
|
|
42
205
|
|
|
43
206
|
//#endregion
|
|
44
207
|
//#region src/config/config.ts
|
|
45
|
-
const DEFAULT_LIMIT$
|
|
208
|
+
const DEFAULT_LIMIT$3 = 20;
|
|
46
209
|
const DEFAULT_PREFETCH_STALE_TIME = 60;
|
|
47
210
|
const QUERY_CONFIG = {
|
|
48
211
|
prefetchStaleTime: DEFAULT_PREFETCH_STALE_TIME,
|
|
49
|
-
limit: DEFAULT_LIMIT$
|
|
212
|
+
limit: DEFAULT_LIMIT$3
|
|
50
213
|
};
|
|
51
214
|
function setQueryConfig(config) {
|
|
52
215
|
if (config.limit != null && config.limit > 0) QUERY_CONFIG.limit = config.limit;
|
|
@@ -55,7 +218,7 @@ function setQueryConfig(config) {
|
|
|
55
218
|
|
|
56
219
|
//#endregion
|
|
57
220
|
//#region src/composables/query/keysetInfiniteQuery.composable.ts
|
|
58
|
-
const DEFAULT_LIMIT$
|
|
221
|
+
const DEFAULT_LIMIT$2 = QUERY_CONFIG.limit;
|
|
59
222
|
function useKeysetInfiniteQuery(options) {
|
|
60
223
|
function getQueryKey() {
|
|
61
224
|
const [queryKey, params] = Object.entries(options.queryKey)[0];
|
|
@@ -72,7 +235,7 @@ function useKeysetInfiniteQuery(options) {
|
|
|
72
235
|
placeholderData: (data) => data,
|
|
73
236
|
queryFn: ({ pageParam }) => options.queryFn({
|
|
74
237
|
key: pageParam,
|
|
75
|
-
limit: options.limit ?? DEFAULT_LIMIT$
|
|
238
|
+
limit: options.limit ?? DEFAULT_LIMIT$2
|
|
76
239
|
}),
|
|
77
240
|
queryKey: getQueryKey()
|
|
78
241
|
});
|
|
@@ -80,18 +243,17 @@ function useKeysetInfiniteQuery(options) {
|
|
|
80
243
|
return Boolean(infiniteQuery.data.value?.pages.find((page) => page.isErr()));
|
|
81
244
|
});
|
|
82
245
|
const result = computed(() => {
|
|
246
|
+
if (infiniteQuery.isLoading.value) return AsyncResult.loading();
|
|
83
247
|
const firstError = infiniteQuery.data.value?.pages.find((page) => page.isErr());
|
|
84
|
-
if (firstError) return err(firstError.error);
|
|
248
|
+
if (firstError) return AsyncResult.err(firstError.error);
|
|
85
249
|
const data = infiniteQuery.data.value?.pages.filter((page) => page.isOk()).flatMap((page) => page.value.data) ?? [];
|
|
86
250
|
const firstPage = infiniteQuery.data.value?.pages[0];
|
|
87
|
-
const meta = firstPage?.isOk() ? firstPage.value.meta : {
|
|
88
|
-
|
|
89
|
-
total: data.length
|
|
90
|
-
};
|
|
91
|
-
return ok({
|
|
251
|
+
const meta = firstPage?.isOk() ? firstPage.value.meta : { next: null };
|
|
252
|
+
const response = {
|
|
92
253
|
data,
|
|
93
254
|
meta: { next: infiniteQuery.hasNextPage.value ? meta.next : null }
|
|
94
|
-
}
|
|
255
|
+
};
|
|
256
|
+
return AsyncResult.ok(response);
|
|
95
257
|
});
|
|
96
258
|
function fetchNextPage() {
|
|
97
259
|
if (!infiniteQuery.hasNextPage.value || infiniteQuery.isFetchingNextPage.value) return;
|
|
@@ -116,7 +278,7 @@ function useKeysetInfiniteQuery(options) {
|
|
|
116
278
|
|
|
117
279
|
//#endregion
|
|
118
280
|
//#region src/composables/query/offsetInfiniteQuery.composable.ts
|
|
119
|
-
const DEFAULT_LIMIT = QUERY_CONFIG.limit;
|
|
281
|
+
const DEFAULT_LIMIT$1 = QUERY_CONFIG.limit;
|
|
120
282
|
function useOffsetInfiniteQuery(options) {
|
|
121
283
|
function getQueryKey() {
|
|
122
284
|
const [first] = Object.entries(options.queryKey);
|
|
@@ -136,7 +298,7 @@ function useOffsetInfiniteQuery(options) {
|
|
|
136
298
|
initialPageParam: 0,
|
|
137
299
|
placeholderData: (data) => data,
|
|
138
300
|
queryFn: ({ pageParam }) => options.queryFn({
|
|
139
|
-
limit: options.limit ?? DEFAULT_LIMIT,
|
|
301
|
+
limit: options.limit ?? DEFAULT_LIMIT$1,
|
|
140
302
|
offset: pageParam ?? 0
|
|
141
303
|
}),
|
|
142
304
|
queryKey: getQueryKey()
|
|
@@ -145,19 +307,21 @@ function useOffsetInfiniteQuery(options) {
|
|
|
145
307
|
return Boolean(infiniteQuery.data.value?.pages.find((page) => page.isErr()));
|
|
146
308
|
});
|
|
147
309
|
const result = computed(() => {
|
|
310
|
+
if (infiniteQuery.isLoading.value) return AsyncResult.loading();
|
|
148
311
|
const firstError = infiniteQuery.data.value?.pages.find((page) => page.isErr());
|
|
149
|
-
if (firstError) return err(firstError.error);
|
|
312
|
+
if (firstError) return AsyncResult.err(firstError.error);
|
|
150
313
|
const data = infiniteQuery.data.value?.pages.filter((page) => page.isOk()).flatMap((page) => page.value.data) ?? [];
|
|
151
314
|
const firstPage = infiniteQuery.data.value?.pages[0];
|
|
152
315
|
const meta = firstPage?.isOk() ? firstPage.value.meta : null;
|
|
153
|
-
|
|
316
|
+
const response = {
|
|
154
317
|
data,
|
|
155
318
|
meta: {
|
|
156
319
|
limit: meta?.limit ?? 0,
|
|
157
320
|
offset: meta?.offset ?? 0,
|
|
158
321
|
total: meta?.total ?? data.length
|
|
159
322
|
}
|
|
160
|
-
}
|
|
323
|
+
};
|
|
324
|
+
return AsyncResult.ok(response);
|
|
161
325
|
});
|
|
162
326
|
function fetchNextPage() {
|
|
163
327
|
if (!infiniteQuery.hasNextPage.value || infiniteQuery.isFetchingNextPage.value) return;
|
|
@@ -208,7 +372,9 @@ function useQuery(options) {
|
|
|
208
372
|
staleTime: options.staleTime,
|
|
209
373
|
enabled: options.isEnabled,
|
|
210
374
|
placeholderData: (data) => data,
|
|
211
|
-
queryFn:
|
|
375
|
+
queryFn: async () => {
|
|
376
|
+
return AsyncResult.fromResult(await options.queryFn());
|
|
377
|
+
},
|
|
212
378
|
queryKey: getQueryKey()
|
|
213
379
|
});
|
|
214
380
|
function getQueryKey() {
|
|
@@ -225,9 +391,319 @@ function useQuery(options) {
|
|
|
225
391
|
isLoading: computed(() => query.isLoading.value),
|
|
226
392
|
isSuccess: computed(() => query.data.value?.isOk() ?? false),
|
|
227
393
|
refetch,
|
|
228
|
-
result: computed(() =>
|
|
394
|
+
result: computed(() => {
|
|
395
|
+
if (query.isLoading.value) return AsyncResult.loading();
|
|
396
|
+
if (query.data.value?.isOk()) return AsyncResult.ok(query.data.value.getValue());
|
|
397
|
+
if (query.data.value?.isErr()) return AsyncResult.err(query.data.value.getError());
|
|
398
|
+
return AsyncResult.loading();
|
|
399
|
+
})
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
//#endregion
|
|
404
|
+
//#region src/factory/createApiInfiniteQueryUtils.ts
|
|
405
|
+
function createApiInfiniteQueryUtils() {
|
|
406
|
+
function useOffsetInfiniteQuery$1(key, queryOptions) {
|
|
407
|
+
const params = queryOptions.params ?? {};
|
|
408
|
+
const queryKey = { [key]: params };
|
|
409
|
+
return useOffsetInfiniteQuery({
|
|
410
|
+
staleTime: queryOptions.staleTime,
|
|
411
|
+
isEnabled: queryOptions.isEnabled,
|
|
412
|
+
limit: queryOptions.limit,
|
|
413
|
+
queryFn: queryOptions.queryFn,
|
|
414
|
+
queryKey
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
function useKeysetInfiniteQuery$1(key, queryOptions) {
|
|
418
|
+
const params = queryOptions.params ?? {};
|
|
419
|
+
const queryKey = { [key]: params };
|
|
420
|
+
return useKeysetInfiniteQuery({
|
|
421
|
+
staleTime: queryOptions.staleTime,
|
|
422
|
+
isEnabled: queryOptions.isEnabled,
|
|
423
|
+
limit: queryOptions.limit,
|
|
424
|
+
queryFn: queryOptions.queryFn,
|
|
425
|
+
queryKey
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
useKeysetInfiniteQuery: useKeysetInfiniteQuery$1,
|
|
430
|
+
useOffsetInfiniteQuery: useOffsetInfiniteQuery$1
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
//#endregion
|
|
435
|
+
//#region src/factory/createApiMutationUtils.ts
|
|
436
|
+
function createApiMutationUtils() {
|
|
437
|
+
function useMutation$2(options) {
|
|
438
|
+
return useMutation({
|
|
439
|
+
isDebug: options.isDebug,
|
|
440
|
+
queryFn: options.queryFn,
|
|
441
|
+
queryKeysToInvalidate: options.queryKeysToInvalidate ?? {}
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
return { useMutation: useMutation$2 };
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
//#endregion
|
|
448
|
+
//#region src/utils/optimisticUpdates.ts
|
|
449
|
+
/**
|
|
450
|
+
* OptimisticUpdates utility class for type-safe optimistic updates
|
|
451
|
+
*/
|
|
452
|
+
var OptimisticUpdates = class {
|
|
453
|
+
constructor(queryClient) {
|
|
454
|
+
this.queryClient = queryClient;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Extract the raw entity from AsyncResult data
|
|
458
|
+
*/
|
|
459
|
+
extractEntityFromAsyncResult(data) {
|
|
460
|
+
if (data === void 0 || data === null) return null;
|
|
461
|
+
if (typeof data === "object" && "isOk" in data) {
|
|
462
|
+
const asyncResult = data;
|
|
463
|
+
if (asyncResult.isOk()) return asyncResult.getValue();
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
return data;
|
|
467
|
+
}
|
|
468
|
+
isInfiniteDataLike(data) {
|
|
469
|
+
return Boolean(data && typeof data === "object" && "pages" in data && Array.isArray(data.pages));
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Determine if an item should be updated
|
|
473
|
+
*/
|
|
474
|
+
shouldUpdateItem(by, item, value) {
|
|
475
|
+
if (typeof by === "function") return by(item);
|
|
476
|
+
if (by && typeof by === "object") return Object.entries(by).every(([key, matchValue]) => {
|
|
477
|
+
const itemValue = item[key];
|
|
478
|
+
return unref(itemValue) === unref(matchValue);
|
|
479
|
+
});
|
|
480
|
+
const idFromValue = value.id;
|
|
481
|
+
const itemId = item["id"];
|
|
482
|
+
if (idFromValue !== void 0 && itemId !== void 0) return unref(itemId) === unref(idFromValue);
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Internal method to update entity based on the "by" option
|
|
487
|
+
*/
|
|
488
|
+
updateEntity(by, currentData, value) {
|
|
489
|
+
if (Array.isArray(currentData)) return currentData.map((item) => {
|
|
490
|
+
return this.shouldUpdateItem(by, item, value) ? {
|
|
491
|
+
...item,
|
|
492
|
+
...value
|
|
493
|
+
} : item;
|
|
494
|
+
});
|
|
495
|
+
if (this.shouldUpdateItem(by, currentData, value)) return {
|
|
496
|
+
...currentData,
|
|
497
|
+
...value
|
|
498
|
+
};
|
|
499
|
+
return currentData;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Wrap a raw entity in an AsyncResult (preserving ok state)
|
|
503
|
+
*/
|
|
504
|
+
wrapEntityInAsyncResult(entity) {
|
|
505
|
+
return AsyncResult.ok(entity);
|
|
506
|
+
}
|
|
507
|
+
get(queryKey, options) {
|
|
508
|
+
if (Array.isArray(queryKey)) {
|
|
509
|
+
const data = this.queryClient.getQueryData(queryKey);
|
|
510
|
+
return this.extractEntityFromAsyncResult(data);
|
|
511
|
+
}
|
|
512
|
+
if (options?.isExact ?? false) {
|
|
513
|
+
const normalizedKey = [queryKey];
|
|
514
|
+
const data = this.queryClient.getQueryData(normalizedKey);
|
|
515
|
+
return this.extractEntityFromAsyncResult(data);
|
|
516
|
+
}
|
|
517
|
+
const allQueries = this.queryClient.getQueryCache().findAll({ predicate: (query) => {
|
|
518
|
+
return query.queryKey[0] === queryKey;
|
|
519
|
+
} });
|
|
520
|
+
const results = [];
|
|
521
|
+
for (const query of allQueries) {
|
|
522
|
+
const data = query.state.data;
|
|
523
|
+
const entity = this.extractEntityFromAsyncResult(data);
|
|
524
|
+
if (entity !== null) results.push(entity);
|
|
525
|
+
}
|
|
526
|
+
return results;
|
|
527
|
+
}
|
|
528
|
+
async invalidate(keyOrTuple) {
|
|
529
|
+
const isSpecific = Array.isArray(keyOrTuple);
|
|
530
|
+
const key = isSpecific ? keyOrTuple[0] : keyOrTuple;
|
|
531
|
+
const params = isSpecific ? keyOrTuple[1] : null;
|
|
532
|
+
await this.queryClient.invalidateQueries({ predicate: (query) => {
|
|
533
|
+
const queryKey = query.queryKey;
|
|
534
|
+
if (queryKey[0] !== key) return false;
|
|
535
|
+
if (isSpecific && params && queryKey[1]) return Object.entries(params).every(([paramKey, paramValue]) => {
|
|
536
|
+
return queryKey[1][paramKey] === paramValue;
|
|
537
|
+
});
|
|
538
|
+
return !isSpecific;
|
|
539
|
+
} });
|
|
540
|
+
}
|
|
541
|
+
set(queryKey, entity) {
|
|
542
|
+
const wrappedData = this.wrapEntityInAsyncResult(entity);
|
|
543
|
+
const normalizedKey = Array.isArray(queryKey) ? queryKey : [queryKey];
|
|
544
|
+
this.queryClient.setQueryData(normalizedKey, wrappedData);
|
|
545
|
+
}
|
|
546
|
+
update(keyOrTuple, options) {
|
|
547
|
+
const by = options.by ?? void 0;
|
|
548
|
+
const value = options.value;
|
|
549
|
+
const isSpecific = Array.isArray(keyOrTuple);
|
|
550
|
+
const key = isSpecific ? keyOrTuple[0] : keyOrTuple;
|
|
551
|
+
const params = isSpecific ? keyOrTuple[1] : null;
|
|
552
|
+
const queries = this.queryClient.getQueryCache().findAll({ predicate: (query) => {
|
|
553
|
+
const queryKey = query.queryKey;
|
|
554
|
+
if (queryKey[0] !== key) return false;
|
|
555
|
+
if (isSpecific && params && queryKey[1]) return Object.entries(params).every(([paramKey, paramValue]) => {
|
|
556
|
+
return queryKey[1][paramKey] === paramValue;
|
|
557
|
+
});
|
|
558
|
+
return !isSpecific;
|
|
559
|
+
} });
|
|
560
|
+
for (const query of queries) {
|
|
561
|
+
const currentData = query.state.data;
|
|
562
|
+
if (this.isInfiniteDataLike(currentData)) {
|
|
563
|
+
const updatedInfiniteData = {
|
|
564
|
+
...currentData,
|
|
565
|
+
pages: currentData.pages.map((page) => {
|
|
566
|
+
if (page && typeof page === "object" && "map" in page && typeof page.map === "function") return page.map((pageValue) => {
|
|
567
|
+
if (pageValue && typeof pageValue === "object" && Array.isArray(pageValue.data)) return {
|
|
568
|
+
...pageValue,
|
|
569
|
+
data: this.updateEntity(by, pageValue.data, value)
|
|
570
|
+
};
|
|
571
|
+
return pageValue;
|
|
572
|
+
});
|
|
573
|
+
return page;
|
|
574
|
+
})
|
|
575
|
+
};
|
|
576
|
+
this.queryClient.setQueryData(query.queryKey, updatedInfiniteData);
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
const rawEntity = this.extractEntityFromAsyncResult(currentData);
|
|
580
|
+
if (rawEntity === null) continue;
|
|
581
|
+
const updatedEntity = this.updateEntity(by, rawEntity, value);
|
|
582
|
+
const wrappedData = this.wrapEntityInAsyncResult(updatedEntity);
|
|
583
|
+
this.queryClient.setQueryData(query.queryKey, wrappedData);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
/**
|
|
588
|
+
* Create an OptimisticUpdates instance
|
|
589
|
+
*/
|
|
590
|
+
function createOptimisticUpdates(queryClient) {
|
|
591
|
+
return new OptimisticUpdates(queryClient);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
//#endregion
|
|
595
|
+
//#region src/factory/createApiOptimisticUpdatesUtils.ts
|
|
596
|
+
function createApiOptimisticUpdatesUtils(options) {
|
|
597
|
+
function useOptimisticUpdates() {
|
|
598
|
+
return new OptimisticUpdates(options.queryClient);
|
|
599
|
+
}
|
|
600
|
+
return { useOptimisticUpdates };
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
//#endregion
|
|
604
|
+
//#region src/factory/createApiPrefetchInfiniteQueryUtils.ts
|
|
605
|
+
const DEFAULT_LIMIT = QUERY_CONFIG.limit;
|
|
606
|
+
function createApiPrefetchInfiniteQueryUtils(options) {
|
|
607
|
+
function usePrefetchOffsetInfiniteQuery(key, queryOptions) {
|
|
608
|
+
const queryKey = [key, queryOptions.params ?? {}];
|
|
609
|
+
async function execute() {
|
|
610
|
+
await options.queryClient.prefetchInfiniteQuery({
|
|
611
|
+
staleTime: queryOptions.staleTime,
|
|
612
|
+
getNextPageParam: (lastPage) => {
|
|
613
|
+
if (lastPage.isErr()) return null;
|
|
614
|
+
const total = lastPage.value.meta.offset + lastPage.value.meta.limit;
|
|
615
|
+
if (total >= lastPage.value.meta.total) return null;
|
|
616
|
+
return total;
|
|
617
|
+
},
|
|
618
|
+
initialPageParam: 0,
|
|
619
|
+
queryFn: ({ pageParam }) => queryOptions.queryFn({
|
|
620
|
+
limit: queryOptions.limit ?? DEFAULT_LIMIT,
|
|
621
|
+
offset: pageParam ?? 0
|
|
622
|
+
}),
|
|
623
|
+
queryKey
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
return { execute };
|
|
627
|
+
}
|
|
628
|
+
function usePrefetchKeysetInfiniteQuery(key, queryOptions) {
|
|
629
|
+
const queryKey = [key, queryOptions.params ?? {}];
|
|
630
|
+
async function execute() {
|
|
631
|
+
await options.queryClient.prefetchInfiniteQuery({
|
|
632
|
+
staleTime: queryOptions.staleTime,
|
|
633
|
+
getNextPageParam: (lastPage) => {
|
|
634
|
+
if (lastPage.isErr()) return null;
|
|
635
|
+
const next = lastPage.value.meta.next;
|
|
636
|
+
if (next === null || next === void 0) return null;
|
|
637
|
+
return next;
|
|
638
|
+
},
|
|
639
|
+
initialPageParam: void 0,
|
|
640
|
+
queryFn: ({ pageParam }) => queryOptions.queryFn({
|
|
641
|
+
key: pageParam,
|
|
642
|
+
limit: queryOptions.limit ?? DEFAULT_LIMIT
|
|
643
|
+
}),
|
|
644
|
+
queryKey
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
return { execute };
|
|
648
|
+
}
|
|
649
|
+
return {
|
|
650
|
+
usePrefetchKeysetInfiniteQuery,
|
|
651
|
+
usePrefetchOffsetInfiniteQuery
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/factory/createApiPrefetchQueryUtils.ts
|
|
657
|
+
function createApiPrefetchQueryUtils(options) {
|
|
658
|
+
function usePrefetchQuery$1(key, queryOptions) {
|
|
659
|
+
const queryKey = [key, queryOptions.params ?? {}];
|
|
660
|
+
async function execute() {
|
|
661
|
+
await options.queryClient.prefetchQuery({
|
|
662
|
+
staleTime: queryOptions.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
|
|
663
|
+
queryFn: async () => {
|
|
664
|
+
return AsyncResult.fromResult(await queryOptions.queryFn());
|
|
665
|
+
},
|
|
666
|
+
queryKey
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
return { execute };
|
|
670
|
+
}
|
|
671
|
+
return { usePrefetchQuery: usePrefetchQuery$1 };
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
//#endregion
|
|
675
|
+
//#region src/factory/createApiQueryUtils.ts
|
|
676
|
+
function createApiQueryUtils() {
|
|
677
|
+
function useQuery$2(key, queryOptions) {
|
|
678
|
+
const params = queryOptions.params ?? {};
|
|
679
|
+
const queryKey = { [key]: params };
|
|
680
|
+
return useQuery({
|
|
681
|
+
staleTime: queryOptions.staleTime,
|
|
682
|
+
isDebug: queryOptions.isDebug,
|
|
683
|
+
isEnabled: queryOptions.isEnabled,
|
|
684
|
+
queryFn: queryOptions.queryFn,
|
|
685
|
+
queryKey
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
return { useQuery: useQuery$2 };
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
//#endregion
|
|
692
|
+
//#region src/factory/createApiUtils.ts
|
|
693
|
+
/**
|
|
694
|
+
* Factory that creates typed composables based on a user-provided query-keys config.
|
|
695
|
+
* This is an alternative to module augmentation of `QueryKeys`.
|
|
696
|
+
*/
|
|
697
|
+
function createApiUtils(options) {
|
|
698
|
+
return {
|
|
699
|
+
...createApiQueryUtils(),
|
|
700
|
+
...createApiPrefetchQueryUtils(options),
|
|
701
|
+
...createApiPrefetchInfiniteQueryUtils(options),
|
|
702
|
+
...createApiInfiniteQueryUtils(),
|
|
703
|
+
...createApiMutationUtils(),
|
|
704
|
+
...createApiOptimisticUpdatesUtils(options)
|
|
229
705
|
};
|
|
230
706
|
}
|
|
231
707
|
|
|
232
708
|
//#endregion
|
|
233
|
-
export { setQueryConfig, useKeysetInfiniteQuery, useMutation, useOffsetInfiniteQuery, usePrefetchQuery, useQuery };
|
|
709
|
+
export { AsyncResult, AsyncResultErr, AsyncResultLoading, AsyncResultOk, OptimisticUpdates, createApiInfiniteQueryUtils, createApiMutationUtils, createApiOptimisticUpdatesUtils, createApiPrefetchInfiniteQueryUtils, createApiPrefetchQueryUtils, createApiQueryUtils, createApiUtils, createOptimisticUpdates, setQueryConfig, useKeysetInfiniteQuery, useMutation, useOffsetInfiniteQuery, usePrefetchQuery, useQuery };
|