@zenstackhq/tanstack-query 3.0.0 → 3.1.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 (56) hide show
  1. package/dist/common/client.d.ts +4 -0
  2. package/dist/common/client.js +38 -0
  3. package/dist/common/client.js.map +1 -0
  4. package/dist/common/query-key.d.ts +39 -0
  5. package/dist/common/query-key.js +38 -0
  6. package/dist/common/query-key.js.map +1 -0
  7. package/dist/common/types.d.ts +60 -0
  8. package/dist/common/types.js +2 -0
  9. package/dist/common/types.js.map +1 -0
  10. package/dist/react.d.ts +99 -150
  11. package/dist/react.js +248 -1178
  12. package/dist/react.js.map +1 -1
  13. package/dist/svelte/index.svelte.d.ts +79 -0
  14. package/dist/svelte/index.svelte.js +245 -0
  15. package/dist/vue.d.ts +313 -342
  16. package/dist/vue.js +224 -1138
  17. package/dist/vue.js.map +1 -1
  18. package/package.json +36 -48
  19. package/.turbo/turbo-build.log +0 -47
  20. package/dist/react.cjs +0 -1240
  21. package/dist/react.cjs.map +0 -1
  22. package/dist/react.d.cts +0 -616
  23. package/dist/svelte.cjs +0 -1224
  24. package/dist/svelte.cjs.map +0 -1
  25. package/dist/svelte.d.cts +0 -381
  26. package/dist/svelte.d.ts +0 -381
  27. package/dist/svelte.js +0 -1183
  28. package/dist/svelte.js.map +0 -1
  29. package/dist/types-C8iIZD-7.d.cts +0 -99
  30. package/dist/types-C8iIZD-7.d.ts +0 -99
  31. package/dist/vue.cjs +0 -1192
  32. package/dist/vue.cjs.map +0 -1
  33. package/dist/vue.d.cts +0 -382
  34. package/eslint.config.js +0 -4
  35. package/src/react.ts +0 -562
  36. package/src/svelte.ts +0 -502
  37. package/src/utils/common.ts +0 -448
  38. package/src/utils/mutator.ts +0 -441
  39. package/src/utils/nested-read-visitor.ts +0 -61
  40. package/src/utils/nested-write-visitor.ts +0 -359
  41. package/src/utils/query-analysis.ts +0 -116
  42. package/src/utils/serialization.ts +0 -39
  43. package/src/utils/types.ts +0 -43
  44. package/src/vue.ts +0 -448
  45. package/test/react-query.test.tsx +0 -1787
  46. package/test/react-typing-test.ts +0 -113
  47. package/test/schemas/basic/input.ts +0 -110
  48. package/test/schemas/basic/models.ts +0 -14
  49. package/test/schemas/basic/schema-lite.ts +0 -172
  50. package/test/schemas/basic/schema.zmodel +0 -35
  51. package/test/svelte-typing-test.ts +0 -111
  52. package/test/vue-typing-test.ts +0 -111
  53. package/tsconfig.json +0 -7
  54. package/tsconfig.test.json +0 -8
  55. package/tsup.config.ts +0 -15
  56. package/vitest.config.ts +0 -11
@@ -1,359 +0,0 @@
1
- import { enumerate } from '@zenstackhq/common-helpers';
2
- import type { FieldDef, SchemaDef } from '@zenstackhq/schema';
3
- import { ORMWriteActions, type MaybePromise, type ORMWriteActionType } from './types';
4
-
5
- type NestingPathItem = { field?: FieldDef; model: string; where: any; unique: boolean };
6
-
7
- /**
8
- * Context for visiting
9
- */
10
- export type NestedWriteVisitorContext = {
11
- /**
12
- * Parent data, can be used to replace fields
13
- */
14
- parent: any;
15
-
16
- /**
17
- * Current field, undefined if toplevel
18
- */
19
- field?: FieldDef;
20
-
21
- /**
22
- * A top-down path of all nested update conditions and corresponding field till now
23
- */
24
- nestingPath: NestingPathItem[];
25
- };
26
-
27
- /**
28
- * NestedWriteVisitor's callback actions. A call back function should return true or void to indicate
29
- * that the visitor should continue traversing its children, or false to stop. It can also return an object
30
- * to let the visitor traverse it instead of its original children.
31
- */
32
- export type NestedWriterVisitorCallback = {
33
- create?: (model: string, data: any, context: NestedWriteVisitorContext) => MaybePromise<boolean | object | void>;
34
-
35
- createMany?: (
36
- model: string,
37
- args: { data: any; skipDuplicates?: boolean },
38
- context: NestedWriteVisitorContext,
39
- ) => MaybePromise<boolean | object | void>;
40
-
41
- connectOrCreate?: (
42
- model: string,
43
- args: { where: object; create: any },
44
- context: NestedWriteVisitorContext,
45
- ) => MaybePromise<boolean | object | void>;
46
-
47
- connect?: (
48
- model: string,
49
- args: object,
50
- context: NestedWriteVisitorContext,
51
- ) => MaybePromise<boolean | object | void>;
52
-
53
- disconnect?: (
54
- model: string,
55
- args: object,
56
- context: NestedWriteVisitorContext,
57
- ) => MaybePromise<boolean | object | void>;
58
-
59
- set?: (model: string, args: object, context: NestedWriteVisitorContext) => MaybePromise<boolean | object | void>;
60
-
61
- update?: (model: string, args: object, context: NestedWriteVisitorContext) => MaybePromise<boolean | object | void>;
62
-
63
- updateMany?: (
64
- model: string,
65
- args: { where?: object; data: any },
66
- context: NestedWriteVisitorContext,
67
- ) => MaybePromise<boolean | object | void>;
68
-
69
- upsert?: (
70
- model: string,
71
- args: { where: object; create: any; update: any },
72
- context: NestedWriteVisitorContext,
73
- ) => MaybePromise<boolean | object | void>;
74
-
75
- delete?: (
76
- model: string,
77
- args: object | boolean,
78
- context: NestedWriteVisitorContext,
79
- ) => MaybePromise<boolean | object | void>;
80
-
81
- deleteMany?: (
82
- model: string,
83
- args: any | object,
84
- context: NestedWriteVisitorContext,
85
- ) => MaybePromise<boolean | object | void>;
86
-
87
- field?: (
88
- field: FieldDef,
89
- action: ORMWriteActionType,
90
- data: any,
91
- context: NestedWriteVisitorContext,
92
- ) => MaybePromise<void>;
93
- };
94
-
95
- /**
96
- * Recursive visitor for nested write (create/update) payload.
97
- */
98
- export class NestedWriteVisitor {
99
- constructor(
100
- private readonly schema: SchemaDef,
101
- private readonly callback: NestedWriterVisitorCallback,
102
- ) {}
103
-
104
- private isWriteAction(value: string): value is ORMWriteActionType {
105
- return ORMWriteActions.includes(value as ORMWriteActionType);
106
- }
107
-
108
- /**
109
- * Start visiting
110
- *
111
- * @see NestedWriterVisitorCallback
112
- */
113
- async visit(model: string, action: ORMWriteActionType, args: any): Promise<void> {
114
- if (!args) {
115
- return;
116
- }
117
-
118
- let topData = args;
119
-
120
- switch (action) {
121
- // create has its data wrapped in 'data' field
122
- case 'create':
123
- topData = topData.data;
124
- break;
125
-
126
- case 'delete':
127
- case 'deleteMany':
128
- topData = topData.where;
129
- break;
130
- }
131
-
132
- await this.doVisit(model, action, topData, undefined, undefined, []);
133
- }
134
-
135
- private async doVisit(
136
- model: string,
137
- action: ORMWriteActionType,
138
- data: any,
139
- parent: any,
140
- field: FieldDef | undefined,
141
- nestingPath: NestingPathItem[],
142
- ): Promise<void> {
143
- if (!data) {
144
- return;
145
- }
146
-
147
- const toplevel = field == undefined;
148
-
149
- const context = { parent, field, nestingPath: [...nestingPath] };
150
- const pushNewContext = (field: FieldDef | undefined, model: string, where: any, unique = false) => {
151
- return { ...context, nestingPath: [...context.nestingPath, { field, model, where, unique }] };
152
- };
153
-
154
- // visit payload
155
- switch (action) {
156
- case 'create':
157
- for (const item of this.enumerateReverse(data)) {
158
- const newContext = pushNewContext(field, model, {});
159
- let callbackResult: any;
160
- if (this.callback.create) {
161
- callbackResult = await this.callback.create(model, item, newContext);
162
- }
163
- if (callbackResult !== false) {
164
- const subPayload = typeof callbackResult === 'object' ? callbackResult : item;
165
- await this.visitSubPayload(model, action, subPayload, newContext.nestingPath);
166
- }
167
- }
168
- break;
169
-
170
- case 'createMany':
171
- case 'createManyAndReturn':
172
- {
173
- const newContext = pushNewContext(field, model, {});
174
- let callbackResult: any;
175
- if (this.callback.createMany) {
176
- callbackResult = await this.callback.createMany(model, data, newContext);
177
- }
178
- if (callbackResult !== false) {
179
- const subPayload = typeof callbackResult === 'object' ? callbackResult : data.data;
180
- await this.visitSubPayload(model, action, subPayload, newContext.nestingPath);
181
- }
182
- }
183
- break;
184
-
185
- case 'connectOrCreate':
186
- for (const item of this.enumerateReverse(data)) {
187
- const newContext = pushNewContext(field, model, item.where);
188
- let callbackResult: any;
189
- if (this.callback.connectOrCreate) {
190
- callbackResult = await this.callback.connectOrCreate(model, item, newContext);
191
- }
192
- if (callbackResult !== false) {
193
- const subPayload = typeof callbackResult === 'object' ? callbackResult : item.create;
194
- await this.visitSubPayload(model, action, subPayload, newContext.nestingPath);
195
- }
196
- }
197
- break;
198
-
199
- case 'connect':
200
- if (this.callback.connect) {
201
- for (const item of this.enumerateReverse(data)) {
202
- const newContext = pushNewContext(field, model, item, true);
203
- await this.callback.connect(model, item, newContext);
204
- }
205
- }
206
- break;
207
-
208
- case 'disconnect':
209
- // disconnect has two forms:
210
- // if relation is to-many, the payload is a unique filter object
211
- // if relation is to-one, the payload can only be boolean `true`
212
- if (this.callback.disconnect) {
213
- for (const item of this.enumerateReverse(data)) {
214
- const newContext = pushNewContext(field, model, item, typeof item === 'object');
215
- await this.callback.disconnect(model, item, newContext);
216
- }
217
- }
218
- break;
219
-
220
- case 'set':
221
- if (this.callback.set) {
222
- for (const item of this.enumerateReverse(data)) {
223
- const newContext = pushNewContext(field, model, item, true);
224
- await this.callback.set(model, item, newContext);
225
- }
226
- }
227
- break;
228
-
229
- case 'update':
230
- for (const item of this.enumerateReverse(data)) {
231
- const newContext = pushNewContext(field, model, item.where);
232
- let callbackResult: any;
233
- if (this.callback.update) {
234
- callbackResult = await this.callback.update(model, item, newContext);
235
- }
236
- if (callbackResult !== false) {
237
- const subPayload =
238
- typeof callbackResult === 'object'
239
- ? callbackResult
240
- : typeof item.data === 'object'
241
- ? item.data
242
- : item;
243
- await this.visitSubPayload(model, action, subPayload, newContext.nestingPath);
244
- }
245
- }
246
- break;
247
-
248
- case 'updateMany':
249
- case 'updateManyAndReturn':
250
- for (const item of this.enumerateReverse(data)) {
251
- const newContext = pushNewContext(field, model, item.where);
252
- let callbackResult: any;
253
- if (this.callback.updateMany) {
254
- callbackResult = await this.callback.updateMany(model, item, newContext);
255
- }
256
- if (callbackResult !== false) {
257
- const subPayload = typeof callbackResult === 'object' ? callbackResult : item;
258
- await this.visitSubPayload(model, action, subPayload, newContext.nestingPath);
259
- }
260
- }
261
- break;
262
-
263
- case 'upsert': {
264
- for (const item of this.enumerateReverse(data)) {
265
- const newContext = pushNewContext(field, model, item.where);
266
- let callbackResult: any;
267
- if (this.callback.upsert) {
268
- callbackResult = await this.callback.upsert(model, item, newContext);
269
- }
270
- if (callbackResult !== false) {
271
- if (typeof callbackResult === 'object') {
272
- await this.visitSubPayload(model, action, callbackResult, newContext.nestingPath);
273
- } else {
274
- await this.visitSubPayload(model, action, item.create, newContext.nestingPath);
275
- await this.visitSubPayload(model, action, item.update, newContext.nestingPath);
276
- }
277
- }
278
- }
279
- break;
280
- }
281
-
282
- case 'delete': {
283
- if (this.callback.delete) {
284
- for (const item of this.enumerateReverse(data)) {
285
- const newContext = pushNewContext(field, model, toplevel ? item.where : item);
286
- await this.callback.delete(model, item, newContext);
287
- }
288
- }
289
- break;
290
- }
291
-
292
- case 'deleteMany':
293
- if (this.callback.deleteMany) {
294
- for (const item of this.enumerateReverse(data)) {
295
- const newContext = pushNewContext(field, model, toplevel ? item.where : item);
296
- await this.callback.deleteMany(model, item, newContext);
297
- }
298
- }
299
- break;
300
-
301
- default: {
302
- throw new Error(`unhandled action type ${action}`);
303
- }
304
- }
305
- }
306
-
307
- private async visitSubPayload(
308
- model: string,
309
- action: ORMWriteActionType,
310
- payload: any,
311
- nestingPath: NestingPathItem[],
312
- ) {
313
- for (const item of enumerate(payload)) {
314
- if (!item || typeof item !== 'object') {
315
- continue;
316
- }
317
- for (const field of Object.keys(item)) {
318
- const fieldDef = this.schema.models[model]?.fields[field];
319
- if (!fieldDef) {
320
- continue;
321
- }
322
-
323
- if (fieldDef.relation) {
324
- if (item[field]) {
325
- // recurse into nested payloads
326
- for (const [subAction, subData] of Object.entries<any>(item[field])) {
327
- if (this.isWriteAction(subAction) && subData) {
328
- await this.doVisit(fieldDef.type, subAction, subData, item[field], fieldDef, [
329
- ...nestingPath,
330
- ]);
331
- }
332
- }
333
- }
334
- } else {
335
- // visit plain field
336
- if (this.callback.field) {
337
- await this.callback.field(fieldDef, action, item[field], {
338
- parent: item,
339
- nestingPath,
340
- field: fieldDef,
341
- });
342
- }
343
- }
344
- }
345
- }
346
- }
347
-
348
- // enumerate a (possible) array in reverse order, so that the enumeration
349
- // callback can safely delete the current item
350
- private *enumerateReverse(data: any) {
351
- if (Array.isArray(data)) {
352
- for (let i = data.length - 1; i >= 0; i--) {
353
- yield data[i];
354
- }
355
- } else {
356
- yield data;
357
- }
358
- }
359
- }
@@ -1,116 +0,0 @@
1
- import type { SchemaDef } from '@zenstackhq/schema';
2
- import { NestedReadVisitor } from './nested-read-visitor';
3
- import { NestedWriteVisitor } from './nested-write-visitor';
4
- import type { ORMWriteActionType } from './types';
5
-
6
- /**
7
- * Gets models read (including nested ones) given a query args.
8
- * @param model
9
- * @param targetModels
10
- * @param schema
11
- * @param args
12
- * @returns
13
- */
14
- export function getReadModels(model: string, schema: SchemaDef, args: any) {
15
- const result = new Set<string>();
16
- result.add(model);
17
- const visitor = new NestedReadVisitor(schema, {
18
- field: (model) => {
19
- result.add(model);
20
- return true;
21
- },
22
- });
23
- visitor.visit(model, args);
24
- return [...result];
25
- }
26
-
27
- /**
28
- * Gets mutated models (including nested ones) given a mutation args.
29
- */
30
- export async function getMutatedModels(
31
- model: string,
32
- operation: ORMWriteActionType,
33
- mutationArgs: any,
34
- schema: SchemaDef,
35
- ) {
36
- const result = new Set<string>();
37
- result.add(model);
38
-
39
- if (mutationArgs) {
40
- const addModel = (model: string) => void result.add(model);
41
-
42
- // add models that are cascaded deleted recursively
43
- const addCascades = (model: string) => {
44
- const cascades = new Set<string>();
45
- const visited = new Set<string>();
46
- collectDeleteCascades(model, schema, cascades, visited);
47
- cascades.forEach((m) => addModel(m));
48
- };
49
-
50
- const visitor = new NestedWriteVisitor(schema, {
51
- create: addModel,
52
- createMany: addModel,
53
- connectOrCreate: addModel,
54
- connect: addModel,
55
- disconnect: addModel,
56
- set: addModel,
57
- update: addModel,
58
- updateMany: addModel,
59
- upsert: addModel,
60
- delete: (model) => {
61
- addModel(model);
62
- addCascades(model);
63
- },
64
- deleteMany: (model) => {
65
- addModel(model);
66
- addCascades(model);
67
- },
68
- });
69
- await visitor.visit(model, operation, mutationArgs);
70
- }
71
-
72
- // include delegate base models recursively
73
- result.forEach((m) => {
74
- getBaseRecursively(m, schema, result);
75
- });
76
-
77
- return [...result];
78
- }
79
-
80
- function collectDeleteCascades(model: string, schema: SchemaDef, result: Set<string>, visited: Set<string>) {
81
- if (visited.has(model)) {
82
- // break circle
83
- return;
84
- }
85
- visited.add(model);
86
-
87
- const modelDef = schema.models[model];
88
- if (!modelDef) {
89
- return;
90
- }
91
-
92
- for (const [modelName, modelDef] of Object.entries(schema.models)) {
93
- if (!modelDef) {
94
- continue;
95
- }
96
- for (const fieldDef of Object.values(modelDef.fields)) {
97
- if (fieldDef.relation?.onDelete === 'Cascade' && fieldDef.type === model) {
98
- if (!result.has(modelName)) {
99
- result.add(modelName);
100
- }
101
- collectDeleteCascades(modelName, schema, result, visited);
102
- }
103
- }
104
- }
105
- }
106
-
107
- function getBaseRecursively(model: string, schema: SchemaDef, result: Set<string>) {
108
- const modelDef = schema.models[model];
109
- if (!modelDef) {
110
- return;
111
- }
112
- if (modelDef.baseModel) {
113
- result.add(modelDef.baseModel);
114
- getBaseRecursively(modelDef.baseModel, schema, result);
115
- }
116
- }
@@ -1,39 +0,0 @@
1
- import { Buffer } from 'buffer';
2
- import Decimal from 'decimal.js';
3
- import SuperJSON from 'superjson';
4
-
5
- SuperJSON.registerCustom<Decimal, string>(
6
- {
7
- isApplicable: (v): v is Decimal =>
8
- v instanceof Decimal ||
9
- // interop with decimal.js
10
- v?.toStringTag === '[object Decimal]',
11
- serialize: (v) => v.toJSON(),
12
- deserialize: (v) => new Decimal(v),
13
- },
14
- 'Decimal'
15
- );
16
-
17
- SuperJSON.registerCustom<Buffer, string>(
18
- {
19
- isApplicable: (v): v is Buffer => Buffer.isBuffer(v),
20
- serialize: (v) => v.toString('base64'),
21
- deserialize: (v) => Buffer.from(v, 'base64'),
22
- },
23
- 'Bytes'
24
- );
25
-
26
- /**
27
- * Serialize the given value with superjson
28
- */
29
- export function serialize(value: unknown): { data: unknown; meta: unknown } {
30
- const { json, meta } = SuperJSON.serialize(value);
31
- return { data: json, meta };
32
- }
33
-
34
- /**
35
- * Deserialize the given value with superjson using the given metadata
36
- */
37
- export function deserialize(value: unknown, meta: any): unknown {
38
- return SuperJSON.deserialize({ json: value as any, meta });
39
- }
@@ -1,43 +0,0 @@
1
- import type { OperationsIneligibleForDelegateModels } from '@zenstackhq/orm';
2
- import type { GetModels, IsDelegateModel, SchemaDef } from '@zenstackhq/schema';
3
-
4
- export type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;
5
-
6
- export const ORMWriteActions = [
7
- 'create',
8
- 'createMany',
9
- 'createManyAndReturn',
10
- 'connectOrCreate',
11
- 'update',
12
- 'updateMany',
13
- 'updateManyAndReturn',
14
- 'upsert',
15
- 'connect',
16
- 'disconnect',
17
- 'set',
18
- 'delete',
19
- 'deleteMany',
20
- ] as const;
21
-
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;
33
-
34
- type WithOptimisticFlag<T> = T extends object
35
- ? T & {
36
- /**
37
- * Indicates if the item is in an optimistic update state
38
- */
39
- $optimistic?: boolean;
40
- }
41
- : T;
42
-
43
- export type WithOptimistic<T> = T extends Array<infer U> ? Array<WithOptimisticFlag<U>> : WithOptimisticFlag<T>;