Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions packages/orm/src/client/crud/dialects/lateral-join-dialect-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,19 @@ export abstract class LateralJoinDialectBase<Schema extends SchemaDef> extends B
objArgs,
...Object.entries<any>((payload as any).include)
.filter(([, value]) => value)
.map(([field]) => ({
[field]: eb.ref(`${parentResultName}$${field}.$data`),
})),
.map(([field, value]) => {
if (field === '_count') {
return {
[field]: this.buildCountJson(
relationModel as GetModels<Schema>,
eb,
relationModelAlias,
value,
),
};
}
return { [field]: eb.ref(`${parentResultName}$${field}.$data`) };
}),
);
}

Expand Down
9 changes: 9 additions & 0 deletions packages/orm/src/client/crud/dialects/sqlite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,15 @@ export class SqliteCrudDialect<Schema extends SchemaDef> extends BaseCrudDialect
...Object.entries<any>((payload as any).include)
.filter(([, value]) => value)
.map(([field, value]) => {
if (field === '_count') {
const subJson = this.buildCountJson(
relationModel,
eb,
tmpAlias(`${parentAlias}$${relationField}`),
value,
);
return [sql.lit(field), subJson];
}
const subJson = this.buildRelationJSON(
relationModel,
eb,
Expand Down
51 changes: 51 additions & 0 deletions tests/e2e/orm/client-api/find.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 +1189,57 @@ describe('Client find tests ', () => {
expect(result3?._count.posts).toBe(1);
});

it('supports _count nested inside an include', async () => {
// regression for https://github.com/zenstackhq/zenstack/issues/2669
const user = await createUser(client, 'u1@test.com');
const [post1] = await createPosts(client, user.id);
await client.comment.createMany({
data: [
{ content: 'c1', postId: post1.id },
{ content: 'c2', postId: post1.id },
],
});

// _count nested inside a relation's `include` (not `select`)
const result = await client.user.findFirst({
include: {
posts: {
include: {
_count: { select: { comments: true } },
},
},
},
});

expect(result?.posts).toHaveLength(2);
const p1 = result?.posts.find((p) => p.id === post1.id);
const p2 = result?.posts.find((p) => p.id !== post1.id);
expect(p1?._count).toEqual({ comments: 2 });
expect(p2?._count).toEqual({ comments: 0 });

// `_count: true` nested inside an include
const result2 = await client.user.findFirst({
include: {
posts: {
include: { _count: true },
},
},
});
expect(result2?.posts.find((p) => p.id === post1.id)?._count).toEqual({ comments: 2 });

// _count nested inside an include, with a filter on the counted relation
const result3 = await client.user.findFirst({
include: {
posts: {
include: {
_count: { select: { comments: { where: { content: 'c1' } } } },
},
},
},
});
expect(result3?.posts.find((p) => p.id === post1.id)?._count).toEqual({ comments: 1 });
});

it('rejects orderBy array elements with multiple keys', async () => {
await createUser(client, 'u1@test.com');

Expand Down
72 changes: 72 additions & 0 deletions tests/regression/test/issue-2669.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { createTestClient } from '@zenstackhq/testtools';
import { describe, expect, it } from 'vitest';

// https://github.com/zenstackhq/zenstack/issues/2669
describe.each([{ provider: 'sqlite' as const }, { provider: 'postgresql' as const }])(
'Regression for issue 2669 ($provider)',
({ provider }) => {
const schema = `
datasource db {
provider = '${provider}'
url = '${provider === 'sqlite' ? 'file:./dev.db' : '$DB_URL'}'
}

model User {
id Int @id @default(autoincrement())
email String @unique
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id])
authorId Int
comments Comment[]
}

model Comment {
id Int @id @default(autoincrement())
content String
post Post @relation(fields: [postId], references: [id])
postId Int
}
`;

it('supports _count inside a nested include', async () => {
const db = await createTestClient(schema, {
provider,
});

await db.user.create({
data: {
email: 'user1@test.com',
posts: {
create: {
title: 'Post1',
comments: {
create: [{ content: 'c1' }, { content: 'c2' }],
},
},
},
},
});

const result = await db.user.findMany({
include: {
posts: {
include: {
_count: {
select: { comments: true },
},
},
},
},
});

expect(result).toHaveLength(1);
expect(result[0]!.posts).toHaveLength(1);
expect(result[0]!.posts[0]!._count).toEqual({ comments: 2 });
});
},
);
Loading