Tabnine
Tabnine は、IDE(例: VS Code, WebStorm, IntelliJなど)の拡張機能として提供されるAIソフトウェア開発プラットフォームです。
概要
以下の方法で開発者がコードをより速く記述するのを助けます
Prisma ORMをTabnineと一緒に使用する理由
TabnineのようなAIエディタは、開発者の生産性を大幅に向上させることができる強力なツールです。以下のワークフローで特にうまく機能します。
- データモデリングとデータベーススキーマ設計
- データベースクエリの構築と最適化
- CRUD機能とその他のボイラープレートコードの生成
- TypedSQLで使用できるプレーンなSQLクエリの生成
- 単体テストと統合テスト用のコード生成
- 大規模なリファクタリングの案内
- シーディングスクリプトの生成
Prismaスキーマの活用
Prismaには独自のスキーマがあるため、Tabnineはデータの基本的な形状を理解し、スタックの他の部分のコードを記述するのに役立ちます。
したがって、まずPrismaスキーマを定義し、その後Tabnineを使用してその周りにアプリケーション層(API呼び出し、DTO、ビジネスロジック、サードパーティ統合など)を構築することをお勧めします。
データモデリングとデータベーススキーマ設計
Tabnineがどのように役立つか
ゼロからデータベーススキーマを設計することは、多くのボイラープレートを伴い、時間がかかることがあります。
Tabnineは以下の方法でこのプロセスを加速できます。
- モデル、インデックス、制約、およびリレーションシップのボイラープレートを生成する。
- 命名規則やその他の慣習に従うことでスキーマの一貫性を保つ。
- 一般的なデータベースパターンに基づいてモデルおよびフィールドの定義を自動補完する。
- 命名規則に基づいてリレーションシップとフィールドの型を提案する。
例:Prismaスキーマの定義
プロンプト
User、Organization、Subscriptionモデルを持つSaaSアプリケーション用のPrismaスキーマを定義します。リレーションシップが適切に設定されていることを確認してください。
生成されたコード
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
email String @unique
name String
organization Organization @relation(fields: [organizationId], references: [id])
organizationId Int
}
model Organization {
id Int @id @default(autoincrement())
name String
slug String @unique
subscription Subscription?
users User[]
}
model Subscription {
id Int @id @default(autoincrement())
organization Organization @relation(fields: [organizationId], references: [id])
organizationId Int @unique
plan String
status Status
}
enum Status {
Active
Paused
Expired
}
データベースクエリの構築と最適化
Tabnineがどのように役立つか
Prisma ORMは、データベースクエリを直感的に記述するための便利な高レベルAPIを提供します。しかし、フィルター、ページネーション、高度なパターンを含むクエリは、依然として複雑になることがあります。
Tabnineは以下の方法で役立ちます。
- スキーマに基づいてPrismaクエリを自動補完する。
- フィルター用の
where
句とページネーションロジック用のskip
/take
オプションを提案する。 - 効率とパフォーマンスの最適化を支援する。
例:リレーションシップを持つデータの取得
プロンプト
アクティブな購読を持つ組織からすべてのアクティブなユーザーを取得するPrismaクエリを生成してください。クエリ結果にユーザーの組織データを含めてください。
生成されたコード
const activeUsers = await prisma.user.findMany({
where: {
organization: {
subscription: {
status: "ACTIVE"
}
}
},
include: {
organization: true
}
});
CRUD機能とその他のボイラープレートコードの生成
Tabnineがどのように役立つか
ほとんどのアプリケーションは、基本的なCRUD操作またはデータベーススキーマの構造から派生するその他のボイラープレートコードを必要とします。例えば、APIレイヤーは、特定のモデルのレコードを作成、読み取り、更新、または削除できる一連のHTTPエンドポイントを公開する場合があります。同様に、フロントエンドは、これらのAPIエンドポイントとやり取りし、UIをそれに応じて更新するためのデータフェッチと状態管理ロジックを必要とします。
このコードを手動で記述する代わりに、Tabnineは以下の方法でこのプロセスを高速化できます。
- バックエンド用のPrisma
create
、read
、update
、delete
操作、およびフロントエンド用のUIコンポーネントを生成する。 - 関数名と引数型を自動補完する。
- DTO、エラー処理、一貫性のあるAPI設計などのベストプラクティスに従いながらボイラープレートコードを記述する。
例:Next.jsでCRUD機能を生成する
プロンプト
上記のスキーマのUserモデルに基づいて、Next.jsアプリのCRUD機能を生成してください。
生成されたコード
APIエンドポイント
import { NextResponse } from 'next/server';
import prisma from '../../../lib/prisma';
export async function GET() {
const users = await prisma.user.findMany({
include: { organization: true },
});
return NextResponse.json(users);
}
export async function POST(request: Request) {
const body = await request.json();
const user = await prisma.user.create({
data: {
email: body.email,
name: body.name,
organization: {
connect: { id: body.organizationId },
},
},
include: { organization: true },
});
return NextResponse.json(user);
}
export async function PUT(request: Request) {
const body = await request.json();
const user = await prisma.user.update({
where: { id: body.id },
data: {
email: body.email,
name: body.name,
organizationId: body.organizationId,
},
include: { organization: true },
});
return NextResponse.json(user);
}
export async function DELETE(request: Request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
const user = await prisma.user.delete({
where: { id: Number(id) },
});
return NextResponse.json(user);
}
Reactコンポーネント
import React, { useState, useEffect } from 'react';
interface User {
id: number;
email: string;
name: string;
organizationId: number;
}
const User: React.FC = () => {
const [users, setUsers] = useState<User[]>([]);
const [newUser, setNewUser] = useState({ email: '', name: '', organizationId: 0 });
useEffect(() => {
fetchUsers();
}, []);
const fetchUsers = async () => {
const response = await fetch('/api/users');
const data = await response.json();
setUsers(data);
};
const createUser = async () => {
await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newUser),
});
fetchUsers();
setNewUser({ email: '', name: '', organizationId: 0 });
};
const deleteUser = async (id: number) => {
await fetch(`/api/users?id=${id}`, { method: 'DELETE' });
fetchUsers();
};
return (
<div>
<h2>Users</h2>
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} ({user.email}) - Org ID: {user.organizationId}
<button onClick={() => deleteUser(user.id)}>Delete</button>
</li>
))}
</ul>
<h3>Create New User</h3>
<input
type="text"
placeholder="Name"
value={newUser.name}
onChange={(e) => setNewUser({ ...newUser, name: e.target.value })}
/>
<input
type="email"
placeholder="Email"
value={newUser.email}
onChange={(e) => setNewUser({ ...newUser, email: e.target.value })}
/>
<input
type="number"
placeholder="Organization ID"
value={newUser.organizationId}
onChange={(e) => setNewUser({ ...newUser, organizationId: Number(e.target.value) })}
/>
<button onClick={createUser}>Create User</button>
</div>
);
};
export default User;
TypedSQLで使用するためのプレーンなSQLクエリの生成
Tabnineがどのように役立つか
Prismaはクエリのための高レベルAPIを提供しますが、時には開発者がクエリをより低レベルで制御するために生のSQLに降りる必要がある場合があります。そのような場合、Prisma ORMで生のSQLクエリの完全な型安全を提供するTypedSQLを使用できます。
一般的な使用例としては、上記のスキーマ例における異なる購読ステータスの割合を計算するなどの集計クエリがあります。
Tabnineは以下の方法で支援できます。
- Prismaスキーマに基づいてSQLクエリを生成する。
- 手作業での試行錯誤なしに複雑な集計を構造化する。
- アプリケーションコードにクエリを統合する。
例:アクティブ、一時停止、期限切れの購読の割合を計算する
プロンプト
アクティブ、一時停止、期限切れの購読の割合を返すSQLクエリを生成してください。
生成されたSQLクエリ
SELECT
status,
COUNT(*) * 100.0 / (SELECT COUNT(*) FROM "Subscription") AS percentage
FROM "Subscription"
GROUP BY status;
アプリケーションコード
import { PrismaClient } from '@prisma/client'
import { subscriptionsReport } from '@prisma/client/sql'
const prisma = new PrismaClient();
const usersWithPostCounts = await prisma.$queryRawTyped(subscriptionsReport())
console.log(usersWithPostCounts)
単体テストと統合テスト用のコード生成
Tabnineがどのように役立つか
テストを記述することは、Prismaベースのアプリケーションが正しく機能し、要件と期待どおりに動作することを保証します。しかし、テストの記述は時間がかかり、予測可能で反復的なパターンに従うことがよくあります。
Tabnineは以下の方法でテスト記述を大幅に高速化できます。
- 単体テストと統合テストの両方のテストボイラープレートを生成する。
- Prismaデータベースインタラクションのモックとフィクスチャを提案する。
- ベストプラクティスに従うようにテストケースを構造化するのを支援する。
- 実際のデータベースまたはインメモリデータベースでPrismaをテストするための統合テストの足場を提供する。
例:Prismaサービスの単体テストの記述
プロンプト
すべてのアクティブなユーザーを取得するPrismaサービス関数のJest単体テストを生成してください。
生成されたコード
import { prismaMock } from '../prisma/singleton';
import { getActiveUsers } from '../services/userService';
test('should return only active users', async () => {
prismaMock.user.findMany.mockResolvedValue([
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' }
]);
const users = await getActiveUsers();
expect(users).toHaveLength(2);
expect(users[0].email).toBe('alice@example.com');
});
大規模なリファクタリングの案内
Tabnineがどのように役立つか
Prisma ORMの型安全なクエリのおかげで、リファクタリングは他のORMよりも安全で予測可能です。スキーマの変更後、生成されたPrisma Clientコードが更新され、TypeScriptコンパイラは変更が必要なすべての箇所を強調表示します。
しかし、ビジネスロジックや複雑なクエリの調整が必要な場合など、リファクタリング中にさらに困難な状況が発生する可能性があります。
Tabnineはリファクタリング中に以下の方法で支援できます。
- コード内のパターンを特定し、一貫性を維持しながらリファクタリングを提案する。
- スキーマ変更後のデータベースクエリの更新を支援し、手作業を減らす。
- ロジックを簡素化および最適化するための関数リライトを提供する。
- コードベース全体で処理する必要がある破壊的変更を提案する。
例:スキーマ変更後のPrismaクエリのリファクタリング
プロンプト
UserモデルのdeletedAt
タイムスタンプフィールドを使用して、このPrismaクエリをソフトデリートに対応するようにリファクタリングしてください。
初期コード
const users = await prisma.user.findMany();
リファクタリングされたコード
const users = await prisma.user.findMany({
where: { deletedAt: null }
});
シーディングスクリプトの生成
Tabnineがどのように役立つか
リアルなテストデータでデータベースをシードするのは面倒な場合があります。リアルなシードデータは、開発中に役立ちます。なぜなら、開発者が実際の使用時にアプリケーションがどのように見えるかについて、より良い印象を与えるからです。Tabnineは、データベースシードを以下の方法で支援できます。
- スキーマに基づいて、特定の要件を持つ構造化されたシードデータを伴うスクリプトを生成する。
- アプリをテストするために使用できる、リアルに見えるプレースホルダーデータを作成する。
- エッジケースをカバーする特定のデータを生成する。
例:シードスクリプトの作成
プロンプト
User、Organization、Subscriptionモデルを埋めるためのPrismaシードスクリプトを生成してください。
生成されたコード
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
await prisma.organization.create({
data: {
name: "Prisma Corp",
slug: "prisma-corp",
subscription: {
create: {
plan: "PRO",
status: "ACTIVE"
}
},
users: {
create: [
{ name: "Alice Doe", email: "alice@prisma.io" },
{ name: "Bob Smith", email: "bob@prisma.io" }
]
}
}
});
console.log("Seed data created successfully");
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
Prismaとつながり続ける
以下の方法でPrismaの旅を続けてください。 私たちの活発なコミュニティに参加しましょう。情報を受け取り、関与し、他の開発者と協力しましょう
- Xでフォローする 発表、ライブイベント、役立つヒントのために。
- Discordに参加する 質問したり、コミュニティと話したり、会話を通して積極的なサポートを受けたりできます。
- YouTubeを購読する チュートリアル、デモ、ストリームのために。
- GitHubで参加する リポジトリにスターを付けたり、問題を報告したり、問題に貢献したりしてください。