NestJSやら他のフレームワークとの組み合わせや、migrationを前提にした資料ばかりなので、既存のDBに対して使うケースを前提にプレーンな環境で構築してみた。
目標
- Prismaを使ってみる
- Prismaで既存のDBに対して操作する
- PrismaでSQL文を投げる
前提
- 動作を確認するためにExpressを使う
- typedSqlを使う
準備
適当な場所に新規ディレクトリを作成して、プロジェクトディレクトリとし、中で下記コマンドを打つ
npm init -y
npm i -S express
npm i -D typescript ts-node prisma @types/node @types/express
npx tsc --init
prisma初期設定
npx prisma init
上記コマンド実行で、prisma/schema.prisma と .env が生成される。
mysqlに変更
こちら、接続したいDBにより内容は変わるが、今回ローカルのdockerで立てた mysql に接続するパターンを記す
prisma/schema.prisma を修正
datasource db {
- provider = "postgresql"
+ provider = "mysql"
url = env("DATABASE_URL")
}
.env を修正
DATABASE_URL="mysql://root:password@localhost:5306/test-db"
DDL
CREATE TABLE `users` (
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ユーザID',
`name` varchar(100) NOT NULL COMMENT 'ユーザ名',
`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
`updatedAt` datetime DEFAULT NULL COMMENT '更新日時',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
DML
INSERT INTO `test-db`.users (id, name, createdAt, updatedAt) VALUES
(1, 'userA', '2025-01-20 15:15:48', NULL),
(2, 'userB', '2025-01-27 05:15:48', NULL);
PrismaクライアントのインストールとExpress初期設定
npm install @prisma/client
./index.ts
import express from "express";
import { PrismaClient } from "@prisma/client";
const app = express();
const PORT = process.env.PORT || 3000;
const prisma = new PrismaClient();
// ルートパスへのリクエスト
app.get("/", (req, res) => {
res.send("Server is running");
});
// リッスンするポートの設定
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
npx ts-node index.ts
で起動して、 ブラウザでlocalhost:3000にアクセスし、「Server is running」が出力していることを確認。
prisma generate
sqlファイルを扱えるように、prisma/schema.prisma
を修正
generator client {
provider = "prisma-client-js"
+ previewFeatures = ["typedSql"]
}
全ユーザ情報を取得するためのSQL
prisma/sql/getUsers.sql
SELECT `id`, `name`, `createdAt`, `updatedAt`
FROM `users`
ORDER BY id
idを指定してユーザ情報を取得するSQL
prisma/sql/getUser.sql
SELECT `id`, `name`, `createdAt`, `updatedAt`
FROM `users` WHERE `id` = ?
LIMIT 1
※ 引数の書き方はDBによって違うらしい 参考
下記コマンドでクライアントを生成
npx prisma generate --sql --allow-no-models
※ よくわからんけど、node_modules内のファイルが書き換えられる
上記までの作業で、用意したSQLを投げることができる。
SQLを修正追加した場合事に generate
コマンドの実行が必要。
Expressの処理の中でSQLを投げ結果を得る
./index.ts に下記を追記
import { getUser, getUsers } from "@prisma/client/sql";
// id指定でユーザ情報を取得
app.get("/getUser/:id(\\d+)", async (req, res) => {
const id = req.params.id;
const users: getUser.Result[] = await prisma.$queryRawTyped(
getUser(Number(id))
);
if (!users || users.length === 0) {
res.send(`<pre>Not Found.<pre>`);
return;
}
res.send(
`<pre>User:${JSON.stringify(users[0], (key, value) =>
typeof value === "bigint" ? Number(value) : value
)}<pre>`
);
});
// 全ユーザ情報を取得
app.get("/getUsers", async (req, res) => {
const users: getUsers.Result[] = await prisma.$queryRawTyped(getUsers());
const userDisplay = users
.map(
(user) =>
`User ${user.id.toString()}: ${JSON.stringify(user, (key, value) =>
typeof value === "bigint" ? Number(value) : value
)}`
)
.join("\n");
res.send(`<pre>${userDisplay}<pre>`);
});
npx ts-node index.ts
で起動して、 ユーザ情報を取得できることを確認。
SQLを直接書いてみる
./index.ts に下記を追記
// id指定でユーザ情報を取得
app.get("/getUser", async (req, res) => {
const { id } = req.query;
const users: any[] = await prisma.$queryRawUnsafe(
`SELECT id, name, createdAt, updatedAt" FROM users WHERE id = ${Number(id)}`
);
if (!users || users.length === 0) {
res.send(`<pre>Not Found.<pre>`);
return;
}
res.send(
`<pre>User:${JSON.stringify(users[0], (key, value) =>
typeof value === "bigint" ? Number(value) : value
)}<pre>`
);
});
まとめ
generate コマンドを避け得て通りたかったがどうやら避けれ無さそう?
※ 方法あったら教えてください
上記で上げたような簡単なSQLであれば、やはり prisma/schema.prisma
にmodelを書いてfindメソッド系で呼び出したりするほうが早そう。
const users = await prisma.user.findMany();
とかね。
javascript, typescriptでのバックエンドの業務をちゃんとやったことがないので、何が正しいのか手探りだけど、数粒の糧にはなったか。。。
※ BEのお仕事ください(切実)
ソース