TypedSQL
TypedSQL 入門
若要開始在您的 Prisma 專案中使用 TypedSQL,請依照下列步驟進行
-
確保您已安裝
@prisma/client
和prisma
,並更新至至少5.19.0
版本。npm install @prisma/client@latest
npm install -D prisma@latest -
將
typedSql
預覽功能標誌新增至您的schema.prisma
檔案generator client {
provider = "prisma-client-js"
previewFeatures = ["typedSql"]
} -
在您的
prisma
目錄內建立一個sql
目錄。您將在此處編寫您的 SQL 查詢。mkdir -p prisma/sql
-
在您的
prisma/sql
目錄中建立新的.sql
檔案。例如,getUsersWithPosts.sql
。請注意,檔案名稱必須是有效的 JS 識別符,且不能以$
開頭。 -
在您的新
.sql
檔案中編寫您的 SQL 查詢。例如prisma/sql/getUsersWithPosts.sqlSELECT u.id, u.name, COUNT(p.id) as "postCount"
FROM "User" u
LEFT JOIN "Post" p ON u.id = p."authorId"
GROUP BY u.id, u.name -
使用
sql
標誌產生 Prisma Client,以確保為您的 SQL 查詢建立 TypeScript 函式和類型警告在以
sql
標誌產生用戶端之前,請確保已套用任何待處理的遷移。prisma generate --sql
如果您不想在每次變更後都重新產生用戶端,則此命令也適用於現有的
--watch
標誌prisma generate --sql --watch
-
現在您可以匯入並在您的 TypeScript 程式碼中使用您的 SQL 查詢
/src/index.tsimport { PrismaClient } from '@prisma/client'
import { getUsersWithPosts } from '@prisma/client/sql'
const prisma = new PrismaClient()
const usersWithPostCounts = await prisma.$queryRawTyped(getUsersWithPosts())
console.log(usersWithPostCounts)
將引數傳遞至 TypedSQL 查詢
若要將引數傳遞至您的 TypedSQL 查詢,您可以使用參數化查詢。這可讓您編寫彈性且可重複使用的 SQL 陳述式,同時保持類型安全。以下是如何操作
-
在您的 SQL 檔案中,使用預留位置來表示您要傳遞的參數。預留位置的語法取決於您的資料庫引擎
- PostgreSQL
- MySQL
- SQLite
對於 PostgreSQL,請使用位置預留位置
$1
、$2
等。prisma/sql/getUsersByAge.sqlSELECT id, name, age
FROM users
WHERE age > $1 AND age < $2對於 MySQL,請使用位置預留位置
?
prisma/sql/getUsersByAge.sqlSELECT id, name, age
FROM users
WHERE age > ? AND age < ?在 SQLite 中,您可以使用許多不同的預留位置。位置預留位置 (
$1
、$2
等)、一般預留位置 (?
) 和具名預留位置 (:minAge
、:maxAge
等) 均可使用。在此範例中,我們將使用具名預留位置:minAge
和:maxAge
prisma/sql/getUsersByAge.sqlSELECT id, name, age
FROM users
WHERE age > :minAge AND age < :maxAge注意請參閱下方關於如何在您的 SQL 檔案中定義引數類型的資訊。
-
當在您的 TypeScript 程式碼中使用產生的函式時,請將引數作為額外參數傳遞至
$queryRawTyped
/src/index.tsimport { PrismaClient } from '@prisma/client'
import { getUsersByAge } from '@prisma/client/sql'
const prisma = new PrismaClient()
const minAge = 18
const maxAge = 30
const users = await prisma.$queryRawTyped(getUsersByAge(minAge, maxAge))
console.log(users)
透過使用參數化查詢,您可以確保類型安全並防止 SQL 注入漏洞。TypedSQL 產生器將根據您的 SQL 查詢為參數建立適當的 TypeScript 類型,為查詢結果和輸入參數提供完整的類型檢查。
將陣列引數傳遞至 TypedSQL
TypedSQL 支援將陣列作為 PostgreSQL 的引數傳遞。將 PostgreSQL 的 ANY
運算子與陣列參數搭配使用。
SELECT id, name, email
FROM users
WHERE id = ANY($1)
import { PrismaClient } from '@prisma/client'
import { getUsersByIds } from '@prisma/client/sql'
const prisma = new PrismaClient()
const userIds = [1, 2, 3]
const users = await prisma.$queryRawTyped(getUsersByIds(userIds))
console.log(users)
TypedSQL 將為陣列參數產生適當的 TypeScript 類型,確保輸入和查詢結果的類型安全。
在傳遞陣列引數時,請注意您的資料庫在單一查詢中支援的最大預留位置數量。對於非常大的陣列,您可能需要將查詢拆分為多個較小的查詢。
在您的 SQL 檔案中定義引數類型
TypedSQL 中的引數類型設定是透過 SQL 檔案中的特定註解完成的。這些註解的形式為
-- @param {Type} $N:alias optional description
其中 Type
是有效的資料庫類型,N
是查詢中引數的位置,而 alias
是在 TypeScript 類型中使用的引數的選用別名。
舉例來說,如果您需要輸入具有別名 name
和描述「使用者的名稱」的單一字串引數,您可以在 SQL 檔案中新增以下註解
-- @param {String} $1:name The name of the user
目前接受的類型為 Int
、BigInt
、Float
、Boolean
、String
、DateTime
、Json
、Bytes
和 Decimal
。
採用上面的範例,SQL 檔案將如下所示
-- @param {Int} $1:minAge
-- @param {Int} $2:maxAge
SELECT id, name, age
FROM users
WHERE age > $1 AND age < $2
引數類型定義的格式與資料庫引擎無關。
陣列引數不支援手動引數類型定義。對於這些引數,您需要依賴 TypedSQL 提供的類型推斷。
範例
如需如何在各種情境中使用 TypedSQL 的實務範例,請參閱 Prisma 範例儲存庫。此儲存庫包含一系列可立即執行的 Prisma 範例專案,示範最佳實務和常見使用案例,包括 TypedSQL 實作。
TypedSQL 的限制
支援的資料庫
TypedSQL 支援最新版本的 MySQL 和 PostgreSQL,無需任何其他配置。對於舊於 8.0 的 MySQL 版本和所有 SQLite 版本,您需要手動描述您的 SQL 檔案中的引數類型。輸入的類型在所有支援版本的 PostgreSQL 和 MySQL 8.0 及更高版本中都會被推斷。
TypedSQL 不適用於 MongoDB,因為它是專為 SQL 資料庫設計的。
需要活動的資料庫連線
TypedSQL 需要活動的資料庫連線才能正常運作。這表示您需要有一個正在執行的資料庫執行個體,Prisma 可以在使用 --sql
標誌產生用戶端時連線到該執行個體。如果在您的 Prisma 配置中提供了 directUrl
,TypedSQL 將使用該 URL 進行連線。
具有動態資料行的動態 SQL 查詢
TypedSQL 不原生支援使用動態新增的資料行建構 SQL 查詢。當您需要建立在執行階段確定資料行的查詢時,您必須使用 $queryRaw
和 $executeRaw
方法。這些方法允許執行原始 SQL,其中可以包含動態資料行選取。
使用動態資料行選取的查詢範例
const columns = 'name, email, age'; // Columns determined at runtime
const result = await prisma.$queryRawUnsafe(
`SELECT ${columns} FROM Users WHERE active = true`
);
在此範例中,要選取的資料行是動態定義的,並包含在 SQL 查詢中。雖然此方法提供了彈性,但它需要仔細注意安全性,特別是避免 SQL 注入漏洞。此外,使用原始 SQL 查詢表示放棄 TypedSQL 的類型安全性和 DX。