zod-prisma-types icon indicating copy to clipboard operation
zod-prisma-types copied to clipboard

It's not possible to omit relation field

Open oceandrama opened this issue 1 year ago • 3 comments

With this schema:

model Article {
  id        Int   @id @default(autoincrement())
  authorId  Int?
  author    User? @relation(fields: [authorId], references: [id])
}

it generates

export const ArticleCreateInputSchema: z.ZodType<Prisma.ArticleCreateInput> = z
  .object({
    author: z.lazy(() => UserCreateNestedOneWithoutArticlesInputSchema).optional()
  })
  .strict();

export const ArticleUncheckedCreateInputSchema: z.ZodType<Omit<Prisma.ArticleUncheckedCreateInput, "userId">> = z
  .object({
    id: z.number().int().optional(),
    authorId: z.number().int().optional().nullable()
  })
  .strict();

You can add omit to authorId

model Article {
  id        Int   @id @default(autoincrement())
  authorId  Int? /// @zod.custom.omit([input])
  author    User? @relation(fields: [authorId], references: [id])
}

to get this

export const ArticleCreateInputSchema: z.ZodType<Prisma.ArticleCreateInput> = z
  .object({
    author: z.lazy(() => UserCreateNestedOneWithoutArticlesInputSchema).optional()
  })
  .strict();

export const ArticleUncheckedCreateInputSchema: z.ZodType<Omit<Prisma.ArticleUncheckedCreateInput, "userId">> = z
  .object({
    id: z.number().int().optional(),
    // omitted: authorId: z.number().int().optional().nullable() })
  .strict();

It's still possible to create article with author using author: { connect: { id } } instead of authorId

And if you try to add omit to author too

model Article {
  id        Int   @id @default(autoincrement())
  authorId  Int? /// @zod.custom.omit([input])
  author    User? @relation(fields: [authorId], references: [id]) /// @zod.custom.omit([input])
}

you recieve an error:

[@zod generator error]: Validator 'custom' is not valid for type 'User'. [Error Location]: Model: 'Article', Field: 'author'.

oceandrama avatar Mar 17 '23 12:03 oceandrama

@oceandrama thanks for the hint. I need to look into this in more detail but I think it is because the omitted fields are currently only propagated to the "normal" create, update, etc. input types and not to the nested ones.

chrishoermann avatar Mar 17 '23 15:03 chrishoermann

I think it is because the omitted fields are currently only propagated to the "normal" create, update, etc. input types and not to the nested ones.

Glad I found this issue, was messing up my use case. Will leave some info incase it helps.

Relevant model from my schema:

model Task {
  id          String    @id @default(auto()) @map("_id") @db.ObjectId
  completed   Boolean   @default(false)
  title       String /// @zod.string.min(1)
  size        TaskSize  @default(MEDIUM)
  description String?
  number      Int   /// @zod.custom.omit(["model", "input"])
  start       DateTime? // Date at which this task can be worked on
  end         DateTime? // Day this task is due
  url         String? // Page that triggered this task to be created
User             User            @relation(fields: [userEmail], references: [email])
  userEmail        String          @unique
}

I am validating my input using the generated TaskUncheckedCreateWithoutUserInputSchema, but was confused why the annotation on the number field wasn't seeming to propogate to the generated schema. I generate that value serverside and append it to the user input, so wanted to omit it from the input types.

I suppose my solution will be to use the base unchecked input type, and simply omit both the user and number types from the input. Would be nice to get support added for the omits on the non-base input versions at some point in the future, or at least update the README to make that clearer.

EDIT: Yep, worked like a charm. As per the OP though, I think you have to stick to the unchecked schema variants for it to work properly.

andenacitelli avatar Apr 02 '23 17:04 andenacitelli

Just thought I'd bump this as well, running into a simlar issue. My use case is that when a user applies for a job, we want to auto-fill the applicant from the auth context.

model JobApplication {
  id           String @id @default(cuid())
  cover_letter String

  job_post    JobPost @relation(fields: [job_post_id], references: [id], onDelete: Cascade)
  job_post_id String

  applicant    Profile @relation(fields: [applicant_id], references: [id], onDelete: Cascade)
  applicant_id String /// @zod.custom.omit([input])

  @@index([job_post_id])
  @@index([applicant_id])
}

Using the unchcked inputs isn't too practical in my example

const application = await ctx.prisma.jobApplication.create({
    data: {
        ...input,
        job_post_id: undefined,
        applicant: {
            connect: {
                id: ctx.session.user.profile_id,
            },
        },
        job_post: {
            connect: {
                id: input.job_post_id,
            },
        },
    },
});

Ideally would love to be able to go

...
applicant    Profile @relation(fields: [applicant_id], references: [id], onDelete: Cascade) /// @zod.custom.omit([input])
...
const application = await ctx.prisma.jobApplication.create({
    data: {
        ...input,
        applicant: {
            connect: {
                id: ctx.session.user.profile_id,
            },
        },
    },
});```

samthompsonkennedy avatar Apr 12 '23 04:04 samthompsonkennedy