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
22 changes: 13 additions & 9 deletions packages/runtime/src/enhancements/node/delegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,20 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
}
}

if (value !== undefined) {
if (value?.orderBy) {
// refetch the field select/include value because it may have been
// updated during injection
const fieldValue = args[kind][field];

if (fieldValue !== undefined) {
if (fieldValue.orderBy) {
// `orderBy` may contain fields from base types
this.injectWhereHierarchy(fieldInfo.type, value.orderBy);
this.injectWhereHierarchy(fieldInfo.type, fieldValue.orderBy);
}

if (this.injectBaseFieldSelect(model, field, value, args, kind)) {
if (this.injectBaseFieldSelect(model, field, fieldValue, args, kind)) {
delete args[kind][field];
} else if (fieldInfo.isDataModel) {
let nextValue = value;
let nextValue = fieldValue;
if (nextValue === true) {
// make sure the payload is an object
args[kind][field] = nextValue = {};
Expand Down Expand Up @@ -1158,11 +1162,11 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
const base = this.getBaseModel(model);

if (base) {
// merge base fields
// fully merge base fields
const baseRelationName = this.makeAuxRelationName(base);
const baseData = entity[baseRelationName];
if (baseData && typeof baseData === 'object') {
const baseAssembled = this.assembleUp(base.name, baseData);
const baseAssembled = this.assembleHierarchy(base.name, baseData);
Object.assign(result, baseAssembled);
}
}
Expand Down Expand Up @@ -1209,14 +1213,14 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
const modelInfo = getModelInfo(this.options.modelMeta, model, true);

if (modelInfo.discriminator) {
// model is a delegate, merge sub model fields
// model is a delegate, fully merge concrete model fields
const subModelName = entity[modelInfo.discriminator];
if (subModelName) {
const subModel = getModelInfo(this.options.modelMeta, subModelName, true);
const subRelationName = this.makeAuxRelationName(subModel);
const subData = entity[subRelationName];
if (subData && typeof subData === 'object') {
const subAssembled = this.assembleDown(subModel.name, subData);
const subAssembled = this.assembleHierarchy(subModel.name, subData);
Object.assign(result, subAssembled);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1361,4 +1361,50 @@ describe('Polymorphism Test', () => {
],
});
});

it('merges hierarchy correctly', async () => {
const { enhance } = await loadSchema(
`
model Asset {
id Int @id @default(autoincrement())
type String
viewCount Int
comments Comment[]
@@delegate(type)
}

model Post extends Asset {
title String
}

model Comment {
id Int @id @default(autoincrement())
type String
asset Asset @relation(fields: [assetId], references: [id])
assetId Int
moderated Boolean
@@delegate(type)
}

model TextComment extends Comment {
text String
}
`,
{ enhancements: ['delegate'] }
);

const db = enhance();
const post = await db.post.create({ data: { title: 'Post1', viewCount: 1 } });
const comment = await db.textComment.create({
data: { text: 'Comment1', moderated: true, asset: { connect: { id: post.id } } },
});

// delegate include delegate
let r = await db.asset.findFirst({ include: { comments: true } });
expect(r).toMatchObject({ viewCount: 1, comments: [comment] });

// concrete include delegate
r = await db.post.findFirst({ include: { comments: true } });
expect(r).toMatchObject({ ...post, comments: [comment] });
});
});
74 changes: 74 additions & 0 deletions tests/regression/tests/issue-1698.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { loadSchema } from '@zenstackhq/testtools';
describe('issue 1968', () => {
it('regression', async () => {
const { enhance } = await loadSchema(
`
model House {
id Int @id @default(autoincrement())
doorTypeId Int
door Door @relation(fields: [doorTypeId], references: [id])
houseType String
@@delegate(houseType)
}
model PrivateHouse extends House {
size Int
}
model Skyscraper extends House {
height Int
}
model Door {
id Int @id @default(autoincrement())
color String
doorType String
houses House[]
@@delegate(doorType)
}
model IronDoor extends Door {
strength Int
}
model WoodenDoor extends Door {
texture String
}
`,
{ enhancements: ['delegate'] }
);

const db = enhance();
const door1 = await db.ironDoor.create({
data: { strength: 100, color: 'blue' },
});
console.log(door1);

const door2 = await db.woodenDoor.create({
data: { texture: 'pine', color: 'red' },
});
console.log(door2);

const house1 = await db.privateHouse.create({
data: { size: 5000, door: { connect: { id: door1.id } } },
});
console.log(house1);

const house2 = await db.skyscraper.create({
data: { height: 3000, door: { connect: { id: door2.id } } },
});
console.log(house2);

const r1 = await db.privateHouse.findFirst({ include: { door: true } });
console.log(r1);
expect(r1).toMatchObject({
door: { color: 'blue', strength: 100 },
});

const r2 = (await db.skyscraper.findMany({ include: { door: true } }))[0];
console.log(r2);
expect(r2).toMatchObject({
door: { color: 'red', texture: 'pine' },
});
});
});
Loading