@codeleap/query 5.8.3 → 5.8.4

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.
@@ -1,954 +0,0 @@
1
- /* eslint-disable max-lines */
2
- import {
3
- useQuery,
4
- useMutation,
5
- useInfiniteQuery,
6
- hashKey,
7
- QueryKey,
8
- } from '@tanstack/react-query'
9
- import { Draft, produce } from 'immer'
10
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
11
- import { deepMerge } from '@codeleap/utils'
12
- import { usePromise } from '@codeleap/hooks'
13
- import { TypeGuards } from '@codeleap/types'
14
- import {
15
- QueryManagerItem,
16
- AppendToPagination,
17
- CreateOptions,
18
- QueryManagerOptions,
19
- MutationCtx,
20
- QueryStateValue,
21
- InfinitePaginationData,
22
- QueryManagerActions,
23
- UpdateOptions,
24
- UseManagerArgs,
25
- GetItemOptions,
26
- DeleteOptions,
27
- SettableOptions,
28
- QueryManagerMeta,
29
- ListOptions,
30
- RetrieveOptions,
31
- OptionChangeListener,
32
- QueryManagerActionTriggers,
33
- UseActionOptions,
34
- PaginationResponse,
35
- UseListSelector,
36
- PageParam,
37
- } from './types'
38
-
39
- export * from './types'
40
-
41
- export class QueryManager<
42
- T extends QueryManagerItem,
43
- ExtraArgs extends Record<string, any> = any,
44
- Meta extends QueryManagerMeta = QueryManagerMeta,
45
- Actions extends QueryManagerActions<T, ExtraArgs, Meta> = QueryManagerActions<T, ExtraArgs, Meta>
46
- > {
47
-
48
- options: QueryManagerOptions<T, ExtraArgs, Meta, Actions>
49
-
50
- meta: Meta
51
-
52
- itemMap: Record<T['id'], T>
53
-
54
- queryStates: Record<string, QueryStateValue<T>> = {}
55
-
56
- optionListeners: OptionChangeListener<QueryManagerOptions<T, ExtraArgs, Meta, Actions>>[]
57
-
58
- constructor(options: QueryManagerOptions<T, ExtraArgs, Meta, Actions>) {
59
- this.options = options
60
-
61
- this.itemMap = {} as Record<T['id'], T>
62
-
63
- this.meta = options?.initialMeta
64
-
65
- this.optionListeners = []
66
-
67
- this.queryStates = {
68
- [hashKey(this.filteredQueryKey())]: {
69
- itemIndexes: {},
70
- pagesById: {},
71
- key: this.queryKeys.list,
72
- } as unknown as QueryStateValue<T>,
73
- }
74
- }
75
-
76
- extractKey(item:T) {
77
- return this.options?.keyExtractor?.(item) ?? item.id
78
- }
79
-
80
- get keySuffixes() {
81
- return {
82
- list: 'list',
83
- infiniteList: 'infinite-list',
84
- create: 'create',
85
- update: 'update',
86
- delete: 'delete',
87
- retrieve: 'retrieve',
88
- }
89
- }
90
-
91
- get actions() {
92
- const actions = this.options.actions ?? {} as Actions
93
-
94
- const actionKeys = Object.keys(actions)
95
-
96
- const actionFunctions = actionKeys.reduce((acc, key) => {
97
- const action = actions[key]
98
- // @ts-ignore
99
- acc[key] = (...args: any[]) => {
100
- return action(this, ...args)
101
- }
102
-
103
- return acc
104
- }, {} as QueryManagerActionTriggers<Actions>)
105
-
106
- return actionFunctions
107
- }
108
-
109
- generateId() {
110
- return this.options.generateId?.() ?? this.knownItemCount()?.count + 1
111
-
112
- }
113
-
114
- useOptions(cb?: OptionChangeListener<QueryManagerOptions<T, ExtraArgs, Meta, Actions>>) {
115
- const [options, setOptions] = useState(this.options)
116
- const [meta, setMeta] = useState(this.meta)
117
-
118
- useEffect(() => {
119
- const idx = this.optionListeners.push((o, meta) => {
120
- setOptions(o)
121
- setMeta(meta)
122
- cb?.(o, meta)
123
- }) - 1
124
-
125
- return () => {
126
- this.optionListeners.splice(idx, 1)
127
- }
128
- })
129
-
130
- return [options, meta] as const
131
- }
132
-
133
- async updateItems(items: T | T[], settingIds?: T['id'] | T['id'][]) {
134
- const itemArr = Array.isArray(items) ? items : [items]
135
-
136
- const setIdsTo = TypeGuards.isNil(settingIds) ? settingIds : TypeGuards.isArray(settingIds) ? settingIds : [settingIds]
137
-
138
- const newItems = []
139
-
140
- const ids = itemArr.map((i, idx) => {
141
- const id = this.extractKey(i)
142
-
143
- let newId = id
144
-
145
- let withNewId = i
146
-
147
- if (setIdsTo?.[idx]) {
148
- newId = setIdsTo[idx]
149
-
150
- withNewId = {
151
- ...(this.itemMap[id] ?? {}),
152
- ...i,
153
- id: newId,
154
- }
155
-
156
- delete this.itemMap[id]
157
- }
158
-
159
- this.itemMap[withNewId.id] = withNewId
160
-
161
- this.queryClient.setQueryData<T>(this.queryKeyFor(id), (old) => {
162
-
163
- return withNewId
164
- })
165
-
166
- if (!TypeGuards.isNil(newId)) {
167
- this.queryClient.setQueryData<T>(this.queryKeyFor(newId), (old) => {
168
- return withNewId
169
- })
170
- }
171
- newItems.push(withNewId)
172
- return id
173
- })
174
-
175
- const promises = Object.values(this.queryStates).map(async ({ key, pagesById }) => {
176
-
177
- this.queryClient.setQueryData<InfinitePaginationData<T>>(key, (old) => {
178
- if (!old) return old
179
-
180
- ids.forEach((id, idx) => {
181
- if (!pagesById[id]) return
182
- const [pageIdx, itemIdx] = pagesById[id]
183
-
184
- const newItem = newItems[idx]
185
-
186
- old.pages[pageIdx].results[itemIdx] = newItem
187
-
188
- })
189
-
190
- this.transformData(old, key)
191
- return old
192
- })
193
-
194
- })
195
-
196
- await Promise.all(promises)
197
-
198
- }
199
-
200
- async getItem(itemId: T['id'], options?: GetItemOptions<T>) {
201
- const i = this.itemMap[itemId]
202
-
203
- if ((!i && !!options?.fetchOnNotFoud) || options?.forceRefetch) {
204
- const item = await this.options.retrieveItem(itemId)
205
- this.updateItems(item)
206
- return item
207
- }
208
- return i
209
- }
210
-
211
- addItem: AppendToPagination<T, ExtraArgs> = async (args) => {
212
- const updateOnList = TypeGuards.isUndefined(args?.onListsWithFilters) ? undefined : hashKey(
213
- this.filteredQueryKey(args.onListsWithFilters),
214
- )
215
-
216
- const promises = Object.entries(this.queryStates).map(async ([hashedKey, { key }]) => {
217
- if (!TypeGuards.isUndefined(updateOnList)) {
218
- if (updateOnList !== hashedKey) {
219
- return
220
- }
221
- }
222
-
223
- this.queryClient.setQueryData<InfinitePaginationData<T>>(key, (_old) => {
224
- const newData = produce(_old, (old) => {
225
- if (!old?.pages?.length || (old?.pages?.length > 1 && old?.pages?.every(page => page.results.length <= 0))) {
226
- old = {
227
- pageParams: [],
228
- pages: [
229
- {
230
- results: [],
231
- count: 0,
232
- next: null,
233
- previous: null,
234
- },
235
- ],
236
- }
237
- }
238
-
239
- const itemsToAppend = (TypeGuards.isArray(args.item) ? args.item : [args.item]) as Draft<T>[]
240
-
241
- if (args.to === 'end') {
242
- const idx = old.pages.length - 1
243
- old.pages[idx].results.push(...itemsToAppend)
244
-
245
- old.pages[idx].count += itemsToAppend.length
246
-
247
- if (old.pageParams[idx]) {
248
- // @ts-ignore
249
- old.pageParams[idx].limit += itemsToAppend.length
250
- } else {
251
- old.pageParams[idx] = {
252
- limit: this.options?.limit ?? itemsToAppend.length,
253
- offset: 0,
254
- }
255
- }
256
-
257
- } else if (args.to === 'start') {
258
- old.pages[0].results.unshift(...itemsToAppend)
259
- // @ts-ignore
260
-
261
- if (old.pageParams[0]) {
262
- // @ts-ignore
263
- old.pageParams[0].offset -= itemsToAppend.length
264
- // @ts-ignore
265
- old.pageParams[0].limit += itemsToAppend.length
266
- } else {
267
- old.pageParams[0] = {
268
- limit: itemsToAppend.length,
269
- offset: -itemsToAppend.length,
270
- }
271
- }
272
-
273
- } else if (!!args.to) {
274
- const appendTo = TypeGuards.isArray(args.to) ? args.to : args.to[hashedKey]
275
-
276
- const [pageIdx, itemIdx] = appendTo
277
- old.pages[pageIdx].results.splice(itemIdx, 0, ...itemsToAppend)
278
-
279
- if (old.pageParams[pageIdx]) {
280
- // @ts-ignore
281
- old.pageParams[pageIdx].offset -= itemsToAppend.length
282
- // @ts-ignore
283
- old.pageParams[pageIdx].limit += itemsToAppend.length
284
- } else {
285
- old.pageParams[pageIdx] = {
286
- limit: itemsToAppend.length,
287
- offset: -itemsToAppend.length,
288
- }
289
- }
290
- }
291
- })
292
-
293
- this.transformData(newData, key)
294
-
295
- return newData
296
- })
297
- })
298
-
299
- await Promise.all(promises)
300
- }
301
-
302
- useAction<T extends keyof Actions>(
303
- action: T,
304
- options?: UseActionOptions<Actions[T]>,
305
- ) {
306
- const mut = useMutation({
307
- mutationKey: [this.name, action, options?.mutationKey],
308
- mutationFn: (vars) => this.options.actions[action](this, vars),
309
- ...options,
310
- })
311
-
312
- return mut
313
- }
314
-
315
- async removeItem(itemId: T['id']) {
316
-
317
- const removedPositions = {} as Record<string, [number, number]>
318
-
319
- const promises = Object.entries(this.queryStates).map(async ([hashedKey, { key, pagesById }]) => {
320
-
321
- this.queryClient.setQueryData<InfinitePaginationData<T>>(key, (old) => {
322
- const [itemPage, itemIdx] = pagesById[itemId]
323
-
324
- old.pages[itemPage].results.splice(itemIdx, 1)
325
- // @ts-ignore
326
- old.pageParams[itemPage].limit -= 1
327
-
328
- removedPositions[hashedKey] = [itemPage, itemIdx]
329
- return old
330
- })
331
- })
332
-
333
- await Promise.all(promises)
334
-
335
- return removedPositions
336
- }
337
-
338
- transformData(data: InfinitePaginationData<T>, key: QueryKey) {
339
- const pagesById = {} as Record<T['id'], [number, number]>
340
- const flatItems = [] as T[]
341
- const itemIndexes = {} as Record<T['id'], number>
342
-
343
- const hashedKey = hashKey(key)
344
-
345
- let pageIdx = 0
346
-
347
- for (const page of data?.pages ?? []) {
348
-
349
- page.results.forEach((i, itemIdx) => {
350
- const flatIdx = flatItems.length
351
- const itemId = i.id
352
-
353
- const include = true
354
-
355
- if (include) {
356
- flatItems.push(i)
357
- }
358
- pagesById[itemId] = [pageIdx, itemIdx]
359
- this.itemMap[itemId] = i
360
- itemIndexes[itemId] = flatIdx
361
- })
362
- pageIdx += 1
363
- }
364
-
365
- this.queryStates[hashedKey] = {
366
- itemIndexes: { ...this.queryStates[hashedKey]?.itemIndexes, ...itemIndexes },
367
- pagesById: { ...this.queryStates[hashedKey]?.pagesById, ...pagesById },
368
- key,
369
- }
370
-
371
- return {
372
- itemMap: this.itemMap,
373
- pagesById,
374
- itemIndexes,
375
- itemList: flatItems,
376
- }
377
- }
378
-
379
- get queryKeys() {
380
- return {
381
- list: [this.name, this.keySuffixes.list],
382
- // infiniteList: [this.name, this.keySuffixes.infiniteList],
383
- create: [this.name, this.keySuffixes.create],
384
- update: [this.name, this.keySuffixes.update],
385
- delete: [this.name, this.keySuffixes.delete],
386
- retrieve: [this.name, this.keySuffixes.retrieve],
387
-
388
- }
389
- }
390
-
391
- get name() {
392
- return this.options.name
393
- }
394
-
395
- get standardLimit() {
396
- return this.options.limit ?? 10
397
- }
398
-
399
- get queryClient() {
400
- return this.options.queryClient
401
- }
402
-
403
- getList(forFilters?: ExtraArgs) {
404
- return this.queryClient.getQueryData<InfinitePaginationData<T>>(this.filteredQueryKey(forFilters))
405
- }
406
-
407
- getListState(forFilters?: ExtraArgs) {
408
- return this.queryClient.getQueryState<InfinitePaginationData<T>>(this.filteredQueryKey(forFilters))
409
- }
410
-
411
- getItemCount(forFilters?: ExtraArgs) {
412
- return this.getList(forFilters)?.pages.reduce((acc, p) => Math.max(p.count, acc), 0)
413
- }
414
-
415
- knownItemCount() {
416
- const res = Object.values(this.queryStates).reduce<{ count: number; lastDatetime?: number }>((acc, { key }) => {
417
- const state = this.queryClient.getQueryState<InfinitePaginationData<T>>(key)
418
-
419
- const lastDatetime = acc.lastDatetime ?? 0
420
-
421
- if (state?.dataUpdatedAt > lastDatetime) {
422
- acc.lastDatetime = state.dataUpdatedAt
423
- const totals = state.data?.pages.reduce((acc, p) => Math.max(p.count, acc), 0)
424
-
425
- acc.count = totals
426
- }
427
-
428
- return acc
429
- }, {
430
- count: 0,
431
- lastDatetime: null,
432
- })
433
-
434
- return res
435
- }
436
-
437
- queryKeyFor(itemId: T['id']) {
438
- return [this.name, this.keySuffixes.retrieve, itemId]
439
- }
440
-
441
- filteredQueryKey(filters = {} as ExtraArgs) {
442
- return [...this.queryKeys.list, filters]
443
- }
444
-
445
- useList(options: ListOptions<T, ExtraArgs> = {}) {
446
- const [isRefreshing, setRefreshing] = useState(false)
447
-
448
- const {
449
- filter = {} as ExtraArgs,
450
- queryOptions,
451
- limit = this.standardLimit,
452
- } = options
453
-
454
- const queryKey = this.filteredQueryKey(filter)
455
-
456
- const hashedKey = hashKey(queryKey)
457
-
458
- const useListEffect = this.options?.useListEffect ?? (() => null)
459
-
460
- const select:ListOptions<T, ExtraArgs>['queryOptions']['select'] = useCallback((data) => {
461
-
462
- const { itemList } = this.transformData(data, queryKey)
463
-
464
- return {
465
- pageParams: data.pageParams,
466
- pages: data?.pages ?? [],
467
- flatItems: itemList,
468
- }
469
-
470
- }, [])
471
-
472
- const query = useInfiniteQuery<PaginationResponse<T>, Error, UseListSelector<T>, QueryKey, PageParam>({
473
- queryKey,
474
-
475
- initialPageParam: {
476
- limit,
477
- offset: 0,
478
- },
479
- queryFn: async (query) => {
480
-
481
- return this.options.listItems(limit, query.pageParam?.offset ?? 0, filter)
482
- },
483
- refetchOnMount: (query) => {
484
-
485
- if (TypeGuards.isBoolean(queryOptions?.refetchOnMount) || TypeGuards.isString(queryOptions?.refetchOnMount)) {
486
- return queryOptions?.refetchOnMount
487
- }
488
- return query.state.dataUpdateCount === 0 || query.isStaleByTime()
489
- },
490
- getNextPageParam: (lastPage, pages) => {
491
- const currentTotal = pages.reduce((acc, p) => p.results.length + acc, 0)
492
-
493
- if (currentTotal >= (lastPage?.count || Infinity)) {
494
- return undefined
495
- }
496
- return {
497
- limit: limit,
498
- offset: currentTotal,
499
- }
500
- },
501
- getPreviousPageParam: (lastPage, pages) => {
502
- const currentTotal = pages.reduce((acc, p) => p.results.length + acc, 0)
503
-
504
- if (currentTotal >= (lastPage?.count || Infinity)) {
505
- return undefined
506
- }
507
- return {
508
- limit: limit,
509
- offset: currentTotal,
510
- }
511
- },
512
- select,
513
-
514
- ...queryOptions,
515
-
516
- })
517
-
518
- const refresh = async () => {
519
- setRefreshing(true)
520
- await this.refresh(filter)
521
- setRefreshing(false)
522
- }
523
-
524
- const listEffect = useListEffect({
525
- query,
526
- refreshQuery: (silent = true) => silent ? this.refresh(filter) : refresh(),
527
- cancelQuery: () => this.queryClient.cancelQueries({ queryKey }),
528
- })
529
-
530
- const itemCount = useMemo(() => {
531
- return query.data?.pages.reduce((acc, p) => Math.max(p.count, acc), 0)
532
- }, [query.data])
533
-
534
- // @ts-ignore
535
- const items = query.data?.flatItems ?? []
536
-
537
- return {
538
- items: items as T[],
539
- query,
540
- getNextPage: query.fetchNextPage,
541
- getPreviousPage: query.fetchPreviousPage,
542
- refresh,
543
- isRefreshing,
544
- itemMap: this.itemMap,
545
- pagesById: this.queryStates[hashedKey]?.pagesById ?? {},
546
- itemIndexes: this.queryStates[hashedKey]?.itemIndexes ?? {},
547
- itemCount,
548
- }
549
- }
550
-
551
- useRetrieve(options?: RetrieveOptions<T>) {
552
- const [isRefreshing, setRefreshing] = useState(false)
553
-
554
- const itemId = options?.id
555
-
556
- const select:RetrieveOptions<T>['queryOptions']['select'] = useCallback((data) => {
557
- this.updateItems(data)
558
- return data
559
- }, [])
560
-
561
- const query = useQuery({
562
- queryKey: this.queryKeyFor(itemId),
563
- initialData: () => {
564
- return this.itemMap[itemId]
565
- },
566
- queryFn: () => {
567
- return this.options.retrieveItem(itemId)
568
- },
569
- select,
570
-
571
- ...options?.queryOptions,
572
- })
573
-
574
- const refresh = async () => {
575
- setRefreshing(true)
576
- await this.refreshItem(itemId)
577
- setRefreshing(false)
578
- }
579
-
580
- return {
581
- data: query.data,
582
- query,
583
- refresh,
584
- isRefreshing,
585
- }
586
- }
587
-
588
- useItem(options?: RetrieveOptions<T>) {
589
- return this.useRetrieve(options)
590
- }
591
-
592
- useCreate(options?: CreateOptions<T>) {
593
-
594
- const [managerOptions, meta] = this.useOptions()
595
-
596
- const tmpOptions = useRef<CreateOptions<T>>(options ?? managerOptions.creation ?? {
597
- appendTo: 'start',
598
- optimistic: false,
599
- })
600
-
601
- const getOptimisticItem = usePromise<T>({
602
- timeout: 1200,
603
- })
604
-
605
- const query = useMutation({
606
- ...options?.mutationOptions,
607
- mutationFn: (data: Partial<T>) => {
608
- return this.options.createItem(data)
609
- },
610
- mutationKey: this.queryKeys.create,
611
- onMutate: async (data) => {
612
- options?.mutationOptions?.onMutate?.(data)
613
- if (!!tmpOptions?.current?.optimistic) {
614
- await this.queryClient.cancelQueries({ queryKey: this.queryKeys.list })
615
- const addedItem = {
616
- id: this.generateId(),
617
- ...data,
618
- } as T
619
- getOptimisticItem.resolve(addedItem)
620
-
621
- const addedId = this.extractKey(addedItem)
622
-
623
- this.addItem({
624
- item: addedItem,
625
- to: tmpOptions?.current?.appendTo || managerOptions.creation?.appendTo || 'start',
626
- onListsWithFilters: tmpOptions.current?.onListsWithFilters,
627
- })
628
-
629
- return {
630
- // previousData,
631
- addedId,
632
- }
633
- }
634
- },
635
- onError: (error, data, ctx: MutationCtx<T>) => {
636
- const isOptimistic = tmpOptions.current?.optimistic
637
-
638
- if (isOptimistic) {
639
- this.removeItem(ctx.addedId)
640
- }
641
- },
642
- onSuccess: (data) => {
643
- if (!tmpOptions.current?.optimistic) {
644
- this.addItem({
645
- item: data,
646
- to: tmpOptions?.current?.appendTo || managerOptions.creation?.appendTo || 'start',
647
- onListsWithFilters: tmpOptions?.current?.onListsWithFilters,
648
- })
649
- } else {
650
- this.updateItems(data)
651
- }
652
- },
653
- })
654
-
655
- const createItem = async (data: Partial<T>, options?: CreateOptions<T>) => {
656
- const prevOptions = { ...(tmpOptions.current ?? {}) }
657
-
658
- if (!!options) {
659
- tmpOptions.current = options
660
- }
661
-
662
- let res: T = null
663
-
664
- if (tmpOptions.current?.optimistic) {
665
- query.mutateAsync(data)
666
- res = await getOptimisticItem._await()
667
- } else {
668
- res = await query.mutateAsync(data)
669
- }
670
-
671
- if (!!options) {
672
- tmpOptions.current = prevOptions
673
- }
674
-
675
- return res
676
- }
677
-
678
- return {
679
- item: query.data,
680
- create: createItem,
681
- query,
682
- }
683
- }
684
-
685
- useUpdate(options?: UpdateOptions<T>) {
686
- const [managerOptions] = this.useOptions()
687
-
688
- const tmpOptions = useRef<UpdateOptions<T>>(options ?? managerOptions.update ?? {
689
- optimistic: false,
690
- })
691
-
692
- const getOptimisticItem = usePromise<T>({
693
- timeout: 1200,
694
- })
695
-
696
- const query = useMutation({
697
- ...options?.mutationOptions,
698
- mutationKey: this.queryKeys.update,
699
- onMutate: async (data) => {
700
- options?.mutationOptions?.onMutate?.(data)
701
- if (tmpOptions.current?.optimistic) {
702
-
703
- const prevItem = await this.getItem(data.id, {
704
- fetchOnNotFoud: false,
705
- })
706
-
707
- if (!prevItem) return
708
-
709
- const optimisticItem:T = {
710
- ...prevItem,
711
- ...data,
712
- }
713
-
714
- getOptimisticItem.resolve(optimisticItem)
715
-
716
- this.updateItems(optimisticItem)
717
-
718
- return {
719
- previousItem: prevItem,
720
- optimisticItem,
721
-
722
- } as MutationCtx<T>
723
- }
724
- },
725
- onError: (error, data, ctx: MutationCtx<T>) => {
726
- if (tmpOptions.current?.optimistic && !!ctx?.previousItem?.id) {
727
- this.updateItems(
728
- ctx.previousItem,
729
- )
730
- }
731
- },
732
- mutationFn: (data: Partial<T>) => {
733
- return this.options.updateItem(data)
734
- },
735
- onSuccess: (data) => {
736
- this.updateItems(data)
737
- },
738
- })
739
-
740
- const update = async (data: Partial<T>, options?: UpdateOptions<T>) => {
741
- const prevOptions = tmpOptions.current
742
- if (!!options) {
743
-
744
- tmpOptions.current = options
745
- }
746
-
747
- let res: T = null
748
-
749
- if (tmpOptions.current?.optimistic) {
750
- query.mutateAsync(data)
751
- res = await getOptimisticItem._await()
752
- } else {
753
-
754
- res = await query.mutateAsync(data)
755
- }
756
-
757
- if (!!options) {
758
- tmpOptions.current = prevOptions
759
- }
760
-
761
- return res
762
- }
763
-
764
- return {
765
- update,
766
- query,
767
- item: query.data,
768
- }
769
- }
770
-
771
- useDelete(options?: DeleteOptions<T>) {
772
-
773
- const [managerOptions] = this.useOptions()
774
-
775
- const tmpOptions = useRef<DeleteOptions<T>>(options ?? managerOptions?.deletion ?? {
776
- optimistic: false,
777
- })
778
-
779
- const getOptimisticItem = usePromise<T>({
780
- timeout: 1200,
781
- })
782
-
783
- const query = useMutation({
784
- ...options?.mutationOptions,
785
- mutationKey: this.queryKeys.delete,
786
- onMutate: async (data) => {
787
- options?.mutationOptions?.onMutate?.(data)
788
- if (tmpOptions.current?.optimistic) {
789
-
790
- const prevItem = await this.getItem(data.id, {
791
- fetchOnNotFoud: false,
792
- })
793
-
794
- getOptimisticItem.resolve(prevItem)
795
-
796
- const removedAt = await this.removeItem(data.id)
797
-
798
- if (!prevItem) return
799
-
800
- return {
801
- previousItem: prevItem,
802
- prevItemPages: removedAt,
803
- } as MutationCtx<T>
804
-
805
- }
806
- },
807
- mutationFn: (data: T) => {
808
- return this.options.deleteItem(data)
809
- },
810
- onError: (error, data, ctx: MutationCtx<T>) => {
811
- if (!!ctx?.previousItem?.id && tmpOptions.current?.optimistic) {
812
- this.addItem({
813
- item: ctx.previousItem,
814
- to: ctx.prevItemPages,
815
- })
816
- }
817
- },
818
- onSuccess: (data) => {
819
- if (!tmpOptions.current?.optimistic) {
820
- this.removeItem(data.id)
821
- }
822
- },
823
-
824
- })
825
-
826
- const _delete = async (data: T, options?: UpdateOptions<T>) => {
827
- const prevOptions = tmpOptions.current
828
- if (!!options) {
829
-
830
- tmpOptions.current = options
831
- }
832
-
833
- let prevItem = null
834
-
835
- if (tmpOptions.current?.optimistic) {
836
- query.mutateAsync(data)
837
- prevItem = await getOptimisticItem._await()
838
- } else {
839
- prevItem = await query.mutateAsync(data)
840
- }
841
-
842
- if (!!options) {
843
- tmpOptions.current = prevOptions
844
- }
845
-
846
- return prevItem
847
- }
848
-
849
- return {
850
- delete: _delete,
851
- query,
852
- }
853
- }
854
-
855
- async refreshItem(itemId: T['id']) {
856
- const newItem = await this.getItem(itemId, {
857
- fetchOnNotFoud: true,
858
- forceRefetch: true,
859
- })
860
-
861
- this.queryClient.setQueryData(this.queryKeyFor(itemId), old => {
862
- return newItem
863
- })
864
-
865
- this.updateItems(newItem)
866
-
867
- return newItem
868
- }
869
-
870
- async refresh(filters?: ExtraArgs) {
871
- if (!!filters) {
872
- const key = this.filteredQueryKey(filters)
873
- this.queryClient.refetchQueries({
874
- queryKey: key,
875
- })
876
-
877
- } else {
878
-
879
- this.queryClient.refetchQueries({
880
- queryKey: this.queryKeys.list,
881
-
882
- })
883
- }
884
- }
885
-
886
- setItem(item: T) {
887
- return this.updateItems(item)
888
- }
889
-
890
- use(options?: UseManagerArgs<T, ExtraArgs>) {
891
-
892
- const list = this.useList({
893
- filter: options?.filter,
894
- queryOptions: options?.listOptions?.queryOptions,
895
- limit: options?.limit,
896
- })
897
- const create = this.useCreate(options?.creation)
898
- const update = this.useUpdate(options?.update)
899
- const del = this.useDelete(options?.deletion)
900
-
901
- const queries = {
902
- create,
903
- update,
904
- del,
905
- }
906
-
907
- return {
908
- items: list.items,
909
- list,
910
- itemMap: list.itemMap,
911
- create: create.create,
912
- update: update.update,
913
- delete: del.delete,
914
- getNextPage: list.getNextPage,
915
- getPreviousPage: list.getPreviousPage,
916
- refreshItem: this.refreshItem.bind(this),
917
- setItem: this.setItem.bind(this),
918
- refresh: list.refresh,
919
- isRefreshing: list.isRefreshing,
920
- actions: this.actions,
921
- updatedAt: list.query.dataUpdatedAt,
922
- queries,
923
- }
924
- }
925
-
926
- setOptions(to: SettableOptions<QueryManagerOptions<T, ExtraArgs, Meta, Actions>>) {
927
- const {
928
- creation = {},
929
- update = {},
930
- deletion = {},
931
- limit,
932
- } = this.options
933
-
934
- const currentOptions = {
935
- creation,
936
- update,
937
- deletion,
938
- limit,
939
- }
940
-
941
- const o = deepMerge(currentOptions, to)
942
-
943
- this.options = {
944
- ...this.options,
945
- ...o,
946
- }
947
-
948
- this.meta = deepMerge(this.meta, to.meta)
949
-
950
- this.optionListeners.forEach((l) => l(this.options, this.meta))
951
- }
952
-
953
- }
954
-