PlanetScale
BaaSプラットフォーム
PlanetScale
概要
PlanetScaleは、Git風のワークフローを採用したサーバーレスMySQLプラットフォームです。データベースのブランチング機能により、スキーマ変更を安全かつ効率的に管理できる革新的なアプローチを提供します。従来のMySQLの強力さとクラウドネイティブの利便性を組み合わせ、開発チームの生産性向上を支援します。
詳細
PlanetScaleは、Vitessクラスタ技術をベースとした次世代のMySQLプラットフォームです。最大の特徴は「データベースブランチング」機能で、コードのブランチと同じようにデータベースのスキーマ変更を管理できます。これにより、開発、テスト、本番環境でのスキーマ変更が安全で追跡可能になります。
Fetch APIベースのJavaScriptクライアントを提供し、従来のコネクションプール管理が不要でサーバーレス環境に最適化されています。また、自動スケーリング、暗号化、バックアップ機能も標準で提供され、運用負荷を大幅に削減します。
メリット・デメリット
メリット
- Git風ワークフロー: データベースのブランチ作成・マージが可能で、スキーマ変更管理が革新的
- サーバーレス対応: コネクション管理不要で、Edge環境やサーバーレス関数から直接接続可能
- ゼロダウンタイム: スキーマ変更やスケーリングが本番環境に影響しない
- 自動バックアップ: ポイントインタイム復旧とブランチ機能による安全なデータ管理
- 高いパフォーマンス: Vitessによる分散アーキテクチャで大規模データに対応
デメリット
- MySQL限定: PostgreSQLなど他のデータベースエンジンは選択できない
- 学習コスト: 従来のMySQLとは異なるワークフローに慣れる必要がある
- コスト: 小規模な用途には価格が高めになる場合がある
- 制限事項: 一部のMySQL機能(外部キー制約等)に制限がある
参考ページ
コード例
1. 基本的な接続とクエリ実行
import { connect } from '@planetscale/database'
const config = {
host: process.env.DATABASE_HOST,
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD
}
const conn = connect(config)
const results = await conn.execute('SELECT * FROM users WHERE active = ?', [true])
console.log(results)
2. 環境変数を使用した接続設定
import { connect } from '@planetscale/database'
const config = {
url: process.env.DATABASE_URL
}
const conn = connect(config)
const result = await conn.execute('SELECT COUNT(*) as total FROM products')
console.log(result.rows[0].total)
3. トランザクション処理
import { connect } from '@planetscale/database'
const conn = connect({
host: process.env.DATABASE_HOST,
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD
})
const results = await conn.transaction(async (tx) => {
const user = await tx.execute('INSERT INTO users (name, email) VALUES (?, ?)', ['太郎', '[email protected]'])
const profile = await tx.execute('INSERT INTO profiles (user_id, bio) VALUES (?, ?)', [user.insertId, 'エンジニア'])
return { user, profile }
})
console.log(results)
4. クライアントファクトリーパターン
import { Client } from '@planetscale/database'
const client = new Client({
host: process.env.DATABASE_HOST,
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD
})
const conn = client.connection()
const results = await conn.execute('SELECT * FROM orders WHERE status = ?', ['pending'])
console.log(results)
5. カスタム型キャスティング
import { connect, cast } from '@planetscale/database'
function customCast(field, value) {
if (field.type === 'INT64' || field.type === 'UINT64') {
return BigInt(value)
}
return cast(field, value)
}
const conn = connect({
cast: customCast,
host: process.env.DATABASE_HOST,
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD
})
const result = await conn.execute('SELECT id, balance FROM accounts WHERE id = ?', [1])
console.log(typeof result.rows[0].balance) // 'bigint'
6. Next.js App Router統合例
// app/api/users/route.ts
import { connect } from '@planetscale/database'
const conn = connect({
url: process.env.DATABASE_URL
})
export async function GET() {
try {
const results = await conn.execute('SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT 10')
return Response.json({ users: results.rows })
} catch (error) {
return Response.json({ error: 'Database query failed' }, { status: 500 })
}
}
export async function POST(request: Request) {
const { name, email } = await request.json()
try {
const result = await conn.execute('INSERT INTO users (name, email) VALUES (?, ?)', [name, email])
return Response.json({ id: result.insertId, name, email }, { status: 201 })
} catch (error) {
return Response.json({ error: 'Failed to create user' }, { status: 500 })
}
}