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(); + }); +});