@zenstackhq/tanstack-query 3.0.0-beta.17 → 3.0.0-beta.18
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/.turbo/turbo-build.log +27 -13
- package/dist/react.cjs +35 -33
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +26 -106
- package/dist/react.d.ts +26 -106
- package/dist/react.js +35 -33
- package/dist/react.js.map +1 -1
- package/dist/svelte.cjs +1224 -0
- package/dist/svelte.cjs.map +1 -0
- package/dist/svelte.d.cts +381 -0
- package/dist/svelte.d.ts +381 -0
- package/dist/svelte.js +1183 -0
- package/dist/svelte.js.map +1 -0
- package/dist/types-BRIDXxNC.d.cts +92 -0
- package/dist/types-BRIDXxNC.d.ts +92 -0
- package/dist/vue.cjs +1192 -0
- package/dist/vue.cjs.map +1 -0
- package/dist/vue.d.cts +382 -0
- package/dist/vue.d.ts +382 -0
- package/dist/vue.js +1152 -0
- package/dist/vue.js.map +1 -0
- package/package.json +43 -11
- package/src/react.ts +168 -155
- package/src/svelte.ts +483 -0
- package/src/utils/common.ts +4 -13
- package/src/utils/types.ts +13 -0
- package/src/vue.ts +429 -0
- package/test/react-typing-test.ts +109 -0
- package/test/schemas/basic/input.ts +40 -0
- package/test/schemas/basic/models.ts +2 -0
- package/test/schemas/basic/schema-lite.ts +48 -0
- package/test/schemas/basic/schema.zmodel +11 -1
- package/test/svelte-typing-test.ts +106 -0
- package/test/vue-typing-test.ts +107 -0
- package/tsup.config.ts +2 -0
package/src/svelte.ts
ADDED
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createInfiniteQuery,
|
|
3
|
+
createMutation,
|
|
4
|
+
createQuery,
|
|
5
|
+
useQueryClient,
|
|
6
|
+
type CreateInfiniteQueryOptions,
|
|
7
|
+
type CreateInfiniteQueryResult,
|
|
8
|
+
type CreateMutationOptions,
|
|
9
|
+
type CreateMutationResult,
|
|
10
|
+
type CreateQueryOptions,
|
|
11
|
+
type CreateQueryResult,
|
|
12
|
+
type DefaultError,
|
|
13
|
+
type InfiniteData,
|
|
14
|
+
type QueryFunction,
|
|
15
|
+
type QueryKey,
|
|
16
|
+
type StoreOrVal,
|
|
17
|
+
} from '@tanstack/svelte-query';
|
|
18
|
+
import { lowerCaseFirst } from '@zenstackhq/common-helpers';
|
|
19
|
+
import type {
|
|
20
|
+
AggregateArgs,
|
|
21
|
+
AggregateResult,
|
|
22
|
+
BatchResult,
|
|
23
|
+
CountArgs,
|
|
24
|
+
CountResult,
|
|
25
|
+
CreateArgs,
|
|
26
|
+
CreateManyAndReturnArgs,
|
|
27
|
+
CreateManyArgs,
|
|
28
|
+
DeleteArgs,
|
|
29
|
+
DeleteManyArgs,
|
|
30
|
+
FindArgs,
|
|
31
|
+
FindUniqueArgs,
|
|
32
|
+
GroupByArgs,
|
|
33
|
+
GroupByResult,
|
|
34
|
+
ModelResult,
|
|
35
|
+
SelectIncludeOmit,
|
|
36
|
+
SelectSubset,
|
|
37
|
+
Subset,
|
|
38
|
+
UpdateArgs,
|
|
39
|
+
UpdateManyAndReturnArgs,
|
|
40
|
+
UpdateManyArgs,
|
|
41
|
+
UpsertArgs,
|
|
42
|
+
} from '@zenstackhq/orm';
|
|
43
|
+
import type { GetModels, SchemaDef } from '@zenstackhq/schema';
|
|
44
|
+
import { getContext, setContext } from 'svelte';
|
|
45
|
+
import { derived, get, type Readable } from 'svelte/store';
|
|
46
|
+
import {
|
|
47
|
+
fetcher,
|
|
48
|
+
getQueryKey,
|
|
49
|
+
makeUrl,
|
|
50
|
+
marshal,
|
|
51
|
+
setupInvalidation,
|
|
52
|
+
setupOptimisticUpdate,
|
|
53
|
+
type APIContext,
|
|
54
|
+
type ExtraMutationOptions,
|
|
55
|
+
type ExtraQueryOptions,
|
|
56
|
+
} from './utils/common';
|
|
57
|
+
import type { TrimDelegateModelOperations } from './utils/types';
|
|
58
|
+
|
|
59
|
+
export type { FetchFn } from './utils/common';
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The default query endpoint.
|
|
63
|
+
*/
|
|
64
|
+
export const DEFAULT_QUERY_ENDPOINT = '/api/model';
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Key for setting and getting the global query context.
|
|
68
|
+
*/
|
|
69
|
+
export const SvelteQueryContextKey = 'zenstack-svelte-query-context';
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Set context for query settings.
|
|
73
|
+
*
|
|
74
|
+
* @deprecated use {@link setQuerySettingsContext} instead.
|
|
75
|
+
*/
|
|
76
|
+
export function setHooksContext(context: APIContext) {
|
|
77
|
+
setContext(SvelteQueryContextKey, context);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Set context for query settings.
|
|
82
|
+
*/
|
|
83
|
+
export function setQuerySettingsContext(context: APIContext) {
|
|
84
|
+
setContext(SvelteQueryContextKey, context);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getQuerySettings() {
|
|
88
|
+
const { endpoint, ...rest } = getContext<APIContext>(SvelteQueryContextKey) ?? {};
|
|
89
|
+
return { endpoint: endpoint ?? DEFAULT_QUERY_ENDPOINT, ...rest };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export type ModelQueryOptions<T> = Omit<CreateQueryOptions<T, DefaultError>, 'queryKey'> & ExtraQueryOptions;
|
|
93
|
+
|
|
94
|
+
export type ModelQueryResult<T> = Readable<UnwrapStore<CreateQueryResult<T, DefaultError>> & { queryKey: QueryKey }>;
|
|
95
|
+
|
|
96
|
+
export type ModelInfiniteQueryOptions<T> = Omit<
|
|
97
|
+
CreateInfiniteQueryOptions<T, DefaultError, InfiniteData<T>>,
|
|
98
|
+
'queryKey' | 'initialPageParam'
|
|
99
|
+
>;
|
|
100
|
+
|
|
101
|
+
export type ModelInfiniteQueryResult<T> = Readable<
|
|
102
|
+
UnwrapStore<CreateInfiniteQueryResult<T, DefaultError>> & {
|
|
103
|
+
queryKey: QueryKey;
|
|
104
|
+
}
|
|
105
|
+
>;
|
|
106
|
+
|
|
107
|
+
export type ModelMutationOptions<T, TArgs> = Omit<CreateMutationOptions<T, DefaultError, TArgs>, 'mutationFn'> &
|
|
108
|
+
ExtraMutationOptions;
|
|
109
|
+
|
|
110
|
+
export type ModelMutationResult<T, TArgs> = CreateMutationResult<T, DefaultError, TArgs>;
|
|
111
|
+
|
|
112
|
+
export type ModelMutationModelResult<
|
|
113
|
+
Schema extends SchemaDef,
|
|
114
|
+
Model extends GetModels<Schema>,
|
|
115
|
+
TArgs extends SelectIncludeOmit<Schema, Model, boolean>,
|
|
116
|
+
Array extends boolean = false,
|
|
117
|
+
> = Readable<
|
|
118
|
+
Omit<UnwrapStore<ModelMutationResult<ModelResult<Schema, Model, TArgs>, TArgs>>, 'mutateAsync'> & {
|
|
119
|
+
mutateAsync<T extends TArgs>(
|
|
120
|
+
args: T,
|
|
121
|
+
options?: ModelMutationOptions<ModelResult<Schema, Model, T>, T>,
|
|
122
|
+
): Promise<Array extends true ? ModelResult<Schema, Model, T>[] : ModelResult<Schema, Model, T>>;
|
|
123
|
+
}
|
|
124
|
+
>;
|
|
125
|
+
|
|
126
|
+
export type ClientHooks<Schema extends SchemaDef> = {
|
|
127
|
+
[Model in GetModels<Schema> as `${Uncapitalize<Model>}`]: ModelQueryHooks<Schema, Model>;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Note that we can potentially use TypeScript's mapped type to directly map from ORM contract, but that seems
|
|
131
|
+
// to significantly slow down tsc performance ...
|
|
132
|
+
export type ModelQueryHooks<Schema extends SchemaDef, Model extends GetModels<Schema>> = TrimDelegateModelOperations<
|
|
133
|
+
Schema,
|
|
134
|
+
Model,
|
|
135
|
+
{
|
|
136
|
+
useFindUnique<T extends FindUniqueArgs<Schema, Model>>(
|
|
137
|
+
args: SelectSubset<T, FindUniqueArgs<Schema, Model>>,
|
|
138
|
+
options?: ModelQueryOptions<ModelResult<Schema, Model, T> | null>,
|
|
139
|
+
): ModelQueryResult<ModelResult<Schema, Model, T> | null>;
|
|
140
|
+
|
|
141
|
+
useFindFirst<T extends FindArgs<Schema, Model, false>>(
|
|
142
|
+
args?: SelectSubset<T, FindArgs<Schema, Model, false>>,
|
|
143
|
+
options?: ModelQueryOptions<ModelResult<Schema, Model, T> | null>,
|
|
144
|
+
): ModelQueryResult<ModelResult<Schema, Model, T> | null>;
|
|
145
|
+
|
|
146
|
+
useFindMany<T extends FindArgs<Schema, Model, true>>(
|
|
147
|
+
args?: SelectSubset<T, FindArgs<Schema, Model, true>>,
|
|
148
|
+
options?: ModelQueryOptions<ModelResult<Schema, Model, T>[]>,
|
|
149
|
+
): ModelQueryResult<ModelResult<Schema, Model, T>[]>;
|
|
150
|
+
|
|
151
|
+
useInfiniteFindMany<T extends FindArgs<Schema, Model, true>>(
|
|
152
|
+
args?: SelectSubset<T, FindArgs<Schema, Model, true>>,
|
|
153
|
+
options?: ModelInfiniteQueryOptions<ModelResult<Schema, Model, T>[]>,
|
|
154
|
+
): ModelInfiniteQueryResult<InfiniteData<ModelResult<Schema, Model, T>[]>>;
|
|
155
|
+
|
|
156
|
+
useCreate<T extends CreateArgs<Schema, Model>>(
|
|
157
|
+
options?: ModelMutationOptions<ModelResult<Schema, Model, T>, T>,
|
|
158
|
+
): ModelMutationModelResult<Schema, Model, T>;
|
|
159
|
+
|
|
160
|
+
useCreateMany<T extends CreateManyArgs<Schema, Model>>(
|
|
161
|
+
options?: ModelMutationOptions<BatchResult, T>,
|
|
162
|
+
): ModelMutationResult<BatchResult, T>;
|
|
163
|
+
|
|
164
|
+
useCreateManyAndReturn<T extends CreateManyAndReturnArgs<Schema, Model>>(
|
|
165
|
+
options?: ModelMutationOptions<ModelResult<Schema, Model, T>[], T>,
|
|
166
|
+
): ModelMutationModelResult<Schema, Model, T, true>;
|
|
167
|
+
|
|
168
|
+
useUpdate<T extends UpdateArgs<Schema, Model>>(
|
|
169
|
+
options?: ModelMutationOptions<ModelResult<Schema, Model, T>, T>,
|
|
170
|
+
): ModelMutationModelResult<Schema, Model, T>;
|
|
171
|
+
|
|
172
|
+
useUpdateMany<T extends UpdateManyArgs<Schema, Model>>(
|
|
173
|
+
options?: ModelMutationOptions<BatchResult, T>,
|
|
174
|
+
): ModelMutationResult<BatchResult, T>;
|
|
175
|
+
|
|
176
|
+
useUpdateManyAndReturn<T extends UpdateManyAndReturnArgs<Schema, Model>>(
|
|
177
|
+
options?: ModelMutationOptions<ModelResult<Schema, Model, T>[], T>,
|
|
178
|
+
): ModelMutationModelResult<Schema, Model, T, true>;
|
|
179
|
+
|
|
180
|
+
useUpsert<T extends UpsertArgs<Schema, Model>>(
|
|
181
|
+
options?: ModelMutationOptions<ModelResult<Schema, Model, T>, T>,
|
|
182
|
+
): ModelMutationModelResult<Schema, Model, T>;
|
|
183
|
+
|
|
184
|
+
useDelete<T extends DeleteArgs<Schema, Model>>(
|
|
185
|
+
options?: ModelMutationOptions<ModelResult<Schema, Model, T>, T>,
|
|
186
|
+
): ModelMutationModelResult<Schema, Model, T>;
|
|
187
|
+
|
|
188
|
+
useDeleteMany<T extends DeleteManyArgs<Schema, Model>>(
|
|
189
|
+
options?: ModelMutationOptions<BatchResult, T>,
|
|
190
|
+
): ModelMutationResult<BatchResult, T>;
|
|
191
|
+
|
|
192
|
+
useCount<T extends CountArgs<Schema, Model>>(
|
|
193
|
+
args?: Subset<T, CountArgs<Schema, Model>>,
|
|
194
|
+
options?: ModelQueryOptions<CountResult<Schema, Model, T>>,
|
|
195
|
+
): ModelQueryResult<CountResult<Schema, Model, T>>;
|
|
196
|
+
|
|
197
|
+
useAggregate<T extends AggregateArgs<Schema, Model>>(
|
|
198
|
+
args: Subset<T, AggregateArgs<Schema, Model>>,
|
|
199
|
+
options?: ModelQueryOptions<AggregateResult<Schema, Model, T>>,
|
|
200
|
+
): ModelQueryResult<AggregateResult<Schema, Model, T>>;
|
|
201
|
+
|
|
202
|
+
useGroupBy<T extends GroupByArgs<Schema, Model>>(
|
|
203
|
+
args: Subset<T, GroupByArgs<Schema, Model>>,
|
|
204
|
+
options?: ModelQueryOptions<GroupByResult<Schema, Model, T>>,
|
|
205
|
+
): ModelQueryResult<GroupByResult<Schema, Model, T>>;
|
|
206
|
+
}
|
|
207
|
+
>;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Gets data query hooks for all models in the schema.
|
|
211
|
+
*/
|
|
212
|
+
export function useClientQueries<Schema extends SchemaDef>(schema: Schema): ClientHooks<Schema> {
|
|
213
|
+
return Object.keys(schema.models).reduce((acc, model) => {
|
|
214
|
+
(acc as any)[lowerCaseFirst(model)] = useModelQueries(schema, model as GetModels<Schema>);
|
|
215
|
+
return acc;
|
|
216
|
+
}, {} as ClientHooks<Schema>);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Gets data query hooks for a specific model in the schema.
|
|
221
|
+
*/
|
|
222
|
+
export function useModelQueries<Schema extends SchemaDef, Model extends GetModels<Schema>>(
|
|
223
|
+
schema: Schema,
|
|
224
|
+
model: Model,
|
|
225
|
+
): ModelQueryHooks<Schema, Model> {
|
|
226
|
+
const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase());
|
|
227
|
+
if (!modelDef) {
|
|
228
|
+
throw new Error(`Model "${model}" not found in schema`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const modelName = modelDef.name;
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
useFindUnique: (args: any, options?: any) => {
|
|
235
|
+
return useInternalQuery(schema, modelName, 'findUnique', args, options);
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
useFindFirst: (args: any, options?: any) => {
|
|
239
|
+
return useInternalQuery(schema, modelName, 'findFirst', args, options);
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
useFindMany: (args: any, options?: any) => {
|
|
243
|
+
return useInternalQuery(schema, modelName, 'findMany', args, options);
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
useInfiniteFindMany: (args: any, options?: any) => {
|
|
247
|
+
return useInternalInfiniteQuery(schema, modelName, 'findMany', args, options);
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
useCreate: (options?: any) => {
|
|
251
|
+
return useInternalMutation(schema, modelName, 'POST', 'create', options);
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
useCreateMany: (options?: any) => {
|
|
255
|
+
return useInternalMutation(schema, modelName, 'POST', 'createMany', options);
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
useCreateManyAndReturn: (options?: any) => {
|
|
259
|
+
return useInternalMutation(schema, modelName, 'POST', 'createManyAndReturn', options);
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
useUpdate: (options?: any) => {
|
|
263
|
+
return useInternalMutation(schema, modelName, 'PUT', 'update', options);
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
useUpdateMany: (options?: any) => {
|
|
267
|
+
return useInternalMutation(schema, modelName, 'PUT', 'updateMany', options);
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
useUpdateManyAndReturn: (options?: any) => {
|
|
271
|
+
return useInternalMutation(schema, modelName, 'PUT', 'updateManyAndReturn', options);
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
useUpsert: (options?: any) => {
|
|
275
|
+
return useInternalMutation(schema, modelName, 'POST', 'upsert', options);
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
useDelete: (options?: any) => {
|
|
279
|
+
return useInternalMutation(schema, modelName, 'DELETE', 'delete', options);
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
useDeleteMany: (options?: any) => {
|
|
283
|
+
return useInternalMutation(schema, modelName, 'DELETE', 'deleteMany', options);
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
useCount: (args: any, options?: any) => {
|
|
287
|
+
return useInternalQuery(schema, modelName, 'count', args, options);
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
useAggregate: (args: any, options?: any) => {
|
|
291
|
+
return useInternalQuery(schema, modelName, 'aggregate', args, options);
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
useGroupBy: (args: any, options?: any) => {
|
|
295
|
+
return useInternalQuery(schema, modelName, 'groupBy', args, options);
|
|
296
|
+
},
|
|
297
|
+
} as ModelQueryHooks<Schema, Model>;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export function useInternalQuery<TQueryFnData, TData>(
|
|
301
|
+
_schema: SchemaDef,
|
|
302
|
+
model: string,
|
|
303
|
+
operation: string,
|
|
304
|
+
args?: StoreOrVal<unknown>,
|
|
305
|
+
options?: StoreOrVal<Omit<CreateQueryOptions<TQueryFnData, DefaultError, TData>, 'queryKey'> & ExtraQueryOptions>,
|
|
306
|
+
) {
|
|
307
|
+
const { endpoint, fetch } = getQuerySettings();
|
|
308
|
+
const argsValue = unwrapStore(args);
|
|
309
|
+
const reqUrl = makeUrl(endpoint, model, operation, argsValue);
|
|
310
|
+
const optionsValue = unwrapStore(options);
|
|
311
|
+
const queryKey = getQueryKey(model, operation, argsValue, {
|
|
312
|
+
infinite: false,
|
|
313
|
+
optimisticUpdate: optionsValue?.optimisticUpdate !== false,
|
|
314
|
+
});
|
|
315
|
+
const queryFn: QueryFunction<TQueryFnData, QueryKey, unknown> = ({ signal }) =>
|
|
316
|
+
fetcher<TQueryFnData>(reqUrl, { signal }, fetch);
|
|
317
|
+
|
|
318
|
+
let mergedOpt: any;
|
|
319
|
+
if (isStore(options)) {
|
|
320
|
+
// options is store
|
|
321
|
+
mergedOpt = derived([options], ([$opt]) => {
|
|
322
|
+
return {
|
|
323
|
+
queryKey,
|
|
324
|
+
queryFn,
|
|
325
|
+
...($opt as object),
|
|
326
|
+
};
|
|
327
|
+
});
|
|
328
|
+
} else {
|
|
329
|
+
// options is value
|
|
330
|
+
mergedOpt = {
|
|
331
|
+
queryKey,
|
|
332
|
+
queryFn,
|
|
333
|
+
...options,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const result = createQuery<TQueryFnData, DefaultError, TData>(mergedOpt);
|
|
338
|
+
return derived(result, (r) => ({
|
|
339
|
+
queryKey,
|
|
340
|
+
...r,
|
|
341
|
+
}));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export function useInternalInfiniteQuery<TQueryFnData, TData>(
|
|
345
|
+
_schema: SchemaDef,
|
|
346
|
+
model: string,
|
|
347
|
+
operation: string,
|
|
348
|
+
args: StoreOrVal<unknown>,
|
|
349
|
+
options:
|
|
350
|
+
| StoreOrVal<
|
|
351
|
+
Omit<
|
|
352
|
+
CreateInfiniteQueryOptions<TQueryFnData, DefaultError, InfiniteData<TData>>,
|
|
353
|
+
'queryKey' | 'initialPageParam'
|
|
354
|
+
>
|
|
355
|
+
>
|
|
356
|
+
| undefined,
|
|
357
|
+
) {
|
|
358
|
+
options = options ?? { getNextPageParam: () => undefined };
|
|
359
|
+
const { endpoint, fetch } = getQuerySettings();
|
|
360
|
+
const argsValue = unwrapStore(args);
|
|
361
|
+
const queryKey = getQueryKey(model, operation, argsValue, { infinite: true, optimisticUpdate: false });
|
|
362
|
+
const queryFn: QueryFunction<TQueryFnData, QueryKey, unknown> = ({ pageParam, signal }) =>
|
|
363
|
+
fetcher<TQueryFnData>(makeUrl(endpoint, model, operation, pageParam ?? argsValue), { signal }, fetch);
|
|
364
|
+
|
|
365
|
+
let mergedOpt: StoreOrVal<CreateInfiniteQueryOptions<TQueryFnData, DefaultError, InfiniteData<TData>>>;
|
|
366
|
+
if (isStore(options)) {
|
|
367
|
+
// options is store
|
|
368
|
+
mergedOpt = derived([options], ([$opt]) => {
|
|
369
|
+
return {
|
|
370
|
+
queryKey,
|
|
371
|
+
queryFn,
|
|
372
|
+
initialPageParam: argsValue,
|
|
373
|
+
...$opt,
|
|
374
|
+
};
|
|
375
|
+
});
|
|
376
|
+
} else {
|
|
377
|
+
// options is value
|
|
378
|
+
mergedOpt = {
|
|
379
|
+
queryKey,
|
|
380
|
+
queryFn,
|
|
381
|
+
initialPageParam: argsValue,
|
|
382
|
+
...options,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const result = createInfiniteQuery<TQueryFnData, DefaultError, InfiniteData<TData>>(mergedOpt);
|
|
387
|
+
return derived(result, (r) => ({
|
|
388
|
+
queryKey,
|
|
389
|
+
...r,
|
|
390
|
+
}));
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Creates a svelte-query mutation
|
|
395
|
+
*
|
|
396
|
+
* @private
|
|
397
|
+
*
|
|
398
|
+
* @param model The name of the model under mutation.
|
|
399
|
+
* @param method The HTTP method.
|
|
400
|
+
* @param operation The mutation operation (e.g. `create`).
|
|
401
|
+
* @param options The svelte-query options.
|
|
402
|
+
* @param checkReadBack Whether to check for read back errors and return undefined if found.
|
|
403
|
+
*/
|
|
404
|
+
export function useInternalMutation<TArgs, R = any>(
|
|
405
|
+
schema: SchemaDef,
|
|
406
|
+
model: string,
|
|
407
|
+
method: 'POST' | 'PUT' | 'DELETE',
|
|
408
|
+
operation: string,
|
|
409
|
+
options?: StoreOrVal<Omit<CreateMutationOptions<R, DefaultError, TArgs>, 'mutationFn'> & ExtraMutationOptions>,
|
|
410
|
+
) {
|
|
411
|
+
const { endpoint, fetch, logging } = getQuerySettings();
|
|
412
|
+
const queryClient = useQueryClient();
|
|
413
|
+
const optionsValue = unwrapStore(options);
|
|
414
|
+
const mutationFn = (data: any) => {
|
|
415
|
+
const reqUrl =
|
|
416
|
+
method === 'DELETE' ? makeUrl(endpoint, model, operation, data) : makeUrl(endpoint, model, operation);
|
|
417
|
+
const fetchInit: RequestInit = {
|
|
418
|
+
method,
|
|
419
|
+
...(method !== 'DELETE' && {
|
|
420
|
+
headers: {
|
|
421
|
+
'content-type': 'application/json',
|
|
422
|
+
},
|
|
423
|
+
body: marshal(data),
|
|
424
|
+
}),
|
|
425
|
+
};
|
|
426
|
+
return fetcher<R>(reqUrl, fetchInit, fetch) as Promise<R>;
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
let mergedOpt: StoreOrVal<CreateMutationOptions<R, DefaultError, TArgs>>;
|
|
430
|
+
|
|
431
|
+
if (isStore(options)) {
|
|
432
|
+
mergedOpt = derived([options], ([$opt]) => ({
|
|
433
|
+
...$opt,
|
|
434
|
+
mutationFn,
|
|
435
|
+
}));
|
|
436
|
+
} else {
|
|
437
|
+
mergedOpt = {
|
|
438
|
+
...options,
|
|
439
|
+
mutationFn,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const invalidateQueries = optionsValue?.invalidateQueries !== false;
|
|
444
|
+
const optimisticUpdate = !!optionsValue?.optimisticUpdate;
|
|
445
|
+
|
|
446
|
+
if (operation) {
|
|
447
|
+
if (invalidateQueries) {
|
|
448
|
+
setupInvalidation(
|
|
449
|
+
model,
|
|
450
|
+
operation,
|
|
451
|
+
schema,
|
|
452
|
+
unwrapStore(mergedOpt),
|
|
453
|
+
(predicate) => queryClient.invalidateQueries({ predicate }),
|
|
454
|
+
logging,
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (optimisticUpdate) {
|
|
459
|
+
setupOptimisticUpdate(
|
|
460
|
+
model,
|
|
461
|
+
operation,
|
|
462
|
+
schema,
|
|
463
|
+
unwrapStore(mergedOpt),
|
|
464
|
+
queryClient.getQueryCache().getAll(),
|
|
465
|
+
(queryKey, data) => queryClient.setQueryData<unknown>(queryKey, data),
|
|
466
|
+
invalidateQueries ? (predicate) => queryClient.invalidateQueries({ predicate }) : undefined,
|
|
467
|
+
logging,
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return createMutation(mergedOpt);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function isStore<T>(opt: unknown): opt is Readable<T> {
|
|
476
|
+
return typeof (opt as any)?.subscribe === 'function';
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function unwrapStore<T>(storeOrValue: StoreOrVal<T>): T {
|
|
480
|
+
return isStore(storeOrValue) ? get(storeOrValue) : storeOrValue;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
type UnwrapStore<T> = T extends Readable<infer U> ? U : T;
|
package/src/utils/common.ts
CHANGED
|
@@ -125,21 +125,12 @@ export type APIContext = {
|
|
|
125
125
|
logging?: boolean;
|
|
126
126
|
};
|
|
127
127
|
|
|
128
|
-
export async function fetcher<R,
|
|
129
|
-
url: string,
|
|
130
|
-
options?: RequestInit,
|
|
131
|
-
customFetch?: FetchFn,
|
|
132
|
-
checkReadBack?: C,
|
|
133
|
-
): Promise<C extends true ? R | undefined : R> {
|
|
128
|
+
export async function fetcher<R>(url: string, options?: RequestInit, customFetch?: FetchFn): Promise<R> {
|
|
134
129
|
const _fetch = customFetch ?? fetch;
|
|
135
130
|
const res = await _fetch(url, options);
|
|
136
131
|
if (!res.ok) {
|
|
137
132
|
const errData = unmarshal(await res.text());
|
|
138
|
-
if (
|
|
139
|
-
checkReadBack !== false &&
|
|
140
|
-
errData.error?.rejectedByPolicy &&
|
|
141
|
-
errData.error?.rejectReason === 'cannot-read-back'
|
|
142
|
-
) {
|
|
133
|
+
if (errData.error?.rejectedByPolicy && errData.error?.rejectReason === 'cannot-read-back') {
|
|
143
134
|
// policy doesn't allow mutation result to be read back, just return undefined
|
|
144
135
|
return undefined as any;
|
|
145
136
|
}
|
|
@@ -208,8 +199,8 @@ export function unmarshal(value: string) {
|
|
|
208
199
|
}
|
|
209
200
|
}
|
|
210
201
|
|
|
211
|
-
export function makeUrl(
|
|
212
|
-
const baseUrl = `${
|
|
202
|
+
export function makeUrl(endpoint: string, model: string, operation: string, args?: unknown) {
|
|
203
|
+
const baseUrl = `${endpoint}/${lowerCaseFirst(model)}/${operation}`;
|
|
213
204
|
if (!args) {
|
|
214
205
|
return baseUrl;
|
|
215
206
|
}
|
package/src/utils/types.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { OperationsIneligibleForDelegateModels } from '@zenstackhq/orm';
|
|
2
|
+
import type { GetModels, IsDelegateModel, SchemaDef } from '@zenstackhq/schema';
|
|
3
|
+
|
|
1
4
|
export type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;
|
|
2
5
|
|
|
3
6
|
export const ORMWriteActions = [
|
|
@@ -17,3 +20,13 @@ export const ORMWriteActions = [
|
|
|
17
20
|
] as const;
|
|
18
21
|
|
|
19
22
|
export type ORMWriteActionType = (typeof ORMWriteActions)[number];
|
|
23
|
+
|
|
24
|
+
type HooksOperationsIneligibleForDelegateModels = OperationsIneligibleForDelegateModels extends any
|
|
25
|
+
? `use${Capitalize<OperationsIneligibleForDelegateModels>}`
|
|
26
|
+
: never;
|
|
27
|
+
|
|
28
|
+
export type TrimDelegateModelOperations<
|
|
29
|
+
Schema extends SchemaDef,
|
|
30
|
+
Model extends GetModels<Schema>,
|
|
31
|
+
T extends Record<string, unknown>,
|
|
32
|
+
> = IsDelegateModel<Schema, Model> extends true ? Omit<T, HooksOperationsIneligibleForDelegateModels> : T;
|