iT邦幫忙

2024 iThome 鐵人賽

DAY 26
0
Modern Web

一些讓你看來很強的 ORM - prisma系列 第 26

Day26. 一些讓你看來很強的 ORM - prisma (TypeSQL)下

  • 分享至 

  • xImage
  •  

prisma day26

今天我們繼續 TypedSQL 經過昨天的 $queryRaw 的介紹,大家應該都知道 raw SQL 根本沒有 type 的概念,所以很容易在寫 SQL 的時候都要對照表去查看對應的欄位,那有什麼方法解決呢,我們就廢話不多說開始今天的內容 TypedSQL 走起~

Demo

在使用 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 為例子

https://ithelp.ithome.com.tw/upload/images/20241011/20145677BihENV1JdB.png

然後這邊是 getPostAndAuthor.sql 的內容,這邊想看所有的 post 對應的 user 是誰,然後用 join 關聯 UserPosttable

//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 clientgenerate 要注意加上 --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 就是對應 SQLfile 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
https://ithelp.ithome.com.tw/upload/images/20241011/20145677yLSNOkYeHJ.png

Passing Arguments

另外你也可加上參數到你的 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~
https://ithelp.ithome.com.tw/upload/images/20241011/20145677yWwcTosMr6.png

如果你要使用兩個以上變數只需要加上 $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
  }
]

Defining Argument Types in your SQL files

另外 prisma 支援你可以在 SQL file 中去定你的 Argumenttype 或是 Argumentname 使用方式如下:

  • 加上 @param 這個變數
  • 你變數的 Type 是什麼
  • $N 則是第幾個參數
  • alias 則是變數的名稱
  • 最後還可以加上 description
-- @param {Type} $N:alias optional description

這邊以 getUsersByAge.sql 為例子,我們取名 minAgemaxAge 然後 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 產出 argumentnametype,寫法是不是很像在寫 jsDoc
https://ithelp.ithome.com.tw/upload/images/20241011/20145677q9RwMsywZ9.png

Dynamic SQL Queries with Dynamic Columns

最後補充一個就是 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


上一篇
Day25. 一些讓你看來很強的 ORM - prisma (TypeSQL)上
下一篇
Day27. 一些讓你看來很強的 ORM - prisma (Scalar Lists)
系列文
一些讓你看來很強的 ORM - prisma30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言