次世代の Node.js ORM 、Prisma をサクッと入門する
最近tRPCを勉強をしてるところ、公式のNext.jsサンプルリポジトリにPrisma
という謎のORMライブラリー使用されてることに気づき🧐、気になって仕方ないので、実際触ってみた内容をまとめます。
Prismaとは
Prisma は、下記のツールで構成される次世代のORMライブラリーです。
- Prisma Client : Node.js および TypeScript 用の自動生成された型安全なクエリ ビルダー
- Prisma Migrate : 宣言型データ モデリングおよび移行システム
- Prisma Studio : データベース内のデータを表示および編集するための GUI
Prisma は、任意のNode.js または TypeScript バックエンド アプリケーション (サーバーレス アプリケーションおよびマイクロサービスを含む) で使用できます。これは、REST API、GraphQL API、gRPC API、またはデータベースを必要とするその他の全てのもの。
Prisma
使ってマイグレーションする際に、移行ファイルは素のSQLで書かれるところは好印象です😊
クイックスタート
まずはプロジェクトの作成とPrisma
のセットアップ、ゼロベースから作ります。
$ mkdir prisma_test
$ cd prisma_test
Prisma
を動作するにはNode.js v14.17.0 以降のバージョンが必要です。
npmでinitしてますがyarnでも構いません。
$ npm init -y
$ yarn add -D typescript ts-node @types/node
$ touch tsconfig.json
tsconfig.jsonに下記の内容を追加します。
{
"compilerOptions": {
"sourceMap": true,
"outDir": "dist",
"strict": true,
"lib": ["esnext"],
"esModuleInterop": true
}
}
次はPrisma
をインストールします。
$ yarn add -D prisma
最後にPrisma CLI
のコマンドを使用してPrisma
をセットアップします。
$ npx prisma init --datasource-provider sqlite
sqlite
使用するのは、テスト用のデータベースを用意する手間を省くためです、
この後マイグレーション実行する際に、自動的にsqliteファイル作ってくれます。
ここまで実行したら、ファイル構成は以下の通りになるはずです。
prisma_test
|-- .env
|-- .gitignore
|-- node_modules
|-- package.json
|-- prisma
|-- |-- schema.prisma
|-- tsconfig.json
|-- yarn.lock
Prisma スキーマでデータをモデル化する
prismaフォルダ配下にあるschema.prismaファイルにUser
、Post
モデルを追加します。
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
+ model User {
+ id Int @id @default(autoincrement())
+ email String @unique
+ name String?
+ posts Post[]
+ }
+ model Post {
+ id Int @id @default(autoincrement())
+ title String
+ content String?
+ published Boolean @default(false)
+ author User @relation(fields: [authorId], references: [id])
+ authorId Int
+ }
Prisma
スキーマのモデルには、主に2つの役目があります。
- 基礎となるデータベースのテーブルを表す
- 生成された Prisma Client API の基盤として機能する
次はマイグレーションを実行して、テーブルを作ります。
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"
SQLite database dev.db created at file:./dev.db
Applying migration `20221031025300_init`
The following migration(s) have been created and applied from new schema changes:
migrations/
└─ 20221031025300_init/
└─ migration.sql
これで、テーブルの作成とマイグレーション履歴ファイルが作られました。
sqliteのデータベースとなるファイルは存在しなかったのですが、実行後、prisma
フォルダの配下にdev.db
が作られます。
Prisma Studio
を使ってできたテーブルを確認できます。
npx prisma studio
Prisma Client を使用してデータベースにデータを追加する
prismaフォルダの配下にscript.ts
ファイルを作ります。
user
テーブルにデータを追加してみます。
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
const user = await prisma.user.create({
data: {
name: 'Alice',
email: 'alice@prisma.io',
},
})
console.log(user)
}
main()
.then(async () => {
await prisma.$disconnect()
})
.catch(async (e) => {
console.error(e)
await prisma.$disconnect()
process.exit(1)
})
下記のコマンドでscript.ts
を実行すると、テーブルにデータが追加されます。
$ npx ts-node script.ts
{ id: 1, email: 'alice@prisma.io', name: 'Alice' }
追加したデータを取得する場合、main関数の中身を修正します。
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
+ const users = await prisma.user.findMany()
+ console.log(users)
}
main()
.then(async () => {
await prisma.$disconnect()
})
.catch(async (e) => {
console.error(e)
await prisma.$disconnect()
process.exit(1)
})
スクリプトを再度実行します。
$ npx ts-node script.ts
[{ id: 1, email: 'alice@prisma.io', name: 'Alice' }]
prisma studioからも確認できます。
その他のCRUD操作は公式ドキュメントを参考にしてください。
テーブルの変更
定義されたPost
モデルにtest
カラムを追加します。
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
+ test String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
下記のコマンドでマイグレーション実行します。
npx prisma migrate dev --name add_post_test
実行後、下記のログが出力されます。
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": SQLite database "dev.db" at "file:./dev.db"
Applying migration `20221031055326_add_post_test`
The following migration(s) have been created and applied from new schema changes:
migrations/
└─ 20221031055326_add_post_test/
└─ migration.sql
prisma/migrations/20221031055326_add_post_test
フォルダは以下にmigration.sql
ファイル作られました。
中身は以下の通りです、素のsqlで変更内容書いてくれるのはわかりやすくていいですね😊
-- AlterTable
ALTER TABLE "Post" ADD COLUMN "test" TEXT;
次はさきほど追加したカラムを削除してみます。
... 一部省略
model Post {
id Int @id @default(autoincrement())
title String
content String?
- test String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
下記のコマンドでマイグレーション実行します。
npx prisma migrate dev --name delete_post_test
ログは以下の通りです。
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": SQLite database "dev.db" at "file:./dev.db"
Applying migration `20221031055549_delete_post_test`
The following migration(s) have been created and applied from new schema changes:
migrations/
└─ 20221031055549_delete_post_test/
└─ migration.sql
prisma/migrations/20221031055549_delete_post_test
フォルダの配下にmigration.sql
ファイルが作られました。
中身は以下の通りです。
/*
Warnings:
- You are about to drop the column `test` on the `Post` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Post" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"title" TEXT NOT NULL,
"content" TEXT,
"published" BOOLEAN NOT NULL DEFAULT false,
"authorId" INTEGER NOT NULL,
CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_Post" ("authorId", "content", "id", "published", "title") SELECT "authorId", "content", "id", "published", "title" FROM "Post";
DROP TABLE "Post";
ALTER TABLE "new_Post" RENAME TO "Post";
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;
その他のマイグレーション操作は公式ドキュメントを参考にしてください。
おわりに
まだ深く使った訳ではありませんが、ORMライブラリーとしては優秀なのではと思いましたね、最近作るシステムの構成は疎結合のものが多い中で、ORMのパーツとしてPrisma
を採用する価値は十分あると個人的に考えてます。
Discussion