unlight/prisma-nestjs-graphql

@Type() from Class transformer missing on relations

jasonmacdonald opened this issue · 1 comments

Hi Unlight,

I'm unsure if I may be missing something, but could you suggest a way to ensure that relations containing a transform call include the required Type() decorator on them?

If you include a transform on a column, any class that includes that entity as a relation does not call the transform when it is included as a nested object.

For example, I have the following Profile model, which contains the field email. I need to ensure that the email is always in lowercase. So, I added the following transform to the email field. Profile is referenced by User and User is referenced by Account.

model Profile {
   ...
   /// @Transformer.Transform(({ value, key, obj, type  }) => value.toLowerCase())
   /// @Validator.IsEmail()
   email      String   @unique
}

model User {
    ...
   profileId    String   @unique @map("profile_id") @db.Uuid
   profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade)
}

model Account {

   ownerId    String   @map("owner_id") @db.Uuid
   owner       User      @relation(fields: [ownerId], references: [id])
}

If you update your email directly as part of a call on ProfileInput, the transformation happens as expected. However, the transform isn't called if the update to email is part of a nested operation, say from a UserInput operation via an {update} on the profile.

This seems to happen because the reference on the generated UserInput class must declare its reference type to Profile with an @Type() decorator. Otherwise, it doesn't get picked up by the ValidationPipe to be run before hitting the resolver.

The only way I have been able to ensure it works in this specific example is with something like this.

  decorate_2_type  = "*Input*"
  decorate_2_field  = "{user,profile,owner}"
  decorate_2_from = "class-transformer"
  decorate_2_arguments = "['() => {propertyType.0}']"
  decorate_2_name  = Type

Here, I declare all the property names that might reference the profile table here. In this case, profile is the reference name on theUser model, and owner is the User reference name on Account. This covers the use case AccountUpdate->UserUpdate->ProfileUpdate and ensures that the class transform still executes.

While this works for this specific scenarios, it quickly becomes untenable when you try to account for every relation name, which might eventually include the profile. Since this nesting can theoretically get deep, and this is only for a single property on a table.

I noticed you already added the type automatically for Where. Is there a way to also add Type() for all relations? Is there any performance impact on that? Or is there an easier way to do this?

I'd be happy to try and submit a PR, but I wanted to check if I might be missing something first.

@unlight Any insights you can provide? Again I'm happy to help out if you point me in the right direction.