跳到主要內容

TypedSQL

TypedSQL 入門

要在您的 Prisma 專案中開始使用 TypedSQL,請遵循以下步驟:

  1. 確保您已安裝並更新 @prisma/clientprisma 到至少 5.19.0 版本。

    npm install @prisma/client@latest
    npm install -D prisma@latest
  2. typedSql 預覽功能標誌新增到您的 schema.prisma 檔案中

    generator client {
    provider = "prisma-client-js"
    previewFeatures = ["typedSql"]
    }
  3. 在您的 prisma 目錄中建立一個 sql 目錄。這是您編寫 SQL 查詢的地方。

    mkdir -p prisma/sql
  4. 在您的 prisma/sql 目錄中建立一個新的 .sql 檔案。例如,getUsersWithPosts.sql。請注意,檔名必須是有效的 JS 識別符號,並且不能以 $ 開頭。

  5. 在新的 .sql 檔案中編寫您的 SQL 查詢。例如

    prisma/sql/getUsersWithPosts.sql
    SELECT 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
  6. 使用 sql 標誌生成 Prisma Client,以確保為您的 SQL 查詢建立 TypeScript 函式和型別

    警告

    在使用 sql 標誌生成客戶端之前,請確保已應用所有待處理的遷移。

    prisma generate --sql

    如果您不想在每次更改後重新生成客戶端,此命令也支援現有的 --watch 標誌

    prisma generate --sql --watch
  7. 現在您可以在 TypeScript 程式碼中匯入和使用您的 SQL 查詢

    /src/index.ts
    import { 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 語句,同時保持型別安全。以下是操作方法:

  1. 在您的 SQL 檔案中,使用佔位符來表示您要傳遞的引數。佔位符的語法取決於您的資料庫引擎

    對於 PostgreSQL,請使用位置佔位符 $1$2 等。

    prisma/sql/getUsersByAge.sql
    SELECT id, name, age
    FROM users
    WHERE age > $1 AND age < $2
    注意

    有關如何在 SQL 檔案中定義引數型別的資訊,請參閱下文。

  2. 在您的 TypeScript 程式碼中使用生成的函式時,將引數作為附加引數傳遞給 $queryRawTyped

    /src/index.ts
    import { 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 運算子和一個數組引數。

prisma/sql/getUsersByIds.sql
SELECT id, name, email
FROM users
WHERE id = ANY($1)
/src/index.ts
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)

當前接受的型別有 IntBigIntFloatBooleanStringDateTimeJsonBytesnullDecimal

以上述示例為例,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)。

致謝

此功能的靈感主要來源於PgTypedSQLx。此外,SQLite 的解析由 SQLx 處理。

© . This site is unofficial and not affiliated with Prisma Data, Inc.