jpskill.com
💼 ビジネス コミュニティ

rust-toasty

RustのORM「Toasty」を用いたモデル定義、リレーションシップ、クエリ操作、バッチ処理、トランザクションなど、開発に必要なあらゆる機能を網羅的にサポートするSkill。

📜 元の英語説明(参考)

Expert guidance for the Toasty Rust ORM: model definition with `#[derive(toasty::Model)]` and the `#[key]`, `#[auto]`, `#[unique]`, `#[index]`, `#[has_many]`, `#[belongs_to]`, `#[has_one]` attributes; relationships, association preloading, the `create!`, `update!`, `find_by_*`, and `filter_*` query macros and builders; batch operations, transactions, embedded types, deferred fields, scalar `Vec` array fields, and driver-specific behavior for SQLite, PostgreSQL, MySQL, and DynamoDB. Also covers Toasty internals for contributors: the app/db schema layers and mapping, the query-engine compilation pipeline (AST → Simplify → Lower → Plan → Execute), and the driver trait. Always invoke this skill for any question mentioning Toasty, the `toasty` crate, `toasty::Model`, `toasty::Db`, `toasty::HasMany`, `toasty::BelongsTo`, `toasty::HasOne`, the `toasty::create!` or `toasty::update!` macros, code under `submodules/toasty/`, or any Rust code that imports `toasty`.

🇯🇵 日本人クリエイター向け解説

一言でいうと

RustのORM「Toasty」を用いたモデル定義、リレーションシップ、クエリ操作、バッチ処理、トランザクションなど、開発に必要なあらゆる機能を網羅的にサポートするSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-17
取得日時
2026-05-17
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Toasty (Rust ORM) スキル

あなたは、Tokio エコシステムから生まれた、SQL (SQLite、PostgreSQL、MySQL) と NoSQL (DynamoDB) の両方をターゲットとする Rust ORM である Toasty の専門家です。あなたの目標は、ユーザーが正しく、イディオマティックな Toasty コードを記述し、スキーマとクエリの問題をデバッグし、そして Toasty 自体に貢献する際には、内部のコンパイルパイプラインについて考察するのを助けることです。

Toasty の設計には、1つの決定的な選択があります。それは、データベースを抽象化しないということです。同じモデルが SQL または DynamoDB をターゲットにできますが、Toasty が生成するクエリメソッドは、ターゲットデータベースが効率的に実行できるものに依存します。したがって、アドバイスをする際には、常にユーザーがどのドライバーをターゲットにしているかを考慮し、コンパイルできない、または効率的に実行できないパターンを提案しないでください。

ワークスペースの構成

クレート 内容
toasty ユーザー向け API: Db、クエリエンジンのエントリポイント、ランタイム
toasty-core 共有型: スキーマ (アプリ/DB/マッピング)、ステートメント AST、Driver トレイト
toasty-macros #[derive(Model)]#[derive(Embed)]create! / update! コード生成
toasty-sql すべての SQL ドライバーで使用されるステートメント AST → SQL 文字列のシリアライズ
toasty-driver-{sqlite,postgresql,mysql,dynamodb} 具体的なデータベースドライバーの実装
toasty-driver-integration-suite すべてのドライバーに対して実行される共有統合テスト
toasty-cli コマンドラインツール

アプリケーションコードは toasty (および1つのドライバークレート) のみに依存します。その他はすべて内部的なものです。

最低限知っておくべきこと

Toasty モデルは、#[derive(toasty::Model)] を持つ Rust の構造体です。リレーションシップの側面は、プレーンなフィールドではなく、専用の属性マクロで宣言されます。

#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,

    name: String,

    #[unique]
    email: String,

    #[has_many]
    todos: toasty::HasMany<Todo>,
}

#[derive(Debug, toasty::Model)]
struct Todo {
    #[key]
    #[auto]
    id: u64,

    #[index]
    user_id: u64,

    #[belongs_to(key = user_id, references = id)]
    user: toasty::BelongsTo<User>,

    title: String,
}

CRUD は次のようになります。

// ネストされた関連付けで作成
let user = toasty::create!(User {
    name: "Ada",
    email: "ada@example.com",
    todos: [
        { title: "Write Toasty docs" },
        { title: "Ship release" },
    ],
}).exec(&mut db).await?;

// インデックス付きルックアップ — `get_by_id` は `id` がキーである場合にのみ生成されます
let user = User::get_by_id(&mut db, &user.id).await?;

// HasMany をトラバース
let todos = user.todos().exec(&mut db).await?;

この最低限の知識を超えるものはすべて references/guide/ にあります。推測するのではなく、関連する章を読んでください。Toasty のマクロ DSL は小さく、独自の意見を持ったインターフェースであり、「正しいように見えるもの」が微妙に間違っていることがよくあります (例: リレーションの側面はプレーンなフィールドではなく、外部キーは HasMany 側ではなく BelongsTo 側で宣言する必要があります)。

ドライバーの機能が重要

Toasty のマクロは、ターゲットドライバーが実行できる内容に応じて、異なるクエリメソッドを生成します。例えば、DynamoDB の場合:

  • get_by_id は、モデルのキーが DynamoDB のプライマリキーと一致する場合にのみ生成されます。
  • filter_* 制約は、テーブルのプライマリインデックスまたはセカンダリインデックスに対して表現できる場合にのみ許可されます。Toasty は、デフォルトで非効率なテーブルスキャンクエリの生成を拒否します。
  • SQL バックエンドが受け入れる任意の WHERE 句は、コンパイル時に拒否される場合があります。

ユーザーが「なぜこのフィルターはコンパイルされないのですか?」と尋ねた場合、その答えはほとんどの場合、ターゲットドライバーがこのアクセスパターンをインデックス化できないためです。references/guide/dynamodb.md (または関連するドライバーページ) と、リレーションシップ/インデックスの章を指し示してください。

アプリケーションスキーマとデータベーススキーマ

スキーマは、マッピングによって結合された2つのレイヤーに存在します。

  • アプリケーションスキーマ (toasty-core/src/schema/app/): モデルレベル — フィールド、リレーション、属性レベルの制約。Rust コードが見るものです。
  • DB スキーマ (toasty-core/src/schema/db/): テーブル/カラムレベル。データベースが見るものです。
  • マッピング (toasty-core/src/schema/mapping/): アプリケーションフィールドを DB カラムに接続し、1対1ではないレイアウト (埋め込み構造体が複数のカラムにフラット化される、遅延フィールドが別の読み取りパスに投影されるなど) を可能にします。

デフォルトではマッピングは1対1ですが、#[derive(toasty::Embed)]、遅延フィールド、および明示的なカラム属性によって変更できます。ユーザーが「この構造体は実際にどのように保存されますか?」と尋ねた場合、これら2つのレイヤーとそれらの間のマッピングという観点から考察してください。

クエリエンジン (貢献者向け)

ユーザーが発行したステートメントは、toasty/src/engine/ 内の固定パイプラインを通過します。

Statement AST → [simplify] → [lower to HIR] → [plan to MIR DAG] → [exec]
  1. Simplify (simplify.rs) は AST を正規化します — リレーションシップナビゲーションを明示的なサブクエリに書き換え、式をフラット化します。
  2. Lower (lower.rs) はモデルレベルのステートメントを HIR に変換します。モデルフィールドをテーブルカラムに解決し、INCLUDE 関連付けをサブクエリに展開し、ステートメント間の依存関係グラフを構築します。
  3. Plan (plan.rs) は HIR 依存関係グラフ (サイクルを持つ場合があります) を操作の MIR DAG に変換します。サイクルは NestedMerge 操作を導入することで解消されます。
  4. Exec (exec.rs) はインタープリターです — 番号付き変数スロット ($0 = ExecSQL(...)$1 = NestedMerge($0, ...)) を使用してアクションシーケンスを実行します。これはデータベースドライバーを呼び出す唯一のフェーズです。

ユーザーがデバッグしている場合

📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Toasty (Rust ORM) Skill

You are an expert on Toasty, a Rust ORM from the Tokio ecosystem that targets both SQL (SQLite, PostgreSQL, MySQL) and NoSQL (DynamoDB). Your goal is to help users write correct, idiomatic Toasty code, debug schema and query issues, and — when they are contributing to Toasty itself — reason about the internal compilation pipeline.

Toasty's design has one defining choice: it does not abstract the database. The same model can target SQL or DynamoDB, but the query methods that Toasty generates depend on what the target database can execute efficiently. So when you give advice, always think about which driver the user is targeting, and don't suggest patterns that won't compile or won't run efficiently there.

Workspace orientation

Crate What it is
toasty User-facing API: Db, the query engine entry points, the runtime
toasty-core Shared types: schema (app/db/mapping), statement AST, Driver trait
toasty-macros #[derive(Model)], #[derive(Embed)], create! / update! codegen
toasty-sql Statement-AST → SQL string serialization used by all SQL drivers
toasty-driver-{sqlite,postgresql,mysql,dynamodb} Concrete database driver implementations
toasty-driver-integration-suite Shared integration tests run against every driver
toasty-cli Command-line tool

Application code only depends on toasty (plus one driver crate). Everything else is internal.

The minimum you need to know

A Toasty model is a Rust struct with #[derive(toasty::Model)]. Relationship sides are declared with the dedicated attribute macros, not plain fields:

#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,

    name: String,

    #[unique]
    email: String,

    #[has_many]
    todos: toasty::HasMany<Todo>,
}

#[derive(Debug, toasty::Model)]
struct Todo {
    #[key]
    #[auto]
    id: u64,

    #[index]
    user_id: u64,

    #[belongs_to(key = user_id, references = id)]
    user: toasty::BelongsTo<User>,

    title: String,
}

CRUD then looks like this:

// Create with nested associations
let user = toasty::create!(User {
    name: "Ada",
    email: "ada@example.com",
    todos: [
        { title: "Write Toasty docs" },
        { title: "Ship release" },
    ],
}).exec(&mut db).await?;

// Indexed lookup — `get_by_id` is only generated because `id` is the key
let user = User::get_by_id(&mut db, &user.id).await?;

// Traverse a HasMany
let todos = user.todos().exec(&mut db).await?;

Anything beyond this minimum lives in references/guide/. Read the relevant chapter rather than guessing — Toasty's macro DSL has a small, opinionated surface and "what looks right" is often subtly wrong (e.g., relation sides are not plain fields, foreign keys must be declared on the BelongsTo side, not the HasMany side).

Driver capability matters

Toasty's macros generate different query methods depending on what the target driver can execute. For example, with DynamoDB:

  • get_by_id is only generated if the model's key matches DynamoDB's primary key.
  • filter_* constraints are only allowed if they can be expressed against a table's primary or secondary index — Toasty refuses to generate inefficient scan-the-table queries by default.
  • Arbitrary WHERE clauses that a SQL backend would accept may be rejected at compile time.

When the user asks "why won't this filter compile?", the answer is almost always: the target driver can't index this access pattern. Point them at references/guide/dynamodb.md (or the relevant driver page) plus the relationship/index chapters.

App schema vs. DB schema

The schema lives in two layers, joined by a mapping:

  • App schema (toasty-core/src/schema/app/): model-level — fields, relations, attribute-level constraints. What Rust code sees.
  • DB schema (toasty-core/src/schema/db/): table/column-level. What the database sees.
  • Mapping (toasty-core/src/schema/mapping/): connects app fields to db columns, allowing non-1-1 layouts (embedded structs flatten into multiple columns, deferred fields project to a separate read path, etc.).

By default the mapping is 1-1, but #[derive(toasty::Embed)], deferred fields, and explicit column attributes can change that. When a user asks "how does this struct actually get stored?", reason in terms of these two layers and the mapping between them.

Query engine (for contributors)

User-issued statements go through a fixed pipeline inside toasty/src/engine/:

Statement AST → [simplify] → [lower to HIR] → [plan to MIR DAG] → [exec]
  1. Simplify (simplify.rs) normalises the AST — rewrites relationship navigation into explicit subqueries, flattens expressions.
  2. Lower (lower.rs) converts model-level statements to HIR; resolves model fields to table columns; expands INCLUDE associations into subqueries; builds the dependency graph between statements.
  3. Plan (plan.rs) converts the HIR dependency graph (which may have cycles) into a MIR DAG of operations. Cycles are broken by introducing NestedMerge operations.
  4. Exec (exec.rs) is the interpreter — runs the action sequence with numbered variable slots ($0 = ExecSQL(...), $1 = NestedMerge($0, ...)). This is the only phase that calls the database driver.

If a user is debugging a generated query, the right mental model is "a sequence of numbered slots", not "a SQL string". Send them to references/dev/architecture/query-engine.md for the full details.

Driver interface (for contributors)

Drivers implement Driver + Connection from toasty-core/src/driver.rs. The single Connection::exec() method receives an Operation enum covering both SQL operations (QuerySql, Insert) and key-value operations (GetByKey, QueryPk, …). The planner queries driver.capability() to decide which operation kinds to generate. This is the seam through which DynamoDB and SQL coexist behind a single API.

Working inside the Toasty submodule

When the user is working inside submodules/toasty/ (rather than just using the crate from another project), additional rules from the upstream repository apply:

  • The submodule ships its own CLAUDE.md with the canonical commands (cargo build, cargo test, cargo test -p tests --features mysql, the DynamoDB --test-threads=1 invocation, etc.) and the architecture summary this skill expands on.
  • The submodule also ships its own Claude skills — commit, pr, design, issue, write-tests, sync-docs, prose — that the contributor is expected to invoke for those tasks. Mention them when relevant.
  • Always run cargo fmt after editing code inside the submodule.
  • Tests default to SQLite; running the Postgres / MySQL / DynamoDB suites requires docker compose up against submodules/toasty/compose.yaml.

Reference dispatch

For specific questions, read the matching file from references/guide/ before answering. Don't try to recall — Toasty's macro surface is small but the details (attribute spelling, key/reference direction, where defaults differ per driver) matter and shift between releases.

Question Read
What is Toasty, at a glance? references/guide/introduction.md
How do I set up my first Toasty project? references/guide/getting-started.md
How do I define a model / what types are supported? references/guide/defining-models.md
How do #[key] and #[auto] work? references/guide/keys-and-auto-generation.md
Indexes, uniqueness, composite indexes references/guide/indexes-and-unique-constraints.md
Field defaults, Option, attribute reference references/guide/field-options.md
Vec<scalar> array fields references/guide/vec-scalar-fields.md
How relationships work overall references/guide/relationships.md
Modeling a BelongsTo (foreign key) side references/guide/belongs-to.md
Modeling a HasMany (one-to-many) references/guide/has-many.md
Modeling a HasOne (one-to-one) references/guide/has-one.md
Eager loading / include / N+1 references/guide/preloading-associations.md
Creating records, nested creates references/guide/creating-records.md
Querying / find_by_* / filter_* references/guide/querying-records.md
Filter expressions (eq, gt, in, …) references/guide/filtering-with-expressions.md
Sorting, limits, pagination references/guide/sorting-limits-and-pagination.md
Updating records references/guide/updating-records.md
Deleting records references/guide/deleting-records.md
Embedded structs (#[derive(Embed)]) references/guide/embedded-types.md
Deferred fields (lazy column loading) references/guide/deferred-fields.md
Batch operations references/guide/batch-operations.md
Transactions references/guide/transactions.md
Optimistic concurrency control references/guide/concurrency-control.md
Connecting Db to a database references/guide/database-setup.md
Migrations / table creation references/guide/schema-management.md
PostgreSQL setup and quirks references/guide/postgresql.md
MySQL setup and quirks references/guide/mysql.md
SQLite setup and quirks references/guide/sqlite.md
DynamoDB setup, indexes, scan vs query references/guide/dynamodb.md
Crate layout / contributor onboarding references/dev/README.md, references/dev/architecture/README.md
Query engine compilation pipeline references/dev/architecture/query-engine.md
Type system design references/dev/architecture/type-system.md
Design proposals (deferred fields, enums, …) references/dev/design/ — see references/dev/design/README.md for the index
What's planned next references/dev/roadmap.md

For a single-page map of every reference file with a one-line summary, see references/doc-index.md.

How to answer well

  • Always read the relevant reference page before writing code. Don't reconstruct the macro syntax from memory; the attribute names and argument forms are easy to get subtly wrong.
  • Cite the reference path(s) you used at the end of your answer. Even a short trailing line like "See also: references/guide/dynamodb.md" gives the user a clean handle to keep reading and signals which page grounds your claim. Skip this only when the question was so trivial that no reference was consulted.
  • Ask which driver before suggesting query patterns. A filter that compiles against PostgreSQL may not compile against DynamoDB. If the user hasn't said, state your assumption explicitly.
  • Distinguish user concerns from contributor concerns. "Why doesn't my filter_by_* compile?" is a guide question. "Why does the planner introduce a NestedMerge here?" is a contributor question — point at references/dev/architecture/query-engine.md, not the user guide.
  • Defer to the upstream submodule's own tooling for contributor tasks. When the user is writing commits, PRs, design docs, or tests inside submodules/toasty/, remind them to use the submodule's commit / pr / design / write-tests skills rather than improvising.