@wisemen/vue-core-api-utils 1.0.0-beta.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +386 -322
- package/dist/index.mjs +329 -248
- 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,60 +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
|
-
await Promise.all(Object.entries(options.queryKeysToInvalidate).map(async ([queryKey, queryKeyParams]) => {
|
|
146
|
-
const qkp = queryKeyParams;
|
|
147
|
-
const paramsWithValues = Object.entries(qkp).reduce((acc, [key, value]) => {
|
|
148
|
-
acc[key] = value(params, responseData);
|
|
149
|
-
return acc;
|
|
150
|
-
}, {});
|
|
151
|
-
if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`, paramsWithValues);
|
|
152
|
-
await queryClient.invalidateQueries({
|
|
153
|
-
exact: false,
|
|
154
|
-
queryKey: [queryKey, paramsWithValues]
|
|
155
|
-
});
|
|
156
|
-
}));
|
|
157
|
-
}
|
|
158
|
-
const mutation = useMutation$1({
|
|
159
|
-
mutationFn: options.queryFn,
|
|
160
|
-
onSuccess: async (result$1, variables) => {
|
|
161
|
-
if (!result$1.isOk()) return;
|
|
162
|
-
const data = result$1.value;
|
|
163
|
-
if (variables !== void 0 && "params" in variables) {
|
|
164
|
-
await onSuccess(data, variables.params);
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
await onSuccess(data, {});
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
async function execute(data) {
|
|
171
|
-
return await mutation.mutateAsync(data);
|
|
172
|
-
}
|
|
173
|
-
const result = computed(() => {
|
|
174
|
-
if (mutation.isPending.value) return AsyncResult.loading();
|
|
175
|
-
if (mutation.isError.value && mutation.error.value) return AsyncResult.err(mutation.error.value);
|
|
176
|
-
if (mutation.isSuccess.value && mutation.data.value !== void 0) {
|
|
177
|
-
const apiResult = mutation.data.value;
|
|
178
|
-
if (apiResult.isOk()) return AsyncResult.ok(apiResult.value);
|
|
179
|
-
if (apiResult.isErr()) return AsyncResult.err(apiResult.error);
|
|
180
|
-
}
|
|
181
|
-
return AsyncResult.loading();
|
|
182
|
-
});
|
|
183
|
-
return {
|
|
184
|
-
isLoading: computed(() => mutation.isPending.value),
|
|
185
|
-
data: computed(() => {
|
|
186
|
-
if (mutation.data.value?.isOk()) return mutation.data.value.value;
|
|
187
|
-
return null;
|
|
188
|
-
}),
|
|
189
|
-
execute,
|
|
190
|
-
result
|
|
191
|
-
};
|
|
138
|
+
function isAsyncResult(value) {
|
|
139
|
+
return value instanceof AsyncResultErr || value instanceof AsyncResultLoading || value instanceof AsyncResultOk;
|
|
192
140
|
}
|
|
193
141
|
|
|
194
142
|
//#endregion
|
|
@@ -199,6 +147,34 @@ const QUERY_CONFIG = {
|
|
|
199
147
|
prefetchStaleTime: DEFAULT_PREFETCH_STALE_TIME,
|
|
200
148
|
limit: DEFAULT_LIMIT$3
|
|
201
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
|
+
}
|
|
202
178
|
function setQueryConfig(config) {
|
|
203
179
|
if (config.limit != null && config.limit > 0) QUERY_CONFIG.limit = config.limit;
|
|
204
180
|
if (config.prefetchStaleTime != null && config.prefetchStaleTime > 0) QUERY_CONFIG.prefetchStaleTime = config.prefetchStaleTime;
|
|
@@ -216,15 +192,17 @@ function useKeysetInfiniteQuery(options) {
|
|
|
216
192
|
staleTime: options.staleTime,
|
|
217
193
|
enabled: options.isEnabled,
|
|
218
194
|
getNextPageParam: (lastPage) => {
|
|
219
|
-
if (lastPage.isErr()) return null;
|
|
220
|
-
return lastPage.
|
|
195
|
+
if (lastPage.isErr() || lastPage.isLoading()) return null;
|
|
196
|
+
return lastPage.getValue().meta.next ?? null;
|
|
221
197
|
},
|
|
222
198
|
initialPageParam: void 0,
|
|
223
199
|
placeholderData: (data) => data,
|
|
224
|
-
queryFn: ({ pageParam }) =>
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
200
|
+
queryFn: async ({ pageParam }) => {
|
|
201
|
+
return AsyncResult.fromResult(await options.queryFn({
|
|
202
|
+
key: pageParam,
|
|
203
|
+
limit: options.limit ?? DEFAULT_LIMIT$2
|
|
204
|
+
}));
|
|
205
|
+
},
|
|
228
206
|
queryKey: getQueryKey()
|
|
229
207
|
});
|
|
230
208
|
const hasError = computed(() => {
|
|
@@ -233,10 +211,10 @@ function useKeysetInfiniteQuery(options) {
|
|
|
233
211
|
const result = computed(() => {
|
|
234
212
|
if (infiniteQuery.isLoading.value) return AsyncResult.loading();
|
|
235
213
|
const firstError = infiniteQuery.data.value?.pages.find((page) => page.isErr());
|
|
236
|
-
if (firstError) return AsyncResult.err(firstError.
|
|
237
|
-
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) ?? [];
|
|
238
216
|
const firstPage = infiniteQuery.data.value?.pages[0];
|
|
239
|
-
const meta = firstPage?.isOk() ? firstPage.
|
|
217
|
+
const meta = firstPage?.isOk() ? firstPage.getValue().meta : { next: null };
|
|
240
218
|
const response = {
|
|
241
219
|
data,
|
|
242
220
|
meta: { next: infiniteQuery.hasNextPage.value ? meta.next : null }
|
|
@@ -278,17 +256,17 @@ function useOffsetInfiniteQuery(options) {
|
|
|
278
256
|
staleTime: options.staleTime,
|
|
279
257
|
enabled: options.isEnabled,
|
|
280
258
|
getNextPageParam: (lastPage) => {
|
|
281
|
-
if (lastPage.isErr()) return null;
|
|
282
|
-
const total = lastPage.
|
|
283
|
-
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;
|
|
284
262
|
return total;
|
|
285
263
|
},
|
|
286
264
|
initialPageParam: 0,
|
|
287
265
|
placeholderData: (data) => data,
|
|
288
|
-
queryFn: ({ pageParam }) => options.queryFn({
|
|
266
|
+
queryFn: async ({ pageParam }) => AsyncResult.fromResult(await options.queryFn({
|
|
289
267
|
limit: options.limit ?? DEFAULT_LIMIT$1,
|
|
290
268
|
offset: pageParam ?? 0
|
|
291
|
-
}),
|
|
269
|
+
})),
|
|
292
270
|
queryKey: getQueryKey()
|
|
293
271
|
});
|
|
294
272
|
const hasError = computed(() => {
|
|
@@ -297,10 +275,10 @@ function useOffsetInfiniteQuery(options) {
|
|
|
297
275
|
const result = computed(() => {
|
|
298
276
|
if (infiniteQuery.isLoading.value) return AsyncResult.loading();
|
|
299
277
|
const firstError = infiniteQuery.data.value?.pages.find((page) => page.isErr());
|
|
300
|
-
if (firstError) return AsyncResult.err(firstError.
|
|
301
|
-
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) ?? [];
|
|
302
280
|
const firstPage = infiniteQuery.data.value?.pages[0];
|
|
303
|
-
const meta = firstPage?.isOk() ? firstPage.
|
|
281
|
+
const meta = firstPage?.isOk() ? firstPage.getValue().meta : null;
|
|
304
282
|
const response = {
|
|
305
283
|
data,
|
|
306
284
|
meta: {
|
|
@@ -332,62 +310,6 @@ function useOffsetInfiniteQuery(options) {
|
|
|
332
310
|
};
|
|
333
311
|
}
|
|
334
312
|
|
|
335
|
-
//#endregion
|
|
336
|
-
//#region src/composables/query/prefetchQuery.composable.ts
|
|
337
|
-
function usePrefetchQuery(query) {
|
|
338
|
-
const queryClient = useQueryClient();
|
|
339
|
-
function getQueryKey() {
|
|
340
|
-
const [first] = Object.entries(query.queryKey);
|
|
341
|
-
if (!first) return [];
|
|
342
|
-
const [queryKey, params] = first;
|
|
343
|
-
return [queryKey, params];
|
|
344
|
-
}
|
|
345
|
-
async function execute() {
|
|
346
|
-
await queryClient.prefetchQuery({
|
|
347
|
-
staleTime: query.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
|
|
348
|
-
queryFn: query.queryFn,
|
|
349
|
-
queryKey: getQueryKey()
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
return { execute };
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
//#endregion
|
|
356
|
-
//#region src/composables/query/query.composable.ts
|
|
357
|
-
function useQuery(options) {
|
|
358
|
-
const isDebug = options.isDebug ?? false;
|
|
359
|
-
const query = useQuery$1({
|
|
360
|
-
staleTime: options.staleTime,
|
|
361
|
-
enabled: options.isEnabled,
|
|
362
|
-
placeholderData: (data) => data,
|
|
363
|
-
queryFn: async () => {
|
|
364
|
-
return AsyncResult.fromResult(await options.queryFn());
|
|
365
|
-
},
|
|
366
|
-
queryKey: getQueryKey()
|
|
367
|
-
});
|
|
368
|
-
function getQueryKey() {
|
|
369
|
-
const [queryKey, params] = Object.entries(options.queryKey)[0];
|
|
370
|
-
if (isDebug) console.debug(`Create query with key ${queryKey}`, params);
|
|
371
|
-
return [queryKey, params];
|
|
372
|
-
}
|
|
373
|
-
async function refetch() {
|
|
374
|
-
await query.refetch();
|
|
375
|
-
}
|
|
376
|
-
return {
|
|
377
|
-
isError: computed(() => query.data.value?.isErr() ?? false),
|
|
378
|
-
isFetching: computed(() => query.isFetching.value),
|
|
379
|
-
isLoading: computed(() => query.isLoading.value),
|
|
380
|
-
isSuccess: computed(() => query.data.value?.isOk() ?? false),
|
|
381
|
-
refetch,
|
|
382
|
-
result: computed(() => {
|
|
383
|
-
if (query.isLoading.value) return AsyncResult.loading();
|
|
384
|
-
if (query.data.value?.isOk()) return AsyncResult.ok(query.data.value.getValue());
|
|
385
|
-
if (query.data.value?.isErr()) return AsyncResult.err(query.data.value.getError());
|
|
386
|
-
return AsyncResult.loading();
|
|
387
|
-
})
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
|
|
391
313
|
//#endregion
|
|
392
314
|
//#region src/factory/createApiInfiniteQueryUtils.ts
|
|
393
315
|
function createApiInfiniteQueryUtils() {
|
|
@@ -420,11 +342,164 @@ function createApiInfiniteQueryUtils() {
|
|
|
420
342
|
}
|
|
421
343
|
|
|
422
344
|
//#endregion
|
|
423
|
-
//#region src/
|
|
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
|
+
|
|
411
|
+
//#endregion
|
|
412
|
+
//#region src/factory/createApiMutationUtils.ts
|
|
413
|
+
function createApiMutationUtils() {
|
|
414
|
+
function useMutation$2(options) {
|
|
415
|
+
return useMutation$1({
|
|
416
|
+
isDebug: options.isDebug,
|
|
417
|
+
queryFn: options.queryFn,
|
|
418
|
+
queryKeysToInvalidate: options.queryKeysToInvalidate ?? {}
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
return { useMutation: useMutation$2 };
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
//#endregion
|
|
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
|
|
424
499
|
/**
|
|
425
|
-
*
|
|
500
|
+
* QueryClient utility class for type-safe query operations
|
|
426
501
|
*/
|
|
427
|
-
var
|
|
502
|
+
var QueryClient = class {
|
|
428
503
|
constructor(queryClient) {
|
|
429
504
|
this.queryClient = queryClient;
|
|
430
505
|
}
|
|
@@ -432,13 +507,11 @@ var OptimisticUpdates = class {
|
|
|
432
507
|
* Extract the raw entity from AsyncResult data
|
|
433
508
|
*/
|
|
434
509
|
extractEntityFromAsyncResult(data) {
|
|
435
|
-
if (data
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
}
|
|
441
|
-
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));
|
|
442
515
|
}
|
|
443
516
|
isInfiniteDataLike(data) {
|
|
444
517
|
return Boolean(data && typeof data === "object" && "pages" in data && Array.isArray(data.pages));
|
|
@@ -446,33 +519,26 @@ var OptimisticUpdates = class {
|
|
|
446
519
|
/**
|
|
447
520
|
* Determine if an item should be updated
|
|
448
521
|
*/
|
|
449
|
-
shouldUpdateItem(by, item
|
|
450
|
-
|
|
451
|
-
if (by && typeof by === "object") return Object.entries(by).every(([key, matchValue]) => {
|
|
452
|
-
const itemValue = item[key];
|
|
453
|
-
return unref(itemValue) === unref(matchValue);
|
|
454
|
-
});
|
|
455
|
-
const idFromValue = value.id;
|
|
456
|
-
const itemId = item["id"];
|
|
457
|
-
if (idFromValue !== void 0 && itemId !== void 0) return unref(itemId) === unref(idFromValue);
|
|
458
|
-
return false;
|
|
522
|
+
shouldUpdateItem(by, item) {
|
|
523
|
+
return by(item);
|
|
459
524
|
}
|
|
460
525
|
/**
|
|
461
526
|
* Internal method to update entity based on the "by" option
|
|
462
527
|
*/
|
|
463
528
|
updateEntity(by, currentData, value) {
|
|
464
529
|
if (Array.isArray(currentData)) return currentData.map((item) => {
|
|
465
|
-
return this.shouldUpdateItem(by, item
|
|
466
|
-
...item,
|
|
467
|
-
...value
|
|
468
|
-
} : item;
|
|
530
|
+
return this.shouldUpdateItem(by, item) ? value(item) : item;
|
|
469
531
|
});
|
|
470
|
-
if (this.shouldUpdateItem(by, currentData
|
|
471
|
-
...currentData,
|
|
472
|
-
...value
|
|
473
|
-
};
|
|
532
|
+
if (this.shouldUpdateItem(by, currentData)) return value(currentData);
|
|
474
533
|
return currentData;
|
|
475
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
|
+
}
|
|
476
542
|
/**
|
|
477
543
|
* Wrap a raw entity in an AsyncResult (preserving ok state)
|
|
478
544
|
*/
|
|
@@ -482,11 +548,13 @@ var OptimisticUpdates = class {
|
|
|
482
548
|
get(queryKey, options) {
|
|
483
549
|
if (Array.isArray(queryKey)) {
|
|
484
550
|
const data = this.queryClient.getQueryData(queryKey);
|
|
551
|
+
if (data == null) return null;
|
|
485
552
|
return this.extractEntityFromAsyncResult(data);
|
|
486
553
|
}
|
|
487
554
|
if (options?.isExact ?? false) {
|
|
488
555
|
const normalizedKey = [queryKey];
|
|
489
556
|
const data = this.queryClient.getQueryData(normalizedKey);
|
|
557
|
+
if (data == null) return null;
|
|
490
558
|
return this.extractEntityFromAsyncResult(data);
|
|
491
559
|
}
|
|
492
560
|
const allQueries = this.queryClient.getQueryCache().findAll({ predicate: (query) => {
|
|
@@ -519,7 +587,7 @@ var OptimisticUpdates = class {
|
|
|
519
587
|
this.queryClient.setQueryData(normalizedKey, wrappedData);
|
|
520
588
|
}
|
|
521
589
|
update(keyOrTuple, options) {
|
|
522
|
-
const by = options.by
|
|
590
|
+
const by = options.by;
|
|
523
591
|
const value = options.value;
|
|
524
592
|
const isSpecific = Array.isArray(keyOrTuple);
|
|
525
593
|
const key = isSpecific ? keyOrTuple[0] : keyOrTuple;
|
|
@@ -538,19 +606,14 @@ var OptimisticUpdates = class {
|
|
|
538
606
|
const updatedInfiniteData = {
|
|
539
607
|
...currentData,
|
|
540
608
|
pages: currentData.pages.map((page) => {
|
|
541
|
-
if (page
|
|
542
|
-
|
|
543
|
-
...pageValue,
|
|
544
|
-
data: this.updateEntity(by, pageValue.data, value)
|
|
545
|
-
};
|
|
546
|
-
return pageValue;
|
|
547
|
-
});
|
|
548
|
-
return page;
|
|
609
|
+
if (!isAsyncResult(page)) return page;
|
|
610
|
+
return page.map((pageValue) => this.updateInfinitePageValue(by, value, pageValue));
|
|
549
611
|
})
|
|
550
612
|
};
|
|
551
613
|
this.queryClient.setQueryData(query.queryKey, updatedInfiniteData);
|
|
552
614
|
continue;
|
|
553
615
|
}
|
|
616
|
+
if (!isAsyncResult(currentData)) continue;
|
|
554
617
|
const rawEntity = this.extractEntityFromAsyncResult(currentData);
|
|
555
618
|
if (rawEntity === null) continue;
|
|
556
619
|
const updatedEntity = this.updateEntity(by, rawEntity, value);
|
|
@@ -559,100 +622,59 @@ var OptimisticUpdates = class {
|
|
|
559
622
|
}
|
|
560
623
|
}
|
|
561
624
|
};
|
|
562
|
-
/**
|
|
563
|
-
* Create an OptimisticUpdates instance
|
|
564
|
-
*/
|
|
565
|
-
function createOptimisticUpdates(queryClient) {
|
|
566
|
-
return new OptimisticUpdates(queryClient);
|
|
567
|
-
}
|
|
568
625
|
|
|
569
626
|
//#endregion
|
|
570
|
-
//#region src/factory/
|
|
571
|
-
function
|
|
572
|
-
function
|
|
573
|
-
return new
|
|
627
|
+
//#region src/factory/createApiQueryClientUtils.ts
|
|
628
|
+
function createApiQueryClientUtils() {
|
|
629
|
+
function useQueryClient$1() {
|
|
630
|
+
return new QueryClient(getQueryClient());
|
|
574
631
|
}
|
|
575
|
-
return {
|
|
632
|
+
return { useQueryClient: useQueryClient$1 };
|
|
576
633
|
}
|
|
577
634
|
|
|
578
635
|
//#endregion
|
|
579
|
-
//#region src/
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
limit: queryOptions.limit ?? DEFAULT_LIMIT,
|
|
596
|
-
offset: pageParam ?? 0
|
|
597
|
-
}),
|
|
598
|
-
queryKey
|
|
599
|
-
});
|
|
600
|
-
}
|
|
601
|
-
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];
|
|
602
652
|
}
|
|
603
|
-
function
|
|
604
|
-
|
|
605
|
-
async function execute() {
|
|
606
|
-
await options.queryClient.prefetchInfiniteQuery({
|
|
607
|
-
staleTime: queryOptions.staleTime,
|
|
608
|
-
getNextPageParam: (lastPage) => {
|
|
609
|
-
if (lastPage.isErr()) return null;
|
|
610
|
-
const next = lastPage.value.meta.next;
|
|
611
|
-
if (next === null || next === void 0) return null;
|
|
612
|
-
return next;
|
|
613
|
-
},
|
|
614
|
-
initialPageParam: void 0,
|
|
615
|
-
queryFn: ({ pageParam }) => queryOptions.queryFn({
|
|
616
|
-
key: pageParam,
|
|
617
|
-
limit: queryOptions.limit ?? DEFAULT_LIMIT
|
|
618
|
-
}),
|
|
619
|
-
queryKey
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
return { execute };
|
|
653
|
+
async function refetch() {
|
|
654
|
+
await query.refetch();
|
|
623
655
|
}
|
|
624
656
|
return {
|
|
625
|
-
|
|
626
|
-
|
|
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
|
+
})
|
|
627
668
|
};
|
|
628
669
|
}
|
|
629
670
|
|
|
630
|
-
//#endregion
|
|
631
|
-
//#region src/factory/createApiPrefetchQueryUtils.ts
|
|
632
|
-
function createApiPrefetchQueryUtils(options) {
|
|
633
|
-
function usePrefetchQuery$1(key, queryOptions) {
|
|
634
|
-
const queryKey = [key, queryOptions.params ?? {}];
|
|
635
|
-
async function execute() {
|
|
636
|
-
await options.queryClient.prefetchQuery({
|
|
637
|
-
staleTime: queryOptions.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
|
|
638
|
-
queryFn: async () => {
|
|
639
|
-
return AsyncResult.fromResult(await queryOptions.queryFn());
|
|
640
|
-
},
|
|
641
|
-
queryKey
|
|
642
|
-
});
|
|
643
|
-
}
|
|
644
|
-
return { execute };
|
|
645
|
-
}
|
|
646
|
-
return { usePrefetchQuery: usePrefetchQuery$1 };
|
|
647
|
-
}
|
|
648
|
-
|
|
649
671
|
//#endregion
|
|
650
672
|
//#region src/factory/createApiQueryUtils.ts
|
|
651
673
|
function createApiQueryUtils() {
|
|
652
674
|
function useQuery$2(key, queryOptions) {
|
|
653
675
|
const params = queryOptions.params ?? {};
|
|
654
676
|
const queryKey = { [key]: params };
|
|
655
|
-
return useQuery({
|
|
677
|
+
return useQuery$1({
|
|
656
678
|
staleTime: queryOptions.staleTime,
|
|
657
679
|
isDebug: queryOptions.isDebug,
|
|
658
680
|
isEnabled: queryOptions.isEnabled,
|
|
@@ -667,17 +689,76 @@ function createApiQueryUtils() {
|
|
|
667
689
|
//#region src/factory/createApiUtils.ts
|
|
668
690
|
/**
|
|
669
691
|
* Factory that creates typed composables based on a user-provided query-keys config.
|
|
670
|
-
*
|
|
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
|
+
* ```
|
|
671
703
|
*/
|
|
672
|
-
function createApiUtils(
|
|
704
|
+
function createApiUtils() {
|
|
673
705
|
return {
|
|
674
706
|
...createApiQueryUtils(),
|
|
675
|
-
...createApiPrefetchQueryUtils(
|
|
676
|
-
...createApiPrefetchInfiniteQueryUtils(
|
|
707
|
+
...createApiPrefetchQueryUtils(),
|
|
708
|
+
...createApiPrefetchInfiniteQueryUtils(),
|
|
677
709
|
...createApiInfiniteQueryUtils(),
|
|
678
|
-
...
|
|
710
|
+
...createApiMutationUtils(),
|
|
711
|
+
...createApiQueryClientUtils()
|
|
679
712
|
};
|
|
680
713
|
}
|
|
681
714
|
|
|
682
715
|
//#endregion
|
|
683
|
-
|
|
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 };
|