Skip to content

Commit e07b5dd

Browse files
authored
merge dev to main (v1.3.0) (#834)
2 parents 9312f40 + 7340060 commit e07b5dd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1872
-163
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "zenstack-monorepo",
3-
"version": "1.2.2",
3+
"version": "1.3.0",
44
"description": "",
55
"scripts": {
66
"build": "pnpm -r build",

packages/language/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenstackhq/language",
3-
"version": "1.2.2",
3+
"version": "1.3.0",
44
"displayName": "ZenStack modeling language compiler",
55
"description": "ZenStack modeling language compiler",
66
"homepage": "https://zenstack.dev",
@@ -9,7 +9,7 @@
99
"generate": "langium generate",
1010
"watch": "concurrently \"langium generate --watch\" \"tsc --watch\"",
1111
"lint": "eslint src --ext ts",
12-
"build": "pnpm lint && pnpm clean && pnpm generate && tsc && copyfiles -F ./README.md ./LICENSE ./package.json dist && pnpm pack dist --pack-destination '../../../.build'",
12+
"build": "pnpm lint --max-warnings=0 && pnpm clean && pnpm generate && tsc && copyfiles -F ./README.md ./LICENSE ./package.json dist && pnpm pack dist --pack-destination '../../../.build'",
1313
"prepublishOnly": "pnpm build"
1414
},
1515
"publishConfig": {

packages/plugins/openapi/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/openapi",
33
"displayName": "ZenStack Plugin and Runtime for OpenAPI",
4-
"version": "1.2.2",
4+
"version": "1.3.0",
55
"description": "ZenStack plugin and runtime supporting OpenAPI",
66
"main": "index.js",
77
"repository": {
@@ -14,7 +14,7 @@
1414
},
1515
"scripts": {
1616
"clean": "rimraf dist",
17-
"build": "pnpm lint && pnpm clean && tsc && copyfiles ./package.json ./README.md ./LICENSE dist && copyfiles -u 1 ./src/plugin.zmodel dist && pnpm pack dist --pack-destination '../../../../.build'",
17+
"build": "pnpm lint --max-warnings=0 && pnpm clean && tsc && copyfiles ./package.json ./README.md ./LICENSE dist && copyfiles -u 1 ./src/plugin.zmodel dist && pnpm pack dist --pack-destination '../../../../.build'",
1818
"watch": "tsc --watch",
1919
"lint": "eslint src --ext ts",
2020
"test": "ZENSTACK_TEST=1 jest",

packages/plugins/swr/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/swr",
33
"displayName": "ZenStack plugin for generating SWR hooks",
4-
"version": "1.2.2",
4+
"version": "1.3.0",
55
"description": "ZenStack plugin for generating SWR hooks",
66
"main": "index.js",
77
"repository": {
@@ -10,7 +10,7 @@
1010
},
1111
"scripts": {
1212
"clean": "rimraf dist",
13-
"build": "pnpm lint && pnpm clean && tsc && copyfiles ./package.json ./README.md ./LICENSE dist && pnpm pack dist --pack-destination '../../../../.build'",
13+
"build": "pnpm lint --max-warnings=0 && pnpm clean && tsc && copyfiles ./package.json ./README.md ./LICENSE dist && pnpm pack dist --pack-destination '../../../../.build'",
1414
"watch": "tsc --watch",
1515
"lint": "eslint src --ext ts",
1616
"test": "ZENSTACK_TEST=1 jest",

packages/plugins/tanstack-query/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/tanstack-query",
33
"displayName": "ZenStack plugin for generating tanstack-query hooks",
4-
"version": "1.2.2",
4+
"version": "1.3.0",
55
"description": "ZenStack plugin for generating tanstack-query hooks",
66
"main": "index.js",
77
"exports": {
@@ -66,7 +66,7 @@
6666
},
6767
"scripts": {
6868
"clean": "rimraf dist",
69-
"build": "pnpm lint && pnpm clean && tsc && tsup-node --config ./tsup.config.ts && tsup-node --config ./tsup-v5.config.ts && node scripts/postbuild && copyfiles ./package.json ./README.md ./LICENSE dist && pnpm pack dist --pack-destination '../../../../.build'",
69+
"build": "pnpm lint --max-warnings=0 && pnpm clean && tsc && tsup-node --config ./tsup.config.ts && tsup-node --config ./tsup-v5.config.ts && node scripts/postbuild && copyfiles ./package.json ./README.md ./LICENSE dist && pnpm pack dist --pack-destination '../../../../.build'",
7070
"watch": "concurrently \"tsc --watch\" \"tsup-node --config ./tsup.config.ts --watch\" \"tsup-node --config ./tsup-v5.config.ts --watch\"",
7171
"lint": "eslint src --ext ts",
7272
"test": "ZENSTACK_TEST=1 jest",

packages/plugins/tanstack-query/src/generator.ts

+72-9
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,23 @@ function generateQueryHook(
7878
overrideReturnType?: string,
7979
overrideInputType?: string,
8080
overrideTypeParameters?: string[],
81-
infinite = false
81+
infinite = false,
82+
optimisticUpdate = false
8283
) {
8384
const capOperation = upperCaseFirst(operation);
8485

8586
const argsType = overrideInputType ?? `Prisma.${model}${capOperation}Args`;
8687
const inputType = `Prisma.SelectSubset<T, ${argsType}>`;
87-
const returnType =
88-
overrideReturnType ?? (returnArray ? `Array<Prisma.${model}GetPayload<T>>` : `Prisma.${model}GetPayload<T>`);
88+
89+
let defaultReturnType = `Prisma.${model}GetPayload<T>`;
90+
if (optimisticUpdate) {
91+
defaultReturnType += '& { $optimistic?: boolean }';
92+
}
93+
if (returnArray) {
94+
defaultReturnType = `Array<${defaultReturnType}>`;
95+
}
96+
97+
const returnType = overrideReturnType ?? defaultReturnType;
8998
const optionsType = makeQueryOptions(target, returnType, infinite, version);
9099

91100
const func = sf.addFunction({
@@ -100,6 +109,15 @@ function generateQueryHook(
100109
name: 'options?',
101110
type: optionsType,
102111
},
112+
...(optimisticUpdate
113+
? [
114+
{
115+
name: 'optimisticUpdate',
116+
type: 'boolean',
117+
initializer: 'true',
118+
},
119+
]
120+
: []),
103121
],
104122
isExported: true,
105123
});
@@ -113,7 +131,7 @@ function generateQueryHook(
113131
makeGetContext(target),
114132
`return ${infinite ? 'useInfiniteModelQuery' : 'useModelQuery'}('${model}', \`\${endpoint}/${lowerCaseFirst(
115133
model
116-
)}/${operation}\`, args, options, fetch);`,
134+
)}/${operation}\`, args, options, fetch${optimisticUpdate ? ', optimisticUpdate' : ''});`,
117135
]);
118136
}
119137

@@ -154,6 +172,11 @@ function generateMutationHook(
154172
type: 'boolean',
155173
initializer: 'true',
156174
},
175+
{
176+
name: 'optimisticUpdate',
177+
type: 'boolean',
178+
initializer: 'false',
179+
},
157180
],
158181
});
159182

@@ -170,7 +193,7 @@ function generateMutationHook(
170193
overrideReturnType ?? model
171194
}, ${checkReadBack}>('${model}', '${httpVerb.toUpperCase()}', \`\${endpoint}/${lowerCaseFirst(
172195
model
173-
)}/${operation}\`, metadata, options, fetch, invalidateQueries, ${checkReadBack})
196+
)}/${operation}\`, metadata, options, fetch, invalidateQueries, ${checkReadBack}, optimisticUpdate)
174197
`,
175198
},
176199
],
@@ -272,8 +295,6 @@ function generateModelHooks(
272295
// findMany
273296
if (mapping.findMany) {
274297
// regular findMany
275-
generateQueryHook(target, version, sf, model.name, 'findMany', true, true);
276-
// infinite findMany
277298
generateQueryHook(
278299
target,
279300
version,
@@ -285,18 +306,60 @@ function generateModelHooks(
285306
undefined,
286307
undefined,
287308
undefined,
309+
false,
288310
true
289311
);
312+
// infinite findMany
313+
generateQueryHook(
314+
target,
315+
version,
316+
sf,
317+
model.name,
318+
'findMany',
319+
true,
320+
true,
321+
undefined,
322+
undefined,
323+
undefined,
324+
true,
325+
false
326+
);
290327
}
291328

292329
// findUnique
293330
if (mapping.findUnique) {
294-
generateQueryHook(target, version, sf, model.name, 'findUnique', false, false);
331+
generateQueryHook(
332+
target,
333+
version,
334+
sf,
335+
model.name,
336+
'findUnique',
337+
false,
338+
false,
339+
undefined,
340+
undefined,
341+
undefined,
342+
false,
343+
true
344+
);
295345
}
296346

297347
// findFirst
298348
if (mapping.findFirst) {
299-
generateQueryHook(target, version, sf, model.name, 'findFirst', false, true);
349+
generateQueryHook(
350+
target,
351+
version,
352+
sf,
353+
model.name,
354+
'findFirst',
355+
false,
356+
true,
357+
undefined,
358+
undefined,
359+
undefined,
360+
false,
361+
true
362+
);
300363
}
301364

302365
// update

packages/plugins/tanstack-query/src/runtime-v5/react.ts

+40-7
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
makeUrl,
2020
marshal,
2121
setupInvalidation,
22+
setupOptimisticUpdate,
2223
type APIContext,
2324
} from '../runtime/common';
2425

@@ -50,18 +51,21 @@ export const Provider = RequestHandlerContext.Provider;
5051
* @param url The request URL.
5152
* @param args The request args object, URL-encoded and appended as "?q=" parameter
5253
* @param options The react-query options object
54+
* @param fetch The fetch function to use for sending the HTTP request
55+
* @param optimisticUpdate Whether to enable automatic optimistic update
5356
* @returns useQuery hook
5457
*/
5558
export function useModelQuery<R>(
5659
model: string,
5760
url: string,
5861
args?: unknown,
5962
options?: Omit<UseQueryOptions<R>, 'queryKey'>,
60-
fetch?: FetchFn
63+
fetch?: FetchFn,
64+
optimisticUpdate = false
6165
) {
6266
const reqUrl = makeUrl(url, args);
6367
return useQuery({
64-
queryKey: getQueryKey(model, url, args),
68+
queryKey: getQueryKey(model, url, args, false, optimisticUpdate),
6569
queryFn: () => fetcher<R, false>(reqUrl, undefined, fetch, false),
6670
...options,
6771
});
@@ -74,6 +78,7 @@ export function useModelQuery<R>(
7478
* @param url The request URL.
7579
* @param args The initial request args object, URL-encoded and appended as "?q=" parameter
7680
* @param options The react-query infinite query options object
81+
* @param fetch The fetch function to use for sending the HTTP request
7782
* @returns useInfiniteQuery hook
7883
*/
7984
export function useInfiniteModelQuery<R>(
@@ -84,14 +89,27 @@ export function useInfiniteModelQuery<R>(
8489
fetch?: FetchFn
8590
) {
8691
return useInfiniteQuery({
87-
queryKey: getQueryKey(model, url, args),
92+
queryKey: getQueryKey(model, url, args, true),
8893
queryFn: ({ pageParam }) => {
8994
return fetcher<R, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false);
9095
},
9196
...options,
9297
});
9398
}
9499

100+
/**
101+
* Creates a react-query mutation
102+
*
103+
* @param model The name of the model under mutation.
104+
* @param method The HTTP method.
105+
* @param url The request URL.
106+
* @param modelMeta The model metadata.
107+
* @param options The react-query options.
108+
* @param fetch The fetch function to use for sending the HTTP request
109+
* @param invalidateQueries Whether to invalidate queries after mutation.
110+
* @param checkReadBack Whether to check for read back errors and return undefined if found.
111+
* @param optimisticUpdate Whether to enable automatic optimistic update
112+
*/
95113
export function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(
96114
model: string,
97115
method: 'POST' | 'PUT' | 'DELETE',
@@ -100,7 +118,8 @@ export function useModelMutation<T, R = any, C extends boolean = boolean, Result
100118
options?: Omit<UseMutationOptions<Result, unknown, T>, 'mutationFn'>,
101119
fetch?: FetchFn,
102120
invalidateQueries = true,
103-
checkReadBack?: C
121+
checkReadBack?: C,
122+
optimisticUpdate = false
104123
) {
105124
const queryClient = useQueryClient();
106125
const mutationFn = (data: any) => {
@@ -118,10 +137,11 @@ export function useModelMutation<T, R = any, C extends boolean = boolean, Result
118137
};
119138

120139
const finalOptions = { ...options, mutationFn };
121-
if (invalidateQueries) {
140+
const operation = url.split('/').pop();
141+
142+
if (operation) {
122143
const { logging } = useContext(RequestHandlerContext);
123-
const operation = url.split('/').pop();
124-
if (operation) {
144+
if (invalidateQueries) {
125145
setupInvalidation(
126146
model,
127147
operation,
@@ -131,6 +151,19 @@ export function useModelMutation<T, R = any, C extends boolean = boolean, Result
131151
logging
132152
);
133153
}
154+
155+
if (optimisticUpdate) {
156+
setupOptimisticUpdate(
157+
model,
158+
operation,
159+
modelMeta,
160+
finalOptions,
161+
queryClient.getQueryCache().getAll(),
162+
(queryKey, data) => queryClient.setQueryData<unknown>(queryKey, data),
163+
invalidateQueries ? (predicate) => queryClient.invalidateQueries({ predicate }) : undefined,
164+
logging
165+
);
166+
}
134167
}
135168

136169
return useMutation(finalOptions);

0 commit comments

Comments
 (0)