icon

nazo6.dev

一覧に戻る
2023/9/1 6 min read

prisma-client-rust入門

この記事はZennにも投稿しています

#概要

prisma-client-rustはJavascript向けのORMであるprismaをRustから使えるようにしたものです。実はprismaのコア部分はRustで書かれているためこういうものも作りやすかったんじゃないかと思います。

#セットアップ

まずはプロジェクトを作成します。cargo new --binでバイナリプロジェクトを作成して、Cargo.tomlをこんな感じに編集します。

Cargo.toml
[package]
name = "app"
version = "0.1.0"
edition = "2021"
 
[dependencies]
axum = { version = "0.6.18", features = ["headers", "query"] }
 
[dependencies.prisma-client-rust]
git = "https://github.com/Brendonovich/prisma-client-rust"
tag = "0.6.9"
default-features = false
features = ["postgresql", "migrations"]
 
[workspace]
resolver = "2"
members = ["prisma-cli"]

prisma-client-rustはcrates.ioでは提供されていないため、gitリポジトリを指定する必要があります(参考: https://github.com/Brendonovich/prisma-client-rust/issues/76 )。

featuresには使用するデータベースの他に他ライブラリとの統合機能を指定できます。ここではpostgresqlとmigration機能を指定しました。 個人的に興味深いものとしてはrspc featureがあります。rspcはRust版trpcみたいなやつで、Rustの型からTypescriptの型を吐き出してフロントエンドで使用することができます。そしてrspc featureを指定することで必要なものをderiveしてくれるわけです。

#cliのセットアップ

JS版と同様、prisma cliを使うことになるのでインストールします。公式の手順に従うことでプロジェクトディレクトリ内でのみcargo prismaコマンドを使用することができるようになります。

#スキーマの作成

次にprismaのスキーマを作成します。プロジェクトディレクトリ直下にprismaフォルダを作成し、その中にschema.prismamigrationsフォルダを作成します。 その後cargo prisma generateを実行することでsrc/prisma.rsが生成されます。このファイルはデバイス固有のものなので.gitignoreに含めるべきです。

#Clientの作成

main.rs
#[tokio::main]
async fn main() -> Result<()> {
    let client = prisma::PrismaClient::_builder()
        .with_url(std::env::var("DATABASE_URL").expect("No DATABASE_URL environment variable"))
        .build()
        .await;
    #[cfg(debug_assertions)]
    {
        info!("db push");
        client._db_push().await.unwrap();
    }
 
    #[cfg(not(debug_assertions))]
    {
        info!("Running database migrations");
        client._migrate_deploy().await?;
        info!("Database migrations completed");
    }
 
	Ok(())
}

このようにPrismaClientを作成することでデータベースにアクセスできます。開発時には_db_pushメソッドを使ってschemaの変更を直接反映させます。実際にはaxumのstateなどにArc<PrismaClient>として入れることになるでしょう。 リリースビルドではprisma migrate devコマンドを使用してマイグレーション用sqlを生成した上でそれらを適用します。

#CRUD操作

基本的なことは公式のdocsを見てもらえばわかると思うのでdocsでは説明が足りないなと感じた箇所について記したいと思います。 以下のサンプルコードでは公式のdocsにもある以下のprisma.schemaを使うことにします。

prisma.schema
generator client {
    provider = "cargo prisma"
    output = "src/prisma.rs"
}
 
model Post {
    id        String   @id @default(cuid())
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
    published Boolean
    title     String
    content   String?
    desc      String?
 
    comments Comment[]
}
 
model Comment {
    id        String   @id @default(cuid())
    createdAt DateTime @default(now())
    content   String
 
    post   Post   @relation(fields: [postID], references: [id])
    postID String
}

#リレーション

prisma-client-rustでは、read時にrelationも含めて取得する方法が2つあります。

#1. .with()fetchを使う

ここに載っているやり方です。

use prisam::{comment, post};
 
let post: post::Data = client
    .post()
    .find_unique(post::id::equals("0".to_string()))
    .with(post::comments::fetch(vec![])
      .with(comment::post::fetch())
    )
    .exec()
    .await
    .unwrap()
    .unwrap();
 
// Safe since post::comments::fetch has been used
for comment in post.comments().unwrap() {
    // Safe since comment::post::fetch has been used
    let post = comment.post().unwrap();
 
    assert_eq!(post.id, "0");
}

このコードのようにwithとfetchを使うことでリレーション先のデータを取得できますがデータが関数の中にあるResultで取得できるので扱いづらいです。

#2. include!()マクロを使用する

このマクロはincludeメソッドに使用できるstructを生成することで型安全かつ簡潔にリレーションの取得を記述することができます。 例えば

prisma::post::include!(post_with_comments {
	comments
})

と記述することで

mod post_with_comments {
    pub struct Data {
        id: String,
        ...
        comments: comments::Data 
    }
    fn include() {
	    ...
    }
}

のようなコードが生成されます。そして

let posts: Vec<_> = client
    .post()
    .find_many(vec![])
    .include(post_with_comments::include())
    .exec()
    .await?;

のようなコードを書くことでpost_with_comments::Data型の値が返ってきます。

2のやり型はJSのprismaと同じような書き心地で非常に便利です。正直1の方法を使う必要はあまりないのではないかと感じました。

#一部の列のみを取得

先程紹介したinclude!()マクロに似たselect!()マクロを使用することで一部の列のみを取得することができます。 また、includeマクロ内でselectキーワードを使用するというようなことも可能で柔軟にデータを取得できます。

Share this article:
一覧に戻る

関連記事

2021/12/27

2023/10/20

#tech/lang/rust
memo

Rust

気づきとかいろいろ

Read Article

2024/3/23

#tech/lang/rust#hardware/keyboard/keyball
blog

RustでKeyballのファームウェアを書きたい話

KeyballのファームウェアはQMKを使ったC言語のものになっています。ですがやはりRust、使いたいですよね?

Read Article

2023/5/26

#tech/lang/rust#tech/database
memo

RustでSQLからコードを生成するcornucopiaについて

SQLからRustのコードを生成して安全にデータベース操作ができる。恐らくGoのsqlcと同じ感じなんだと思う。

Read Article

2023/11/15

#tech/lang/rust
memo

Rustでジョブキュー的なもの

実行するコマンド(EnqueueかClear)をチャネルで受け取る

Read Article

2025/12/13

2025/12/14

#tech/lang/rust
blog

RustでデスクトップGUI - gpui入門 Part1 (gpuiの仕組み・状態管理の基礎編)

gpui解説記事のPart1。gpuiのレンダリング方法や状態管理について、実際のソースを見ながら詳しく解説します。

Read Article

2024/4/26

2024/5/22

#tech/lang/rust#hardware/keyboard/keyball
blog

RustとEmbassyでKeyballのファームウェアを作った

以前RustでKeyballのファームウェアを書きたい話で、ATMega32U4向けのファームウェアの作成をRustで試みたという話を書きましたが、結論から言うとこれは諦めてProMicro RP2040向けのファームウェアをRustで書くことにしました。

Read Article

2023/8/27

#tech/lang/rust
memo

Rustのserde_jsonでエラーの発生箇所を知る方法

serde_jsonではパースエラー発生時にどのプロパティでエラーが発生したのかわからない

Read Article

2023/6/27

#tech/lang/rust
memo

Rustのtargetフォルダを軽くする

cargo-sweepを使う

Read Article

2022/2/13

#tech/lang/rust
memo

Rustアプリにwasmerを埋め込む

dioxusを使ってwebでもdesktopでも動くアプリを作りたい

Read Article

2025/3/29

#tech/lang/rust
memo

Rustアプリのメモリ使用量を調査する

主にstatic領域のメモリ使用量を調査するのに有益。embassyの独立したタスクなどのサイズが見れる。

Read Article

2023/9/10

2023/12/18

#tech/lang/rust
blog

SerdeのDeserializerを実装する(Part1)

Serdeで任意の形式のファイルなどをデシリアライズする際にはDeserializerを書く必要があります。この記事では基本的なDeserializerの書き方を解説します。 正直自分もあまり理解していない部分が多々あるのですが世に出ている情報が少ないので書くことにしました。

Read Article

2023/12/18

2023/12/19

#tech/lang/rust
blog

SerdeのDeserializerを実装する(Part2 JSON編)

この記事はRust Advent Calendar 2023 シリーズ3の19日目の記事です。

Read Article

2024/5/24

#hardware/keyboard#tech/lang/rust
blog

USB HIDキーボードでメディアキーを操作する方法

USB HIDでは0x80がVolume Up、0x81がVolume Downに割り当てられており、さらに0xEDや0xEEでもVolume UpやDownができそうですが、実はこれらは全て動きません(Windowsでは)。

Read Article

2021/12/25

#tech/lang/rust
memo

tauriでWindows上でproductionビルドでのみ画像が表示されない(fetchエラーが発生する)

誰の役にも立たない気がするけどハマったのでメモ

Read Article

2023/11/18

#tech/lang/rust
blog

tokioで作ったサーバーをdockerで起動すると終了が遅くなるときの対処法

axumなどを作ってRustでサーバーを作るとdocker compose stopなどが微妙に遅くてイライラだったのでそれを解決する方法です。

Read Article

2025/4/9

2025/11/5

#tech/lang/rust
blog

「Rustが嫌いです。」の感想

https://zenn.dev/miguel/articles/f052de93fc9980

Read Article

© 2025 nazo6. All rights reserved.