diff --git a/package.json b/package.json index e896bb5f..a0350c89 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenstack-monorepo", - "version": "2.5.0", + "version": "2.5.1", "description": "", "scripts": { "build": "pnpm -r build", diff --git a/packages/ide/jetbrains/build.gradle.kts b/packages/ide/jetbrains/build.gradle.kts index d3a2d9fb..4de7e00d 100644 --- a/packages/ide/jetbrains/build.gradle.kts +++ b/packages/ide/jetbrains/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "dev.zenstack" -version = "2.5.0" +version = "2.5.1" repositories { mavenCentral() diff --git a/packages/ide/jetbrains/package.json b/packages/ide/jetbrains/package.json index b48439ad..996d97e5 100644 --- a/packages/ide/jetbrains/package.json +++ b/packages/ide/jetbrains/package.json @@ -1,6 +1,6 @@ { "name": "jetbrains", - "version": "2.5.0", + "version": "2.5.1", "displayName": "ZenStack JetBrains IDE Plugin", "description": "ZenStack JetBrains IDE plugin", "homepage": "https://zenstack.dev", diff --git a/packages/language/package.json b/packages/language/package.json index 2369cbab..70391df8 100644 --- a/packages/language/package.json +++ b/packages/language/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/language", - "version": "2.5.0", + "version": "2.5.1", "displayName": "ZenStack modeling language compiler", "description": "ZenStack modeling language compiler", "homepage": "https://zenstack.dev", diff --git a/packages/misc/redwood/package.json b/packages/misc/redwood/package.json index 784826ca..48dc879e 100644 --- a/packages/misc/redwood/package.json +++ b/packages/misc/redwood/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/redwood", "displayName": "ZenStack RedwoodJS Integration", - "version": "2.5.0", + "version": "2.5.1", "description": "CLI and runtime for integrating ZenStack with RedwoodJS projects.", "repository": { "type": "git", diff --git a/packages/plugins/openapi/package.json b/packages/plugins/openapi/package.json index 38f55551..b8d5a5bd 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": "2.5.0", + "version": "2.5.1", "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 7b36c053..0f2c9358 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": "2.5.0", + "version": "2.5.1", "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 c35644f8..1dd116b9 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": "2.5.0", + "version": "2.5.1", "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 4f457071..89053c14 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": "2.5.0", + "version": "2.5.1", "description": "ZenStack plugin for tRPC", "main": "index.js", "repository": { diff --git a/packages/runtime/package.json b/packages/runtime/package.json index ec9e03ff..923f7688 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/runtime", "displayName": "ZenStack Runtime Library", - "version": "2.5.0", + "version": "2.5.1", "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 75b71d61..5d71d44a 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -3,7 +3,7 @@ "publisher": "zenstack", "displayName": "ZenStack Language Tools", "description": "FullStack enhancement for Prisma ORM: seamless integration from database to UI", - "version": "2.5.0", + "version": "2.5.1", "author": { "name": "ZenStack Team" }, diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 6cd79658..3d1cf97d 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/sdk", - "version": "2.5.0", + "version": "2.5.1", "description": "ZenStack plugin development SDK", "main": "index.js", "scripts": { diff --git a/packages/sdk/src/model-meta-generator.ts b/packages/sdk/src/model-meta-generator.ts index d4cf52ab..469cfa88 100644 --- a/packages/sdk/src/model-meta-generator.ts +++ b/packages/sdk/src/model-meta-generator.ts @@ -29,6 +29,7 @@ import { getRelationField, hasAttribute, isAuthInvocation, + isDelegateModel, isEnumFieldReference, isForeignKeyField, isIdField, @@ -298,8 +299,15 @@ function getBackLink(field: DataModelField) { const relName = getRelationName(field); - // in case of polymorphism, the source model is the base delegate model - const sourceModel = field.$inheritedFrom ?? (field.$container as DataModel); + let sourceModel: DataModel; + if (field.$inheritedFrom && isDelegateModel(field.$inheritedFrom)) { + // field is inherited from a delegate model, use it as the source + sourceModel = field.$inheritedFrom; + } else { + // otherwise use the field's container model as the source + sourceModel = field.$container as DataModel; + } + const targetModel = field.type.reference.ref as DataModel; for (const otherField of targetModel.fields) { diff --git a/packages/server/package.json b/packages/server/package.json index f3e91395..3c2854f4 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/server", - "version": "2.5.0", + "version": "2.5.1", "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 aa856216..6a1b1a03 100644 --- a/packages/testtools/package.json +++ b/packages/testtools/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/testtools", - "version": "2.5.0", + "version": "2.5.1", "description": "ZenStack Test Tools", "main": "index.js", "private": true, diff --git a/tests/integration/tests/enhancements/with-policy/abstract.test.ts b/tests/integration/tests/enhancements/with-policy/abstract.test.ts new file mode 100644 index 00000000..0987df37 --- /dev/null +++ b/tests/integration/tests/enhancements/with-policy/abstract.test.ts @@ -0,0 +1,91 @@ +import { loadSchema } from '@zenstackhq/testtools'; + +describe('Abstract models', () => { + it('connect test1', async () => { + const { enhance } = await loadSchema( + ` + model User { + id Int @id @default(autoincrement()) + profile Profile? @relation(fields: [profileId], references: [id]) + profileId Int? @unique + + @@allow('create,read', true) + @@allow('update', auth().id == 1) + } + + abstract model BaseProfile { + id Int @id @default(autoincrement()) + user User? + + @@allow('all', true) + } + + model Profile extends BaseProfile { + name String + } + ` + ); + + const db = enhance({ id: 2 }); + const user = await db.user.create({ data: { id: 1 } }); + const profile = await db.profile.create({ data: { id: 1, name: 'John' } }); + await expect( + db.profile.update({ where: { id: 1 }, data: { user: { connect: { id: user.id } } } }) + ).toBeRejectedByPolicy(); + await expect( + db.user.update({ where: { id: 1 }, data: { profile: { connect: { id: profile.id } } } }) + ).toBeRejectedByPolicy(); + + const db1 = enhance({ id: 1 }); + await expect( + db1.profile.update({ where: { id: 1 }, data: { user: { connect: { id: user.id } } } }) + ).toResolveTruthy(); + await expect( + db1.user.update({ where: { id: 1 }, data: { profile: { connect: { id: profile.id } } } }) + ).toResolveTruthy(); + }); + + it('connect test2', async () => { + const { enhance } = await loadSchema( + ` + model User { + id Int @id @default(autoincrement()) + profile Profile? + + @@allow('all', true) + } + + abstract model BaseProfile { + id Int @id @default(autoincrement()) + user User? @relation(fields: [userId], references: [id]) + userId Int? @unique + + @@allow('create,read', true) + @@allow('update', auth().id == 1) + } + + model Profile extends BaseProfile { + name String + } + ` + ); + + const db = enhance({ id: 2 }); + const user = await db.user.create({ data: { id: 1 } }); + const profile = await db.profile.create({ data: { id: 1, name: 'John' } }); + await expect( + db.profile.update({ where: { id: 1 }, data: { user: { connect: { id: user.id } } } }) + ).toBeRejectedByPolicy(); + await expect( + db.user.update({ where: { id: 1 }, data: { profile: { connect: { id: profile.id } } } }) + ).toBeRejectedByPolicy(); + + const db1 = enhance({ id: 1 }); + await expect( + db1.profile.update({ where: { id: 1 }, data: { user: { connect: { id: user.id } } } }) + ).toResolveTruthy(); + await expect( + db1.user.update({ where: { id: 1 }, data: { profile: { connect: { id: profile.id } } } }) + ).toResolveTruthy(); + }); +});