@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.
- package/dist/factors/createQueryManager.d.ts +36 -0
- package/dist/factors/createQueryManager.d.ts.map +1 -0
- package/dist/factors/createQueryOperations.d.ts +35 -0
- package/dist/factors/createQueryOperations.d.ts.map +1 -0
- package/dist/factors/index.d.ts +3 -0
- package/dist/factors/index.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lib/Mutations.d.ts +103 -0
- package/dist/lib/Mutations.d.ts.map +1 -0
- package/dist/lib/QueryClientEnhanced/index.d.ts +41 -0
- package/dist/lib/QueryClientEnhanced/index.d.ts.map +1 -0
- package/dist/lib/QueryClientEnhanced/types.d.ts +51 -0
- package/dist/lib/QueryClientEnhanced/types.d.ts.map +1 -0
- package/dist/lib/QueryKeys.d.ts +173 -0
- package/dist/lib/QueryKeys.d.ts.map +1 -0
- package/dist/lib/QueryManager.d.ts +202 -0
- package/dist/lib/QueryManager.d.ts.map +1 -0
- package/dist/lib/QueryOperations/index.d.ts +228 -0
- package/dist/lib/QueryOperations/index.d.ts.map +1 -0
- package/dist/lib/QueryOperations/types.d.ts +42 -0
- package/dist/lib/QueryOperations/types.d.ts.map +1 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/types/core.d.ts +29 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/types/create.d.ts +21 -0
- package/dist/types/create.d.ts.map +1 -0
- package/dist/types/delete.d.ts +18 -0
- package/dist/types/delete.d.ts.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/list.d.ts +19 -0
- package/dist/types/list.d.ts.map +1 -0
- package/dist/types/retrieve.d.ts +17 -0
- package/dist/types/retrieve.d.ts.map +1 -0
- package/dist/types/update.d.ts +13 -0
- package/dist/types/update.d.ts.map +1 -0
- package/dist/types/utility.d.ts +23 -0
- package/dist/types/utility.d.ts.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/misc.d.ts +5 -0
- package/dist/utils/misc.d.ts.map +1 -0
- package/package.json +23 -8
- package/src/lib/Mutations.ts +30 -44
- package/src/lib/QueryClientEnhanced/index.ts +32 -4
- package/src/lib/QueryClientEnhanced/types.ts +25 -0
- package/src/lib/QueryKeys.ts +4 -2
- package/src/lib/QueryManager.ts +37 -33
- package/src/lib/QueryOperations/index.ts +11 -3
- package/src/lib/QueryOperations/types.ts +4 -3
- package/src/tests/setup.ts +14 -0
- package/src/types/core.ts +8 -1
- package/src/types/create.ts +10 -1
- package/src/types/delete.ts +8 -1
- package/src/types/list.ts +5 -0
- package/src/types/retrieve.ts +9 -0
- package/src/types/update.ts +3 -0
- package/src/types/utility.ts +5 -0
- package/src/utils/misc.ts +2 -0
- 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>
|
|
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>
|
|
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
|
package/src/tests/setup.ts
CHANGED
|
@@ -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>[]
|
package/src/types/create.ts
CHANGED
|
@@ -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
|
}
|
package/src/types/delete.ts
CHANGED
|
@@ -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
|
package/src/types/retrieve.ts
CHANGED
|
@@ -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
|
}
|
package/src/types/update.ts
CHANGED
|
@@ -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
|
}
|
package/src/types/utility.ts
CHANGED
|
@@ -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
|
-
}
|