[[📒Articles]] > [[📒2021 Articles]]
![[2021-06-30.jpg|cover-picture]]
## はじめに
[[TypeScript]]の[[ORM]]として近年注目されている[[Prisma]]を少し使ってみた。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://www.prisma.io/images/favicon-32x32.png" />
<span class="link-card-v2-site-name">Prisma</span>
</div>
<div class="link-card-v2-title">
Prisma | Instant Postgres plus an ORM for simpler db workflows
</div>
<div class="link-card-v2-content">
Build, fortify, and grow your application easily with an intuitive data model, type-safety, automated migrations ...
</div>
<img class="link-card-v2-image" src="https://cdn.sanity.io/images/p2zxqf70/production/384386cb3c2c21b3ad27c6b6758547fe18b08ac1-1200x630.png" />
<a href="https://www.prisma.io/"></a>
</div>
何かを作ったわけではなく軽くいじった程度だ。雰囲気を軽く知りたいという方向けであり、[[Prisma]]の知見を知りたい方に有用な情報はないと思う。
## プロジェクトの取得
[Download the starter project]のコマンドを使い、以下の構成を作る。
[Download the starter project]: https://www.prisma.io/docs/getting-started/quickstart#1-download-the-starter-project
```ls
.
├── package.json
├── prisma
│ ├── dev.db
│ └── schema.prisma
├── script.ts
└── tsconfig.json
```
## 依存関係のインストール
中に入って`npm i`すればOK。
## ソースコードを書く
`script.ts`を開く。
```ts:script.ts
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
// A `main` function so that you can use async/await
async function main() {
// ... you will write your Prisma Client queries here
}
main()
.catch(e => {
throw e
})
.finally(async () => {
await prisma.$disconnect()
})
```
### すべてのユーザーを取得
`main`関数の中に実装を追加する。
```ts:script.ts#main()
async function main() {
const users = await prisma.user.findMany();
console.dir(users, { depth: null });
}
```
実行すると`User`テーブルの全レコードを取得/表示できる。
```bash
$ npm run dev
[
{ id: 1, email: '
[email protected]', name: 'Sarah' },
{ id: 2, email: '
[email protected]', name: 'Maria' }
]
```
### Where句の指定
`where`に条件句を指定する。
```ts:script.ts#main()
async function main() {
const users = await prisma.user.findMany({
where: { name: "Maria" },
});
console.dir(users, { depth: null });
}
```
実行すると`User`テーブルで`name = 'Maria'`なレコードのみ取得/表示できる。
```bash
$ npm run dev
[ { id: 2, email: '
[email protected]', name: 'Maria' } ]
```
### 関連テーブルのプロパティを含めて取得
`include`に`posts`を指定すると、関連テーブルの`posts`を含めた結果が取得できる。よしなに補完もされる。
```ts:script.ts#main()
async function main() {
// usersの型は (User & {posts: Post[]})[]
const users = await prisma.user.findMany({
include: { posts: true },
});
console.dir(users, { depth: null });
}
```
```bash
$ npm run dev
[
{ id: 1, email: '
[email protected]', name: 'Sarah', posts: [] },
{
id: 2,
email: '
[email protected]',
name: 'Maria',
posts: [
{
id: 1,
title: 'Hello World',
content: null,
published: false,
authorId: 2
}
]
}
]
```
## テーブル定義を変える
[Using Prisma Migrate TypeScript PostgreSQL]に従ってテーブル定義を変えてみる。
[Using Prisma Migrate TypeScript PostgreSQL]: https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/using-prisma-migrate-typescript-postgres
データベースを直接いじるのではなく`schema.prisma`ファイルを変更する。ここからデータベースとClientが自動生成される。以下のようにしてみた。
```schema:schema.prisma
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Human {
id Int @id @default(autoincrement())
name String
address String?
}
```
データベースから元々あったテーブルを消してから、[[Prisma Migrate]]を実行する。
```bash
$ npx prisma migrate dev --name init
Environment variables loaded from .env
Prisma schema loaded from prisma\schema.prisma
Datasource "db": SQLite database "dev.db" at "file:./dev.db"
The following migration(s) have been created and applied from new schema changes:
migrations/
└─ 20210630135457_init/
└─ migration.sql
Your database is now in sync with your schema.
✔ Generated Prisma Client (2.26.0) to .\node_modules\@prisma\client in 86ms
```
[[ジャーナルファイル]]や実行したsqlファイルなど作成される。
```ls
./prisma
├── dev.db
├── dev.db-journal
├── migrations
│ ├── 20210630135457_init
│ │ └── migration.sql
│ └── migration_lock.toml
└── schema.prisma
```
`migration.sql`は実行済みなので、データベースに`Human`テーブルが作成されている。
## クライアントコードの自動生成
[Install Prisma Client]を参考に[[Prisma Client]]を作成する。既にインストールはされているため`npm install`はスキップする。
[Install Prisma Client]: https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/install-prisma-client-typescript-postgres/
`prisma generate`コマンドを実行する。
````bash
$ npx prisma generate
Environment variables loaded from .env
Prisma schema loaded from prisma\schema.prisma
✔ Generated Prisma Client (2.26.0) to .\node_modules\@prisma\client in 83ms
You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client
```
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
```
````
`node_modules/@prisma`配下に作成されるのが実にユニークだ。`schema.prisma`さえバージョン管理しておけば、作成された[[Prisma Client]]を管理する必要はない。
なお、`npm install @prisma/client`を実行したあとにも`prisma generate`は自動実行される。そのため、初回インストール時に個別のコマンドを打つ必要はない。
## ソースコードの修正
先ほど実装した`script.ts`が早速エラーとなっている。[[Prisma Client]]の定義が変わったためだ。なんという安心感だろうか。
![[Pasted image 20210630231051.png]]
### データの登録
データベースがカラッポになったので一度登録処理を書く。
```ts:script.ts#main
async function main() {
const records = [
{ name: "Ichiro", address: "America" },
{ name: "Jiro", address: "Japan" },
{ name: "Saburo" },
];
await Promise.all(records.map((r) => prisma.human.create({ data: r })));
}
```
実行すると`Human`テーブルに3つのレコードが登録される。
```bash
npm run dev
```
必須のプロパティ(`name`など)がない場合は型エラーとなる。冗長なプロパティがある場合は実行エラーにならないが、データベースにはデータが挿入されなかった。設定で調整できるのかもしれない。
### データの取得
先ほどと同じようなコードを書く。
```ts:script.ts#main
async function main() {
const humans = await prisma.human.findMany();
console.dir(humans);
}
```
先ほど登録したデータを取得できる。
```bash
$ npm run dev
[
{ id: 1, name: 'Jiro', address: 'Japan' },
{ id: 2, name: 'Saburo', address: null },
{ id: 3, name: 'Ichiro', address: 'America' }
]
```
## まとめ
[[Prisma]]を使って以下の流れを一通り体験してみた。
- サンプルプロジェクトを動かす
- `schema.prisma`ファイルでテーブル定義を変更する
- `prisma migrate`コマンドでDBテーブルを自動生成する
- `prisma generate`コマンドで[[Prisma Client]]を自動生成する
特筆すべきはSchemaファイルの定義さえ管理すれば、DBもClientコードも同期できることだろう。使い始める前に少し学習が必要だが、慣れれば安全で気持ち良い開発ができそうだ。
パフォーマンスが求められる要件だとORMは諸刃の剣になり得る。だが、そうでない場合なら、[[TypeScript]]や[[Node.js]]を使うのであれば[[Prisma]]は[[ORM]]として有力な選択肢になるだろう。