diff --git a/package.json b/package.json index 7a161fe47..556149eac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenstack-monorepo", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "description": "", "scripts": { "build": "pnpm -r build", diff --git a/packages/language/package.json b/packages/language/package.json index d8b521145..5c2e8bc97 100644 --- a/packages/language/package.json +++ b/packages/language/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/language", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "displayName": "ZenStack modeling language compiler", "description": "ZenStack modeling language compiler", "homepage": "https://zenstack.dev", diff --git a/packages/plugins/openapi/package.json b/packages/plugins/openapi/package.json index 1bf11bc76..175cd84b7 100644 --- a/packages/plugins/openapi/package.json +++ b/packages/plugins/openapi/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/openapi", "displayName": "ZenStack Plugin and Runtime for OpenAPI", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "description": "ZenStack plugin and runtime supporting OpenAPI", "main": "index.js", "repository": { diff --git a/packages/plugins/swr/package.json b/packages/plugins/swr/package.json index 642252a55..083912f6c 100644 --- a/packages/plugins/swr/package.json +++ b/packages/plugins/swr/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/swr", "displayName": "ZenStack plugin for generating SWR hooks", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "description": "ZenStack plugin for generating SWR hooks", "main": "index.js", "repository": { diff --git a/packages/plugins/tanstack-query/package.json b/packages/plugins/tanstack-query/package.json index fa7589bf9..130c4b051 100644 --- a/packages/plugins/tanstack-query/package.json +++ b/packages/plugins/tanstack-query/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/tanstack-query", "displayName": "ZenStack plugin for generating tanstack-query hooks", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "description": "ZenStack plugin for generating tanstack-query hooks", "main": "index.js", "exports": { diff --git a/packages/plugins/trpc/package.json b/packages/plugins/trpc/package.json index 303b5e81f..3f5723880 100644 --- a/packages/plugins/trpc/package.json +++ b/packages/plugins/trpc/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/trpc", "displayName": "ZenStack plugin for tRPC", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "description": "ZenStack plugin for tRPC", "main": "index.js", "repository": { diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 55e3f8ca7..f310a999d 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/runtime", "displayName": "ZenStack Runtime Library", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "description": "Runtime of ZenStack for both client-side and server-side environments.", "repository": { "type": "git", diff --git a/packages/schema/package.json b/packages/schema/package.json index 6121048bd..8de326b9a 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -3,7 +3,7 @@ "publisher": "zenstack", "displayName": "ZenStack Language Tools", "description": "A toolkit for building secure CRUD apps with Next.js + Typescript", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "author": { "name": "ZenStack Team" }, diff --git a/packages/schema/src/plugins/model-meta/index.ts b/packages/schema/src/plugins/model-meta/index.ts index 892f57c36..ce6d82785 100644 --- a/packages/schema/src/plugins/model-meta/index.ts +++ b/packages/schema/src/plugins/model-meta/index.ts @@ -11,6 +11,7 @@ import type { RuntimeAttribute } from '@zenstackhq/runtime'; import { createProject, emitProject, + getAttributeArg, getAttributeArgs, getDataModels, getLiteral, @@ -182,14 +183,25 @@ function isRelationOwner(field: DataModelField, backLink: DataModelField | undef return false; } - if (hasAttribute(field, '@relation')) { - // this field has `@relation` attribute + if (!backLink) { + // CHECKME: can this really happen? return true; - } else if (!backLink || !hasAttribute(backLink, '@relation')) { - // if the opposite side field doesn't have `@relation` attribute either, - // it's an implicit many-to-many relation, both sides are owners + } + + if (!hasAttribute(field, '@relation') && !hasAttribute(backLink, '@relation')) { + // if neither side has `@relation` attribute, it's an implicit many-to-many relation, + // both sides are owners return true; - } else { + } + + return holdsForeignKey(field); +} + +function holdsForeignKey(field: DataModelField) { + const relation = field.attributes.find((attr) => attr.decl.ref?.name === '@relation'); + if (!relation) { return false; } + const fields = getAttributeArg(relation, 'fields'); + return !!fields; } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index e429e8107..d9e744361 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/sdk", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "description": "ZenStack plugin development SDK", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index a39d0f358..030f70d3d 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/server", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "displayName": "ZenStack Server-side Adapters", "description": "ZenStack server-side adapters", "homepage": "https://zenstack.dev", diff --git a/packages/testtools/package.json b/packages/testtools/package.json index 63513bd2a..1836a12ef 100644 --- a/packages/testtools/package.json +++ b/packages/testtools/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/testtools", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "description": "ZenStack Test Tools", "main": "index.js", "publishConfig": { diff --git a/tests/integration/tests/regression/issues.test.ts b/tests/integration/tests/regression/issues.test.ts index 88551a62d..afb709667 100644 --- a/tests/integration/tests/regression/issues.test.ts +++ b/tests/integration/tests/regression/issues.test.ts @@ -300,4 +300,58 @@ describe('GitHub issues regression', () => { }, }); }); + + it('issue 609', async () => { + const { withPolicy, prisma } = await loadSchema( + ` + model User { + id String @id @default(cuid()) + comments Comment[] + } + + model Comment { + id String @id @default(cuid()) + parentCommentId String? + replies Comment[] @relation("CommentToComment") + parent Comment? @relation("CommentToComment", fields: [parentCommentId], references: [id]) + comment String + author User @relation(fields: [authorId], references: [id]) + authorId String + + @@allow('read,create', true) + @@allow('update,delete', auth() == author) + } + ` + ); + + await prisma.user.create({ + data: { + id: '1', + comments: { + create: { + id: '1', + comment: 'Comment 1', + }, + }, + }, + }); + + await prisma.user.create({ + data: { + id: '2', + }, + }); + + // connecting a child comment from a different user to a parent comment should succeed + const db = withPolicy({ id: '2' }); + await expect( + db.comment.create({ + data: { + comment: 'Comment 2', + author: { connect: { id: '2' } }, + parent: { connect: { id: '1' } }, + }, + }) + ).toResolveTruthy(); + }); });