Skip to content

Commit 03d6f7f

Browse files
authored
fix(delegate): update @updatedAt fields inherited from delegate bases automatically (#2119)
1 parent 943b768 commit 03d6f7f

File tree

4 files changed

+72
-23
lines changed

4 files changed

+72
-23
lines changed

packages/runtime/src/enhancements/node/delegate.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
NestedWriteVisitor,
1111
clone,
1212
enumerate,
13+
getFields,
1314
getIdFields,
1415
getModelInfo,
1516
isDelegateModel,
@@ -816,12 +817,19 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
816817
return super.updateMany(args);
817818
}
818819

819-
const simpleUpdateMany = Object.keys(args.data).every((key) => {
820+
let simpleUpdateMany = Object.keys(args.data).every((key) => {
820821
// check if the `data` clause involves base fields
821822
const fieldInfo = resolveField(this.options.modelMeta, this.model, key);
822823
return !fieldInfo?.inheritedFrom;
823824
});
824825

826+
// check if there are any `@updatedAt` fields from delegate base models
827+
if (simpleUpdateMany) {
828+
if (this.getUpdatedAtFromDelegateBases(this.model).length > 0) {
829+
simpleUpdateMany = false;
830+
}
831+
}
832+
825833
return this.queryUtils.transaction(this.prisma, (tx) =>
826834
this.doUpdateMany(tx, this.model, args, simpleUpdateMany)
827835
);
@@ -947,6 +955,13 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
947955
return !fieldInfo?.inheritedFrom;
948956
});
949957

958+
// check if there are any `@updatedAt` fields from delegate base models
959+
if (simpleUpdateMany) {
960+
if (this.getUpdatedAtFromDelegateBases(model).length > 0) {
961+
simpleUpdateMany = false;
962+
}
963+
}
964+
950965
if (simpleUpdateMany) {
951966
// check if the `where` clause involves base fields
952967
simpleUpdateMany = Object.keys(args.where || {}).every((key) => {
@@ -1053,6 +1068,15 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
10531068
delete data[field];
10541069
}
10551070
}
1071+
1072+
// if we're updating any field, we need to take care of updating `@updatedAt`
1073+
// fields inherited from delegate base models
1074+
if (Object.keys(data).length > 0) {
1075+
const updatedAtFields = this.getUpdatedAtFromDelegateBases(model);
1076+
for (const fieldInfo of updatedAtFields) {
1077+
this.injectBaseFieldData(model, fieldInfo, new Date(), data, 'update');
1078+
}
1079+
}
10561080
}
10571081

10581082
// #endregion
@@ -1477,5 +1501,20 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
14771501
return result;
14781502
}
14791503

1504+
private getUpdatedAtFromDelegateBases(model: string) {
1505+
const result: FieldInfo[] = [];
1506+
const modelFields = getFields(this.options.modelMeta, model);
1507+
for (const fieldInfo of Object.values(modelFields)) {
1508+
if (
1509+
fieldInfo.attributes?.some((attr) => attr.name === '@updatedAt') &&
1510+
fieldInfo.inheritedFrom &&
1511+
isDelegateModel(this.options.modelMeta, fieldInfo.inheritedFrom)
1512+
) {
1513+
result.push(fieldInfo);
1514+
}
1515+
}
1516+
return result;
1517+
}
1518+
14801519
// #endregion
14811520
}

tests/integration/tests/enhancements/with-delegate/enhanced-client.test.ts

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,8 @@ describe('Polymorphism Test', () => {
476476
it('update simple', async () => {
477477
const { db, videoWithOwner: video } = await setup();
478478

479+
const read = await db.ratedVideo.findUnique({ where: { id: video.id } });
480+
479481
// update with concrete
480482
let updated = await db.ratedVideo.update({
481483
where: { id: video.id },
@@ -484,6 +486,7 @@ describe('Polymorphism Test', () => {
484486
});
485487
expect(updated.rating).toBe(200);
486488
expect(updated.owner).toBeTruthy();
489+
expect(updated.updatedAt.getTime()).toBeGreaterThan(read.updatedAt.getTime());
487490

488491
// update with base
489492
updated = await db.video.update({
@@ -613,17 +616,18 @@ describe('Polymorphism Test', () => {
613616
});
614617

615618
// updateMany with filter
616-
await expect(
617-
db.user.update({
618-
where: { id: user.id },
619-
data: {
620-
ratedVideos: { updateMany: { where: { duration: 1 }, data: { rating: 333 } } },
621-
},
622-
include: { ratedVideos: true },
623-
})
624-
).resolves.toMatchObject({
619+
const read = await db.ratedVideo.findFirst({ where: { duration: 1 } });
620+
const r = await db.user.update({
621+
where: { id: user.id },
622+
data: {
623+
ratedVideos: { updateMany: { where: { duration: 1 }, data: { rating: 333 } } },
624+
},
625+
include: { ratedVideos: true },
626+
});
627+
expect(r).toMatchObject({
625628
ratedVideos: expect.arrayContaining([expect.objectContaining({ rating: 333 })]),
626629
});
630+
expect(r.ratedVideos[0].updatedAt.getTime()).toBeGreaterThan(read.updatedAt.getTime());
627631

628632
// updateMany without filter
629633
await expect(
@@ -1025,22 +1029,23 @@ describe('Polymorphism Test', () => {
10251029
).rejects.toThrow('is a delegate');
10261030

10271031
// update
1028-
await expect(
1029-
db.ratedVideo.upsert({
1030-
where: { id: video.id },
1031-
create: {
1032-
viewCount: 1,
1033-
duration: 300,
1034-
url: 'xyz',
1035-
rating: 100,
1036-
owner: { connect: { id: user.id } },
1037-
},
1038-
update: { duration: 200 },
1039-
})
1040-
).resolves.toMatchObject({
1032+
const read = await db.ratedVideo.findUnique({ where: { id: video.id } });
1033+
const r = await db.ratedVideo.upsert({
1034+
where: { id: video.id },
1035+
create: {
1036+
viewCount: 1,
1037+
duration: 300,
1038+
url: 'xyz',
1039+
rating: 100,
1040+
owner: { connect: { id: user.id } },
1041+
},
1042+
update: { duration: 200 },
1043+
});
1044+
expect(r).toMatchObject({
10411045
id: video.id,
10421046
duration: 200,
10431047
});
1048+
expect(r.updatedAt.getTime()).toBeGreaterThan(read.updatedAt.getTime());
10441049

10451050
// create
10461051
const created = await db.ratedVideo.upsert({

tests/integration/tests/enhancements/with-delegate/plugin-interaction.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ describe('Polymorphic Plugin Interaction Test', () => {
6565
id: 1,
6666
assetType: 'video',
6767
createdAt: new Date(),
68+
updatedAt: new Date(),
6869
viewCount: 100,
6970
})
7071
).toBeTruthy();
@@ -74,6 +75,7 @@ describe('Polymorphic Plugin Interaction Test', () => {
7475
id: 1,
7576
assetType: 'video',
7677
createdAt: new Date(),
78+
updatedAt: new Date(),
7779
viewCount: 100,
7880
videoType: 'ratedVideo', // should be stripped
7981
}).videoType
@@ -87,6 +89,7 @@ describe('Polymorphic Plugin Interaction Test', () => {
8789
duration: 100,
8890
url: 'http://example.com',
8991
createdAt: new Date(),
92+
updatedAt: new Date(),
9093
viewCount: 100,
9194
})
9295
).toBeTruthy();
@@ -98,6 +101,7 @@ describe('Polymorphic Plugin Interaction Test', () => {
98101
videoType: 'ratedVideo',
99102
url: 'http://example.com',
100103
createdAt: new Date(),
104+
updatedAt: new Date(),
101105
viewCount: 100,
102106
})
103107
).toThrow('duration');

tests/integration/tests/enhancements/with-delegate/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ model User {
1212
model Asset {
1313
id Int @id @default(autoincrement())
1414
createdAt DateTime @default(now())
15+
updatedAt DateTime @updatedAt
1516
viewCount Int @default(0)
1617
owner User? @relation(fields: [ownerId], references: [id])
1718
ownerId Int?

0 commit comments

Comments
 (0)