Skip to content

merge dev to main (v1.8.0) #975

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:

strategy:
matrix:
node-version: [18.x]
node-version: [20.x]
prisma-version: [v4, v5]

steps:
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,18 @@ The following diagram gives a high-level architecture overview of ZenStack.

## Examples

### Todo SaaS App
### Schema Samples

The [sample repo](https://github.com/zenstackhq/authz-modeling-samples) includes the following patterns:

- ACL
- RBAC
- ABAC
- Multi-Tenancy

You can use [this blog post](https://zenstack.dev/blog/model-authz) as an introduction.

### Multi-Tenant Todo App

Check out the [Multi-tenant Todo App](https://zenstack-todo.vercel.app/) for a running example. You can find different implementations below:

Expand Down Expand Up @@ -213,6 +224,8 @@ Join our [discord server](https://discord.gg/Ykhr738dUe) for chat and updates!

If you like ZenStack, join us to make it a better tool! Please use the [Contributing Guide](CONTRIBUTING.md) for details on how to get started, and don't hesitate to join [Discord](https://discord.gg/Ykhr738dUe) to share your thoughts.

Please also consider [sponsoring our work](https://github.com/sponsors/zenstackhq) to speed up the development of ZenStack. Thank you!

## License

[MIT](LICENSE)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zenstack-monorepo",
"version": "1.7.1",
"version": "1.8.0",
"description": "",
"scripts": {
"build": "pnpm -r build",
Expand Down
3 changes: 3 additions & 0 deletions packages/ide/jetbrains/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions packages/ide/jetbrains/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Changelog

## [Unreleased]

### Added
- Auto-completion is now supported inside attributes.
37 changes: 34 additions & 3 deletions packages/ide/jetbrains/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.date

plugins {
id("java")
id("org.jetbrains.kotlin.jvm") version "1.9.21"
id("org.jetbrains.intellij") version "1.16.1"
id("org.jetbrains.changelog") version "2.2.0"
}

group = "dev.zenstack"
version = "1.7.1"
version = "1.8.0"

repositories {
mavenCentral()
Expand Down Expand Up @@ -52,8 +56,17 @@ tasks {
}

patchPluginXml {
sinceBuild.set("231")
untilBuild.set("241.*")
sinceBuild.set("233.2")
untilBuild.set("251.*")
changeNotes.set(provider {
changelog.renderItem(
changelog
.getUnreleased()
.withHeader(false)
.withEmptySections(false),
Changelog.OutputType.HTML
)
})
}

signPlugin {
Expand All @@ -66,3 +79,21 @@ tasks {
token.set(System.getenv("PUBLISH_TOKEN"))
}
}

changelog {
header.set(provider { "[${version.get()}] - ${date()}" })
introduction.set(
"""
[ZenStack](https://zenstack.dev) is a toolkit that simplifies the development of a web app's backend. This plugin provides code editing experiences for its ZModel schema language.

## Features

- Syntax highlighting
- Error highlighting
- Go to definition
- Code completion
- Formatting
""".trimIndent()
)
groups.set(listOf("Added", "Changed", "Deprecated", "Removed", "Fixed", "Security"))
}
2 changes: 1 addition & 1 deletion packages/ide/jetbrains/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jetbrains",
"version": "1.7.1",
"version": "1.8.0",
"displayName": "ZenStack JetBrains IDE Plugin",
"description": "ZenStack JetBrains IDE plugin",
"homepage": "https://zenstack.dev",
Expand Down
2 changes: 1 addition & 1 deletion packages/language/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/language",
"version": "1.7.1",
"version": "1.8.0",
"displayName": "ZenStack modeling language compiler",
"description": "ZenStack modeling language compiler",
"homepage": "https://zenstack.dev",
Expand Down
2 changes: 1 addition & 1 deletion packages/misc/redwood/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/redwood",
"displayName": "ZenStack RedwoodJS Integration",
"version": "1.7.1",
"version": "1.8.0",
"description": "CLI and runtime for integrating ZenStack with RedwoodJS projects.",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/openapi/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/openapi",
"displayName": "ZenStack Plugin and Runtime for OpenAPI",
"version": "1.7.1",
"version": "1.8.0",
"description": "ZenStack plugin and runtime supporting OpenAPI",
"main": "index.js",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/swr/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/swr",
"displayName": "ZenStack plugin for generating SWR hooks",
"version": "1.7.1",
"version": "1.8.0",
"description": "ZenStack plugin for generating SWR hooks",
"main": "index.js",
"repository": {
Expand Down
7 changes: 6 additions & 1 deletion packages/plugins/swr/tests/swr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@ ${sharedModel}
{
provider: 'postgresql',
pushDb: false,
extraDependencies: [`${origDir}/dist`, '[email protected]', '@types/[email protected]', 'swr@^2'],
extraDependencies: [
`${path.join(__dirname, '../dist')}`,
'[email protected]',
'@types/[email protected]',
'swr@^2',
],
compile: true,
}
);
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/tanstack-query/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/tanstack-query",
"displayName": "ZenStack plugin for generating tanstack-query hooks",
"version": "1.7.1",
"version": "1.8.0",
"description": "ZenStack plugin for generating tanstack-query hooks",
"main": "index.js",
"exports": {
Expand Down
97 changes: 57 additions & 40 deletions packages/plugins/tanstack-query/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ function generateQueryHook(
const capOperation = upperCaseFirst(operation);

const argsType = overrideInputType ?? `Prisma.${model}${capOperation}Args`;
const inputType = `Prisma.SelectSubset<T, ${argsType}>`;
const inputType = `Prisma.SelectSubset<TArgs, ${argsType}>`;

let defaultReturnType = `Prisma.${model}GetPayload<T>`;
let defaultReturnType = `Prisma.${model}GetPayload<TArgs>`;
if (optimisticUpdate) {
defaultReturnType += '& { $optimistic?: boolean }';
}
Expand All @@ -95,11 +95,16 @@ function generateQueryHook(
}

const returnType = overrideReturnType ?? defaultReturnType;
const optionsType = makeQueryOptions(target, returnType, infinite, version);
const optionsType = makeQueryOptions(target, 'TQueryFnData', 'TData', infinite, version);

const func = sf.addFunction({
name: `use${infinite ? 'Infinite' : ''}${capOperation}${model}`,
typeParameters: overrideTypeParameters ?? [`T extends ${argsType}`],
typeParameters: overrideTypeParameters ?? [
`TArgs extends ${argsType}`,
`TQueryFnData = ${returnType} `,
'TData = TQueryFnData',
'TError = DefaultError',
],
parameters: [
{
name: optionalInput ? 'args?' : 'args',
Expand Down Expand Up @@ -129,7 +134,9 @@ function generateQueryHook(

func.addStatements([
makeGetContext(target),
`return ${infinite ? 'useInfiniteModelQuery' : 'useModelQuery'}('${model}', \`\${endpoint}/${lowerCaseFirst(
`return ${
infinite ? 'useInfiniteModelQuery' : 'useModelQuery'
}<TQueryFnData, TData, TError>('${model}', \`\${endpoint}/${lowerCaseFirst(
model
)}/${operation}\`, args, options, fetch${optimisticUpdate ? ', optimisticUpdate' : ''});`,
]);
Expand Down Expand Up @@ -403,7 +410,7 @@ function generateModelHooks(
'aggregate',
false,
false,
`Prisma.Get${modelNameCap}AggregateType<T>`
`Prisma.Get${modelNameCap}AggregateType<TArgs>`
);
}

Expand All @@ -415,16 +422,27 @@ function generateModelHooks(
useName = model.name;
}

const returnType = `{} extends InputErrors ?
Array<PickEnumerable<Prisma.${modelNameCap}GroupByOutputType, TArgs['by']> &
{
[P in ((keyof TArgs) & (keyof Prisma.${modelNameCap}GroupByOutputType))]: P extends '_count'
? TArgs[P] extends boolean
? number
: Prisma.GetScalarType<TArgs[P], Prisma.${modelNameCap}GroupByOutputType[P]>
: Prisma.GetScalarType<TArgs[P], Prisma.${modelNameCap}GroupByOutputType[P]>
}
> : InputErrors`;

const typeParameters = [
`T extends Prisma.${useName}GroupByArgs`,
`HasSelectOrTake extends Prisma.Or<Prisma.Extends<'skip', Prisma.Keys<T>>, Prisma.Extends<'take', Prisma.Keys<T>>>`,
`TArgs extends Prisma.${useName}GroupByArgs`,
`HasSelectOrTake extends Prisma.Or<Prisma.Extends<'skip', Prisma.Keys<TArgs>>, Prisma.Extends<'take', Prisma.Keys<TArgs>>>`,
`OrderByArg extends Prisma.True extends HasSelectOrTake ? { orderBy: Prisma.${useName}GroupByArgs['orderBy'] }: { orderBy?: Prisma.${useName}GroupByArgs['orderBy'] },`,
`OrderFields extends Prisma.ExcludeUnderscoreKeys<Prisma.Keys<Prisma.MaybeTupleToUnion<T['orderBy']>>>`,
`ByFields extends Prisma.MaybeTupleToUnion<T['by']>`,
`OrderFields extends Prisma.ExcludeUnderscoreKeys<Prisma.Keys<Prisma.MaybeTupleToUnion<TArgs['orderBy']>>>`,
`ByFields extends Prisma.MaybeTupleToUnion<TArgs['by']>`,
`ByValid extends Prisma.Has<ByFields, OrderFields>`,
`HavingFields extends Prisma.GetHavingFields<T['having']>`,
`HavingFields extends Prisma.GetHavingFields<TArgs['having']>`,
`HavingValid extends Prisma.Has<ByFields, HavingFields>`,
`ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False`,
`ByEmpty extends TArgs['by'] extends never[] ? Prisma.True : Prisma.False`,
`InputErrors extends ByEmpty extends Prisma.True
? \`Error: "by" must not be empty.\`
: HavingValid extends Prisma.False
Expand All @@ -440,8 +458,8 @@ function generateModelHooks(
\` in "having" needs to be provided in "by"\`,
]
}[HavingFields]
: 'take' extends Prisma.Keys<T>
? 'orderBy' extends Prisma.Keys<T>
: 'take' extends Prisma.Keys<TArgs>
? 'orderBy' extends Prisma.Keys<TArgs>
? ByValid extends Prisma.True
? {}
: {
Expand All @@ -450,8 +468,8 @@ function generateModelHooks(
: \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\`
}[OrderFields]
: 'Error: If you provide "take", you also need to provide "orderBy"'
: 'skip' extends Prisma.Keys<T>
? 'orderBy' extends Prisma.Keys<T>
: 'skip' extends Prisma.Keys<TArgs>
? 'orderBy' extends Prisma.Keys<TArgs>
? ByValid extends Prisma.True
? {}
: {
Expand All @@ -467,19 +485,11 @@ function generateModelHooks(
? never
: \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\`
}[OrderFields]`,
`TQueryFnData = ${returnType}`,
`TData = TQueryFnData`,
`TError = DefaultError`,
];

const returnType = `{} extends InputErrors ?
Array<PickEnumerable<Prisma.${modelNameCap}GroupByOutputType, T['by']> &
{
[P in ((keyof T) & (keyof Prisma.${modelNameCap}GroupByOutputType))]: P extends '_count'
? T[P] extends boolean
? number
: Prisma.GetScalarType<T[P], Prisma.${modelNameCap}GroupByOutputType[P]>
: Prisma.GetScalarType<T[P], Prisma.${modelNameCap}GroupByOutputType[P]>
}
> : InputErrors`;

generateQueryHook(
target,
version,
Expand All @@ -489,7 +499,7 @@ function generateModelHooks(
false,
false,
returnType,
`Prisma.SubsetIntersection<T, Prisma.${useName}GroupByArgs, OrderByArg> & InputErrors`,
`Prisma.SubsetIntersection<TArgs, Prisma.${useName}GroupByArgs, OrderByArg> & InputErrors`,
typeParameters
);
}
Expand All @@ -504,7 +514,7 @@ function generateModelHooks(
'count',
false,
true,
`T extends { select: any; } ? T['select'] extends true ? number : Prisma.GetScalarType<T['select'], Prisma.${modelNameCap}CountAggregateOutputType> : number`
`TArgs extends { select: any; } ? TArgs['select'] extends true ? number : Prisma.GetScalarType<TArgs['select'], Prisma.${modelNameCap}CountAggregateOutputType> : number`
);
}
}
Expand Down Expand Up @@ -552,12 +562,13 @@ function makeBaseImports(target: TargetFramework, version: TanStackVersion) {
`import { useModelQuery, useInfiniteModelQuery, useModelMutation } from '${runtimeImportBase}/${target}';`,
`import type { PickEnumerable, CheckSelect } from '${runtimeImportBase}';`,
`import metadata from './__model_meta';`,
`type DefaultError = Error;`,
];
switch (target) {
case 'react':
return [
`import type { UseMutationOptions, UseQueryOptions, UseInfiniteQueryOptions, InfiniteData } from '@tanstack/react-query';`,
`import { RequestHandlerContext, getHooksContext } from '${runtimeImportBase}/${target}';`,
`import { getHooksContext } from '${runtimeImportBase}/${target}';`,
...shared,
];
case 'vue':
Expand All @@ -573,32 +584,38 @@ function makeBaseImports(target: TargetFramework, version: TanStackVersion) {
...(version === 'v5'
? [`import type { InfiniteData, StoreOrVal } from '@tanstack/svelte-query';`]
: []),
`import { SvelteQueryContextKey, type RequestHandlerContext, getHooksContext } from '${runtimeImportBase}/${target}';`,
`import { getHooksContext } from '${runtimeImportBase}/${target}';`,
...shared,
];
default:
throw new PluginError(name, `Unsupported target: ${target}`);
}
}

function makeQueryOptions(target: string, returnType: string, infinite: boolean, version: TanStackVersion) {
function makeQueryOptions(
target: string,
returnType: string,
dataType: string,
infinite: boolean,
version: TanStackVersion
) {
switch (target) {
case 'react':
return infinite
? version === 'v4'
? `Omit<UseInfiniteQueryOptions<${returnType}>, 'queryKey'>`
: `Omit<UseInfiniteQueryOptions<${returnType}, unknown, InfiniteData<${returnType}>>, 'queryKey'>`
: `Omit<UseQueryOptions<${returnType}>, 'queryKey'>`;
? `Omit<UseInfiniteQueryOptions<${returnType}, TError, ${dataType}>, 'queryKey'>`
: `Omit<UseInfiniteQueryOptions<${returnType}, TError, InfiniteData<${dataType}>>, 'queryKey'>`
: `Omit<UseQueryOptions<${returnType}, TError, ${dataType}>, 'queryKey'>`;
case 'vue':
return `Omit<Use${infinite ? 'Infinite' : ''}QueryOptions<${returnType}>, 'queryKey'>`;
return `Omit<Use${infinite ? 'Infinite' : ''}QueryOptions<${returnType}, TError, ${dataType}>, 'queryKey'>`;
case 'svelte':
return infinite
? version === 'v4'
? `Omit<CreateInfiniteQueryOptions<${returnType}>, 'queryKey'>`
: `StoreOrVal<Omit<CreateInfiniteQueryOptions<${returnType}, unknown, InfiniteData<${returnType}>>, 'queryKey'>>`
? `Omit<CreateInfiniteQueryOptions<${returnType}, TError, ${dataType}>, 'queryKey'>`
: `StoreOrVal<Omit<CreateInfiniteQueryOptions<${returnType}, TError, InfiniteData<${dataType}>>, 'queryKey'>>`
: version === 'v4'
? `Omit<CreateQueryOptions<${returnType}>, 'queryKey'>`
: `StoreOrVal<Omit<CreateQueryOptions<${returnType}>, 'queryKey'>>`;
? `Omit<CreateQueryOptions<${returnType}, TError, ${dataType}>, 'queryKey'>`
: `StoreOrVal<Omit<CreateQueryOptions<${returnType}, TError, ${dataType}>, 'queryKey'>>`;
default:
throw new PluginError(name, `Unsupported target: ${target}`);
}
Expand Down
Loading