@wisemen/vue-core-api-utils 1.0.0-beta.2 → 1.0.1
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.md +59 -0
- package/dist/index.d.mts +319 -270
- package/dist/index.mjs +316 -261
- package/package.json +11 -5
- package/LICENSE +0 -21
- package/README.md +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { err, ok } from "neverthrow";
|
|
2
|
-
import {
|
|
3
|
-
import { computed
|
|
2
|
+
import { QueryClient as QueryClient$1, VueQueryPlugin, useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
|
|
3
|
+
import { computed } from "vue";
|
|
4
4
|
|
|
5
5
|
//#region src/async-result/asyncResult.ts
|
|
6
6
|
/**
|
|
@@ -135,72 +135,8 @@ const AsyncResult = {
|
|
|
135
135
|
return AsyncResultOk._create(value);
|
|
136
136
|
}
|
|
137
137
|
};
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
//#region src/composables/mutation/mutation.composable.ts
|
|
141
|
-
function useMutation(options) {
|
|
142
|
-
const isDebug = options.isDebug ?? false;
|
|
143
|
-
const queryClient = useQueryClient();
|
|
144
|
-
async function onSuccess(responseData, params) {
|
|
145
|
-
if (!options.queryKeysToInvalidate) return;
|
|
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
|
-
}
|
|
152
|
-
const qkp = queryKeyParams;
|
|
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]) => {
|
|
160
|
-
acc[key] = value(params, responseData);
|
|
161
|
-
return acc;
|
|
162
|
-
}, {});
|
|
163
|
-
if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`, paramsWithValues);
|
|
164
|
-
await queryClient.invalidateQueries({
|
|
165
|
-
exact: false,
|
|
166
|
-
queryKey: [queryKey, paramsWithValues]
|
|
167
|
-
});
|
|
168
|
-
}));
|
|
169
|
-
}
|
|
170
|
-
const mutation = useMutation$1({
|
|
171
|
-
mutationFn: options.queryFn,
|
|
172
|
-
onSuccess: async (result$1, variables) => {
|
|
173
|
-
if (!result$1.isOk()) return;
|
|
174
|
-
const data = result$1.value;
|
|
175
|
-
if (variables !== void 0 && "params" in variables) {
|
|
176
|
-
await onSuccess(data, variables.params);
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
await onSuccess(data, {});
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
async function execute(data) {
|
|
183
|
-
return await mutation.mutateAsync(data);
|
|
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
|
-
});
|
|
195
|
-
return {
|
|
196
|
-
isLoading: computed(() => mutation.isPending.value),
|
|
197
|
-
data: computed(() => {
|
|
198
|
-
if (mutation.data.value?.isOk()) return mutation.data.value.value;
|
|
199
|
-
return null;
|
|
200
|
-
}),
|
|
201
|
-
execute,
|
|
202
|
-
result
|
|
203
|
-
};
|
|
138
|
+
function isAsyncResult(value) {
|
|
139
|
+
return value instanceof AsyncResultErr || value instanceof AsyncResultLoading || value instanceof AsyncResultOk;
|
|
204
140
|
}
|
|
205
141
|
|
|
206
142
|
//#endregion
|
|
@@ -211,6 +147,34 @@ const QUERY_CONFIG = {
|
|
|
211
147
|
prefetchStaleTime: DEFAULT_PREFETCH_STALE_TIME,
|
|
212
148
|
limit: DEFAULT_LIMIT$3
|
|
213
149
|
};
|
|
150
|
+
let globalQueryClient = null;
|
|
151
|
+
/**
|
|
152
|
+
* Initialize the API utilities with a QueryClient.
|
|
153
|
+
* Call this once during app setup (e.g. in a plugin or main.ts).
|
|
154
|
+
*
|
|
155
|
+
* After calling this, `createApiUtils()` can be called without options.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* import { initializeApiUtils } from '@wisemen/vue-core-api-utils'
|
|
160
|
+
*
|
|
161
|
+
* const queryClient = new QueryClient()
|
|
162
|
+
* initializeApiUtils(queryClient)
|
|
163
|
+
*
|
|
164
|
+
* // Then in your api lib:
|
|
165
|
+
* export const { useQuery, useMutation, ... } = createApiUtils<MyQueryKeys>()
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
function initializeApiUtils(queryClient) {
|
|
169
|
+
globalQueryClient = queryClient;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* @internal
|
|
173
|
+
*/
|
|
174
|
+
function getQueryClient() {
|
|
175
|
+
if (globalQueryClient == null) throw new Error("[api-utils] QueryClient not available. Call initializeApiUtils(queryClient) before using createApiUtils().");
|
|
176
|
+
return globalQueryClient;
|
|
177
|
+
}
|
|
214
178
|
function setQueryConfig(config) {
|
|
215
179
|
if (config.limit != null && config.limit > 0) QUERY_CONFIG.limit = config.limit;
|
|
216
180
|
if (config.prefetchStaleTime != null && config.prefetchStaleTime > 0) QUERY_CONFIG.prefetchStaleTime = config.prefetchStaleTime;
|
|
@@ -228,15 +192,17 @@ function useKeysetInfiniteQuery(options) {
|
|
|
228
192
|
staleTime: options.staleTime,
|
|
229
193
|
enabled: options.isEnabled,
|
|
230
194
|
getNextPageParam: (lastPage) => {
|
|
231
|
-
if (lastPage.isErr()) return null;
|
|
232
|
-
return lastPage.
|
|
195
|
+
if (lastPage.isErr() || lastPage.isLoading()) return null;
|
|
196
|
+
return lastPage.getValue().meta.next ?? null;
|
|
233
197
|
},
|
|
234
198
|
initialPageParam: void 0,
|
|
235
199
|
placeholderData: (data) => data,
|
|
236
|
-
queryFn: ({ pageParam }) =>
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
200
|
+
queryFn: async ({ pageParam }) => {
|
|
201
|
+
return AsyncResult.fromResult(await options.queryFn({
|
|
202
|
+
key: pageParam,
|
|
203
|
+
limit: options.limit ?? DEFAULT_LIMIT$2
|
|
204
|
+
}));
|
|
205
|
+
},
|
|
240
206
|
queryKey: getQueryKey()
|
|
241
207
|
});
|
|
242
208
|
const hasError = computed(() => {
|
|
@@ -245,10 +211,10 @@ function useKeysetInfiniteQuery(options) {
|
|
|
245
211
|
const result = computed(() => {
|
|
246
212
|
if (infiniteQuery.isLoading.value) return AsyncResult.loading();
|
|
247
213
|
const firstError = infiniteQuery.data.value?.pages.find((page) => page.isErr());
|
|
248
|
-
if (firstError) return AsyncResult.err(firstError.
|
|
249
|
-
const data = infiniteQuery.data.value?.pages.filter((page) => page.isOk()).flatMap((page) => page.
|
|
214
|
+
if (firstError) return AsyncResult.err(firstError.getError());
|
|
215
|
+
const data = infiniteQuery.data.value?.pages.filter((page) => page.isOk()).flatMap((page) => page.getValue().data) ?? [];
|
|
250
216
|
const firstPage = infiniteQuery.data.value?.pages[0];
|
|
251
|
-
const meta = firstPage?.isOk() ? firstPage.
|
|
217
|
+
const meta = firstPage?.isOk() ? firstPage.getValue().meta : { next: null };
|
|
252
218
|
const response = {
|
|
253
219
|
data,
|
|
254
220
|
meta: { next: infiniteQuery.hasNextPage.value ? meta.next : null }
|
|
@@ -290,17 +256,17 @@ function useOffsetInfiniteQuery(options) {
|
|
|
290
256
|
staleTime: options.staleTime,
|
|
291
257
|
enabled: options.isEnabled,
|
|
292
258
|
getNextPageParam: (lastPage) => {
|
|
293
|
-
if (lastPage.isErr()) return null;
|
|
294
|
-
const total = lastPage.
|
|
295
|
-
if (total >= lastPage.
|
|
259
|
+
if (lastPage.isErr() || lastPage.isLoading()) return null;
|
|
260
|
+
const total = lastPage.getValue().meta.offset + lastPage.getValue().meta.limit;
|
|
261
|
+
if (total >= lastPage.getValue().meta.total) return null;
|
|
296
262
|
return total;
|
|
297
263
|
},
|
|
298
264
|
initialPageParam: 0,
|
|
299
265
|
placeholderData: (data) => data,
|
|
300
|
-
queryFn: ({ pageParam }) => options.queryFn({
|
|
266
|
+
queryFn: async ({ pageParam }) => AsyncResult.fromResult(await options.queryFn({
|
|
301
267
|
limit: options.limit ?? DEFAULT_LIMIT$1,
|
|
302
268
|
offset: pageParam ?? 0
|
|
303
|
-
}),
|
|
269
|
+
})),
|
|
304
270
|
queryKey: getQueryKey()
|
|
305
271
|
});
|
|
306
272
|
const hasError = computed(() => {
|
|
@@ -309,10 +275,10 @@ function useOffsetInfiniteQuery(options) {
|
|
|
309
275
|
const result = computed(() => {
|
|
310
276
|
if (infiniteQuery.isLoading.value) return AsyncResult.loading();
|
|
311
277
|
const firstError = infiniteQuery.data.value?.pages.find((page) => page.isErr());
|
|
312
|
-
if (firstError) return AsyncResult.err(firstError.
|
|
313
|
-
const data = infiniteQuery.data.value?.pages.filter((page) => page.isOk()).flatMap((page) => page.
|
|
278
|
+
if (firstError) return AsyncResult.err(firstError.getError());
|
|
279
|
+
const data = infiniteQuery.data.value?.pages.filter((page) => page.isOk()).flatMap((page) => page.getValue().data) ?? [];
|
|
314
280
|
const firstPage = infiniteQuery.data.value?.pages[0];
|
|
315
|
-
const meta = firstPage?.isOk() ? firstPage.
|
|
281
|
+
const meta = firstPage?.isOk() ? firstPage.getValue().meta : null;
|
|
316
282
|
const response = {
|
|
317
283
|
data,
|
|
318
284
|
meta: {
|
|
@@ -344,62 +310,6 @@ function useOffsetInfiniteQuery(options) {
|
|
|
344
310
|
};
|
|
345
311
|
}
|
|
346
312
|
|
|
347
|
-
//#endregion
|
|
348
|
-
//#region src/composables/query/prefetchQuery.composable.ts
|
|
349
|
-
function usePrefetchQuery(query) {
|
|
350
|
-
const queryClient = useQueryClient();
|
|
351
|
-
function getQueryKey() {
|
|
352
|
-
const [first] = Object.entries(query.queryKey);
|
|
353
|
-
if (!first) return [];
|
|
354
|
-
const [queryKey, params] = first;
|
|
355
|
-
return [queryKey, params];
|
|
356
|
-
}
|
|
357
|
-
async function execute() {
|
|
358
|
-
await queryClient.prefetchQuery({
|
|
359
|
-
staleTime: query.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
|
|
360
|
-
queryFn: query.queryFn,
|
|
361
|
-
queryKey: getQueryKey()
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
return { execute };
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
//#endregion
|
|
368
|
-
//#region src/composables/query/query.composable.ts
|
|
369
|
-
function useQuery(options) {
|
|
370
|
-
const isDebug = options.isDebug ?? false;
|
|
371
|
-
const query = useQuery$1({
|
|
372
|
-
staleTime: options.staleTime,
|
|
373
|
-
enabled: options.isEnabled,
|
|
374
|
-
placeholderData: (data) => data,
|
|
375
|
-
queryFn: async () => {
|
|
376
|
-
return AsyncResult.fromResult(await options.queryFn());
|
|
377
|
-
},
|
|
378
|
-
queryKey: getQueryKey()
|
|
379
|
-
});
|
|
380
|
-
function getQueryKey() {
|
|
381
|
-
const [queryKey, params] = Object.entries(options.queryKey)[0];
|
|
382
|
-
if (isDebug) console.debug(`Create query with key ${queryKey}`, params);
|
|
383
|
-
return [queryKey, params];
|
|
384
|
-
}
|
|
385
|
-
async function refetch() {
|
|
386
|
-
await query.refetch();
|
|
387
|
-
}
|
|
388
|
-
return {
|
|
389
|
-
isError: computed(() => query.data.value?.isErr() ?? false),
|
|
390
|
-
isFetching: computed(() => query.isFetching.value),
|
|
391
|
-
isLoading: computed(() => query.isLoading.value),
|
|
392
|
-
isSuccess: computed(() => query.data.value?.isOk() ?? false),
|
|
393
|
-
refetch,
|
|
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
313
|
//#endregion
|
|
404
314
|
//#region src/factory/createApiInfiniteQueryUtils.ts
|
|
405
315
|
function createApiInfiniteQueryUtils() {
|
|
@@ -431,11 +341,78 @@ function createApiInfiniteQueryUtils() {
|
|
|
431
341
|
};
|
|
432
342
|
}
|
|
433
343
|
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/composables/mutation/mutation.composable.ts
|
|
346
|
+
function useMutation$1(options) {
|
|
347
|
+
const isDebug = options.isDebug ?? false;
|
|
348
|
+
const queryClient = useQueryClient();
|
|
349
|
+
async function onSuccess(responseData, params) {
|
|
350
|
+
if (!options.queryKeysToInvalidate) return;
|
|
351
|
+
await Promise.all(Object.entries(options.queryKeysToInvalidate).map(async ([queryKey, queryKeyParams]) => {
|
|
352
|
+
if (!queryKeyParams) {
|
|
353
|
+
if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`);
|
|
354
|
+
await queryClient.invalidateQueries({ queryKey: [queryKey] });
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
const qkp = queryKeyParams;
|
|
358
|
+
const paramEntries = Object.entries(qkp);
|
|
359
|
+
if (paramEntries.length === 0) {
|
|
360
|
+
if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`);
|
|
361
|
+
await queryClient.invalidateQueries({ queryKey: [queryKey] });
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const paramsWithValues = paramEntries.reduce((acc, [key, value]) => {
|
|
365
|
+
acc[key] = value(params, responseData);
|
|
366
|
+
return acc;
|
|
367
|
+
}, {});
|
|
368
|
+
if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`, paramsWithValues);
|
|
369
|
+
await queryClient.invalidateQueries({
|
|
370
|
+
exact: false,
|
|
371
|
+
queryKey: [queryKey, paramsWithValues]
|
|
372
|
+
});
|
|
373
|
+
}));
|
|
374
|
+
}
|
|
375
|
+
const mutation = useMutation({
|
|
376
|
+
mutationFn: options.queryFn,
|
|
377
|
+
onSuccess: async (result$1, variables) => {
|
|
378
|
+
if (!result$1.isOk()) return;
|
|
379
|
+
const data = result$1.value;
|
|
380
|
+
if (variables !== void 0 && "params" in variables) {
|
|
381
|
+
await onSuccess(data, variables.params);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
await onSuccess(data, {});
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
async function execute(data) {
|
|
388
|
+
return await mutation.mutateAsync(data);
|
|
389
|
+
}
|
|
390
|
+
const result = computed(() => {
|
|
391
|
+
if (mutation.isPending.value) return AsyncResult.loading();
|
|
392
|
+
if (mutation.isError.value) return AsyncResult.err(mutation.error.value);
|
|
393
|
+
if (mutation.isSuccess.value && mutation.data.value !== void 0) {
|
|
394
|
+
const apiResult = mutation.data.value;
|
|
395
|
+
if (apiResult.isOk()) return AsyncResult.ok(apiResult.value);
|
|
396
|
+
if (apiResult.isErr()) return AsyncResult.err(apiResult.error);
|
|
397
|
+
}
|
|
398
|
+
return AsyncResult.loading();
|
|
399
|
+
});
|
|
400
|
+
return {
|
|
401
|
+
isLoading: computed(() => mutation.isPending.value),
|
|
402
|
+
data: computed(() => {
|
|
403
|
+
if (mutation.data.value?.isOk()) return mutation.data.value.value;
|
|
404
|
+
return null;
|
|
405
|
+
}),
|
|
406
|
+
execute,
|
|
407
|
+
result
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
434
411
|
//#endregion
|
|
435
412
|
//#region src/factory/createApiMutationUtils.ts
|
|
436
413
|
function createApiMutationUtils() {
|
|
437
414
|
function useMutation$2(options) {
|
|
438
|
-
return useMutation({
|
|
415
|
+
return useMutation$1({
|
|
439
416
|
isDebug: options.isDebug,
|
|
440
417
|
queryFn: options.queryFn,
|
|
441
418
|
queryKeysToInvalidate: options.queryKeysToInvalidate ?? {}
|
|
@@ -445,11 +422,84 @@ function createApiMutationUtils() {
|
|
|
445
422
|
}
|
|
446
423
|
|
|
447
424
|
//#endregion
|
|
448
|
-
//#region src/
|
|
425
|
+
//#region src/factory/createApiPrefetchInfiniteQueryUtils.ts
|
|
426
|
+
const DEFAULT_LIMIT = QUERY_CONFIG.limit;
|
|
427
|
+
function createApiPrefetchInfiniteQueryUtils() {
|
|
428
|
+
function usePrefetchOffsetInfiniteQuery(key, queryOptions) {
|
|
429
|
+
const queryKey = [key, queryOptions.params ?? {}];
|
|
430
|
+
const queryClient = getQueryClient();
|
|
431
|
+
async function execute() {
|
|
432
|
+
await queryClient.prefetchInfiniteQuery({
|
|
433
|
+
staleTime: queryOptions.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
|
|
434
|
+
getNextPageParam: (lastPage) => {
|
|
435
|
+
if (lastPage.isErr()) return null;
|
|
436
|
+
const total = lastPage.value.meta.offset + lastPage.value.meta.limit;
|
|
437
|
+
if (total >= lastPage.value.meta.total) return null;
|
|
438
|
+
return total;
|
|
439
|
+
},
|
|
440
|
+
initialPageParam: 0,
|
|
441
|
+
queryFn: ({ pageParam }) => queryOptions.queryFn({
|
|
442
|
+
limit: queryOptions.limit ?? DEFAULT_LIMIT,
|
|
443
|
+
offset: pageParam ?? 0
|
|
444
|
+
}),
|
|
445
|
+
queryKey
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
return { execute };
|
|
449
|
+
}
|
|
450
|
+
function usePrefetchKeysetInfiniteQuery(key, queryOptions) {
|
|
451
|
+
const queryKey = [key, queryOptions.params ?? {}];
|
|
452
|
+
async function execute() {
|
|
453
|
+
await getQueryClient().prefetchInfiniteQuery({
|
|
454
|
+
staleTime: queryOptions.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
|
|
455
|
+
getNextPageParam: (lastPage) => {
|
|
456
|
+
if (lastPage.isErr()) return null;
|
|
457
|
+
const next = lastPage.value.meta.next;
|
|
458
|
+
if (next === null || next === void 0) return null;
|
|
459
|
+
return next;
|
|
460
|
+
},
|
|
461
|
+
initialPageParam: void 0,
|
|
462
|
+
queryFn: ({ pageParam }) => queryOptions.queryFn({
|
|
463
|
+
key: pageParam,
|
|
464
|
+
limit: queryOptions.limit ?? DEFAULT_LIMIT
|
|
465
|
+
}),
|
|
466
|
+
queryKey
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
return { execute };
|
|
470
|
+
}
|
|
471
|
+
return {
|
|
472
|
+
usePrefetchKeysetInfiniteQuery,
|
|
473
|
+
usePrefetchOffsetInfiniteQuery
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
//#endregion
|
|
478
|
+
//#region src/factory/createApiPrefetchQueryUtils.ts
|
|
479
|
+
function createApiPrefetchQueryUtils() {
|
|
480
|
+
function usePrefetchQuery(key, queryOptions) {
|
|
481
|
+
const queryClient = getQueryClient();
|
|
482
|
+
const queryKey = [key, queryOptions.params ?? {}];
|
|
483
|
+
async function execute() {
|
|
484
|
+
await queryClient.prefetchQuery({
|
|
485
|
+
staleTime: queryOptions.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
|
|
486
|
+
queryFn: async () => {
|
|
487
|
+
return AsyncResult.fromResult(await queryOptions.queryFn());
|
|
488
|
+
},
|
|
489
|
+
queryKey
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
return { execute };
|
|
493
|
+
}
|
|
494
|
+
return { usePrefetchQuery };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
//#endregion
|
|
498
|
+
//#region src/utils/query-client/queryClient.ts
|
|
449
499
|
/**
|
|
450
|
-
*
|
|
500
|
+
* QueryClient utility class for type-safe query operations
|
|
451
501
|
*/
|
|
452
|
-
var
|
|
502
|
+
var QueryClient = class {
|
|
453
503
|
constructor(queryClient) {
|
|
454
504
|
this.queryClient = queryClient;
|
|
455
505
|
}
|
|
@@ -457,13 +507,11 @@ var OptimisticUpdates = class {
|
|
|
457
507
|
* Extract the raw entity from AsyncResult data
|
|
458
508
|
*/
|
|
459
509
|
extractEntityFromAsyncResult(data) {
|
|
460
|
-
if (data
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}
|
|
466
|
-
return data;
|
|
510
|
+
if (data.isOk()) return data.getValue();
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
hasDataArray(value) {
|
|
514
|
+
return Boolean(value && typeof value === "object" && Array.isArray(value.data));
|
|
467
515
|
}
|
|
468
516
|
isInfiniteDataLike(data) {
|
|
469
517
|
return Boolean(data && typeof data === "object" && "pages" in data && Array.isArray(data.pages));
|
|
@@ -471,33 +519,26 @@ var OptimisticUpdates = class {
|
|
|
471
519
|
/**
|
|
472
520
|
* Determine if an item should be updated
|
|
473
521
|
*/
|
|
474
|
-
shouldUpdateItem(by, item
|
|
475
|
-
|
|
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;
|
|
522
|
+
shouldUpdateItem(by, item) {
|
|
523
|
+
return by(item);
|
|
484
524
|
}
|
|
485
525
|
/**
|
|
486
526
|
* Internal method to update entity based on the "by" option
|
|
487
527
|
*/
|
|
488
528
|
updateEntity(by, currentData, value) {
|
|
489
529
|
if (Array.isArray(currentData)) return currentData.map((item) => {
|
|
490
|
-
return this.shouldUpdateItem(by, item
|
|
491
|
-
...item,
|
|
492
|
-
...value
|
|
493
|
-
} : item;
|
|
530
|
+
return this.shouldUpdateItem(by, item) ? value(item) : item;
|
|
494
531
|
});
|
|
495
|
-
if (this.shouldUpdateItem(by, currentData
|
|
496
|
-
...currentData,
|
|
497
|
-
...value
|
|
498
|
-
};
|
|
532
|
+
if (this.shouldUpdateItem(by, currentData)) return value(currentData);
|
|
499
533
|
return currentData;
|
|
500
534
|
}
|
|
535
|
+
updateInfinitePageValue(by, value, pageValue) {
|
|
536
|
+
if (!this.hasDataArray(pageValue)) return pageValue;
|
|
537
|
+
return {
|
|
538
|
+
...pageValue,
|
|
539
|
+
data: this.updateEntity(by, pageValue.data, value)
|
|
540
|
+
};
|
|
541
|
+
}
|
|
501
542
|
/**
|
|
502
543
|
* Wrap a raw entity in an AsyncResult (preserving ok state)
|
|
503
544
|
*/
|
|
@@ -507,11 +548,13 @@ var OptimisticUpdates = class {
|
|
|
507
548
|
get(queryKey, options) {
|
|
508
549
|
if (Array.isArray(queryKey)) {
|
|
509
550
|
const data = this.queryClient.getQueryData(queryKey);
|
|
551
|
+
if (data == null) return null;
|
|
510
552
|
return this.extractEntityFromAsyncResult(data);
|
|
511
553
|
}
|
|
512
554
|
if (options?.isExact ?? false) {
|
|
513
555
|
const normalizedKey = [queryKey];
|
|
514
556
|
const data = this.queryClient.getQueryData(normalizedKey);
|
|
557
|
+
if (data == null) return null;
|
|
515
558
|
return this.extractEntityFromAsyncResult(data);
|
|
516
559
|
}
|
|
517
560
|
const allQueries = this.queryClient.getQueryCache().findAll({ predicate: (query) => {
|
|
@@ -544,7 +587,7 @@ var OptimisticUpdates = class {
|
|
|
544
587
|
this.queryClient.setQueryData(normalizedKey, wrappedData);
|
|
545
588
|
}
|
|
546
589
|
update(keyOrTuple, options) {
|
|
547
|
-
const by = options.by
|
|
590
|
+
const by = options.by;
|
|
548
591
|
const value = options.value;
|
|
549
592
|
const isSpecific = Array.isArray(keyOrTuple);
|
|
550
593
|
const key = isSpecific ? keyOrTuple[0] : keyOrTuple;
|
|
@@ -563,19 +606,14 @@ var OptimisticUpdates = class {
|
|
|
563
606
|
const updatedInfiniteData = {
|
|
564
607
|
...currentData,
|
|
565
608
|
pages: currentData.pages.map((page) => {
|
|
566
|
-
if (page
|
|
567
|
-
|
|
568
|
-
...pageValue,
|
|
569
|
-
data: this.updateEntity(by, pageValue.data, value)
|
|
570
|
-
};
|
|
571
|
-
return pageValue;
|
|
572
|
-
});
|
|
573
|
-
return page;
|
|
609
|
+
if (!isAsyncResult(page)) return page;
|
|
610
|
+
return page.map((pageValue) => this.updateInfinitePageValue(by, value, pageValue));
|
|
574
611
|
})
|
|
575
612
|
};
|
|
576
613
|
this.queryClient.setQueryData(query.queryKey, updatedInfiniteData);
|
|
577
614
|
continue;
|
|
578
615
|
}
|
|
616
|
+
if (!isAsyncResult(currentData)) continue;
|
|
579
617
|
const rawEntity = this.extractEntityFromAsyncResult(currentData);
|
|
580
618
|
if (rawEntity === null) continue;
|
|
581
619
|
const updatedEntity = this.updateEntity(by, rawEntity, value);
|
|
@@ -584,100 +622,59 @@ var OptimisticUpdates = class {
|
|
|
584
622
|
}
|
|
585
623
|
}
|
|
586
624
|
};
|
|
587
|
-
/**
|
|
588
|
-
* Create an OptimisticUpdates instance
|
|
589
|
-
*/
|
|
590
|
-
function createOptimisticUpdates(queryClient) {
|
|
591
|
-
return new OptimisticUpdates(queryClient);
|
|
592
|
-
}
|
|
593
625
|
|
|
594
626
|
//#endregion
|
|
595
|
-
//#region src/factory/
|
|
596
|
-
function
|
|
597
|
-
function
|
|
598
|
-
return new
|
|
627
|
+
//#region src/factory/createApiQueryClientUtils.ts
|
|
628
|
+
function createApiQueryClientUtils() {
|
|
629
|
+
function useQueryClient$1() {
|
|
630
|
+
return new QueryClient(getQueryClient());
|
|
599
631
|
}
|
|
600
|
-
return {
|
|
632
|
+
return { useQueryClient: useQueryClient$1 };
|
|
601
633
|
}
|
|
602
634
|
|
|
603
635
|
//#endregion
|
|
604
|
-
//#region src/
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
limit: queryOptions.limit ?? DEFAULT_LIMIT,
|
|
621
|
-
offset: pageParam ?? 0
|
|
622
|
-
}),
|
|
623
|
-
queryKey
|
|
624
|
-
});
|
|
625
|
-
}
|
|
626
|
-
return { execute };
|
|
636
|
+
//#region src/composables/query/query.composable.ts
|
|
637
|
+
function useQuery$1(options) {
|
|
638
|
+
const isDebug = options.isDebug ?? false;
|
|
639
|
+
const query = useQuery({
|
|
640
|
+
staleTime: options.staleTime,
|
|
641
|
+
enabled: options.isEnabled,
|
|
642
|
+
placeholderData: (data) => data,
|
|
643
|
+
queryFn: async () => {
|
|
644
|
+
return AsyncResult.fromResult(await options.queryFn());
|
|
645
|
+
},
|
|
646
|
+
queryKey: getQueryKey()
|
|
647
|
+
});
|
|
648
|
+
function getQueryKey() {
|
|
649
|
+
const [queryKey, params] = Object.entries(options.queryKey)[0];
|
|
650
|
+
if (isDebug) console.debug(`Create query with key ${queryKey}`, params);
|
|
651
|
+
return [queryKey, params];
|
|
627
652
|
}
|
|
628
|
-
function
|
|
629
|
-
|
|
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 };
|
|
653
|
+
async function refetch() {
|
|
654
|
+
await query.refetch();
|
|
648
655
|
}
|
|
649
656
|
return {
|
|
650
|
-
|
|
651
|
-
|
|
657
|
+
isError: computed(() => query.data.value?.isErr() ?? false),
|
|
658
|
+
isFetching: computed(() => query.isFetching.value),
|
|
659
|
+
isLoading: computed(() => query.isLoading.value),
|
|
660
|
+
isSuccess: computed(() => query.data.value?.isOk() ?? false),
|
|
661
|
+
refetch,
|
|
662
|
+
result: computed(() => {
|
|
663
|
+
if (query.isLoading.value) return AsyncResult.loading();
|
|
664
|
+
if (query.data.value?.isOk()) return AsyncResult.ok(query.data.value.getValue());
|
|
665
|
+
if (query.data.value?.isErr()) return AsyncResult.err(query.data.value.getError());
|
|
666
|
+
return AsyncResult.loading();
|
|
667
|
+
})
|
|
652
668
|
};
|
|
653
669
|
}
|
|
654
670
|
|
|
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
671
|
//#endregion
|
|
675
672
|
//#region src/factory/createApiQueryUtils.ts
|
|
676
673
|
function createApiQueryUtils() {
|
|
677
674
|
function useQuery$2(key, queryOptions) {
|
|
678
675
|
const params = queryOptions.params ?? {};
|
|
679
676
|
const queryKey = { [key]: params };
|
|
680
|
-
return useQuery({
|
|
677
|
+
return useQuery$1({
|
|
681
678
|
staleTime: queryOptions.staleTime,
|
|
682
679
|
isDebug: queryOptions.isDebug,
|
|
683
680
|
isEnabled: queryOptions.isEnabled,
|
|
@@ -692,18 +689,76 @@ function createApiQueryUtils() {
|
|
|
692
689
|
//#region src/factory/createApiUtils.ts
|
|
693
690
|
/**
|
|
694
691
|
* Factory that creates typed composables based on a user-provided query-keys config.
|
|
695
|
-
*
|
|
692
|
+
*
|
|
693
|
+
* Requires `initializeApiUtils(queryClient)` to be called first.
|
|
694
|
+
*
|
|
695
|
+
* @example
|
|
696
|
+
* ```typescript
|
|
697
|
+
* // In app setup (plugin or main.ts):
|
|
698
|
+
* initializeApiUtils(queryClient)
|
|
699
|
+
*
|
|
700
|
+
* // In your api lib:
|
|
701
|
+
* export const { useQuery, useMutation, useQueryClient } = createApiUtils<MyQueryKeys>()
|
|
702
|
+
* ```
|
|
696
703
|
*/
|
|
697
|
-
function createApiUtils(
|
|
704
|
+
function createApiUtils() {
|
|
698
705
|
return {
|
|
699
706
|
...createApiQueryUtils(),
|
|
700
|
-
...createApiPrefetchQueryUtils(
|
|
701
|
-
...createApiPrefetchInfiniteQueryUtils(
|
|
707
|
+
...createApiPrefetchQueryUtils(),
|
|
708
|
+
...createApiPrefetchInfiniteQueryUtils(),
|
|
702
709
|
...createApiInfiniteQueryUtils(),
|
|
703
710
|
...createApiMutationUtils(),
|
|
704
|
-
...
|
|
711
|
+
...createApiQueryClientUtils()
|
|
705
712
|
};
|
|
706
713
|
}
|
|
707
714
|
|
|
708
715
|
//#endregion
|
|
709
|
-
|
|
716
|
+
//#region src/plugin/apiUtilsPlugin.ts
|
|
717
|
+
/**
|
|
718
|
+
* Create a Vue plugin that sets up TanStack Query and initializes API utilities.
|
|
719
|
+
*
|
|
720
|
+
* This plugin handles:
|
|
721
|
+
* - Creating a QueryClient with the provided config
|
|
722
|
+
* - Installing VueQueryPlugin on the app
|
|
723
|
+
* - Initializing the global QueryClient for api-utils
|
|
724
|
+
*
|
|
725
|
+
* @example
|
|
726
|
+
* ```typescript
|
|
727
|
+
* import { apiUtilsPlugin } from '@wisemen/vue-core-api-utils'
|
|
728
|
+
* import { vueQueryClientConfig } from '@wisemen/vue-core-configs'
|
|
729
|
+
*
|
|
730
|
+
* app.use(apiUtilsPlugin(vueQueryClientConfig()))
|
|
731
|
+
* ```
|
|
732
|
+
*
|
|
733
|
+
* @param config - QueryClient configuration
|
|
734
|
+
* @returns A Vue plugin that can be used with app.use()
|
|
735
|
+
*/
|
|
736
|
+
function apiUtilsPlugin(config) {
|
|
737
|
+
const queryClient = new QueryClient$1(config);
|
|
738
|
+
return { install: (app) => {
|
|
739
|
+
app.use(VueQueryPlugin, { queryClient });
|
|
740
|
+
initializeApiUtils(queryClient);
|
|
741
|
+
} };
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
//#endregion
|
|
745
|
+
//#region src/types/sort.type.ts
|
|
746
|
+
let SortDirection = /* @__PURE__ */ function(SortDirection$1) {
|
|
747
|
+
SortDirection$1["ASC"] = "asc";
|
|
748
|
+
SortDirection$1["DESC"] = "desc";
|
|
749
|
+
return SortDirection$1;
|
|
750
|
+
}({});
|
|
751
|
+
|
|
752
|
+
//#endregion
|
|
753
|
+
//#region src/utils/sort/sort.utils.ts
|
|
754
|
+
var SortUtil = class {
|
|
755
|
+
static toDto(sort, sortKeyMap) {
|
|
756
|
+
return sort.filter((s) => s.direction !== null).map((s) => ({
|
|
757
|
+
key: sortKeyMap[s.key],
|
|
758
|
+
order: s.direction === SortDirection.ASC ? SortDirection.ASC : SortDirection.DESC
|
|
759
|
+
}));
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
//#endregion
|
|
764
|
+
export { ApiError, ApiErrorObject, ApiExpectedError, ApiKnownErrorObject, ApiResult, ApiUnexpectedError, ApiUnknownErrorObject, AsyncApiResult, AsyncResult, AsyncResultErr, AsyncResultLoading, AsyncResultOk, KeysetPagination, KeysetPaginationParams, KeysetPaginationResponse, KeysetPaginationResult, OffsetPagination, OffsetPaginationParams, OffsetPaginationResponse, OffsetPaginationResult, PaginatedDataDto, QueryClient, QueryClientUpdateOptions, Sort, SortDirection, SortUtil, apiUtilsPlugin, createApiInfiniteQueryUtils, createApiMutationUtils, createApiPrefetchInfiniteQueryUtils, createApiPrefetchQueryUtils, createApiQueryClientUtils, createApiQueryUtils, createApiUtils, getQueryClient as getTanstackQueryClient, initializeApiUtils, setQueryConfig };
|