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和:maxAgeprisma/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
要指示引數可為空,請在別名後新增問號
-- @param {String} $1:name? The name of the user (optional)
當前接受的型別有 Int、BigInt、Float、Boolean、String、DateTime、Json、Bytes、null 和 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 需要一個活躍的資料庫連線才能正常工作。這意味著在透過 --sql 標誌生成客戶端時,您需要有一個 Prisma 可以連線的正在執行的資料庫例項。如果在您的 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)。