From 79a6d60d08b5c67dc0a40ab138f1648168935b68 Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Wed, 4 Mar 2026 18:30:58 -0800 Subject: [PATCH] fix(orm): handle self-referential relations in delegate models during schema push Skip self-referential FK relations when building the topological sort graph in SchemaDbPusher, preventing a false cycle error when a model using @@delegate inheritance also has a self-referential relation. Fixes #2435 Co-Authored-By: Claude Sonnet 4.6 --- .../src/client/helpers/schema-db-pusher.ts | 4 ++ tests/regression/test/issue-2435.test.ts | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/regression/test/issue-2435.test.ts diff --git a/packages/orm/src/client/helpers/schema-db-pusher.ts b/packages/orm/src/client/helpers/schema-db-pusher.ts index 9c16e61e2..4886687ef 100644 --- a/packages/orm/src/client/helpers/schema-db-pusher.ts +++ b/packages/orm/src/client/helpers/schema-db-pusher.ts @@ -84,6 +84,10 @@ export class SchemaDbPusher { for (const field of Object.values(model.fields)) { // relation order if (field.relation && field.relation.fields && field.relation.references) { + // skip self-referential relations to avoid false cycle in toposort + if (field.type === model.name) { + continue; + } const targetModel = requireModel(this.schema, field.type); // edge: fk side -> target model graph.push([model, targetModel]); diff --git a/tests/regression/test/issue-2435.test.ts b/tests/regression/test/issue-2435.test.ts new file mode 100644 index 000000000..944805942 --- /dev/null +++ b/tests/regression/test/issue-2435.test.ts @@ -0,0 +1,37 @@ +import { createTestClient } from '@zenstackhq/testtools'; +import { describe, expect, it } from 'vitest'; + +// https://github.com/zenstackhq/zenstack/issues/2435 +describe('Regression for issue 2435', () => { + it('should not throw cyclic dependency error when delegate model has a self-referential relation', async () => { + await expect( + createTestClient( + ` +enum ContentType { + POST + ARTICLE + QUESTION +} + +model Content { + id Int @id @default(autoincrement()) + type ContentType + @@delegate(type) +} + +model Post extends Content { + post1s Post1[] + replies Post[] @relation("PostReplies") + parentId Int? + parent Post? @relation("PostReplies", fields: [parentId], references: [id]) +} + +model Post1 extends Content { + post Post @relation(fields: [postId], references: [id]) + postId Int +} + `, + ), + ).toResolveTruthy(); + }); +});