Rubyと筋肉とギターとわたし

筋トレが仕事です

【Prisma】upsertがうまく動かないときに確認すること

おひさしどうもてぃです。

最近は個人開発で自分のshopだったりhomeブログだったり作っていて、あまり記事をアウトプットできてなかったので書きます。

いつも通り解決シリーズです。

環境

  • NestJS 8.0.0
  • Prisma client 4.0.0

NestJS × Prisma × GraphQLの構成です。

問題

Prismaのupsertで要求されるwhereの型にidしか表示されず、他の条件(たとえばemailとか)を入れたとしてもエラーを返されていました。

該当のコードはこちら。

import { Injectable } from '@nestjs/common'
import { Prisma, User } from '@prisma/client'
import { PrismaService } from '~/prisma/prisma.service'

@Injectable()
export class UsersService {
  constructor(private readonly prisma: PrismaService) {}

  // auth validateで使用
  async findOrCreateBy(email: string): Promise<User> {
    return await this.prisma.user.upsert({
      where: { email: email },
      update: { email: email },
      create: { email: email, name: 'test user' },
    })
  }
}

ちな、Prisma公式を参考にしました。

www.prisma.io

上のままだと型のエラーが出ていたのでupsertの定義元の型を確認してみました。

すると…

  /**
   * User upsert
   */
  export type UserUpsertArgs = {
    /**
     * Select specific fields to fetch from the User
     * 
    **/
    select?: UserSelect | null
    /**
     * Choose, which related nodes to fetch as well.
     * 
    **/
    include?: UserInclude | null
    /**
     * The filter to search for the User to update in case it exists.
     * 
    **/
    where: UserWhereUniqueInput
    /**
     * In case the User found by the `where` argument doesn't exist, create a new User with this data.
     * 
    **/
    create: XOR<UserCreateInput, UserUncheckedCreateInput>
    /**
     * In case the User was found with the provided `where` argument, update it with this data.
     * 
    **/
    update: XOR<UserUpdateInput, UserUncheckedUpdateInput>
  }
  .
  .
  .

  export type UserWhereUniqueInput = {
    id?: string
  }

upsertのwhereに使われているのは UserWhereUniqueInputで、この子を確認してみるとidしか型にない…

どういうこと!?

公式をもっとちゃんと見ましょう

そういうこと。

Upsertのところをもっとちゃんと見てみましょう。

www.prisma.io

↑のwhereのところに注目。

Wraps all unique fields of a model so that individual records can be selected

unique field、これだわ。

もっとわかりやっすく書いてほしい…(切実)、せめて大文字とか。

解決

ということで、prisma.schemaにunique制約をかけて…

// User(ユーザー)
model User {
  id             String     @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
  email          String?    @unique() @default("")
  phoneNumber    String?    @unique() @default("") @map("phone_number")
  companyName    String?    @default("") @map("company_name")
  address String?    @default("")

  createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
  updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz(6)
}

マイグレーションをかければ

$ npx prisma migrate dev --name add_unique --skip-seed

UserWhereUniqueInputがこんな感じになりました。

  export type UserWhereUniqueInput = {
    id?: string
    email?: string
    phoneNumber?: string
  }

ちゃんとUnique制約つけたカラムが追加されてました。