PrismaのTypedSQLを使ってみる

PrismaのTypedSQLを使ってみる

2025.11.29

はじめに

Prismaでは複雑なSQLクエリを実行したい場合、$queryRaw$executeRawを使用できます。しかしながら、これらの構文はPrisma Clientによる型の恩恵を受けられず、スキーマ変更に追従しづらいというデメリットがあります。Prisma5.19.0で、この問題を解決するTypedSQLという機能がリリースされています。この記事ではTypedSQLを使用し、どのように型安全性が保証されるのか確認します。

Writing Type-safe SQL with TypedSQL and Prisma Client

注意点

この機能は記事執筆時点でプレビュー版です。

前提

バージョン5.19.0以上のPrisma及びPrisma Clientがインストール済みであること。

また、この記事ではPrismaのインストール方法は割愛します。

使ってみる

使用するスキーマ定義とデータ

この記事では、以下のスキーマ定義を使用します。

model User {
  id   Int    @id @default(autoincrement())
  name String @db.VarChar(100)

  posts Post[]

  @@map(name: "users")
}

model Post {
  id         Int    @id @default(autoincrement())
  title      String
  category   String
  created_by Int
  author     User   @relation(fields: [created_by], references: [id])

  @@map(name: "posts")
}

以下のようなデータが入っています。

usersテーブル

20251129_p_01

postsテーブル

20251129_p_02

基本的な使い方

schema.prismaにプレビュー機能フラグを追加します。

generator client {
  provider = "prisma-client-js"
  output   = "../generated/prisma"
  previewFeatures = ["typedSql"]   <--- 追加
}

続いて、prisma/sqlフォルダを作成し、SQLファイルを格納します。この記事では、以下のようなクエリをgetPostsByUsername.sqlとして作成しました。

select p.id, p.title, p.category
from posts p
inner join users u on u.id = p.created_by
where u.name = $1;

以下のコマンドを実行し、クライアントを生成します。

prisma generate --sql

クライアントを生成すると、以下のようにSQLファイルがインポートできるようになります。

import { prisma } from './client'
import { getPostsByUsername } from './generated/prisma/sql';

クエリを実行したい場合は、$queryRawTyped()を使用します。クエリにパラメータを渡したい場合は、以下のように引数として指定します。

const posts = await prisma.$queryRawTyped(getPostsByUsername('加藤 三郎_001'))

実行すると、以下のような結果が返り、クエリが正常に実行されたことがわかります。

[
  { id: 1, title: '応用編 Docker テクニック', category: 'Technology' },
  { id: 2, title: '実践的な React チュートリアル', category: 'Security' },
  { id: 3, title: '最新 TypeScript 設計パターン', category: 'Backend' },
  { id: 4, title: '応用編 テスト ベストプラクティス', category: 'WebDevelopment' },
  { id: 5, title: '完全ガイド Git ベストプラクティス', category: 'Architecture' },
  { id: 6, title: '徹底解説 テスト 活用法', category: 'Frontend' },
  { id: 7, title: '最新 React 設計パターン', category: 'Programming' },
  { id: 8, title: '初心者向け API設計 の基本', category: 'Backend' },
  { id: 9, title: '応用編 Docker 活用法', category: 'Testing' }
]

返ってきたデータの型推論もできています。

20251129_p_03

SQLファイルを以下のように変更します。

select p.id, p.title, p.category
from posts p
inner join users u on u.id = p.created_by
where u.name = $1
and p.category = $2;  <--- 追加

クライアントを再生成します。

prisma generate --sql

すると、以下のようにエラーになります。クエリ内のパラメータとコード上での引数の不一致が、ちゃんと検知されます。

20251129_p_04

ちなみに、SQLファイルを変更するたびにクライアントの生成が必要となりますが、--watchオプションをつけることで保存のたびに自動的に再生成されます。

20251129_p_05

これにより、SQLファイルの変更が即座にTypeScriptコードに反映され、開発者体験が向上します。

生成される型

prisma generateコマンドによって以下のような型が自動生成されます。

/**
 * @param text
 * @param text
 */
export const getPostsByUsername: (text: string, text: string) => $runtime.TypedSql<getPostsByUsername.Parameters, getPostsByUsername.Result>

export namespace getPostsByUsername {
  export type Parameters = [text: string, text: string]
  export type Result = {
    id: number
    title: string
    category: string
  }
}

この型により、パラメータの型と数、および戻り値の型が保証されます。

ちなみに、以下のような記法でコメントを書くことで、使う側にとってよりわかりやすくなります。

-- @param {String} $1:ユーザ名
select p.id, p.title, p.category
from posts p
inner join users u on u.id = p.created_by
where u.full_name = $1;

20251129_p_06

マイグレーションする場合

name列をfull_nameにリネームしてみます。

schema.prismaでUserテーブルを以下のように変更します。

model User {
  id   Int    @id @default(autoincrement())
  full_name String @db.VarChar(100)  <--- 変更

  posts Post[]

  @@map(name: "users")
}

この時点でクライアントの再生成を行います。

prisma generate
prisma generate --sql

特にエラーなくコマンドが実行できました。

以下のマイグレーションファイルを生成し、データベースに適用します。

ALTER TABLE "users" RENAME COLUMN "name" TO "full_name";

再度クライアントを生成します。

prisma generate --sql

今度は以下のエラーが表示されました。

Error: Errors while reading sql files:

In prisma\sql\getPostsByUsername.sql:
Error: column u.name does not exist

マイグレーションをする場合は、スキーマファイルの変更だけでなく、データベースに適用された内容に基づいて型のチェックがされるようです。

おわりに

冒頭で述べた通り、$queryRaw$executeRawの代替として、複雑なSQLクエリを型安全を保ちつつ管理したい場合に適しています。プレビュー版ではありますが、Prismaの公式ドキュメントでも以下のように述べられています。

With Prisma ORM 5.19.0, we have released TypedSQL. TypedSQL is a new way to write SQL queries that are type-safe and even easier to add to your workflow.

We strongly recommend using TypedSQL queries over the legacy raw queries described below whenever possible.

また、SQLクエリに対する完全なコントロールが必要なためORMによるクエリ自動生成機能が使えない場合や、既に生クエリで書かれたプロジェクトにPrismaを段階的に導入するといった場合も使える機能かと思います。

今回試してみましたが、型安全を保ちながらSQLの表現力を活用できる強力な機能だと感じました。

この記事がどなたかの参考になれば幸いです。

この記事をシェアする

FacebookHatena blogX

関連記事