Skip to content

Commit d28a8db

Browse files
committed
fix: nested createMany with skipDuplicates option is not handled correctly
1 parent 269809a commit d28a8db

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

packages/runtime/src/enhancements/policy/handler.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,10 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
734734
) => {
735735
for (const item of enumerate(args.data)) {
736736
if (args.skipDuplicates) {
737-
if (await this.hasDuplicatedUniqueConstraint(model, item, db)) {
737+
// get a reversed query to include fields inherited from upstream mutation,
738+
// it'll be merged with the create payload for unique constraint checking
739+
const reversedQuery = this.utils.buildReversedQuery(context);
740+
if (await this.hasDuplicatedUniqueConstraint(model, { ...reversedQuery, ...item }, db)) {
738741
if (this.shouldLogQuery) {
739742
this.logger.info(`[policy] \`createMany\` skipping duplicate ${formatObject(item)}`);
740743
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { loadSchema } from '@zenstackhq/testtools';
2+
3+
describe('issue 1162', () => {
4+
it('regression', async () => {
5+
const { enhance } = await loadSchema(
6+
`
7+
model User {
8+
id String @id @default(cuid())
9+
companies CompanyUser[]
10+
@@allow('all', true)
11+
}
12+
13+
model Company {
14+
id String @id @default(cuid())
15+
users CompanyUser[]
16+
@@allow('all', true)
17+
}
18+
19+
model CompanyUser {
20+
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
21+
companyId String
22+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
23+
userId String
24+
@@id([companyId, userId])
25+
@@allow('all', true)
26+
}
27+
`,
28+
{ logPrismaQuery: true }
29+
);
30+
31+
const db = enhance();
32+
33+
await db.user.create({ data: { id: 'abc' } });
34+
await db.user.create({ data: { id: 'def' } });
35+
await db.company.create({ data: { id: '1', users: { create: { userId: 'abc' } } } });
36+
await expect(
37+
db.company.update({
38+
where: { id: '1' },
39+
data: {
40+
users: {
41+
createMany: {
42+
data: [{ userId: 'abc' }, { userId: 'def' }],
43+
skipDuplicates: true,
44+
},
45+
},
46+
},
47+
include: { users: true },
48+
})
49+
).resolves.toMatchObject({
50+
users: expect.arrayContaining([
51+
{ companyId: '1', userId: 'abc' },
52+
{ companyId: '1', userId: 'def' },
53+
]),
54+
});
55+
});
56+
});

0 commit comments

Comments
 (0)