こんばんわ、hisayukiです❗
前回に引き続き、BlitzJSを進めていこうかと思います。
今回はDatabase周りを進めていこうと思います。
Database setup
ここではPrisma StudioでDBの中身を見るフェーズです。
ただ前回も書いちゃったんで端折ります。
また、DBの種類をSQLitghtから別のRDBに切り替えるフェーズでもありますが、それは次回MySQLの切り替えを1記事書こうかなと思います。
Scaffolding(スキャフォールディング )
BlitzはCLIのgenerateコマンドから、Page、Model、CRUD(Queries、Mutations)を自動生成してくれます。
今回はQuestionモデルとChoiceモデルを作成していきます。
Question
まずはQuestionモデル
blitz generate all question text:string
generateコマンドで作成されるModelは、デフォルトでid、createdAt、updatedAtフィールドが作成されます。
questionモデルには追加でtextフィールドを追加します。
CREATE app/pages/questions/[questionId].tsx
CREATE app/pages/questions/[questionId]/edit.tsx
CREATE app/pages/questions/index.tsx
CREATE app/pages/questions/new.tsx
CREATE app/questions/components/QuestionForm.tsx
CREATE app/questions/queries/getQuestion.ts
CREATE app/questions/queries/getQuestions.ts
CREATE app/questions/mutations/createQuestion.ts
CREATE app/questions/mutations/deleteQuestion.ts
CREATE app/questions/mutations/updateQuestion.ts
✔ Model for 'question' created in schema.prisma:
> model Question {
> id Int @default(autoincrement()) @id
> createdAt DateTime @default(now())
> updatedAt DateTime @updatedAt
> text String
> }
? Run 'prisma migrate dev' to update your database? (Y/n) ‣ true
マイグレーションをするか聞かれるので、YESで進めます
✔ Run 'prisma migrate dev' to update your database? (Y/n) · true
Environment variables loaded from .env
Prisma schema loaded from db/schema.prisma
Datasource "db": SQLite database "db.sqlite" at "file:./db.sqlite"
? Name of migration ›
マイグレーションに名前をつけるように言われるので、今回はadd questionと付けます。
✔ Name of migration … add question
The following migration(s) have been created and applied from new schema changes:
migrations/
└─ 20210504065423_add_question/
└─ migration.sql
Your database is now in sync with your schema.
✔ Generated Prisma Client (2.20.1) to ./node_modules/@prisma/client in 107ms
これでQuestionテーブルを作成するマイグレーションファイルが出来上がります。
migration.sqlの中身はこんな感じになっています。
CREATE TABLE "Question" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
"text" TEXT NOT NULL
);
コードを確認すると、このように追加されています。
先程付けたadd questionはmigrationsディレクトリの中に作られています。
schema.prismaも更新されています。
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
// --------------------------------------
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String?
email String @unique
hashedPassword String?
role String @default("USER")
tokens Token[]
sessions Session[]
}
model Session {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
expiresAt DateTime?
handle String @unique
hashedSessionToken String?
antiCSRFToken String?
publicData String?
privateData String?
user User? @relation(fields: [userId], references: [id])
userId Int?
}
model Token {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
hashedToken String
type String
// See note below about TokenType enum
// type TokenType
expiresAt DateTime
sentTo String
user User @relation(fields: [userId], references: [id])
userId Int
@@unique([hashedToken, type])
}
// NOTE: It's highly recommended to use an enum for the token type
// but enums only work in Postgres.
// See: https://blitzjs.com/docs/database-overview#switch-to-postgresql
// enum TokenType {
// RESET_PASSWORD
// }
model Question {
id Int @default(autoincrement()) @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
text String
}
Choice
次にChoiceモデルを作成します。
先程はgenerateコマンドの際にallを指定していました。
blitz generate all question text:string
このallの部分は変更することで、欲しいファイルのみに変えることが出来ます。
こちらのページを参考にしてください。
ChoiceモデルではPageは不要のため、resourceでgenerateコマンドを実行します。
blitz generate resource choice text:string votes:int:default=0 belongsTo:question
追加でtextとvotesフィールドを追加します。
加えて、Questionモデルとリレーションを張るようにしています。
CREATE app/choices/queries/getChoice.ts
CREATE app/choices/queries/getChoices.ts
CREATE app/choices/mutations/createChoice.ts
CREATE app/choices/mutations/deleteChoice.ts
CREATE app/choices/mutations/updateChoice.ts
✔ Model for 'choice' created in schema.prisma:
> model Choice {
> id Int @default(autoincrement()) @id
> createdAt DateTime @default(now())
> updatedAt DateTime @updatedAt
> text String
> votes Int @default(0)
> question Question @relation(fields: [questionId], references: [id])
> questionId Int
> }
✔ Run 'prisma migrate dev' to update your database? (Y/n) · false
この段階では、Question側のモデルにChoiseフィールドがないのでマイグレーションはNoにしておきます。
このコマンドでChoiseのModel、Queries、Mutationsが出来ています。
QuestionとChoiceを紐付ける
この紐付けはschema.prismaを手動で更新します
QuestionのフィールドにChoiceの配列を追加します。
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
// --------------------------------------
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String?
email String @unique
hashedPassword String?
role String @default("USER")
tokens Token[]
sessions Session[]
}
model Session {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
expiresAt DateTime?
handle String @unique
hashedSessionToken String?
antiCSRFToken String?
publicData String?
privateData String?
user User? @relation(fields: [userId], references: [id])
userId Int?
}
model Token {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
hashedToken String
type String
// See note below about TokenType enum
// type TokenType
expiresAt DateTime
sentTo String
user User @relation(fields: [userId], references: [id])
userId Int
@@unique([hashedToken, type])
}
// NOTE: It's highly recommended to use an enum for the token type
// but enums only work in Postgres.
// See: https://blitzjs.com/docs/database-overview#switch-to-postgresql
// enum TokenType {
// RESET_PASSWORD
// }
model Question {
id Int @default(autoincrement()) @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
text String
choices Choice[] //これを追加
}
model Choice {
id Int @default(autoincrement()) @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
text String
votes Int @default(0)
question Question @relation(fields: [questionId], references: [id])
questionId Int
}
schema.prismaを更新したら、マイグレーションコマンドを実行します。
blitz prisma migrate dev
Environment variables loaded from .env
Prisma schema loaded from db/schema.prisma
Datasource "db": SQLite database "db.sqlite" at "file:./db.sqlite"
? Name of migration › add choice
マイグレーションに名前をつけるように言われるので、add choiceと付けます。
The following migration(s) have been created and applied from new schema changes:
migrations/
└─ 20210504112340_add_choice/
└─ migration.sql
Your database is now in sync with your schema.
✔ Generated Prisma Client (2.20.1) to ./node_modules/@prisma/client in 129ms
これでChoiceを追加した際のマイグレーションファイルが出来ました。
Blitz consoleからDBを更新する
Blitz CLIにはデフォルトでPrisma用データベースクライアントが用意されています。
データベースクライアントを使って、データ操作をしていきます。
blitz console
You have entered the Blitz console
Tips: - Exit by typing .exit or pressing Ctrl-D
- Use your db like this: await db.project.findMany()
- Use your queries/mutations like this: await getProjects({})
Loading Modules 14/18
⚡️ >
最初にQuestionテーブルのレコードを全件取得します。
⚡ > await db.question.findMany()
[]
まだデータが入ってないので[]で返ってきます
次にQuestionテーブルに1件レコードを追加し、結果を変数qに入れます
⚡️ > let q = await db.question.create({data: {text: "What's new?"}})
undefined
Loading Modules 14/18
Loading Modules 12/18
Loading Modules 15/18
変数qの中身を確認します。
⚡️ > q
{
id: 1,
createdAt: 2021-05-04T11:44:31.978Z,
updatedAt: 2021-05-04T11:44:31.979Z,
text: "What's new?"
}
変数qの中のtextだけを見てみます。
⚡️ > q.text
"What's new?"
追加したレコードのidは1なので、id:1のレコードを更新します。
⚡️ > q = await db.question.update({where: {id: 1}, data: {text: "What's up?"}})
{
id: 1,
createdAt: 2021-05-04T11:44:31.978Z,
updatedAt: 2021-05-04T11:49:40.804Z,
text: "What's up?"
}
Loading Modules 13/18
Loading Modules 15/18
Loading Modules 15/18
Loading Modules 14/18
undefined
最後にまた全件レコード取得をします。
⚡ > await db.question.findMany()
[
{
id: 1,
createdAt: 2021-05-04T11:44:31.978Z,
updatedAt: 2021-05-04T11:49:40.804Z,
text: "What's up?"
}
]
このように、ちょっとしたレコードの参照や、追加などはCLIから行えます。
といっても、Prisma Studioが強力なのでそっちでやっちゃっても良いわけですが・・・😅
一応、CLI派用、GUI派用どちらからでもDBの操作はBlitzのみで行なえます。
まとめ
今回はスキャフォールディングを含めたデータベース周りのチュートリアルを進めました。
generateコマンドで一気に永続化層からPageまでを作ってくれるのは強力ですね。
気になったのはCRUDを一気に作るのは良いけど、利用しないのもあるのでは?って思った。
そもそもRailsやってきてないから、こういうものと言われたらそうなのかもしれないけど・・・
CRUDは必要になったときに、必要なものを作ればいい派なので使うかわからないもの作られてもなーって感じです。
一応、generateコマンド時にQueryとMutationどちらかしか作らないとかはできそうだけど🤔
取得系と更新系くらいは分けて作るようにしたほうがよさそうかなーって思いました。
にしても、やっぱPrismaが強力すぎるな・・・😅
コメント