生のクエリ
Prisma ORM 5.19.0
で、TypedSQL がリリースされました。TypedSQL は、型安全でワークフローへの追加がさらに容易な SQL クエリを記述する新しい方法です。
可能な限り、以下のレガシーな生のクエリではなく、TypedSQL クエリを使用することを強くお勧めします。
Prisma Client は、データベースに生のクエリを送信するオプションをサポートしています。以下の場合に、生のクエリを使用することをお勧めします。
- 高度に最適化されたクエリを実行したい場合
- Prisma Client がまだサポートしていない機能が必要な場合(イシューを上げることを検討してください)
生のクエリは、Prisma ORM がサポートするすべてのリレーショナルデータベースで利用できます。さらに、バージョン 3.9.0
以降では MongoDB でも生のクエリがサポートされています。詳細については、関連セクションを参照してください。
リレーショナルデータベースでの生のクエリ
リレーショナルデータベースの場合、Prisma Client は生のクエリを送信できる4つのメソッドを公開しています。これらを使用できます。
$queryRaw
: 実際のレコードを返す(例:SELECT
を使用)。$executeRaw
: 影響を受けた行数を返す(例:UPDATE
またはDELETE
の後)。$queryRawUnsafe
: 生の文字列を使用して実際のレコードを返す(例:SELECT
を使用)。$executeRawUnsafe
: 生の文字列を使用して影響を受けた行数を返す(例:UPDATE
またはDELETE
の後)。
名前に「Unsafe」が含まれるメソッドははるかに柔軟ですが、**SQL インジェクションに対してコードが脆弱になる重大なリスク**があります。
他の2つのメソッドは、単純なテンプレートタグで使用しても安全であり、文字列の構築や連結は行いません。**ただし**、これらのメソッドが特定の方法で使用される場合、SQL インジェクションを引き起こす可能性があるため、より複雑なユースケースでは注意が必要です。詳細については、以下のSQL インジェクション対策セクションを参照してください。
注意: 上記リストのすべてのメソッドは、一度に**1つ**のクエリしか実行できません。2つ目のクエリを追加することはできません。例えば、
select 1; select 2;
でいずれかのメソッドを呼び出しても機能しません。
$queryRaw
$queryRaw
は実際のデータベースレコードを返します。例えば、次の SELECT
クエリは、User
テーブルの各レコードのすべてのフィールドを返します。
const result = await prisma.$queryRaw`SELECT * FROM User`;
このメソッドはタグ付きテンプレートとして実装されており、変数を簡単に挿入できるテンプレートリテラルを渡すことができます。これにより、Prisma Client は SQL インジェクションから安全なプリペアドステートメントを作成します。
const email = "emelie@prisma.io";
const result = await prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}`;
Prisma.sql
ヘルパーを使用することもできます。実際、$queryRaw
メソッドはテンプレート文字列または Prisma.sql
ヘルパー**のみ**を受け入れます。
const email = "emelie@prisma.io";
const result = await prisma.$queryRaw(Prisma.sql`SELECT * FROM User WHERE email = ${email}`);
信頼できない入力をこのメソッドに渡されるクエリに組み込むために文字列ビルディングを使用すると、SQL インジェクション攻撃の可能性が開かれます。SQL インジェクション攻撃は、データの変更または削除を引き起こす可能性があります。推奨されるメカニズムは、このメソッドを実行する時点でクエリのテキストを含めることです。このリスクに関する詳細およびそれを防ぐ方法の例については、以下のSQL インジェクション対策セクションを参照してください。
考慮事項
以下に注意してください。
-
テンプレート変数は SQL 文字列リテラル内では使用できません。例えば、以下のクエリは**機能しません**。
const name = "Bob";
await prisma.$queryRaw`SELECT 'My name is ${name}';`;代わりに、文字列全体を変数として渡すか、文字列連結を使用することができます。
const name = "My name is Bob";
await prisma.$queryRaw`SELECT ${name};`;const name = "Bob";
await prisma.$queryRaw`SELECT 'My name is ' || ${name};`; -
テンプレート変数は、データ値(上記の例の
email
など)にのみ使用できます。列名、テーブル名、データベース名などの識別子や、SQL キーワードには変数は使用できません。例えば、以下の2つのクエリは**機能しません**。const myTable = "user";
await prisma.$queryRaw`SELECT * FROM ${myTable};`;const ordering = "desc";
await prisma.$queryRaw`SELECT * FROM Table ORDER BY ${ordering};`; -
Prisma は、
$queryRaw
および$queryRawUnsafe
によって返されるすべてのデータベース値を対応する JavaScript の型にマッピングします。詳細はこちら。 -
$queryRaw
は PostgreSQL データベースでの動的なテーブル名をサポートしていません。詳細はこちら
戻り値の型
$queryRaw
は配列を返します。各オブジェクトはデータベースレコードに対応します。
[
{ id: 1, email: "emelie@prisma.io", name: "Emelie" },
{ id: 2, email: "yin@prisma.io", name: "Yin" },
]
$queryRaw
の結果に型を付けることもできます。
署名
$queryRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): PrismaPromise<T>;
$queryRaw
結果の型付け
PrismaPromise<T>
は、ジェネリック型パラメータ T
を使用します。$queryRaw
メソッドを呼び出すときに T
の型を決定できます。次の例では、$queryRaw
は User[]
を返します。
// import the generated `User` type from the `@prisma/client` module
import { User } from "@prisma/client";
const result = await prisma.$queryRaw<User[]>`SELECT * FROM User`;
// result is of type: `User[]`
注意: 型を指定しない場合、
$queryRaw
はデフォルトでunknown
になります。
モデルの**特定のフィールド**を選択する場合、または関連を含める場合は、結果が適切に型付けされるようにするために、Prisma Client の生成された型を活用することに関するドキュメントを参照してください。
生の SQL を使用する際の型の注意点
$queryRaw
の結果に型を付ける場合、生データが常に推奨される TypeScript の型と一致するとは限りません。例えば、次の Prisma モデルには published
という名前の Boolean
フィールドが含まれています。
model Post {
id Int @id @default(autoincrement())
published Boolean @default(false)
title String
content String?
}
次のクエリはすべての投稿を返します。次に、各 Post
の published
フィールドの値を表示します。
const result = await prisma.$queryRaw<Post[]>`SELECT * FROM Post`;
result.forEach((x) => {
console.log(x.published);
});
通常の CRUD クエリの場合、Prisma Client のクエリエンジンはすべてのデータベースで戻り値の型を標準化します。**生のクエリでは標準化されません**。データベースプロバイダが MySQL の場合、返される値は 1
または 0
です。しかし、データベースプロバイダが PostgreSQL の場合、値は true
または false
になります。
注意: Prisma は JavaScript の整数を
INT8
として PostgreSQL に送信します。これは、INT4
のみを入力として受け入れるユーザー定義関数と競合する可能性があります。PostgreSQL データベースと組み合わせて$queryRaw
を使用する場合は、入力型をINT8
に更新するか、クエリパラメータをINT4
にキャストしてください。
PostgreSQL の動的テーブル名
テーブル名を補間することはできません。これは、$queryRaw
で動的なテーブル名を使用できないことを意味します。代わりに、次のように$queryRawUnsafe
を使用する必要があります。
let userTable = "User";
let result = await prisma.$queryRawUnsafe(`SELECT * FROM ${userTable}`);
$queryRawUnsafe
をユーザー入力と組み合わせて使用すると、SQL インジェクション攻撃のリスクがあることに注意してください。詳細はこちら。
$queryRawUnsafe()
$queryRawUnsafe()
メソッドを使用すると、生文字列(またはテンプレート文字列)をデータベースに渡すことができます。
このメソッドをユーザー入力(つまり、SELECT * FROM table WHERE columnx = ${userInput}
)と共に使用すると、SQL インジェクション攻撃の可能性が開かれます。SQL インジェクション攻撃は、データの変更または削除を引き起こす可能性があります。
可能な限り、代わりに $queryRaw
メソッドを使用する必要があります。正しく使用した場合、$queryRaw
メソッドははるかに安全ですが、特定の状況下では $queryRaw
メソッドも脆弱になる可能性があることに注意してください。詳細については、以下のSQL インジェクション対策セクションを参照してください。
次のクエリは、User
テーブルの各レコードのすべてのフィールドを返します。
// import the generated `User` type from the `@prisma/client` module
import { User } from "@prisma/client";
const result = await prisma.$queryRawUnsafe("SELECT * FROM User");
パラメーター化されたクエリを実行することもできます。次の例では、メールアドレスに文字列 emelie@prisma.io
が含まれるすべてのユーザーを返します。
prisma.$queryRawUnsafe("SELECT * FROM users WHERE email = $1", "emelie@prisma.io");
注意: Prisma は JavaScript の整数を
INT8
として PostgreSQL に送信します。これは、INT4
のみを入力として受け入れるユーザー定義関数と競合する可能性があります。PostgreSQL データベースと組み合わせてパラメータ化された$queryRawUnsafe
クエリを使用する場合は、入力型をINT8
に更新するか、クエリパラメータをINT4
にキャストしてください。
パラメーター化されたクエリの使用に関する詳細については、以下のパラメーター化されたクエリセクションを参照してください。
署名
$queryRawUnsafe<T = unknown>(query: string, ...values: any[]): PrismaPromise<T>;
$executeRaw
$executeRaw
は、UPDATE
や DELETE
のようなデータベース操作によって影響を受けた行数を返します。この関数はデータベースレコードを**返しません**。次のクエリはデータベース内のレコードを更新し、更新されたレコードの数を返します。
const result: number =
await prisma.$executeRaw`UPDATE User SET active = true WHERE emailValidated = true`;
このメソッドはタグ付きテンプレートとして実装されており、変数を簡単に挿入できるテンプレートリテラルを渡すことができます。これにより、Prisma Client は SQL インジェクションから安全なプリペアドステートメントを作成します。
const emailValidated = true;
const active = true;
const result: number =
await prisma.$executeRaw`UPDATE User SET active = ${active} WHERE emailValidated = ${emailValidated};`;
信頼できない入力をこのメソッドに渡されるクエリに組み込むために文字列ビルディングを使用すると、SQL インジェクション攻撃の可能性が開かれます。SQL インジェクション攻撃は、データの変更または削除を引き起こす可能性があります。推奨されるメカニズムは、このメソッドを実行する時点でクエリのテキストを含めることです。このリスクに関する詳細およびそれを防ぐ方法の例については、以下のSQL インジェクション対策セクションを参照してください。
考慮事項
以下に注意してください。
-
$executeRaw
は、単一の文字列内に複数のクエリをサポートしていません(例:ALTER TABLE
とCREATE TABLE
を同時に)。 -
Prisma Client はプリペアドステートメントを送信し、プリペアドステートメントは SQL ステートメントのサブセットのみを許可します。例えば、
START TRANSACTION
は許可されません。MySQL がプリペアドステートメントで許可する構文の詳細はこちらで確認できます。 -
PREPARE
はALTER
をサポートしていません - 回避策を参照してください。 -
テンプレート変数は SQL 文字列リテラル内では使用できません。例えば、以下のクエリは**機能しません**。
const name = "Bob";
await prisma.$executeRaw`UPDATE user SET greeting = 'My name is ${name}';`;代わりに、文字列全体を変数として渡すか、文字列連結を使用することができます。
const name = "My name is Bob";
await prisma.$executeRaw`UPDATE user SET greeting = ${name};`;const name = "Bob";
await prisma.$executeRaw`UPDATE user SET greeting = 'My name is ' || ${name};`; -
テンプレート変数は、データ値(上記の例の
email
など)にのみ使用できます。列名、テーブル名、データベース名などの識別子や、SQL キーワードには変数は使用できません。例えば、以下の2つのクエリは**機能しません**。const myTable = "user";
await prisma.$executeRaw`UPDATE ${myTable} SET active = true;`;const ordering = "desc";
await prisma.$executeRaw`UPDATE User SET active = true ORDER BY ${desc};`;
戻り値の型
$executeRaw
は number
を返します。
署名
$executeRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): PrismaPromise<number>;
$executeRawUnsafe()
$executeRawUnsafe()
メソッドを使用すると、生文字列(またはテンプレート文字列)をデータベースに渡すことができます。$executeRaw
と同様に、データベースレコードは**返さず**、影響を受けた行数を返します。
このメソッドをユーザー入力(つまり、SELECT * FROM table WHERE columnx = ${userInput}
)と共に使用すると、SQL インジェクション攻撃の可能性が開かれます。SQL インジェクション攻撃は、データの変更または削除を引き起こす可能性があります。
可能な限り、代わりに $executeRaw
メソッドを使用する必要があります。正しく使用した場合、$executeRaw
メソッドははるかに安全ですが、特定の状況下では $executeRaw
メソッドも脆弱になる可能性があることに注意してください。詳細については、以下のSQL インジェクション対策セクションを参照してください。
次の例では、テンプレート文字列を使用してデータベース内のレコードを更新します。その後、更新されたレコードの数を返します。
const emailValidated = true;
const active = true;
const result = await prisma.$executeRawUnsafe(
`UPDATE User SET active = ${active} WHERE emailValidated = ${emailValidated}`
);
同じことをパラメーター化されたクエリとして記述できます。
const result = prisma.$executeRawUnsafe(
"UPDATE User SET active = $1 WHERE emailValidated = $2",
"yin@prisma.io",
true
);
パラメーター化されたクエリの使用に関する詳細については、以下のパラメーター化されたクエリセクションを参照してください。
署名
$executeRawUnsafe<T = unknown>(query: string, ...values: any[]): PrismaPromise<number>;
生クエリの型マッピング
Prisma は、$queryRaw
および $queryRawUnsafe
によって返されるすべてのデータベース値を、対応するJavaScript の型にマッピングします。この動作は、findMany()
のような通常の Prisma クエリメソッドと同じです。
機能の利用可能性
- v3.14.x と v3.15.x では、生のクエリの型マッピングはプレビュー機能
improvedQueryRaw
で利用可能でした。バージョン 4.0.0 で生のクエリの型マッピングを一般利用可能(GA)にしたため、バージョン 4.0.0 以降ではimprovedQueryRaw
を使用する必要はありません。 - バージョン 4.0.0 より前は、SQLite で生のクエリの型マッピングは利用できませんでした。
例として、テーブルから BigInt
、Bytes
、Decimal
、Date
型の列を選択する生のクエリを取り上げます。
const result = await prisma.$queryRaw`SELECT bigint, bytes, decimal, date FROM "Table";`;
console.log(result);
{ bigint: BigInt("123"), bytes: <Buffer 01 02>), decimal: Decimal("12.34"), date: Date("<some_date>") }
result
オブジェクトでは、データベース値が対応する JavaScript の型にマッピングされています。
以下の表は、データベースで使用される型と、生クエリによって返される JavaScript の型との変換を示しています。
データベース型 | JavaScript 型 |
---|---|
テキスト | 文字列 |
32ビット整数 | 数値 |
32ビット符号なし整数 | BigInt |
浮動小数点数 | 数値 |
倍精度数値 | 数値 |
64ビット整数 | BigInt |
Decimal / 数値 | Decimal |
バイト | Uint8Array (v6より前: Buffer ) |
Json | オブジェクト |
DateTime | 日付 |
日付 | 日付 |
時刻 | 日付 |
Uuid | 文字列 |
Xml | 文字列 |
各データベースの型の正確な名前はデータベースによって異なります。例えば、ブール型は PostgreSQL では boolean
、CockroachDB では STRING
と呼ばれます。スカラー型リファレンスで、各データベースの型の完全な詳細を確認してください。
生クエリの型キャスト動作
Prisma Client の生クエリでは、パラメータが SQL 関数またはクエリの期待される型である必要があります。Prisma Client は、微妙な暗黙的なキャストを行いません。
例として、PostgreSQL の LENGTH
関数を使用する次のクエリを考えてみましょう。この関数は入力として text
型のみを受け入れます。
await prisma.$queryRaw`SELECT LENGTH(${42});`;
このクエリはエラーを返します。
// ERROR: function length(integer) does not exist
// HINT: No function matches the given name and argument types. You might need to add explicit type casts.
この場合の解決策は、42
を明示的に text
型にキャストすることです。
await prisma.$queryRaw`SELECT LENGTH(${42}::text);`;
機能の利用可能性: この機能はバージョン 4.0.0 以降で一般利用可能(GA)です。v3.14.x および v3.15.x では、プレビュー機能 improvedQueryRaw
で利用可能でした。
バージョン 4.0.0 より前の上記の例では、Prisma ORM は 42
を暗黙的に text
に強制変換し、明示的なキャストを必要としませんでした。
一方、以下の生クエリは現在正しく動作し、整数結果を返し、以前は失敗していました。
await prisma.$queryRaw`SELECT ${1.5}::int as int`;
// Now: [{ int: 2 }]
// Before: db error: ERROR: incorrect binary data format in bind parameter 1
トランザクション
2.10.0 以降では、トランザクション内で .$executeRaw()
および .$queryRaw()
を使用できます。
変数の使用
$executeRaw
と $queryRaw
はタグ付きテンプレートとして実装されています。タグ付きテンプレートは、Prisma Client で生 SQL と変数を使用する推奨される方法です。
次の例には、${userId}
という名前のプレースホルダーが含まれています。
const userId = 42;
const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${userId};`;
✔ $queryRaw
および $executeRaw
のタグ付きテンプレートバージョンを使用する利点には以下が含まれます。
- Prisma Client はすべての変数をエスケープします。
- タグ付きテンプレートはデータベースに依存しません。変数を
$1
(PostgreSQL) または?
(MySQL) のどちらで記述するかを覚える必要はありません。 - SQL Template Tag は便利なヘルパーへのアクセスを提供します。
- 埋め込みの、名前付き変数は読みやすいです。
注意: タグ付きテンプレートのプレースホルダーにテーブル名や列名を渡すことはできません。例えば、
SELECT ?
として、条件に基づいて*
やid, name
を渡すことはできません。
タグ付きテンプレートヘルパー
Prisma Client は特にSQL Template Tagを使用しており、多くのヘルパーを公開しています。例えば、次のクエリは join()
を使用して ID のリストを渡します。
import { Prisma } from "@prisma/client";
const ids = [1, 3, 5, 10, 20];
const result = await prisma.$queryRaw`SELECT * FROM User WHERE id IN (${Prisma.join(ids)})`;
次の例では、empty
と sql
ヘルパーを使用して、userName
が空かどうかによってクエリを変更します。
import { Prisma } from "@prisma/client";
const userName = "";
const result = await prisma.$queryRaw`SELECT * FROM User ${
userName ? Prisma.sql`` : Prisma.empty // Cannot use "" or NULL here!
}`;
ALTER
制限 (PostgreSQL)
PostgreSQL は、プリペアドステートメントでの ALTER
の使用をサポートしていません。つまり、次のクエリは**機能しません**。
await prisma.$executeRaw`ALTER USER prisma WITH PASSWORD "${password}"`;
await prisma.$executeRaw(Prisma.sql`ALTER USER prisma WITH PASSWORD "${password}"`);
次のクエリを使用することはできますが、${password}
がエスケープされないため、これは潜在的に**安全ではありません**ので注意してください。
await prisma.$executeRawUnsafe('ALTER USER prisma WITH PASSWORD "$1"', password})
非サポート型
Unsupported
型は、$queryRaw
または $queryRawUnsafe
で使用する前に、Prisma Client がサポートする型にキャストする必要があります。例えば、location
フィールドに Unsupported
型を持つ次のモデルを考えてみましょう。
model Country {
location Unsupported("point")?
}
このサポートされていないフィールドに対する次のクエリは**機能しません**。
await prisma.$queryRaw`SELECT location FROM Country;`;
代わりに、**もしあなたの Unsupported
カラムがキャストをサポートしているなら**、Unsupported
フィールドをサポートされている任意の Prisma Client の型にキャストしてください。
最も一般的に Unsupported
列をキャストしたい型は String
です。例えば、PostgreSQL では、これは text
型にマッピングされます。
await prisma.$queryRaw`SELECT location::text FROM Country;`;
したがって、データベースは Prisma Client がサポートするデータの String
表現を提供します。
サポートされている Prisma 型の詳細については、関連するデータベースのPrisma コネクタの概要を参照してください。
SQL インジェクション対策
Prisma Client で SQL インジェクションを回避する理想的な方法は、可能な限り ORM モデルを使用してクエリを実行することです。
それが不可能な場合で、生のクエリが必要な場合は、Prisma Client が様々な生メソッドを提供しますが、これらのメソッドを安全に使用することが重要です。
このセクションでは、これらのメソッドを安全かつ安全でない方法で使用する様々な例を提供します。これらの例はPrisma Playgroundでテストできます。
$queryRaw
および $executeRaw
で
$queryRaw
および $executeRaw
のシンプルで安全な使い方
これらのメソッドは、タグ付きテンプレートを使用する際にすべての変数をエスケープし、すべてのクエリをプリペアドステートメントとして送信することで、SQL インジェクションのリスクを軽減できます。
$queryRaw`...`; // Tagged template
$executeRaw`...`; // Tagged template
次の例は SQL インジェクションに対して安全です ✅
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const result = await prisma.$queryRaw`SELECT id, name FROM "User" WHERE name = ${inputString}`;
console.log(result);
$queryRaw
および $executeRaw
の安全でない使い方
ただし、これらのメソッドを安全でない方法で使用することも可能です。
一つの方法は、ユーザー入力を安全でない方法で連結するタグ付きテンプレートを人工的に生成することです。
次の例は SQL インジェクションに対して脆弱です ❌
// Unsafely generate query text
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`; // SQL Injection
const query = `SELECT id, name FROM "User" WHERE name = ${inputString}`;
// Version for Typescript
const stringsArray: any = [...[query]];
// Version for Javascript
const stringsArray = [...[query]];
// Use the `raw` property to impersonate a tagged template
stringsArray.raw = [query];
// Use queryRaw
const result = await prisma.$queryRaw(stringsArray);
console.log(result);
これらのメソッドを脆弱にするもう一つの方法は、Prisma.raw
関数の誤用です。
以下の例はすべて SQL インジェクションに対して脆弱です ❌
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const result = await prisma.$queryRaw`SELECT id, name FROM "User" WHERE name = ${Prisma.raw(
inputString
)}`;
console.log(result);
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const result = await prisma.$queryRaw(
Prisma.raw(`SELECT id, name FROM "User" WHERE name = ${inputString}`)
);
console.log(result);
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const query = Prisma.raw(`SELECT id, name FROM "User" WHERE name = ${inputString}`);
const result = await prisma.$queryRaw(query);
console.log(result);
より複雑なシナリオで $queryRaw
および $executeRaw
を安全に使用する
クエリの実行とは別に生クエリを構築する
生のクエリを別の場所で、またはパラメータとは別に構築したい場合は、以下のいずれかの方法を使用する必要があります。
この例では、sql
ヘルパーメソッドが変数を含めてクエリテキストを安全に構築するために使用されています。これは SQL インジェクションに対して安全です ✅
// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
// Safe if the text query below is completely trusted content
const query = Prisma.sql`SELECT id, name FROM "User" WHERE name = ${inputString}`;
const result = await prisma.$queryRaw(query);
console.log(result);
この例は SQL インジェクションに対して安全 ✅ です。sql
ヘルパーメソッドは、入力値のパラメータマーカーを含むクエリテキストを構築するために使用されています。各変数はマーカーシンボル(MySQL の場合は ?
、PostgreSQL の場合は $1
、$2
など)で表されます。この例は PostgreSQL クエリのみを示しています。
// Version for Typescript
const query: any;
// Version for Javascript
const query;
// Safe if the text query below is completely trusted content
query = Prisma.sql`SELECT id, name FROM "User" WHERE name = $1`;
// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
query.values = [inputString];
const result = await prisma.$queryRaw(query);
console.log(result);
注記: PostgreSQL 変数は
$1
などで表されます。
生クエリを別の場所または段階的に構築する
クエリを実行する場所以外の場所で生のクエリを構築したい場合、理想的な方法は、クエリのセグメントから Sql
オブジェクトを作成し、それにパラメータ値を渡すことです。
次の例では、パラメーター化する変数が2つあります。Prisma.sql
に渡されるクエリ文字列が信頼できるコンテンツのみを含んでいる限り、この例は SQL インジェクションに対して安全です ✅
// Example is safe if the text query below is completely trusted content
const query1 = `SELECT id, name FROM "User" WHERE name = `; // The first parameter would be inserted after this string
const query2 = ` OR name = `; // The second parameter would be inserted after this string
const inputString1 = "Fred";
const inputString2 = `'Sarah' UNION SELECT id, title FROM "Post"`;
const query = Prisma.sql([query1, query2, ""], inputString1, inputString2);
const result = await prisma.$queryRaw(query);
console.log(result);
注:
Prisma.sql
の最初のパラメータとして渡される文字列配列は、sql
関数がパラメータの数よりも1つ多いクエリセグメントを期待するため、最後に空の文字列を持つ必要があることに注意してください。
生クエリを1つの大きな文字列に構築したい場合でも可能です。ただし、これは潜在的に危険な Prisma.raw
メソッドを使用するため、注意が必要です。また、Prisma が通常提供するような関連データベースのマーカーを提供できないため、データベースに正しいパラメーターマーカーを使用してクエリを構築する必要があります。
Prisma.raw
に渡されるクエリ文字列が信頼できるコンテンツのみを含んでいる限り、次の例は SQL インジェクションに対して安全です ✅
// Version for Typescript
const query: any;
// Version for Javascript
const query;
// Example is safe if the text query below is completely trusted content
const query1 = `SELECT id, name FROM "User" `;
const query2 = `WHERE name = $1 `;
query = Prisma.raw(`${query1}${query2}`);
// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
query.values = [inputString];
const result = await prisma.$queryRaw(query);
console.log(result);
$queryRawUnsafe
および $executeRawUnsafe
で
$queryRawUnsafe
および $executeRawUnsafe
を安全でない方法で使用する
タグ付きテンプレートを使用できない場合は、代わりに$queryRawUnsafe
または$executeRawUnsafe
を使用できます。ただし、**これらの関数はコード内の SQL インジェクション脆弱性のリスクを大幅に高めることに注意してください**。
次の例では query
と inputString
を連結しています。この例では Prisma Client は inputString
をエスケープ**できません**❌。これにより、SQL インジェクションに対して脆弱になります。
const inputString = '"Sarah" UNION SELECT id, title, content FROM Post'; // SQL Injection
const query = "SELECT id, name, email FROM User WHERE name = " + inputString;
const result = await prisma.$queryRawUnsafe(query);
console.log(result);
パラメーター化されたクエリ
タグ付きテンプレートの代替として、$queryRawUnsafe
は、各変数がシンボル(MySQL の場合は ?
、PostgreSQL の場合は $1
、$2
など)で表される標準的なパラメーター化クエリをサポートしています。この例は PostgreSQL クエリのみを示しています。
次の例は SQL インジェクションに対して安全です ✅
const userName = "Sarah";
const email = "sarah@prisma.io";
const result = await prisma.$queryRawUnsafe(
"SELECT * FROM User WHERE (name = $1 OR email = $2)",
userName,
email
);
注: PostgreSQL 変数は
$1
および$2
で表されます。
タグ付きテンプレートと同様に、このように変数を提供した場合、Prisma Client はすべての変数をエスケープします。
注意: パラメータ化されたクエリにテーブル名や列名を変数として渡すことはできません。例えば、
SELECT ?
として、条件に基づいて*
やid, name
を渡すことはできません。
パラメーター化された PostgreSQL ILIKE
クエリ
ILIKE
を使用する場合、%
ワイルドカード文字はクエリ (string
) ではなく、変数自体に含める必要があります。この例は SQL インジェクションに対して安全です ✅。
const userName = "Sarah";
const emailFragment = "prisma.io";
const result = await prisma.$queryRawUnsafe(
'SELECT * FROM "User" WHERE (name = $1 OR email ILIKE $2)',
userName,
`%${emailFragment}`
);
注:
%$2
を引数として使用しても機能しません。
MongoDB での生のクエリ
MongoDB のバージョン 3.9.0
以降では、Prisma Client は生のクエリを送信できる3つのメソッドを公開しています。これらを使用できます。
$runCommandRaw
: データベースに対してコマンドを実行します。<model>.findRaw
: フィルターに一致するドキュメントをゼロ個以上見つけます。<model>.aggregateRaw
: コレクションに対して集約操作を実行します。
$runCommandRaw()
$runCommandRaw()
は、データベースに対して生の MongoDB コマンドを実行します。入力として、以下の例外を除き、すべてのMongoDB データベースコマンドを受け入れます。
find
(代わりにfindRaw()
を使用)aggregate
(代わりにaggregateRaw()
を使用)
$runCommandRaw()
を使用して MongoDB データベースコマンドを実行する場合、以下の点に注意してください。
$runCommandRaw()
を呼び出すときに渡すオブジェクトは、MongoDB データベースコマンドの構文に従う必要があります。- MongoDB データベースコマンドに適切なロールでデータベースに接続する必要があります。
次の例では、2つのレコードが同じ _id
で挿入されます。これは通常のドキュメント検証をバイパスします。
prisma.$runCommandRaw({
insert: "Pets",
bypassDocumentValidation: true,
documents: [
{
_id: 1,
name: "Felinecitas",
type: "Cat",
breed: "Russian Blue",
age: 12,
},
{
_id: 1,
name: "Nao Nao",
type: "Dog",
breed: "Chow Chow",
age: 2,
},
],
});
"find"
または "aggregate"
コマンドを含むクエリには $runCommandRaw()
を使用しないでください。すべてのデータを取得できない可能性があります。これは、MongoDB が MongoDB セッションにアタッチされたカーソルを返すためであり、毎回同じ MongoDB セッションにヒットするとは限らないためです。これらのクエリには、代わりに特殊なfindRaw()
およびaggregateRaw()
メソッドを使用する必要があります。
戻り値の型
$runCommandRaw()
は、入力によって形状が異なる JSON
オブジェクトを返します。
署名
$runCommandRaw(command: InputJsonObject): PrismaPromise<JsonObject>;
findRaw()
<model>.findRaw()
は実際のデータベースレコードを返します。User
コレクションでフィルターに一致するドキュメントをゼロ個以上見つけます。
const result = await prisma.user.findRaw({
filter: { age: { $gt: 25 } },
options: { projection: { _id: false } },
});
戻り値の型
<model>.findRaw()
は、入力によって形状が異なる JSON
オブジェクトを返します。
署名
<model>.findRaw(args?: {filter?: InputJsonObject, options?: InputJsonObject}): PrismaPromise<JsonObject>;
aggregateRaw()
<model>.aggregateRaw()
は集約されたデータベースレコードを返します。User
コレクションに対して集約操作を実行します。
const result = await prisma.user.aggregateRaw({
pipeline: [
{ $match: { status: "registered" } },
{ $group: { _id: "$country", total: { $sum: 1 } } },
],
});
戻り値の型
<model>.aggregateRaw()
は、入力によって形状が異なる JSON
オブジェクトを返します。
署名
<model>.aggregateRaw(args?: {pipeline?: InputJsonObject[], options?: InputJsonObject}): PrismaPromise<JsonObject>;
pipeline
: 集約パイプラインを介してドキュメントストリームを処理および変換するための集約ステージの配列。options
:aggregate
コマンドに渡す追加オプション。
注意点
ObjectId
や Date
のようなカスタムオブジェクトを扱う場合、それらをMongoDB 拡張 JSON 仕様に従って渡す必要があります。例:
const result = await prisma.user.aggregateRaw({
pipeline: [
{ $match: { _id: { $oid: id } } }
// ^ notice the $oid convention here
],
});