@codeleap/query 6.2.3 → 6.8.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.
Files changed (62) hide show
  1. package/dist/factors/createQueryManager.d.ts +36 -0
  2. package/dist/factors/createQueryManager.d.ts.map +1 -0
  3. package/dist/factors/createQueryOperations.d.ts +35 -0
  4. package/dist/factors/createQueryOperations.d.ts.map +1 -0
  5. package/dist/factors/index.d.ts +3 -0
  6. package/dist/factors/index.d.ts.map +1 -0
  7. package/dist/index.d.ts +4 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/lib/Mutations.d.ts +103 -0
  10. package/dist/lib/Mutations.d.ts.map +1 -0
  11. package/dist/lib/QueryClientEnhanced/index.d.ts +41 -0
  12. package/dist/lib/QueryClientEnhanced/index.d.ts.map +1 -0
  13. package/dist/lib/QueryClientEnhanced/types.d.ts +51 -0
  14. package/dist/lib/QueryClientEnhanced/types.d.ts.map +1 -0
  15. package/dist/lib/QueryKeys.d.ts +173 -0
  16. package/dist/lib/QueryKeys.d.ts.map +1 -0
  17. package/dist/lib/QueryManager.d.ts +202 -0
  18. package/dist/lib/QueryManager.d.ts.map +1 -0
  19. package/dist/lib/QueryOperations/index.d.ts +228 -0
  20. package/dist/lib/QueryOperations/index.d.ts.map +1 -0
  21. package/dist/lib/QueryOperations/types.d.ts +42 -0
  22. package/dist/lib/QueryOperations/types.d.ts.map +1 -0
  23. package/dist/lib/index.d.ts +6 -0
  24. package/dist/lib/index.d.ts.map +1 -0
  25. package/dist/types/core.d.ts +29 -0
  26. package/dist/types/core.d.ts.map +1 -0
  27. package/dist/types/create.d.ts +21 -0
  28. package/dist/types/create.d.ts.map +1 -0
  29. package/dist/types/delete.d.ts +18 -0
  30. package/dist/types/delete.d.ts.map +1 -0
  31. package/dist/types/index.d.ts +8 -0
  32. package/dist/types/index.d.ts.map +1 -0
  33. package/dist/types/list.d.ts +19 -0
  34. package/dist/types/list.d.ts.map +1 -0
  35. package/dist/types/retrieve.d.ts +17 -0
  36. package/dist/types/retrieve.d.ts.map +1 -0
  37. package/dist/types/update.d.ts +13 -0
  38. package/dist/types/update.d.ts.map +1 -0
  39. package/dist/types/utility.d.ts +23 -0
  40. package/dist/types/utility.d.ts.map +1 -0
  41. package/dist/utils/index.d.ts +2 -0
  42. package/dist/utils/index.d.ts.map +1 -0
  43. package/dist/utils/misc.d.ts +5 -0
  44. package/dist/utils/misc.d.ts.map +1 -0
  45. package/package.json +23 -8
  46. package/src/lib/Mutations.ts +30 -44
  47. package/src/lib/QueryClientEnhanced/index.ts +32 -4
  48. package/src/lib/QueryClientEnhanced/types.ts +25 -0
  49. package/src/lib/QueryKeys.ts +4 -2
  50. package/src/lib/QueryManager.ts +37 -33
  51. package/src/lib/QueryOperations/index.ts +11 -3
  52. package/src/lib/QueryOperations/types.ts +4 -3
  53. package/src/tests/setup.ts +14 -0
  54. package/src/types/core.ts +8 -1
  55. package/src/types/create.ts +10 -1
  56. package/src/types/delete.ts +8 -1
  57. package/src/types/list.ts +5 -0
  58. package/src/types/retrieve.ts +9 -0
  59. package/src/types/update.ts +3 -0
  60. package/src/types/utility.ts +5 -0
  61. package/src/utils/misc.ts +2 -0
  62. package/package.json.bak +0 -27
@@ -1,11 +1,12 @@
1
1
  import { QueryClient } from '../../types'
2
+ import { QueryClientEnhanced } from '../QueryClientEnhanced'
2
3
 
3
4
  /**
4
5
  * Configuration options for QueryOperations
5
6
  */
6
7
  export type QueryOperationsOptions = {
7
8
  /** The React Query client instance */
8
- queryClient: QueryClient
9
+ queryClient: QueryClient | QueryClientEnhanced
9
10
  }
10
11
 
11
12
  /**
@@ -13,14 +14,14 @@ export type QueryOperationsOptions = {
13
14
  * @template T - The input data type
14
15
  * @template R - The return data type
15
16
  */
16
- export type MutationFn<T = any, R = any> = (data: T) => Promise<R> | R
17
+ export type MutationFn<T = any, R = any> = (data: T) => Promise<R>
17
18
 
18
19
  /**
19
20
  * Generic query function type
20
21
  * @template T - The parameters type
21
22
  * @template R - The return data type
22
23
  */
23
- export type QueryFn<T = any, R = any> = (params?: T) => Promise<R> | R
24
+ export type QueryFn<T = any, R = any> = (params?: T) => Promise<R>
24
25
 
25
26
  /**
26
27
  * Utility type to infer mutation function parameters
@@ -2,6 +2,7 @@ import { afterEach, beforeEach } from 'bun:test'
2
2
  import { QueryClient } from '@tanstack/react-query'
3
3
  import { cleanup } from '@testing-library/react'
4
4
 
5
+ /** Fixture entity used across `@codeleap/query` test suites. Satisfies `QueryItem` via the `id` field. */
5
6
  export interface TestUser {
6
7
  id: string
7
8
  name: string
@@ -10,11 +11,16 @@ export interface TestUser {
10
11
  createdAt: string
11
12
  }
12
13
 
14
+ /** Filter shape accepted by the mock list API for `TestUser` fixtures. */
13
15
  export interface TestUserFilters {
14
16
  status?: 'active' | 'inactive'
15
17
  search?: string
16
18
  }
17
19
 
20
+ /**
21
+ * Creates a `QueryClient` pre-configured for unit tests: retries disabled, zero garbage-collection time.
22
+ * Construct a fresh instance per test to prevent cache bleed between tests.
23
+ */
18
24
  export const createTestQueryClient = () => {
19
25
  return new QueryClient({
20
26
  defaultOptions: {
@@ -29,6 +35,7 @@ export const createTestQueryClient = () => {
29
35
  })
30
36
  }
31
37
 
38
+ /** Returns a single `TestUser` fixture. Pass `overrides` to pin specific fields; all others default to deterministic placeholder values. */
32
39
  export const createMockUser = (overrides: Partial<TestUser> = {}): TestUser => ({
33
40
  id: `user-${Date.now()}-${Math.random()}`,
34
41
  name: 'John Doe',
@@ -38,6 +45,7 @@ export const createMockUser = (overrides: Partial<TestUser> = {}): TestUser => (
38
45
  ...overrides,
39
46
  })
40
47
 
48
+ /** Returns an array of `count` distinct `TestUser` fixtures with sequential ids (`user-1`, `user-2`, …). */
41
49
  export const createMockUsers = (count: number): TestUser[] => {
42
50
  return Array.from({ length: count }, (_, i) => createMockUser({
43
51
  id: `user-${i + 1}`,
@@ -46,6 +54,11 @@ export const createMockUsers = (count: number): TestUser[] => {
46
54
  }))
47
55
  }
48
56
 
57
+ /**
58
+ * Returns a self-contained set of in-memory CRUD functions compatible with `QueryManagerOptions`.
59
+ * All five API functions share the same internal `users` array — mutations are reflected immediately in subsequent reads without any async delay.
60
+ * The returned `getUsersArray`, `addUser`, `clearUsers`, and `setUsers` helpers let tests seed or inspect state directly without going through the API layer.
61
+ */
49
62
  export const createMockApiFunctions = () => {
50
63
  const users: TestUser[] = []
51
64
 
@@ -116,4 +129,5 @@ afterEach(() => {
116
129
  cleanup()
117
130
  })
118
131
 
132
+ /** Pauses execution for `ms` milliseconds. Use in tests to allow async state updates to settle before asserting. */
119
133
  export const waitFor = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
package/src/types/core.ts CHANGED
@@ -1,22 +1,29 @@
1
1
  import { UseInfiniteQueryResult, useQueryClient } from '@tanstack/react-query'
2
+ import { QueryClientEnhanced } from '../lib'
2
3
 
4
+ /** Minimum shape required for any entity managed by QueryManager. */
3
5
  export type QueryItem = {
4
6
  id: string | number
5
7
  }
6
8
 
9
+ /** Cursor value used to request a specific page in an infinite list query. */
7
10
  export type PageParam = number
8
11
 
12
+ /** Raw page payload returned by `listFn` — a flat array of items for one page. */
9
13
  export type ListPaginationResponse<T extends QueryItem> = T[]
10
14
 
15
+ /** Constructor options for `QueryManager`. All `*Fn` fields are optional; omitting one disables the corresponding operation and its generated hooks. */
11
16
  export type QueryManagerOptions<T extends QueryItem, F> = {
12
17
  name: string
13
18
 
14
- queryClient: ReturnType<typeof useQueryClient>
19
+ queryClient: ReturnType<typeof useQueryClient> | QueryClientEnhanced
15
20
 
16
21
  listFn?: (limit: number, offset: number, filters: F) => Promise<ListPaginationResponse<T>>
17
22
 
23
+ /** Page size sent to `listFn`. Defaults to 10 when omitted. */
18
24
  listLimit?: number
19
25
 
26
+ /** Side-effect hook called on every render with the current infinite-list query result. Useful for syncing list state into external stores. */
20
27
  useListEffect?: (listQuery: UseInfiniteQueryResult<{
21
28
  pageParams: number[]
22
29
  pages: ListPaginationResponse<T>[]
@@ -2,15 +2,24 @@ import { UseMutationOptions } from '@tanstack/react-query'
2
2
  import { QueryItem } from './core'
3
3
  import { RemovedItemMap } from './utility'
4
4
 
5
+ /** Rollback context threaded through an optimistic create mutation. `tempId` identifies the placeholder item inserted before the server responds. */
5
6
  export type CreateMutationCtx = {
6
7
  tempId?: QueryItem['id']
7
8
  }
8
9
 
10
+ /** Options forwarded to React Query's `useMutation` for a create operation. `mutationKey` and `mutationFn` are managed internally. */
9
11
  export type CreateMutationOptions<T extends QueryItem, F> = Omit<
10
- UseMutationOptions<T, Error, Partial<T>, CreateMutationCtx>,
12
+ UseMutationOptions<T, Error, Partial<T>, CreateMutationCtx|undefined>,
11
13
  'mutationKey' | 'mutationFn'
12
14
  > & {
15
+ /** Insert a placeholder item immediately and replace it on success; roll back on error. */
13
16
  optimistic?: boolean
17
+ /** List query filters active at the time of the create, used to target the correct cached list for the optimistic insert. */
14
18
  listFilters?: F
19
+ /**
20
+ * Where to insert the item in the cached list.
21
+ * - `'start'` / `'end'` — prepend or append to the flat item array.
22
+ * - `RemovedItemMap` — re-insert at the exact page/index coordinates recorded during a previous delete (used internally for rollback).
23
+ */
15
24
  appendTo?: RemovedItemMap | 'start' | 'end'
16
25
  }
@@ -2,14 +2,21 @@ import { UseMutationOptions } from '@tanstack/react-query'
2
2
  import { QueryItem } from './core'
3
3
  import { RemovedItemMap } from './utility'
4
4
 
5
+ /**
6
+ * Rollback context captured before an optimistic delete.
7
+ * `removedAt` records the exact page/index coordinates of the removed item so it can be re-inserted at the same position if the mutation fails.
8
+ * `null` means the item was not found in any cached page.
9
+ */
5
10
  export type DeleteMutationCtx<T> = {
6
11
  previousItem: T | undefined
7
- removedAt: RemovedItemMap
12
+ removedAt: RemovedItemMap | null
8
13
  }
9
14
 
15
+ /** Options forwarded to React Query's `useMutation` for a delete operation. `mutationKey` and `mutationFn` are managed internally. */
10
16
  export type DeleteMutationOptions<T extends QueryItem, F> = Omit<
11
17
  UseMutationOptions<unknown, Error, T['id'], DeleteMutationCtx<T>>,
12
18
  'mutationKey' | 'mutationFn'
13
19
  > & {
20
+ /** Remove the item from every cached list page immediately and restore it on error. */
14
21
  optimistic?: boolean
15
22
  }
package/src/types/list.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { QueryKey, UseInfiniteQueryOptions } from '@tanstack/react-query'
2
2
  import { ListPaginationResponse, PageParam, QueryItem } from './core'
3
3
 
4
+ /**
5
+ * Normalised shape of the infinite-query cache entry.
6
+ * `allItems` is a convenience flat-merge of every page's items — use it for rendering; use `pages` when you need per-page boundaries.
7
+ */
4
8
  export type ListSelector<T extends QueryItem> = {
5
9
  pageParams: PageParam[]
6
10
  pages: ListPaginationResponse<T>[]
@@ -15,6 +19,7 @@ type InfiniteQueryOptions<T extends QueryItem> = UseInfiniteQueryOptions<
15
19
  PageParam
16
20
  >
17
21
 
22
+ /** Options accepted by the generated `useList` hook. Extends React Query's infinite-query options; `limit` and `filters` are forwarded to `listFn`. */
18
23
  export type ListQueryOptions<T extends QueryItem, F> = Partial<InfiniteQueryOptions<T>> & {
19
24
  limit?: number
20
25
  filters?: F
@@ -1,12 +1,21 @@
1
1
  import { QueryKey, UndefinedInitialDataOptions } from '@tanstack/react-query'
2
2
  import { QueryItem } from './core'
3
3
 
4
+ /** Pass-through options forwarded to React Query's `useQuery` for a retrieve query. `queryKey` and `queryFn` are managed internally and cannot be overridden. */
4
5
  export type RetrieveQueryOptions<T extends QueryItem> = Omit<
5
6
  UndefinedInitialDataOptions<T, Error, T, QueryKey>,
6
7
  'queryKey' | 'queryFn'
7
8
  >
8
9
 
9
10
  export type RetrieveDataOptions = {
11
+ /**
12
+ * When `true`, skips the network fetch and returns only what is already in the cache.
13
+ * When `false` (default), falls back to a network fetch if the cache is empty.
14
+ */
10
15
  onlyQueryData?: boolean
16
+ /**
17
+ * When `true`, searches all cached list pages for the item before issuing a dedicated retrieve request.
18
+ * Avoids a redundant round-trip when the item was already loaded by a list query.
19
+ */
11
20
  deepSearch?: boolean
12
21
  }
@@ -1,14 +1,17 @@
1
1
  import { UseMutationOptions } from '@tanstack/react-query'
2
2
  import { QueryItem } from './core'
3
3
 
4
+ /** Rollback context captured before an optimistic update is applied. Both fields are `undefined` when the item was not in cache at mutation time. */
4
5
  export type UpdateMutationCtx<T> = {
5
6
  previousItem: T | undefined
6
7
  optimisticItem: T | undefined
7
8
  }
8
9
 
10
+ /** Options forwarded to React Query's `useMutation` for an update operation. `mutationKey` and `mutationFn` are managed internally. */
9
11
  export type UpdateMutationOptions<T extends QueryItem, F> = Omit<
10
12
  UseMutationOptions<T, Error, Partial<T>, UpdateMutationCtx<T>>,
11
13
  'mutationKey' | 'mutationFn'
12
14
  > & {
15
+ /** Apply the updated fields to the cache immediately and revert to `previousItem` on error. */
13
16
  optimistic?: boolean
14
17
  }
@@ -1,19 +1,24 @@
1
1
  import { QueryItem } from './core';
2
2
  import { QueryKey, useQueryClient } from '@tanstack/react-query'
3
3
 
4
+ /** Alias for the React Query client instance type — avoids importing `useQueryClient` at every call site. */
4
5
  export type QueryClient = ReturnType<typeof useQueryClient>
5
6
 
7
+ /** An entity that may carry a client-generated `tempId` while an optimistic create is in-flight. */
6
8
  export type WithTempId<T extends QueryItem> = T & {
7
9
  tempId?: QueryItem['id']
8
10
  }
9
11
 
12
+ /** Exact location of an item inside the paginated cache: which page it lives on and its index within that page. */
10
13
  export type ItemPosition = {
11
14
  pageIndex: number
12
15
  itemIndex: number
13
16
  }
14
17
 
18
+ /** Sparse map of every cached list that contained a deleted item, together with the position it occupied. Used to re-insert the item on rollback. */
15
19
  export type RemovedItemMap = [QueryKey, ItemPosition][]
16
20
 
21
+ /** Standard DRF-style paginated envelope. Wrap your API response in this type when the backend uses `count / next / previous / results`. */
17
22
  export type PaginationResponse<T extends QueryItem> = {
18
23
  count: number
19
24
  next: string
package/src/utils/misc.ts CHANGED
@@ -36,8 +36,10 @@ function uuidV4() {
36
36
  return uuid
37
37
  }
38
38
 
39
+ /** Prefix used on every optimistically-created item id. Check `id.startsWith(tempIdPrefix)` to distinguish placeholder items from server-assigned ids. */
39
40
  export const tempIdPrefix = 'temp-id'
40
41
 
42
+ /** Returns a unique placeholder id for optimistic creates. The format is `temp-id-<uuidv4>` and is guaranteed never to collide with server-assigned ids. */
41
43
  export const generateTempId = () => {
42
44
  return tempIdPrefix + '-' + uuidV4()
43
45
  }
package/package.json.bak DELETED
@@ -1,27 +0,0 @@
1
- {
2
- "name": "@codeleap/query",
3
- "version": "6.2.3",
4
- "main": "src/index.ts",
5
- "license": "UNLICENSED",
6
- "repository": {
7
- "url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
8
- "type": "git",
9
- "directory": "packages/query"
10
- },
11
- "devDependencies": {
12
- "@codeleap/config": "workspace:*",
13
- "@codeleap/types": "workspace:*",
14
- "ts-node-dev": "1.1.8"
15
- },
16
- "scripts": {
17
- "build": "echo 'No build needed'"
18
- },
19
- "peerDependencies": {
20
- "@codeleap/types": "workspace:*",
21
- "typescript": "5.5.2",
22
- "@tanstack/react-query": "5.89.0"
23
- },
24
- "dependencies": {
25
- "fast-deep-equal": "3.1.3"
26
- }
27
- }