prisma 入門

# 事前準備

## M1 Macにnodeとnpmをinstallする
こちらの記事にinstall手順がわかりやすくまとめられており、手順通りに行えば、問題なくinstall作業が完了できると思います。

https://nullnull.dev/blog/how-to-install-node-js-and-npm-on-m1-mac/#%F0%9F%8F%A9%F0%9F%91%A8%F0%9F%92%95____%F0%9F%92%95%F0%9F%91%A9

installの際には、LTSの最新版である `v16.14.2` を指定してinstallを行いました。

```
user@localhost ~ % nvm ls-remote
       v16.13.0   (LTS: Gallium)
       v16.13.1   (LTS: Gallium)
       v16.13.2   (LTS: Gallium)
       v16.14.0   (LTS: Gallium)
       v16.14.1   (LTS: Gallium)
->     v16.14.2   (Latest LTS: Gallium)
```

# prisma Quickstart
公式ドキュメントのQuickstartを進めていき、prismaの基本事項をざっと確認します。

https://www.prisma.io/docs/getting-started/quickstart


`npm run dev` を実行するとエラーが出るので、エラー文に従って、 `prisma generate` を実行します。

```
user@localhost ~ % npm run dev
Error: @prisma/client did not initialize yet. Please run "prisma generate" and try to import it again.
In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues
at new PrismaClient (/Users/nagaitakuya/MyWorkspace/starter/node_modules/.prisma/client/index.js:3:11)
at Object.<anonymous> (/Users/nagaitakuya/MyWorkspace/starter/script.ts:3:16)
at Module._compile (node:internal/modules/cjs/loader:1103:14)
at Module.m._compile (/Users/nagaitakuya/MyWorkspace/starter/node_modules/ts-node/src/index.ts:1455:23)
at Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
at Object.require.extensions.<computed> [as .ts] (/Users/nagaitakuya/MyWorkspace/starter/node_modules/ts-node/src/index.ts:1458:12)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
at phase4 (/Users/nagaitakuya/MyWorkspace/starter/node_modules/ts-node/src/bin.ts:567:12)
```

## prisma generate
以下のコマンドを叩くことで、Prisma schemaを読み、Prisma Clientコードを自動で作成できるそうです。

```
npx prisma generate
```

### npxとは(余談)
`npx` とはローカルでコマンドを実行する際に使用されるコマンドです。
node v5.2 以降では標準で内包されているみたいです。

npm でコマンドを実行する際に使用される `npm run <コマンド名>` を実行するためには、 `packge.json` にあらかじめ定義する必要があります。

```json
  "scripts": {
    "dev": "ts-node ./script.ts",
    "prisma": "prisma generate"
  },
```
未定義の場合、コマンドを実行できません。

```
user@localhost starter % npm run prisma generate
npm ERR! Missing script: "prisma"
npm ERR! 
npm ERR! To see a list of scripts, run:
npm ERR!   npm run

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/nagaitakuya/.npm/_logs/2022-04-09T03_19_27_775Z-debug-0.log
```

一方で、 npxを使用することで、`packge.json` にあらかじめ定義されていなくても、 `npx prisma generate` でコマンドを実行することができます。

https://nodejs.dev/learn/the-npx-nodejs-package-runner
https://zenn.dev/ryuu/articles/what-npxcommand

## npm run dev を再実行
ちなみに、 `npm run dev` は package.jsonにて次のようなコマンドが定義されています。

```json
"ts-node ./script.ts"
```

再度、 `npm run dev` を実行すると、 レコードを取得することができました！！

```json
[
  { id: 1, email: 'sarah@prisma.io', name: 'Sarah', posts: [] },
    {
      id: 2,
      email: 'maria@prisma.io',
      name: 'Maria',
  posts: [
      {
        id: 1,
        title: 'Hello World',
        content: null,
        published: false,
        authorId: 2
      }
    ]
  }
]
```

# MySQLとの接続を行う

* 新規プロジェクトでDBが用意されていない場合

https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases-typescript-mysql

* 既存プロジェクトでDBが既に用意されている場合

https://www.prisma.io/docs/getting-started/setup-prisma/add-to-existing-project/relational-databases-typescript-mysql

今回は、既存プロジェクトでDBが既に用意されていたので、上記のうち２つ目に絞って進めていきたいと思います。

# まず初めに
prismaを使い始める際には以下のコマンドを実行して、 スキーマを定義するためのファイルを生成します。

```
npx prisma init 
```

* ディレクトリ構成

```
.
├── node_modules
└── prisma
       └── shema.prisma
```

# 既存のDBからスキーマを持ってくる
以下のコマンドを実行すると、 既存のDBからテーブル定義などのスキーマを持ってきて、 `schema.prisma` に反映することができます。

```
npx prisma db pull
```

# テーブル間でリレーションを定義する
1対多のリレーションを定義する場合、 以下の例で考えると、
`Post` model(1対多の1側)に 
`author    User     @relation(fields: [authorId], references: [id])`
を定義し、

`User` model(1対多の多側)に
`posts   Post[]`
を定義してやると、 `Post` テーブルと `User` テーブル間で1対多のリレーションを定義することができる。

```scheme
model Post {
  id        Int      @id @default(autoincrement())
  title     String   @db.VarChar(255)
  createdAt DateTime @default(now()) @db.Timestamp(6)
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

model Profile {
  id     Int     @id @default(autoincrement())
  bio    String?
  user   User    @relation(fields: [userId], references: [id])
  userId Int     @unique
}

model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique @db.VarChar(255)
  name    String?  @db.VarChar(255)
  posts   Post[]
  profile Profile?
}
```
https://www.prisma.io/docs/concepts/components/prisma-schema/relations#relation-fields

クエリを発行する際に1対多のリレーションをもつテーブル間でjoinする方法については後ほど記述します。

# DBのテーブル名 & カラム名にmodel & フィールドをマッピングする
modelに関しては `@@map("table_name")` model内のフィールドに関しては、 `@map("colomn_name")` でDB側のテーブル名及び、カラム名にマッピングを行うことができるそうです。

```scheme
model MyUser {
  userId    Int     @id @default(autoincrement()) @map("user_id")
  firstName String? @map("first_name")
  lastName  String  @unique @map("last_name")

  @@map("my_user")
}
```

https://www.prisma.io/docs/concepts/components/prisma-schema/data-model#mapping-model-names-to-tables-or-collections

# prisma clientに反映する
新規で`schema.prisma` を作成した際、及び `schema.prisma` を編集した際には、以下のコマンドを実行して、 prisma client への反映を行う必要があります。

```
npx prisma generate
```

`schema.prisma` に定義されたスキーマがprisma clientに反映されるフローの詳細については公式チュートリアルにて図解がされています。

https://res.cloudinary.com/prismaio/image/upload/v1628761155/docs/FensWfo.png

# テーブルのjoinを行った上でレコードを取得する
`include` を使用してやることでテーブルのjoinを行うためのクエリを発行した上で、レコードの取得が行えるようになります。

```typescript
  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
      profile: true,
    },
  })
```

https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#include

## joinを行ったテーブルの中で特定のカラムだけ取得したい場合

```typescript
const users = await prisma.user.findMany({
  select: {
    name: true,
    posts: {
      select: {
        title: true,
      },
    },
  },
})
```
https://www.prisma.io/docs/concepts/components/prisma-client/select-fields#include-relations-and-select-relation-fields

## select 文を発行する際の reference

https://www.prisma.io/docs/concepts/components/prisma-client/select-fields