I have entity object User defined like:
@Entity({
name: 'user',
})
export class User extends RootBaseEntity {
@Column({ type: String })
uid: string;
@Index()
@Column({ type: String, unique: true })
email: string;
@Column()
@Exclude({ toPlainOnly: true })
password: string;
@Index()
@Column({ type: String, name: 'first_name' })
firstName: string | null;
@Index()
@Column({ type: String, name: 'last_name' })
lastName: string | null;
@ManyToOne(() => Role, (role) => role.users, {
eager: true,
})
@JoinColumn({ name: 'role_id', referencedColumnName: 'id' })
role: Role;
@ManyToOne(() => Status, (status) => status.users, {
eager: true,
})
@JoinColumn({ name: 'status_id', referencedColumnName: 'id' })
status: Status;
}
Role and Status are also entities defined like:
@Entity({
name: 'role',
})
export class Role extends RootBaseEntity {
@Column({
type: 'enum',
enum: RoleEnum,
name: 'name',
})
@Index({
unique: true,
})
name: string;
@OneToMany(() => User, (user) => user.role)
@JoinColumn({ referencedColumnName: 'id' })
users: User[];
}
,
@Entity({
name: 'status',
})
export class Status extends RootBaseEntity {
@Column({
type: 'enum',
enum: StatusEnum,
name: 'name',
})
@Index({
unique: true,
})
name: string;
@OneToMany(() => User, (user) => user.status)
@JoinColumn({ referencedColumnName: 'id' })
users: User[];
}
Example of entire User entity:
{
id: 1,
createdAt: 2024-01-31T13:20:42.910Z,
updatedAt: 2024-01-31T13:20:42.910Z,
deletedAt: null,
uid: '07ed21c5-f183-49ac-bba9-433118cf20cb',
email: '[email protected]',
password: '$2a$10$Ts0y.5CdnTRsP6Yy2ZZJsunNiqfRej9oNSFw7wmr.DK9z7SoFmWou',
firstName: 'Super',
lastName: 'Admin',
role: {
id: 2,
createdAt: 2024-01-31T13:20:42.783Z,
updatedAt: 2024-01-31T13:20:42.783Z,
deletedAt: null,
name: 'admin'
},
status: {
id: 1,
createdAt: 2024-01-31T13:20:42.797Z,
updatedAt: 2024-01-31T13:20:42.797Z,
deletedAt: null,
name: 'active'
}
}
I want to transform User entity to UserDto, which should in the end look like this:
{
uid: "a103234b-1b46-414b-a380-7090d8939b4f",
email: "[email protected]",
firstName: "John",
lastName: "Doe",
role: 1,
status: 1,
createdAt: "2024-01-31T13:20:43.007Z"
}
Properties role and status should be equal to Role.id and Status.id.
What I currently have defined as UserDto:
@Exclude()
export class UserDto {
@Expose()
@IsString()
uid: string;
@Expose()
@IsString()
email: string;
@Expose()
@IsString()
firstName: string;
@Expose()
@IsString()
lastName: string;
Expose()
@Type(() => RoleDto['id'])
@Transform(({ value }) => {
console.log(value);
return value.id;
})
role: RoleDto['id'];
@Expose()
@Type(() => StatusDto)
@Transform(({ value }) => value.id)
status: StatusDto['id'];
@Expose()
@IsDate()
createdAt: Date;
}
RoleDto and StatusDto are defined like:
@Exclude()
export class RoleDto {
@Expose()
@IsNumber()
id: number;
}
,
@Exclude()
export class StatusDto {
@Expose()
@IsNumber()
id: number;
}
The problem:
In the @Transform decorator, when I return value.id and then console.log(value), I get two logs:
1.
{
id: 2,
createdAt: 2024-01-31T13:20:42.783Z,
updatedAt: 2024-01-31T13:20:42.783Z,
deletedAt: null,
name: 'admin'
}
2
And since I'm returning value.id, in the second iteration there is no more id property, but the value is just plain number (the actual id), and thus the role is set to undefined.
How to work around this? What am I missing here? Is there a better solution to this simple conversion from User to UserDto? Thanks
You need to add a property to the transformation decorator toClassOnly.
Here's an explanation from the developer https://github.com/nestjs/nest/issues/3842#issuecomment-575041486