@demokit-ai/tanstack-query 0.1.0 → 0.2.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/README.md +238 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# @demokit-ai/tanstack-query
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
TanStack Query v5 adapter for DemoKit - mock queries and mutations for demo mode.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @demokit-ai/tanstack-query @demokit-ai/core @demokit-ai/react @tanstack/react-query
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- **Demo Query Client** - Intercept queries and return fixtures
|
|
17
|
+
- **Mutation Mocking** - Mock mutation operations in demo mode
|
|
18
|
+
- **Key Matching** - Pattern-based query key matching
|
|
19
|
+
- **Provider Pattern** - Centralized fixture management
|
|
20
|
+
- **Optimistic Updates** - Demo-aware optimistic update handling
|
|
21
|
+
- Full TypeScript support
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Demo Query Client
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
29
|
+
import { createDemoQueryClient } from '@demokit-ai/tanstack-query'
|
|
30
|
+
|
|
31
|
+
const queryClient = createDemoQueryClient({
|
|
32
|
+
isEnabled: () => localStorage.getItem('demoMode') === 'true',
|
|
33
|
+
fixtures: {
|
|
34
|
+
users: [
|
|
35
|
+
{ id: '1', name: 'Demo User' },
|
|
36
|
+
{ id: '2', name: 'Another User' },
|
|
37
|
+
],
|
|
38
|
+
'users/:id': ({ params }) => ({
|
|
39
|
+
id: params.id,
|
|
40
|
+
name: 'Demo User',
|
|
41
|
+
email: 'demo@example.com',
|
|
42
|
+
}),
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
function App() {
|
|
47
|
+
return (
|
|
48
|
+
<QueryClientProvider client={queryClient}>
|
|
49
|
+
<YourApp />
|
|
50
|
+
</QueryClientProvider>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Using with useQuery
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { useQuery } from '@tanstack/react-query'
|
|
59
|
+
|
|
60
|
+
function UserList() {
|
|
61
|
+
const { data, isLoading } = useQuery({
|
|
62
|
+
queryKey: ['users'],
|
|
63
|
+
queryFn: () => fetch('/api/users').then((r) => r.json()),
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
// In demo mode, returns fixtures automatically
|
|
67
|
+
if (isLoading) return <div>Loading...</div>
|
|
68
|
+
return <ul>{data?.map((u) => <li key={u.id}>{u.name}</li>)}</ul>
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Provider Pattern
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { DemoQueryProvider, useDemoQuery } from '@demokit-ai/tanstack-query'
|
|
76
|
+
|
|
77
|
+
const fixtures = {
|
|
78
|
+
users: [{ id: '1', name: 'Demo User' }],
|
|
79
|
+
products: [{ id: '1', name: 'Demo Product', price: 99.99 }],
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function App() {
|
|
83
|
+
return (
|
|
84
|
+
<DemoQueryProvider fixtures={fixtures} enabled>
|
|
85
|
+
<YourApp />
|
|
86
|
+
<DemoControls />
|
|
87
|
+
</DemoQueryProvider>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function DemoControls() {
|
|
92
|
+
const { enabled, toggle, setFixture } = useDemoQuery()
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div>
|
|
96
|
+
<button onClick={toggle}>Demo: {enabled ? 'ON' : 'OFF'}</button>
|
|
97
|
+
<button onClick={() => setFixture('custom', { custom: true })}>
|
|
98
|
+
Add Custom Fixture
|
|
99
|
+
</button>
|
|
100
|
+
</div>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Mutation Mocking
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
109
|
+
import { createDemoMutation } from '@demokit-ai/tanstack-query'
|
|
110
|
+
|
|
111
|
+
function CreateUser() {
|
|
112
|
+
const queryClient = useQueryClient()
|
|
113
|
+
|
|
114
|
+
const mutation = useMutation({
|
|
115
|
+
mutationFn: createDemoMutation({
|
|
116
|
+
mutationFn: (data) =>
|
|
117
|
+
fetch('/api/users', {
|
|
118
|
+
method: 'POST',
|
|
119
|
+
body: JSON.stringify(data),
|
|
120
|
+
}).then((r) => r.json()),
|
|
121
|
+
isEnabled: () => true,
|
|
122
|
+
fixture: (variables) => ({
|
|
123
|
+
id: 'new-id',
|
|
124
|
+
...variables,
|
|
125
|
+
created: true,
|
|
126
|
+
}),
|
|
127
|
+
}),
|
|
128
|
+
onSuccess: () => {
|
|
129
|
+
queryClient.invalidateQueries({ queryKey: ['users'] })
|
|
130
|
+
},
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<button
|
|
135
|
+
onClick={() => mutation.mutate({ name: 'New User' })}
|
|
136
|
+
disabled={mutation.isPending}
|
|
137
|
+
>
|
|
138
|
+
Create User
|
|
139
|
+
</button>
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Dynamic Fixtures
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
const fixtures = {
|
|
148
|
+
// Static fixture
|
|
149
|
+
config: { version: '1.0', features: ['demo'] },
|
|
150
|
+
|
|
151
|
+
// Dynamic fixture based on query key
|
|
152
|
+
'users/:id': ({ params }) => ({
|
|
153
|
+
id: params.id,
|
|
154
|
+
name: `User ${params.id}`,
|
|
155
|
+
email: `user${params.id}@example.com`,
|
|
156
|
+
}),
|
|
157
|
+
|
|
158
|
+
// Function fixture with full context
|
|
159
|
+
search: ({ queryKey }) => {
|
|
160
|
+
const [, { query }] = queryKey
|
|
161
|
+
return [
|
|
162
|
+
{ id: '1', title: `Result for: ${query}` },
|
|
163
|
+
]
|
|
164
|
+
},
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Query Key Matching
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
const fixtures = {
|
|
172
|
+
// Exact match
|
|
173
|
+
users: [...],
|
|
174
|
+
|
|
175
|
+
// Parameter matching
|
|
176
|
+
'users/:id': ({ params }) => ({ id: params.id }),
|
|
177
|
+
|
|
178
|
+
// Nested keys (arrays)
|
|
179
|
+
'users/:id/orders': ({ params }) => [
|
|
180
|
+
{ id: '1', userId: params.id, total: 99.99 },
|
|
181
|
+
],
|
|
182
|
+
|
|
183
|
+
// Wildcard matching
|
|
184
|
+
'users/*': ({ queryKey }) => ({
|
|
185
|
+
path: queryKey.join('/'),
|
|
186
|
+
}),
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## API Reference
|
|
191
|
+
|
|
192
|
+
### `createDemoQueryClient(options)`
|
|
193
|
+
|
|
194
|
+
Create a demo-aware QueryClient.
|
|
195
|
+
|
|
196
|
+
Options:
|
|
197
|
+
- `isEnabled` - Function to check if demo mode is enabled
|
|
198
|
+
- `fixtures` - Fixture definitions by query key pattern
|
|
199
|
+
- `delay` - Simulated delay in milliseconds
|
|
200
|
+
- `defaultOptions` - Default QueryClient options
|
|
201
|
+
|
|
202
|
+
### `DemoQueryProvider`
|
|
203
|
+
|
|
204
|
+
Props:
|
|
205
|
+
- `fixtures` - Fixture definitions
|
|
206
|
+
- `enabled` - Whether demo mode is enabled
|
|
207
|
+
- `delay` - Simulated delay in milliseconds
|
|
208
|
+
- `children` - React children
|
|
209
|
+
|
|
210
|
+
### `useDemoQuery()`
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
- `enabled` - Whether demo mode is enabled
|
|
214
|
+
- `toggle()` - Toggle demo mode
|
|
215
|
+
- `fixtures` - Current fixtures
|
|
216
|
+
- `setFixture(key, fixture)` - Set a fixture
|
|
217
|
+
- `removeFixture(key)` - Remove a fixture
|
|
218
|
+
- `clearFixtures()` - Clear all fixtures
|
|
219
|
+
|
|
220
|
+
### `createDemoMutation(options)`
|
|
221
|
+
|
|
222
|
+
Create a demo-aware mutation function.
|
|
223
|
+
|
|
224
|
+
Options:
|
|
225
|
+
- `mutationFn` - The real mutation function
|
|
226
|
+
- `isEnabled` - Function to check if demo mode is enabled
|
|
227
|
+
- `fixture` - Mutation fixture (static or function)
|
|
228
|
+
- `delay` - Simulated delay in milliseconds
|
|
229
|
+
|
|
230
|
+
### `createQueryKeyMatcher(fixtures)`
|
|
231
|
+
|
|
232
|
+
Create a matcher function for query keys.
|
|
233
|
+
|
|
234
|
+
Returns a function that takes a query key and returns the matching fixture.
|
|
235
|
+
|
|
236
|
+
## License
|
|
237
|
+
|
|
238
|
+
MIT
|