drizzle-orm-expert
Drizzle ORM エキスパートワークフロースキル。ユーザーが TypeScript 向け Drizzle ORM のエキスパートを必要とする場合(スキーマ設計、リレーショナルクエリ、マイグレーション、サーバーレスデータベース統合)に、このスキルを使用します。Drizzle を用いた型安全なデータベースレイヤーの構築時に、マージや引き継ぎ前に上流ワークフロー、コピーされたサポートファイル、プロヴェナンスを保持する必要がある場合に活用できます。
description の原文を見る
Drizzle ORM Expert workflow skill. Use this skill when the user needs Expert in Drizzle ORM for TypeScript — schema design, relational queries, migrations, and serverless database integration. Use when building type-safe database layers with Drizzle and the operator should preserve the upstream workflow, copied support files, and provenance before merging or handing off.
SKILL.md 本文
Drizzle ORM Expert
概要
この公開インテイクコピーは、https://github.com/sickn33/antigravity-awesome-skills から plugins/antigravity-awesome-skills-claude/skills/drizzle-orm-expert をパッケージ化し、その出典を隠さずにネイティブ Omni Skills の編集形式に変換したものです。
オペレータがアップストリームワークフロー、サポートファイル、およびリポジトリコンテキストをそのまま保持する必要があり、公開バリデータと非公開エンハンサーが通常のダウンストリームフローを続行できるようにするときに使用します。
このインテイクはコピーされたアップストリームファイルをそのままにしておき、metadata.json の external_source ブロックと ORIGIN.md をプロビナンスアンカーとして使用します。
Drizzle ORM Expert
あなたは本番レベルの Drizzle ORM エキスパートです。TypeScript で Drizzle ORM を使用してタイプセーフで高性能なデータベースレイヤーを構築するのに開発者を支援します。スキーマ設計、リレーショナルクエリAPI、Drizzle Kit マイグレーション、および Next.js、tRPC、サーバーレスデータベース(Neon、PlanetScale、Turso、Supabase)との統合に精通しています。
アップストリームの見出しに完全にマッピングされなかったインポートされたソースセクションは以下またはサポートファイルに保持されています。主要なインポートセクション:コア概念、スキーマ設計パターン、クエリパターン、パフォーマンス最適化、Next.js 統合、制限事項。
このスキルをいつ使用するか
このセクションをトリガーフィルタとして使用してください。オペレータがファイルを読み込む、コマンドを実行する、またはプルリクエストを開く前に、アクティベーション境界を明確にする必要があります。
- ユーザーが新規または既存のプロジェクトで Drizzle ORM をセットアップするよう求めている場合に使用します
- TypeScript ファーストアプローチで Drizzle のデータベーススキーマを設計するときに使用します
- 複雑なリレーショナルクエリ(結合、サブクエリ、集計)を記述するときに使用します
- Drizzle Kit マイグレーションのセットアップまたはトラブルシューティングを行うときに使用します
- Drizzle を Next.js App Router、tRPC、または Hono と統合するときに使用します
- データベースパフォーマンスを最適化するときに使用します(プリペアドステートメント、バッチ処理、接続プーリング)
操作テーブル
| 状況 | ここから始める | 重要な理由 |
|---|---|---|
| 初回使用 | metadata.json | コピーされたワークフローに触れる前に、external_source ブロックを通じてリポジトリ、ブランチ、コミット、インポートされたパスを確認します |
| プロビナンスレビュー | ORIGIN.md | レビュアーにインポートされたソースの平易言語の監査証跡を提供します |
| ワークフロー実行 | SKILL.md | 実行を実質的に変更するコピーされた最小ファイルから開始します |
| サポートコンテキスト | SKILL.md | パッケージ全体を読み込まずに、次に関連性の高いコピーされたソースファイルを追加します |
| ハンドオフの決定 | ## 関連スキル | タスクが逸脱するときにより強力なネイティブスキルに切り替えるのに役立ちます |
ワークフロー
このワークフローは意図的に編集的かつ運用的です。インポートされたソースをオペレータにとって有用に保ちながら、ダウンストリームエンハンサーフローに供給される公開インテイク標準を満たします。
-
設定
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./db/schema.ts",
out: "./drizzle",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
コマンド
# スキーマの変更からマイグレーション SQL を生成
npx drizzle-kit generate
# スキーマを直接データベースにプッシュ(開発のみ — マイグレーションファイルをスキップ)
npx drizzle-kit push
# 保留中のマイグレーションを実行(本番)
npx drizzle-kit migrate
# Drizzle Studio を開く(GUI データベースブラウザ)
npx drizzle-kit studio
PostgreSQL(Neon Serverless)
// db/index.ts
import { drizzle } from "drizzle-orm/neon-http";
import { neon } from "@neondatabase/serverless";
import * as schema from "./schema";
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });
SQLite(Turso/LibSQL)
import { drizzle } from "drizzle-orm/libsql";
import { createClient } from "@libsql/client";
import * as schema from "./schema";
const client = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN,
});
export const db = drizzle(client, { schema });
MySQL(PlanetScale)
import { drizzle } from "drizzle-orm/planetscale-serverless";
import { Client } from "@planetscale/database";
import * as schema from "./schema";
const client = new Client({ url: process.env.DATABASE_URL! });
export const db = drizzle(client, { schema });
- ユーザーの目標、インポートされたワークフローのスコープ、このスキルがまだタスクに適切なルータであるかどうかを確認します。
- コピーされたアップストリームサポートファイルを読み込む前に、概要とプロビナンスファイルをお読みください。
- 現在のリクエストの結果を実質的に変更する参照、例、プロンプト、またはスクリプトのみを読み込みます。
- アップストリームワークフローを実行しながら、ワーキングノートでプロビナンスとソースの境界を明確に保ちます。
- コピーされたファイルで指すことができる証拠に対して、アップストリームの期待と結果を検証します。
インポートされたワークフローのメモ
インポート:マイグレーションワークフロー(Drizzle Kit)
設定
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./db/schema.ts",
out: "./drizzle",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
コマンド
# スキーマの変更からマイグレーション SQL を生成
npx drizzle-kit generate
# スキーマを直接データベースにプッシュ(開発のみ — マイグレーションファイルをスキップ)
npx drizzle-kit push
# 保留中のマイグレーションを実行(本番)
npx drizzle-kit migrate
# Drizzle Studio を開く(GUI データベースブラウザ)
npx drizzle-kit studio
インポート:データベースクライアントのセットアップ
PostgreSQL(Neon Serverless)
// db/index.ts
import { drizzle } from "drizzle-orm/neon-http";
import { neon } from "@neondatabase/serverless";
import * as schema from "./schema";
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });
SQLite(Turso/LibSQL)
import { drizzle } from "drizzle-orm/libsql";
import { createClient } from "@libsql/client";
import * as schema from "./schema";
const client = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN,
});
export const db = drizzle(client, { schema });
MySQL(PlanetScale)
import { drizzle } from "drizzle-orm/planetscale-serverless";
import { Client } from "@planetscale/database";
import * as schema from "./schema";
const client = new Client({ url: process.env.DATABASE_URL! });
export const db = drizzle(client, { schema });
インポート:コア概念
Drizzle を選ぶ理由
Drizzle ORM は TypeScript ファースト ORM で、実行時のオーバーヘッドがゼロです。クエリエンジンバイナリを使用する Prisma とは異なり、Drizzle は生 SQL にコンパイルされるため、エッジランタイムとサーバーレスに最適です。主な利点は以下の通りです:
- SQL のような API:SQL を知っていれば、Drizzle を知っています
- ゼロ依存:小さなバンドル、Cloudflare Workers、Vercel Edge、Deno で動作します
- 完全な型推論:スキーマ → 型 → クエリはすべてコンパイル時に接続されています
- リレーショナルクエリAPI:N+1 の問題なしで Prisma のようなネストされたインクルードができます
例
例 1:アップストリームワークフローを直接要求する
@drizzle-orm-expert を使用して <task> を処理します。コピーされたアップストリームワークフローから開始し、結果を変更するファイルのみを読み込み、回答でプロビナンスを見えるようにします。
説明: これはオペレータがインポートされたワークフローが必要だが、リポジトリ全体は必要ではない場合に最も安全な開始点です。
例 2:プロビナンスに基づくレビューを要求する
@drizzle-orm-expert を metadata.json と ORIGIN.md に対してレビューして、最初に読み込むコピーされたアップストリームファイルとその理由を説明します。
説明: レビューまたはトラブルシューティングの前に、出典と ファイル選択の正確で監査可能な説明が必要な場合に使用します。
例 3:実行前にコピーされたサポートファイルを絞り込む
@drizzle-orm-expert を <task> に使用します。結果を変更するコピーされた参照、例、またはスクリプトのみを読み込み、進める前にファイルを明示的に名前を付けます。
説明: これはスキルをデフォルトで全体パッケージを読み込む代わりに、段階的開示と一致させて保ちます。
例 4:レビュアーパケットを構築する
@drizzle-orm-expert をコピーされたアップストリームファイルとプロビナンスを使用してレビューして、マージ前のギャップを要約します。
説明: これは PR が人間によるレビューを待っており、反復可能な監査パケットが必要な場合に有用です。
ベストプラクティス
生成された公開スキルをアップストリームリポジトリの周りにレビュー可能なパッケージ化レイヤーとして扱います。目標はプロビナンスを明確に保ち、実行を実質的に改善するコピーされたソース資料のみを読み込むことです。
- ✅ すべきこと:すべてのスキーマ定義を単一の db/schema.ts に保持するか、ドメイン別に分割します(db/schema/users.ts、db/schema/posts.ts)
- ✅ すべきこと:手動インターフェースの代わりに InferSelectModel と InferInsertModel をタイプセーフティのために使用します
- ✅ すべきこと:N+1 の問題を回避するために、ネストされたデータにリレーショナルクエリAPI(db.query.*)を使用します
- ✅ すべきこと:本番環境で頻繁に実行されるクエリにプリペアドステートメントを使用します
- ✅ すべきこと:本番環境で drizzle-kit generate + migrate を使用します(push は決して使用しません)
- ✅ すべきこと:リレーショナルクエリAPI を有効にするために drizzle() に { schema } を渡します
- ❌ すべきでないこと:本番環境で drizzle-kit push を使用します — データ喪失を引き起こす可能性があります
インポートされた操作メモ
インポート:ベストプラクティス
- ✅ すべきこと: すべてのスキーマ定義を単一の
db/schema.tsに保持するか、ドメイン別に分割します(db/schema/users.ts、db/schema/posts.ts) - ✅ すべきこと: 手動インターフェースの代わりに
InferSelectModelとInferInsertModelをタイプセーフティのために使用します - ✅ すべきこと: N+1 の問題を回避するために、ネストされたデータにリレーショナルクエリAPI(
db.query.*)を使用します - ✅ すべきこと: 本番環境で頻繁に実行されるクエリにプリペアドステートメントを使用します
- ✅ すべきこと: 本番環境で
drizzle-kit generate+migrateを使用します(決してpushを使用しません) - ✅ すべきこと: リレーショナルクエリAPI を有効にするために
drizzle()に{ schema }を渡します - ❌ すべきでないこと: 本番環境で
drizzle-kit pushを使用します — データ喪失を引き起こす可能性があります - ❌ すべきでないこと: Drizzle クエリビルダーが操作をサポートしている場合に生 SQL を記述します
- ❌ すべきでないこと:
db.query.*をwithで使用したい場合にrelations()を定義することを忘れてください - ❌ すべきでないこと: サーバーレスでリクエストごとに新しいデータベース接続を作成します — 接続プーリングを使用します
トラブルシューティング
問題:オペレータがインポートされたコンテキストをスキップして、あまりにも一般的に回答した
症状: 結果は plugins/antigravity-awesome-skills-claude/skills/drizzle-orm-expert のアップストリームワークフローを無視するか、プロビナンスに言及しないか、またはコピーされたソースファイルをまったく使用しません。
解決策: metadata.json、ORIGIN.md、および最も関連性の高いコピーされたアップストリームファイルを再度開きます。external_source ブロックを最初に確認してから、プロビナンスを再度述べて続行します。
問題:インポートされたワークフローがレビュー中に不完全に見える
症状: レビュアーは生成された SKILL.md を見ることができますが、どの参照、例、またはスクリプトが現在のタスクに重要であるかを素早く判断できません。
解決策: 選択したパスを正当化する正確なコピーされた参照、例、スクリプト、またはアセットを指します。ギャップがまだ実在する場合は、隠すのではなく PR に記録します。
問題:タスクが異なる専門分野にドリフトした
症状: インポートされたスキルは正しい場所で開始されますが、作業はデバッグ、アーキテクチャ、設計、セキュリティ、またはリリース オーケストレーションに変わり、ネイティブスキルが より良く処理します。 解決策: 関連スキルセクションを使用して意図的にハンドオフします。インポートされたプロビナンスを可視に保ち、次のスキルが盲目で開始する代わりに正しいコンテキストを継承できるようにします。
インポートされたトラブルシューティングメモ
インポート:トラブルシューティング
問題: db.query.tableName が未定義
解決策: すべてのスキーマオブジェクト(関係を含む)を drizzle() に渡します:drizzle(client, { schema })
問題: スキーマ変更後のマイグレーション競合
解決策: npx drizzle-kit generate を実行して新しいマイグレーションを作成してから、npx drizzle-kit migrate を実行します
問題: MySQL で .returning() に関する型エラー
解決策: MySQL は RETURNING をサポートしていません。代わりに .execute() を使用して、結果から insertId を読みます。
関連スキル
@00-andruia-consultant- このインポートされたスキルがコンテキストを確立した後、作業がそのネイティブ専門分野で より良く処理される場合に使用します。@00-andruia-consultant-v2- このインポートされたスキルがコンテキストを確立した後、作業がそのネイティブ専門分野で より良く処理される場合に使用します。@10-andruia-skill-smith- このインポートされたスキルがコンテキストを確立した後、作業がそのネイティブ専門分野で より良く処理される場合に使用します。@10-andruia-skill-smith-v2- このインポートされたスキルがコンテキストを確立した後、作業がそのネイティブ専門分野で より良く処理される場合に使用します。
追加リソース
このサポートマトリックスと以下のリンクされたファイルをこのインポートされたスキルのオペレータパケットとして使用します。それらは一般的なスカッフォルディングではなく、実際のコピーされたソース資料を反映する必要があります。
| リソースファミリ | レビュアーに提供するもの | 例パス |
|---|---|---|
references | アップストリームからコピーされた参照メモ、ガイド、または背景資料 | references/n/a |
examples | アップストリームからコピーされた作成例または再利用可能なプロンプト | examples/n/a |
scripts | 実行またはバリデーションを変更するアップストリームヘルパースクリプト | scripts/n/a |
agents | インポートされたパッケージの一部である、ルーティングまたはデリゲーションメモ | agents/n/a |
assets | ソースパッケージからコピーされたサポートアセットまたはスキーマ | assets/n/a |
インポートされた参照メモ
インポート:スキーマ設計パターン
テーブル定義
// db/schema.ts
import { pgTable, text, integer, timestamp, boolean, uuid, pgEnum } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
// 列挙型
export const roleEnum = pgEnum("role", ["admin", "user", "moderator"]);
// ユーザーテーブル
export const users = pgTable("users", {
id: uuid("id").defaultRandom().primaryKey(),
email: text("email").notNull().unique(),
name: text("name").notNull(),
role: roleEnum("role").default("user").notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
// 外部キー付きの投稿テーブル
export const posts = pgTable("posts", {
id: uuid("id").defaultRandom().primaryKey(),
title: text("title").notNull(),
content: text("content"),
published: boolean("published").default(false).notNull(),
authorId: uuid("author_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
});
関係
// db/relations.ts
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}));
型推論
// スキーマから直接型を推論 — 個別の型ファイルは不要です
import type { InferSelectModel, InferInsertModel } from "drizzle-orm";
export type User = InferSelectModel<typeof users>;
export type NewUser = InferInsertModel<typeof users>;
export type Post = InferSelectModel<typeof posts>;
export type NewPost = InferInsertModel<typeof posts>;
インポート:クエリパターン
SELECT クエリ(SQL のような API)
import { eq, and, like, desc, count, sql } from "drizzle-orm";
// 基本的なセレクト
const allUsers = await db.select().from(users);
// 条件でフィルター
const admins = await db.select().from(users).where(eq(users.role, "admin"));
// 部分的セレクト(特定のカラムのみ)
const emails = await db.select({ email: users.email }).from(users);
// 結合クエリ
const postsWithAuthors = await db
.select({
title: posts.title,
authorName: users.name,
})
.from(posts)
.innerJoin(users, eq(posts.authorId, users.id))
.where(eq(posts.published, true))
.orderBy(desc(posts.createdAt))
.limit(10);
// 集計
const postCounts = await db
.select({
authorId: posts.authorId,
postCount: count(posts.id),
})
.from(posts)
.groupBy(posts.authorId);
リレーショナルクエリ(Prisma のような API)
// ネストされたインクルード — Drizzle は単一のクエリで解決します
const usersWithPosts = await db.query.users.findMany({
with: {
posts: {
where: eq(posts.published, true),
orderBy: [desc(posts.createdAt)],
limit: 5,
},
},
});
// ネストされたデータで 1 つを検索
const user = await db.query.users.findFirst({
where: eq(users.id, userId),
with: { posts: true },
});
挿入、更新、削除
// リターニング付きで挿入
const [newUser] = await db
.insert(users)
.values({ email: "dev@example.com", name: "Dev" })
.returning();
// バッチ挿入
await db.insert(posts).values([
{ title: "Post 1", authorId: newUser.id },
{ title: "Post 2", authorId: newUser.id },
]);
// 更新
await db.update(users).set({ name: "Updated" }).where(eq(users.id, userId));
// 削除
await db.delete(posts).where(eq(posts.authorId, userId));
トランザクション
const result = await db.transaction(async (tx) => {
const [user] = await tx.insert(users).values({ email, name }).returning();
await tx.insert(posts).values({ title: "Welcome Post", authorId: user.id });
return user;
});
インポート:パフォーマンス最適化
プリペアドステートメント
// 一度準備して、何度も実行
const getUserById = db.query.users
.findFirst({
where: eq(users.id, sql.placeholder("id")),
})
.prepare("get_user_by_id");
// パラメータで実行
const user = await getUserById.execute({ id: "abc-123" });
バッチ操作
// db.batch() を使用して複数の独立したクエリを 1 つのラウンドトリップで実行
const [allUsers, recentPosts] = await db.batch([
db.select().from(users),
db.select().from(posts).orderBy(desc(posts.createdAt)).limit(10),
]);
スキーマでのインデックス
import { index, uniqueIndex } from "drizzle-orm/pg-core";
export const posts = pgTable(
"posts",
{
id: uuid("id").defaultRandom().primaryKey(),
title: text("title").notNull(),
authorId: uuid("author_id").references(() => users.id).notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
},
(table) => [
index("posts_author_idx").on(table.authorId),
index("posts_created_idx").on(table.createdAt),
]
);
インポート:Next.js 統合
サーバーコンポーネント使用法
// app/users/page.tsx (React サーバーコンポーネント)
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- diegosouzapw
- ライセンス
- MIT
- 最終更新
- 2026/5/10
Source: https://github.com/diegosouzapw/awesome-omni-skills / ライセンス: MIT