メインコンテンツにスキップ

ロークエリ

警告

Prisma ORM 5.19.0 で、TypedSQL をリリースしました。TypedSQLは、型安全で、ワークフローにもさらに簡単に追加できる新しいSQLクエリの記述方法です。

可能な場合は常に、以下で説明する従来のロークエリよりもTypedSQLクエリを使用することを強くお勧めします。

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 の型を決定できます。次の例では、$queryRawUser[] を返します。

// 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?
}

次のクエリは、すべての投稿を返します。次に、各 Postpublished フィールドの値をプリントアウトします。

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の整数をPostgreSQLに INT8 として送信します。これは、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の整数をPostgreSQLに INT8 として送信します。これは、INT4 のみを入力として受け入れるユーザー定義関数と競合する可能性があります。パラメータ化された $queryRawUnsafe クエリをPostgreSQLデータベースと組み合わせて使用する場合は、入力型を INT8 に更新するか、クエリパラメータを INT4 にキャストしてください。

パラメータ化されたクエリの使用に関する詳細については、以下のパラメータ化されたクエリセクションを参照してください。

シグネチャ

$queryRawUnsafe<T = unknown>(query: string, ...values: any[]): PrismaPromise<T>;

$executeRaw

$executeRaw は、UPDATEDELETE など、データベース操作によって影響を受けた行数を返します。この関数は、データベースレコードを返しません。次のクエリは、データベース内のレコードを更新し、更新されたレコード数のカウントを返します。

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 TABLECREATE TABLE を一緒に)をサポートしていません。

  • Prisma Clientはプリペアドステートメントを送信し、プリペアドステートメントはSQLステートメントのサブセットのみを許可します。たとえば、START TRANSACTION は許可されていません。MySQLがプリペアドステートメントで許可する構文の詳細については、こちらをご覧ください

  • PREPAREALTER をサポートしていません - 回避策を参照してください。

  • テンプレート変数は、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};`;

戻り値の型

$executeRawnumber を返します。

シグネチャ

$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では利用できませんでした。

例として、テーブルから BigIntBytesDecimalDate 型の列を選択するロークエリを見てみましょう。

const result = await prisma.$queryRaw`SELECT bigint, bytes, decimal, date FROM "Table";`;

console.log(result);
表示CLI結果
{ 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 / numericDecimal
BytesUint8Arrayv6より前Buffer
Jsonオブジェクト
DateTime日付
日付日付
時間日付
Uuid文字列
Xml文字列

各データベース型の正確な名前はデータベースによって異なることに注意してください。たとえば、boolean型は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以降で一般提供されています。v3.14.xおよびv3.15.xでは、プレビュー機能 improvedQueryRaw で利用できました。

バージョン4.0.0より前の上記の例では、Prisma ORMは 42text に暗黙的に強制変換し、明示的なキャストは必要ありません。

一方、次のロークエリは、整数結果を正しく返し、以前は失敗していました。

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`WHERE name = ${userName}` : 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でサポートされている型にキャストする必要があります。たとえば、Unsupported 型の location フィールドを持つ次のモデルを見てみましょう。

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 の安全でない使用

ただし、これらのメソッドを安全でない方法で使用することも可能です。

1つの方法は、ユーザー入力を安全でない方法で連結するタグ付きテンプレートを人為的に生成することです。

次の例は、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);

これらのメソッドを脆弱にするもう1つの方法は、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インジェクション脆弱性のリスクを大幅に高めることに注意してください

次の例では、queryinputString を連結しています。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でのロークエリ

バージョン 3.9.0 以降のMongoDBの場合、Prisma Clientはロークエリを送信できる3つのメソッドを公開しています。使用できるのは次のとおりです。

  • データベースに対してコマンドを実行するには $runCommandRaw
  • フィルタに一致する0個以上のドキュメントを検索するには <model>.findRaw
  • コレクションに対して集計操作を実行するには <model>.aggregateRaw

$runCommandRaw()

$runCommandRaw() は、生のMongoDBコマンドをデータベースに対して実行します。入力として、すべてのMongoDBデータベースコマンドを受け入れますが、次の例外があります。

$runCommandRaw() を使用してMongoDBデータベースコマンドを実行する場合、次の点に注意してください。

  • $runCommandRaw() を呼び出すときに渡すオブジェクトは、MongoDBデータベースコマンドの構文に従う必要があります。
  • MongoDBデータベースコマンドに適したロールを使用してデータベースに接続する必要があります。

次の例では、クエリは同じ _id で2つのレコードを挿入します。これにより、通常のドキュメント検証がバイパスされます。

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,
},
],
});
警告

$runCommandRaw() は、"find" コマンドまたは "aggregate" コマンドを含むクエリには使用しないでください。すべてのデータを取得できない可能性があります。これは、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>;
  • filter: クエリ述語フィルター。指定しない場合、コレクション内のすべてのドキュメントが述語に一致します。
  • options: find コマンドに渡す追加オプション。

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>;

注意点

ObjectIdDate などのカスタムオブジェクトを扱う場合、MongoDB Extended JSON 仕様に従って渡す必要があります。例

const result = await prisma.user.aggregateRaw({
pipeline: [
{ $match: { _id: { $oid: id } } }
// ^ notice the $oid convention here
],
});