Skip to content

Commit e9482fe

Browse files
ymc9claude
andauthored
fix(orm): fix _count returning 0 for self-referential relations on delegate models (#2555)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 744c760 commit e9482fe

File tree

2 files changed

+55
-4
lines changed

2 files changed

+55
-4
lines changed

packages/orm/src/client/crud/dialects/base-dialect.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,25 +1292,29 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
12921292
const fieldModel = fieldDef.type as GetModels<Schema>;
12931293
let fieldCountQuery: SelectQueryBuilder<any, any, any>;
12941294

1295+
// Use a unique alias for the subquery to avoid ambiguous references when
1296+
// fieldModel === model (self-referential relation on a delegate model)
1297+
const subQueryAlias = tmpAlias(`${parentAlias}$_${field}$count`);
1298+
12951299
// join conditions
12961300
const m2m = getManyToManyRelation(this.schema, model, field);
12971301
if (m2m) {
12981302
// many-to-many relation, count the join table
1299-
fieldCountQuery = this.buildModelSelect(fieldModel, fieldModel, value as any, false)
1303+
fieldCountQuery = this.buildModelSelect(fieldModel, subQueryAlias, value as any, false)
13001304
.innerJoin(m2m.joinTable, (join) =>
13011305
join
1302-
.onRef(`${m2m.joinTable}.${m2m.otherFkName}`, '=', `${fieldModel}.${m2m.otherPKName}`)
1306+
.onRef(`${m2m.joinTable}.${m2m.otherFkName}`, '=', `${subQueryAlias}.${m2m.otherPKName}`)
13031307
.onRef(`${m2m.joinTable}.${m2m.parentFkName}`, '=', `${parentAlias}.${m2m.parentPKName}`),
13041308
)
13051309
.select(eb.fn.countAll().as(`_count$${field}`));
13061310
} else {
13071311
// build a nested query to count the number of records in the relation
1308-
fieldCountQuery = this.buildModelSelect(fieldModel, fieldModel, value as any, false).select(
1312+
fieldCountQuery = this.buildModelSelect(fieldModel, subQueryAlias, value as any, false).select(
13091313
eb.fn.countAll().as(`_count$${field}`),
13101314
);
13111315

13121316
// join conditions
1313-
const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
1317+
const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, subQueryAlias);
13141318
for (const [left, right] of joinPairs) {
13151319
fieldCountQuery = fieldCountQuery.whereRef(left, '=', right);
13161320
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { createTestClient } from '@zenstackhq/testtools';
2+
import { describe, expect, it } from 'vitest';
3+
4+
// https://github.com/zenstackhq/zenstack/issues/2452
5+
describe('Regression for issue 2452', () => {
6+
it('should return correct _count for self-referential relations in delegate models', async () => {
7+
const db = await createTestClient(
8+
`
9+
enum ContentType {
10+
Post
11+
Article
12+
Question
13+
}
14+
15+
model Content {
16+
id Int @id @default(autoincrement())
17+
type ContentType
18+
@@delegate(type)
19+
}
20+
21+
model Post extends Content {
22+
replies Post[] @relation("PostReplies")
23+
parentId Int?
24+
parent Post? @relation("PostReplies", fields: [parentId], references: [id])
25+
}
26+
`,
27+
);
28+
29+
// Create a parent post with 2 replies
30+
const parent = await db.post.create({
31+
data: {
32+
replies: {
33+
create: [{}, {}],
34+
},
35+
},
36+
});
37+
38+
// Query with _count should return the correct count
39+
const result = await db.post.findFirst({
40+
where: { id: parent.id },
41+
include: { _count: { select: { replies: true } } },
42+
});
43+
44+
expect(result).toBeTruthy();
45+
expect(result._count.replies).toBe(2);
46+
});
47+
});

0 commit comments

Comments
 (0)