Prismaではじめてのばっくえんど
今までフロントばっっかやってきたので、バックもやりたいと思います。
TypeScriptとReact(Next)をやってきたので、同じTypeScriptで書けるPrismaのチュートリアルを触っていきます。
Make sure you have your database connection URL at hand.
とあるように、PostgreSQLは別途用意していおいて、URLから叩ける状態にする必要があります。今回はDockerの練習も兼ねて、Dockerでザクっと建てる方向で行きます。
まずはPostgreSQL公式のDockerイメージを落とします。これで最新版のPostgreSQLが準備できるはず。
$ docker pull postgres
んで、コンテナを起動。
$ docker run --name posgre-container -d -e POSTGRES_PASSWORD=pass1 postgres
docker ps
を叩くと…
ウオー!! ちゃんとコンテナ動いてますね。PostgreSQLってデフォルトのポート番号5432
なんだ。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cc7a3a0dc888 postgres "docker-entrypoint.s…" 3 minutes ago Up 2 minutes 5432/tcp posgre-container
Docker詳しくないんで調べたら、
-
name
: コンテナ名を指名する。 -
-d
: デタッチモードにする。- コンテナ実行時に使うルートプロセスが終了すると、 --rm オプションを指定していない限りコンテナを終了するんだって。
-
-e
: コンテナ内の任意の環境変数を設定する。- ここではパスワードが環境変数になっているんかな。
- 最後の
postgres
: さっき落としてきたイメージの名前
みたいな感じらしい。オプション多すぎて毎回設定するの大変そうこなみ
参考
PostgreSQL in Dockerはとりあえず動いている前提で進めます。次はPrismaの設定やっていきます。
とりあえずnpm関係のコマンドを叩きましょう。
$ npm init -y
$ npm install prisma typescript ts-node @types/node --save-dev
tsconfig.json
を設定します。
{
"compilerOptions": {
"sourceMap": true,
"outDir": "dist",
"strict": true,
"lib": ["esnext"],
"esModuleInterop": true
}
}
んで、npx prisma
でPrisma CLIを呼び出せるようにします。
$ npx prisma
◭ Prisma is a modern DB toolkit to query, migrate and model your database (https://prisma.io)
Usage
$ prisma [command]
Commands
init Setup Prisma for your app
generate Generate artifacts (e.g. Prisma Client)
db Manage your database schema and lifecycle
migrate Migrate your database
studio Browse your data with Prisma Studio
format Format your schema
...
すぐに終わったからinitできてない感あるけど、できてるっぽい。
そして、以下を叩く。
$ npx prisma init
✔ Your Prisma schema was created at prisma/schema.prisma
You can now open it in your favorite editor.
Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver (Preview) or mongodb (Preview).
3. Run prisma db pull to turn your database schema into a Prisma schema.
4. Run prisma generate to generate the Prisma Client. You can then start querying your database.
More information in our documentation:
https://pris.ly/d/getting-started
このコマンドにより、プロジェクトのルートに、schema.prisma
というファイルと.env
ファイルを含むprisma
という新しいディレクトリが作成されます。
schema.prisma
には、データベース接続とPrismaクライアント・ジェネレータを含むPrismaスキーマが含まれるらしいです。.env
は,環境変数を定義するためのdotenvファイルで、これ以降のデータベース接続に使っていきます。
参考
オプション多すぎて毎回設定するの大変そうこなみ
こういう時のためのDocker Composeだろォ!
というわけで、さっき叩いたコマンドをdocker-compose.yml
に書いていきます。
なお環境の再現性を高めるために、イメージのバージョンは3.9
に指定することにします。
# ファイルフォーマットのバージョン。
# ファイル作成時点で3が最新かつ安定。
version: "3.9"
# サービスという単位でコンテナを管理。
services:
postgres-container:
# DockerリポジトリからPullするDockerイメージ。
# ファイル作成時点で13.4が最新かつ安定。
image: postgres:13.4
# ポート番号を指定。
# localhostの5432番ポート宛ての通信を、コンテナの5432番ポートに転送。
ports:
- 5432:5432
# サービス(コンテナ)内の環境変数を設定。
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
# 本来、PostgreSQLのデータは/var/lib/postgresql/data直下に作成されるが、
# Dockerdaで/var/lib/postgresql/dataにデータを作成しようとすると失敗する。
# そのため、アドホックではあるがデータ作成ディレクトリを1層深くしている。
PGDATA: /var/lib/postgresql/data/pgdata
# ホストOS(PC)上にdbボリュームを定義して、
# PostgresSQLのコンテナの/var/lib/postgresql/data/pgdataというディレクトリを、dbボリュームにマウント。
volumes:
- ./db:/var/lib/postgresql/data
そして以下をぶっ叩く。-d
を指定すると、コンテナをデーモンとしてバックグラウンドで起動できます。
docker-compose up -d
すると同じようにコンテナが起動します。いいね。
Creating network "prisma-tutorial_default" with the default driver
Pulling postgres-container (postgres:13.4)...
13.4: Pulling from library/postgres
a330b6cecb98: Already exists
3b0b899b4747: Pull complete
cc0b2671a552: Pull complete
...
Digest: sha256:97e5e91582e89514277912d4b7c95bceabdede3482e32395bcb40099abd9c506
Status: Downloaded newer image for postgres:13.4
Creating prisma-tutorial_postgres-container_1 ... done
参考
データベースをPrismaとくっつけます。
.dnv
内のDATABASE_URL
にPostgreSQLのURLを入れます。URLの詳細は、公式ドキュメントのここに書いてあります。
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
参考
Prisma Migrateをやっていきます。
schema.prisma
に、以下の項目を追記します。詳しい事はあとで説明があると思うので、今はコピペ~。
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String @db.VarChar(255)
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
name String?
posts Post[]
profile Profile?
}
そして以下のコマンドを叩きます。これにより、新しいSQLファイルが作成されて、データベースに対してマイグレーションファイルが実行されます。(実行って何するんですかね…ちょっとまだよく分からん…)
npx prisma migrate dev --name init
できたっぽいですね!
これにより、以下のSQLファイルが生成されます。 何書いてるのか全然分かんねぇぜ!!!
-- CreateTable
CREATE TABLE "Post" (
"id" SERIAL NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"title" VARCHAR(255) NOT NULL,
"content" TEXT,
"published" BOOLEAN NOT NULL DEFAULT false,
"authorId" INTEGER NOT NULL,
CONSTRAINT "Post_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Profile" (
"id" SERIAL NOT NULL,
"bio" TEXT,
"userId" INTEGER NOT NULL,
CONSTRAINT "Profile_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "User" (
"id" SERIAL NOT NULL,
"email" TEXT NOT NULL,
"name" TEXT,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "Profile_userId_key" ON "Profile"("userId");
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
-- AddForeignKey
ALTER TABLE "Post" ADD CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Profile" ADD CONSTRAINT "Profile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ちょっと気になったので、マイグレーションという単語を調べてみます。
こちらのサイトによると、マイグレーションとは
DBに保存されているデータを保持したまま、テーブルの作成やカラムの変更などを行うための機能
のことらしいです。データベースの構造を変えるというクリティカルな操作を安全に行うために、RailsやPrismaが使われているってことかぁ。
参考
え、プロジェクトのルートのdb/pgdata
内にデータマウントされてなくない?生成されたファイル入ってないんだけど?って思ってたら、どうやらマウントディレクトリは特別なヤツらしい。
なんでも仮想マシンで、通常は入れないんだとか。ここではそういうもんだと割り切って進めるかぁ。
Prisma Clientをやっていきます。まずはnpm install
から。
npm install @prisma/client
Prisma Cliantによって、TypeScriptでデータベースを編集できるようになります。以下にそのスクリプトを書きます。
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
// データベースにクエリを送信する
}
main()
.catch((e) => {
throw e;
})
.finally(async () => {
// スクリプトが終了したら、データベース接続を閉じる
await prisma.$disconnect();
});
このmain()
関数内にクエリを書いて、「データベースからすべてのUserレコードを読み込み、結果を表示する」操作を行います。
async function main() {
// データベースにクエリを送信する
const allUsers = await prisma.user.findMany();
console.log(allUsers);
}
そしてnpx
で実行すると…
npx ts-node index.ts
いいね。今はデータベースに何も入っていないから、空の配列が返されていますね。
同様に、今度はデータベースに書き込みをしていきます。
async function main() {
await prisma.user.create({
data: {
name: 'Alice',
email: 'alice@prisma.io',
posts: {
create: { title: 'Hello World' },
},
profile: {
create: { bio: 'I like turtles' },
},
},
})
const allUsers = await prisma.user.findMany({
include: {
posts: true,
profile: true,
},
})
console.dir(allUsers, { depth: null })
}
そして同様にnpx
で実行すると...
いいね。userにユーザー情報を追加して表示できていますね。
データの更新をするには
async function main() {
const post = await prisma.post.update({
where: { id: 1 },
data: { published: true },
})
console.log(post)
}
を追加すればいいですね。実行すると
のように、POSTのデータが取得できますね
参考
PostgreSQLのコンテナを止めると、こんな感じで404みたいなやつを返してくれました。