-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(client): reproduction for #16423 m:n dangling pivot table entry …
…after deleting (#16428) * test(client): reproduction for #16423 m:n dangling pivot table entry after deleting Closes #16423 * Update packages/client/tests/functional/issues/16390-relation-mode-m-n-dangling-pivot/tests.ts [skip ci]
- Loading branch information
Showing
3 changed files
with
328 additions
and
0 deletions.
There are no files selected for viewing
23 changes: 23 additions & 0 deletions
23
packages/client/tests/functional/issues/16390-relation-mode-m-n-dangling-pivot/_matrix.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { defineMatrix } from '../../_utils/defineMatrix' | ||
import { Providers } from '../../_utils/providers' | ||
|
||
export default defineMatrix(() => [ | ||
[ | ||
{ | ||
provider: Providers.POSTGRESQL, | ||
relationMode: 'prisma', | ||
}, | ||
{ | ||
provider: Providers.POSTGRESQL, | ||
relationMode: '', // empty means default (foreignKeys) | ||
}, | ||
{ | ||
provider: Providers.MYSQL, | ||
relationMode: 'prisma', | ||
}, | ||
{ | ||
provider: Providers.MYSQL, | ||
relationMode: '', // empty means default (foreignKeys) | ||
}, | ||
], | ||
]) |
35 changes: 35 additions & 0 deletions
35
...s/client/tests/functional/issues/16390-relation-mode-m-n-dangling-pivot/prisma/_schema.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import testMatrix from '../_matrix' | ||
|
||
export default testMatrix.setupSchema(({ provider, relationMode }) => { | ||
// if relationMode is not defined, we do not add the line | ||
const relationModeLine = relationMode ? `relationMode = "${relationMode}"` : '' | ||
|
||
const schemaHeader = /* Prisma */ ` | ||
generator client { | ||
provider = "prisma-client-js" | ||
} | ||
datasource db { | ||
provider = "${provider}" | ||
url = env("DATABASE_URI_${provider}") | ||
${relationModeLine} | ||
} | ||
` | ||
return /* Prisma */ ` | ||
${schemaHeader} | ||
model Item { | ||
id Int @id @default(autoincrement()) | ||
categories Category[] | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime? @updatedAt | ||
} | ||
model Category { | ||
id Int @id @default(autoincrement()) | ||
items Item[] | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime? @updatedAt | ||
} | ||
` | ||
}) |
270 changes: 270 additions & 0 deletions
270
packages/client/tests/functional/issues/16390-relation-mode-m-n-dangling-pivot/tests.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
import testMatrix from './_matrix' | ||
|
||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
|
||
// @ts-ignore this is just for type checks | ||
declare let prisma: import('@prisma/client').PrismaClient | ||
|
||
testMatrix.setupTestSuite( | ||
(suiteConfig, suiteMeta) => { | ||
describe('issue 16390', () => { | ||
afterEach(async () => { | ||
// Start from a clean state | ||
await prisma.item.deleteMany({}) | ||
await prisma.category.deleteMany({}) | ||
if (suiteConfig['provider'] === 'mysql') { | ||
await prisma.$executeRaw`TRUNCATE TABLE \`_CategoryToItem\`;` | ||
} else { | ||
await prisma.$executeRaw`TRUNCATE TABLE "_CategoryToItem";` | ||
} | ||
}) | ||
|
||
afterAll(async () => { | ||
await prisma.$disconnect() | ||
}) | ||
|
||
test('when deleting an item, the corresponding entry in the implicit pivot table should be deleted', async () => { | ||
// Create one category | ||
const category = await prisma.category.create({ | ||
data: {}, | ||
}) | ||
expect(category).toMatchObject({ | ||
id: 1, | ||
createdAt: expect.any(Date), | ||
updatedAt: expect.any(Date), | ||
}) | ||
|
||
// Create one item linked to the category | ||
const item = await prisma.item.create({ | ||
data: { | ||
categories: { | ||
connect: { | ||
id: category.id, | ||
}, | ||
}, | ||
}, | ||
include: { | ||
categories: true, | ||
}, | ||
}) | ||
expect(item).toMatchObject({ | ||
categories: [{ id: 1, createdAt: expect.any(Date), updatedAt: expect.any(Date) }], | ||
id: 1, | ||
createdAt: expect.any(Date), | ||
updatedAt: expect.any(Date), | ||
}) | ||
|
||
// Check the pivot table entries | ||
let pivotTable | ||
if (suiteConfig['provider'] === 'mysql') { | ||
pivotTable = await prisma.$queryRaw`SELECT * FROM \`_CategoryToItem\`;` | ||
} else { | ||
pivotTable = await prisma.$queryRaw`SELECT * FROM "_CategoryToItem";` | ||
} | ||
expect(pivotTable).toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
A: 1, | ||
B: 1, | ||
}, | ||
] | ||
`) | ||
|
||
// Delete the item | ||
expect( | ||
await prisma.item.delete({ | ||
where: { | ||
id: item.id, | ||
}, | ||
}), | ||
).toMatchObject({ | ||
id: 1, | ||
createdAt: expect.any(Date), | ||
updatedAt: expect.any(Date), | ||
}) | ||
|
||
// Item query now returns null | ||
expect( | ||
await prisma.item.findUnique({ | ||
where: { | ||
id: item.id, | ||
}, | ||
include: { | ||
categories: true, | ||
}, | ||
}), | ||
).toBeNull() | ||
|
||
// Category has no items | ||
expect( | ||
await prisma.category.findUnique({ | ||
where: { | ||
id: category.id, | ||
}, | ||
include: { | ||
items: true, | ||
}, | ||
}), | ||
).toMatchObject({ | ||
id: 1, | ||
items: [], | ||
createdAt: expect.any(Date), | ||
updatedAt: expect.any(Date), | ||
}) | ||
|
||
// Everything looks good but.... | ||
// Let's check the pivot table | ||
|
||
// Check the pivot table entries | ||
let pivotTableAfterDelete | ||
if (suiteConfig['provider'] === 'mysql') { | ||
pivotTableAfterDelete = await prisma.$queryRaw`SELECT * FROM \`_CategoryToItem\`;` | ||
} else { | ||
pivotTableAfterDelete = await prisma.$queryRaw`SELECT * FROM "_CategoryToItem";` | ||
} | ||
|
||
// ... the pivot table entry is still there! | ||
// This is a bug in the relationMode="prisma" emulation | ||
if (suiteConfig.relationMode === 'prisma') { | ||
expect(pivotTableAfterDelete).toStrictEqual([ | ||
{ | ||
A: 1, | ||
B: 1, | ||
}, | ||
]) | ||
} else { | ||
// This is the expected behavior for prisma and foreignKeys | ||
// once this bug is fixed | ||
expect(pivotTableAfterDelete).toStrictEqual([]) | ||
} | ||
}) | ||
}) | ||
|
||
test('when deleting a category, the corresponding entry in the implicit pivot table should be deleted', async () => { | ||
// Create one category | ||
const category = await prisma.category.create({ | ||
data: {}, | ||
}) | ||
expect(category).toMatchObject({ | ||
id: 2, | ||
createdAt: expect.any(Date), | ||
updatedAt: expect.any(Date), | ||
}) | ||
|
||
// Create one item linked to the category | ||
const item = await prisma.item.create({ | ||
data: { | ||
categories: { | ||
connect: { | ||
id: category.id, | ||
}, | ||
}, | ||
}, | ||
include: { | ||
categories: true, | ||
}, | ||
}) | ||
expect(item).toMatchObject({ | ||
categories: [{ id: 2, createdAt: expect.any(Date), updatedAt: expect.any(Date) }], | ||
id: 2, | ||
createdAt: expect.any(Date), | ||
updatedAt: expect.any(Date), | ||
}) | ||
|
||
// Check the pivot table entries | ||
let pivotTable | ||
if (suiteConfig['provider'] === 'mysql') { | ||
pivotTable = await prisma.$queryRaw`SELECT * FROM \`_CategoryToItem\`;` | ||
} else { | ||
pivotTable = await prisma.$queryRaw`SELECT * FROM "_CategoryToItem";` | ||
} | ||
expect(pivotTable).toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
A: 2, | ||
B: 2, | ||
}, | ||
] | ||
`) | ||
|
||
// Delete the category | ||
expect( | ||
await prisma.category.delete({ | ||
where: { | ||
id: item.id, | ||
}, | ||
}), | ||
).toMatchObject({ | ||
id: 2, | ||
createdAt: expect.any(Date), | ||
updatedAt: expect.any(Date), | ||
}) | ||
|
||
// Category query now returns null | ||
expect( | ||
await prisma.category.findUnique({ | ||
where: { | ||
id: category.id, | ||
}, | ||
include: { | ||
items: true, | ||
}, | ||
}), | ||
).toBeNull() | ||
|
||
// Item has no category | ||
expect( | ||
await prisma.item.findUnique({ | ||
where: { | ||
id: item.id, | ||
}, | ||
include: { | ||
categories: true, | ||
}, | ||
}), | ||
).toMatchObject({ | ||
id: 2, | ||
categories: [], | ||
createdAt: expect.any(Date), | ||
updatedAt: expect.any(Date), | ||
}) | ||
|
||
// Everything looks good but.... | ||
// Let's check the pivot table | ||
|
||
// Check the pivot table entries | ||
let pivotTableAfterDelete | ||
if (suiteConfig['provider'] === 'mysql') { | ||
pivotTableAfterDelete = await prisma.$queryRaw`SELECT * FROM \`_CategoryToItem\`;` | ||
} else { | ||
pivotTableAfterDelete = await prisma.$queryRaw`SELECT * FROM "_CategoryToItem";` | ||
} | ||
|
||
// ... the pivot table entry is still there! | ||
// This is a bug in the relationMode="prisma" emulation | ||
// | ||
// TODO once the bug is fixed: remove conditional | ||
// pivot table should be empty | ||
if (suiteConfig.relationMode === 'prisma') { | ||
expect(pivotTableAfterDelete).toStrictEqual([ | ||
{ | ||
A: 2, | ||
B: 2, | ||
}, | ||
]) | ||
} else { | ||
// This is the expected behavior for prisma and foreignKeys | ||
// once this bug is fixed | ||
expect(pivotTableAfterDelete).toStrictEqual([]) | ||
} | ||
}) | ||
}, | ||
// Use `optOut` to opt out from testing the default selected providers | ||
// otherwise the suite will require all providers to be specified. | ||
{ | ||
optOut: { | ||
from: ['sqlite', 'mongodb', 'cockroachdb', 'sqlserver'], | ||
reason: 'Only testing postgresql and mysql', | ||
}, | ||
}, | ||
) |