今天我們繼續 TypedSQL 經過昨天的 $queryRaw 的介紹,大家應該都知道 raw SQL 根本沒有 type 的概念,所以很容易在寫 SQL 的時候都要對照表去查看對應的欄位,那有什麼方法解決呢,我們就廢話不多說開始今天的內容 TypedSQL 走起~
在使用 TypedSQL 之前大家記得安裝最新的 prisma 版本,要記得你的 prisma 必須要是 5.19.0 以上才有 TypedSQL 的功能喔
>npm install @prisma/client@latest
>npm install -D prisma@latest
接著到你的 schema.prisma 加上 typedSql 這個 previewFeatures
//schema.prisma
generator client {
provider = "prisma-client-js"
previewFeatures = ["typedSql"]
}
然後新增 prisma/sql 這個 folder ,在這邊的 folder 你可以加上任何你想執行的 SQL 指令,這邊以 getPostAndAuthor.sql 為例子

然後這邊是 getPostAndAuthor.sql 的內容,這邊想看所有的 post 對應的 user 是誰,然後用 join 關聯 User 跟 Post 的 table
//getPostAndAuthor.sql
Select
p.id as "postId",
p.title as "postTitle",
p.content as "postContent",
p.published
FROM "Post" as p
JOIN "User" as u on p."authorId" = u.id
ORDER By p."createAt" DESC
這邊使用 prisma client 的 generate 要注意加上 --sql 因為我們要轉換的是 SQL
>npx prisma generate --sql
同樣 prisma generate 也有支援 watch 功能,如果需要可以加上
>prisma generate --sql --watch
之後 prisma client 就會把 SQL 的內容加到 node_modules 中
>npx prisma generate --sql
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
✔ Generated Prisma Client (v5.20.0) to ./node_modules/@prisma/client in 76ms
Start by importing your Prisma Client (See: http://pris.ly/d/importing-client)
Tip: Easily identify and fix slow SQL queries in your app. Optimize helps you enhance your visibility: https://pris.ly/--optimize
使用時候就可以自動從 @prisma import 進來,那 function name 就是對應 SQL 的 file name,然後用 prisma 的 $queryRawTyped 這個 methods 去執行你的 SQL function
import { getPostAndAuthor } from "@prisma/client/sql";
const result = await prisma.$queryRawTyped(getPostAndAuthor())
執行 index.ts 後就成功拿到資料拉~是不時很神奇呢~以後只需要 call function 就好不用自己寫 raw SQL 了
[
//..
{
postId: 2641,
postTitle: 'atqui',
postContent: 'tamquam',
published: false
},
... 120 more items
]
甚至 result 還有 type ~
另外你也可加上參數到你的 SQL file 中,這邊加上 getPostAndAuthorByPostId.sql 然後 $1 當作你要查詢 post.id 的變數
// getPostAndAuthorByPostId.sql
Select
p.id as "postId",
p.title as "postTitle",
p.content as "postContent",
p.published
FROM "Post" as p
JOIN "User" as u on p."authorId" = u.id
WHERE p.id = $1
ORDER By p."createAt" DESC
再次跑完 generate 後你就可以使用了
>npx prisma generate --sql
import {
getPostAndAuthor,
getPostAndAuthorByPostId,
} from "@prisma/client/sql";
const result = await prisma.$queryRawTyped(getPostAndAuthorByPostId(2231))
一樣執行 index.ts 資料也如預期返回~
[
{
postId: 2231,
postTitle: 'rerum',
postContent: 'copiose',
published: false
}
]
那因為 post.id 我們是定 number 如果參數 type 不對也會跳 type error~
如果你要使用兩個以上變數只需要加上 $2 就好
//getUsersByAge.sql
Select
u.id as "userId",
u.email as "userEmail",
u.name as "userName",
u.age as "userAge"
FROM "User" as u
WHERE u.age > $1 AND u.age < $2
const userByAge = await prisma.$queryRawTyped(getUsersByAge(10, 20))
這邊一樣也如預期返回我們要的資料~
[
{
userId: 1400,
userEmail: 'Eulalia20@hotmail.com',
userName: 'Greg Kassulke',
userAge: 16
}
]
另外 prisma 支援你可以在 SQL file 中去定你的 Argument 的 type 或是 Argument 的 name 使用方式如下:
@param 這個變數-- @param {Type} $N:alias optional description
這邊以 getUsersByAge.sql 為例子,我們取名 minAge 跟 maxAge 然後 type 都是 number
-- @params {Int} $1:minAge get user by min Age range
-- @params {Int} $2:maxAge get user by max Age range
Select
u.id as "userId",
u.email as "userEmail",
u.name as "userName",
u.age as "userAge"
FROM "User" as u
WHERE u.age > $1 AND u.age < $2
然後你會看到 prisma client 就自動根據我們定義的 @params 產出 argument 的 name 跟 type,寫法是不是很像在寫 jsDoc ~
最後補充一個就是 TypedSQL 有一個限制是,如果你需要在 runtime 的時候才會知道你要拿到的 Select column 是什麼的話,你無法用 argument 的方式搭配 TypedSQL 幫你 generate ,反之你只能透過 queryRawUnsafe 的方式
但這可能會衍生一個隱患是 SQL injection 所以使用時要謹慎考慮一下
const columns = 'name, email, age'; // Columns determined at runtime
const result = await prisma.$queryRawUnsafe(
`SELECT ${columns} FROM Users WHERE active = true`
);
✅ 前端社群 :
https://lihi3.cc/kBe0Y