database-migration
Sequelize・TypeORM・Prisma などの主要 ORM を対象に、データベーススキーマおよびデータマイグレーションを管理します。ロールバック戦略やゼロダウンタイムデプロイへの対応も含み、本番環境での安全な移行をサポートします。
description の原文を見る
Master database schema and data migrations across ORMs (Sequelize, TypeORM, Prisma), including rollback strategies and zero-downtime deployments.
SKILL.md 本文
データベースマイグレーション
Sequelize、TypeORM、Prisma などの複数の ORM にわたるデータベーススキーマおよびデータマイグレーションをマスターし、ロールバック戦略およびゼロダウンタイムデプロイメントに対応します。
このスキルを使用しない場合
- タスクがデータベースマイグレーションと無関係である場合
- このスコープ外の異なるドメインまたはツールが必要な場合
指示
- 目標、制約条件、および必要な入力を明確にします。
- 関連するベストプラクティスを適用し、結果を検証します。
- 実行可能なステップと検証を提供します。
- 詳細な例が必要な場合は、
resources/implementation-playbook.mdを開いてください。
このスキルを使用する場合
- 異なる ORM 間でマイグレーションする場合
- スキーマ変換を実行する場合
- データベース間でデータを移動する場合
- ロールバック手順を実装する場合
- ゼロダウンタイムデプロイメント
- データベースバージョンアップグレード
- データモデルのリファクタリング
ORM マイグレーション
Sequelize マイグレーション
// migrations/20231201-create-users.js
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('users', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
email: {
type: Sequelize.STRING,
unique: true,
allowNull: false
},
createdAt: Sequelize.DATE,
updatedAt: Sequelize.DATE
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('users');
}
};
// 実行: npx sequelize-cli db:migrate
// ロールバック: npx sequelize-cli db:migrate:undo
TypeORM マイグレーション
// migrations/1701234567-CreateUsers.ts
import { MigrationInterface, QueryRunner, Table } from 'typeorm';
export class CreateUsers1701234567 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'users',
columns: [
{
name: 'id',
type: 'int',
isPrimary: true,
isGenerated: true,
generationStrategy: 'increment'
},
{
name: 'email',
type: 'varchar',
isUnique: true
},
{
name: 'created_at',
type: 'timestamp',
default: 'CURRENT_TIMESTAMP'
}
]
})
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('users');
}
}
// 実行: npm run typeorm migration:run
// ロールバック: npm run typeorm migration:revert
Prisma マイグレーション
// schema.prisma
model User {
id Int @id @default(autoincrement())
email String @unique
createdAt DateTime @default(now())
}
// マイグレーション生成: npx prisma migrate dev --name create_users
// 適用: npx prisma migrate deploy
スキーマ変換
デフォルト値を持つカラムの追加
// 安全なマイグレーション: デフォルト値を持つカラムを追加
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.addColumn('users', 'status', {
type: Sequelize.STRING,
defaultValue: 'active',
allowNull: false
});
},
down: async (queryInterface) => {
await queryInterface.removeColumn('users', 'status');
}
};
カラム名変更(ゼロダウンタイム)
// ステップ 1: 新しいカラムを追加
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.addColumn('users', 'full_name', {
type: Sequelize.STRING
});
// 古いカラムからデータをコピー
await queryInterface.sequelize.query(
'UPDATE users SET full_name = name'
);
},
down: async (queryInterface) => {
await queryInterface.removeColumn('users', 'full_name');
}
};
// ステップ 2: アプリケーションを更新して新しいカラムを使用
// ステップ 3: 古いカラムを削除
module.exports = {
up: async (queryInterface) => {
await queryInterface.removeColumn('users', 'name');
},
down: async (queryInterface, Sequelize) => {
await queryInterface.addColumn('users', 'name', {
type: Sequelize.STRING
});
}
};
カラム型の変更
module.exports = {
up: async (queryInterface, Sequelize) => {
// 大規模テーブルの場合、複数ステップアプローチを使用
// 1. 新しいカラムを追加
await queryInterface.addColumn('users', 'age_new', {
type: Sequelize.INTEGER
});
// 2. データをコピーして変換
await queryInterface.sequelize.query(`
UPDATE users
SET age_new = CAST(age AS INTEGER)
WHERE age IS NOT NULL
`);
// 3. 古いカラムを削除
await queryInterface.removeColumn('users', 'age');
// 4. 新しいカラムをリネーム
await queryInterface.renameColumn('users', 'age_new', 'age');
},
down: async (queryInterface, Sequelize) => {
await queryInterface.changeColumn('users', 'age', {
type: Sequelize.STRING
});
}
};
データ変換
複雑なデータマイグレーション
module.exports = {
up: async (queryInterface, Sequelize) => {
// すべてのレコードを取得
const [users] = await queryInterface.sequelize.query(
'SELECT id, address_string FROM users'
);
// 各レコードを変換
for (const user of users) {
const addressParts = user.address_string.split(',');
await queryInterface.sequelize.query(
`UPDATE users
SET street = :street,
city = :city,
state = :state
WHERE id = :id`,
{
replacements: {
id: user.id,
street: addressParts[0]?.trim(),
city: addressParts[1]?.trim(),
state: addressParts[2]?.trim()
}
}
);
}
// 古いカラムを削除
await queryInterface.removeColumn('users', 'address_string');
},
down: async (queryInterface, Sequelize) => {
// 元のカラムを再構築
await queryInterface.addColumn('users', 'address_string', {
type: Sequelize.STRING
});
await queryInterface.sequelize.query(`
UPDATE users
SET address_string = CONCAT(street, ', ', city, ', ', state)
`);
await queryInterface.removeColumn('users', 'street');
await queryInterface.removeColumn('users', 'city');
await queryInterface.removeColumn('users', 'state');
}
};
ロールバック戦略
トランザクションベースのマイグレーション
module.exports = {
up: async (queryInterface, Sequelize) => {
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.addColumn(
'users',
'verified',
{ type: Sequelize.BOOLEAN, defaultValue: false },
{ transaction }
);
await queryInterface.sequelize.query(
'UPDATE users SET verified = true WHERE email_verified_at IS NOT NULL',
{ transaction }
);
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
},
down: async (queryInterface) => {
await queryInterface.removeColumn('users', 'verified');
}
};
チェックポイントベースのロールバック
module.exports = {
up: async (queryInterface, Sequelize) => {
// バックアップテーブルを作成
await queryInterface.sequelize.query(
'CREATE TABLE users_backup AS SELECT * FROM users'
);
try {
// マイグレーションを実行
await queryInterface.addColumn('users', 'new_field', {
type: Sequelize.STRING
});
// マイグレーションを検証
const [result] = await queryInterface.sequelize.query(
"SELECT COUNT(*) as count FROM users WHERE new_field IS NULL"
);
if (result[0].count > 0) {
throw new Error('Migration verification failed');
}
// バックアップを削除
await queryInterface.dropTable('users_backup');
} catch (error) {
// バックアップから復元
await queryInterface.sequelize.query('DROP TABLE users');
await queryInterface.sequelize.query(
'CREATE TABLE users AS SELECT * FROM users_backup'
);
await queryInterface.dropTable('users_backup');
throw error;
}
}
};
ゼロダウンタイムマイグレーション
ブルーグリーンデプロイメント戦略
// フェーズ 1: 変更を後方互換性のあるものにする
module.exports = {
up: async (queryInterface, Sequelize) => {
// 新しいカラムを追加(古いコードと新しいコードの両方が機能)
await queryInterface.addColumn('users', 'email_new', {
type: Sequelize.STRING
});
}
};
// フェーズ 2: 両方のカラムに書き込むコードをデプロイ
// フェーズ 3: データをバックフィル
module.exports = {
up: async (queryInterface) => {
await queryInterface.sequelize.query(`
UPDATE users
SET email_new = email
WHERE email_new IS NULL
`);
}
};
// フェーズ 4: 新しいカラムから読み取るコードをデプロイ
// フェーズ 5: 古いカラムを削除
module.exports = {
up: async (queryInterface) => {
await queryInterface.removeColumn('users', 'email');
}
};
クロスデータベースマイグレーション
PostgreSQL から MySQL へ
// 相違点を処理
module.exports = {
up: async (queryInterface, Sequelize) => {
const dialectName = queryInterface.sequelize.getDialect();
if (dialectName === 'mysql') {
await queryInterface.createTable('users', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
data: {
type: Sequelize.JSON // MySQL JSON タイプ
}
});
} else if (dialectName === 'postgres') {
await queryInterface.createTable('users', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
data: {
type: Sequelize.JSONB // PostgreSQL JSONB タイプ
}
});
}
}
};
リソース
- references/orm-switching.md: ORM マイグレーションガイド
- references/schema-migration.md: スキーマ変換パターン
- references/data-transformation.md: データマイグレーションスクリプト
- references/rollback-strategies.md: ロールバック手順
- assets/schema-migration-template.sql: SQL マイグレーションテンプレート
- assets/data-migration-script.py: データマイグレーションユーティリティ
- scripts/test-migration.sh: マイグレーションテストスクリプト
ベストプラクティス
- 常にロールバックを提供: すべての up() に down() が必要
- マイグレーションをテスト: ステージング環境で最初にテスト
- トランザクションを使用: 可能な場合はアトミックなマイグレーション
- まずバックアップ: マイグレーション前に必ずバックアップ
- 小さな変更: 小さく増分的なステップに分割
- 監視: デプロイ中にエラーを監視
- 文書化: 理由と方法を説明
- べき等性: マイグレーションは再実行可能であるべき
よくある落とし穴
- ロールバック手順のテストを忘れる
- ダウンタイム戦略なしで破壊的な変更を行う
- NULL 値の処理を忘れる
- インデックスパフォーマンスを考慮しない
- 外部キー制約を無視する
- 一度に大量のデータをマイグレーションする
制限事項
- 上記で説明したスコープに明確に合致するタスクの場合のみ、このスキルを使用してください。
- 出力を環境固有の検証、テスト、または専門家レビューの代わりとしないでください。
- 必要な入力、権限、安全性の境界、または成功基準が不足している場合は停止して明確にしてください。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- sickn33
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/sickn33/antigravity-awesome-skills / ライセンス: MIT
関連スキル
hugging-face-trackio
Trackioを使用してMLトレーニング実験を追跡・可視化できます。トレーニング中のメトリクスログ記録(Python API)、トレーニング診断のアラート発火、ログされたメトリクスの取得・分析(CLI)が必要な場合に活用してください。リアルタイムダッシュボード表示、Webhookを使用したアラート、HF Space同期、自動化向けのJSON出力に対応しています。
btc-bottom-model
ビットコインのサイクルタイミングモデルで、加重スコアリングシステムを搭載しています。日次パルス(4指標、32ポイント)とウィークリー構造(9指標、68ポイント)の2カテゴリーにわたる13の指標を追跡し、0~100のマーケットヒートスコアを算出します。ETFフロー、ファンディングレート、ロング/ショート比率、恐怖・貪欲指数、LTH-MVRV、NUPL、SOPR(LTH+STH)、LTH供給率、移動平均倍率(365日MA、200週MA)、週次RSI、出来高トレンドに対応します。市場サイクル全体を通じて買いと売りの両方の推奨を提供します。ビットコインの底値拾い、BTCサイクルポジション、買い時・売り時、オンチェーン指標、MVRV、NUPL、SOPR、LTH動向、ETFの流出入、ファンディングレート、恐怖指数、ビットコインが過熱状態か、マイナーコスト、暗号資産市場のセンチメント、BTCのポジションサイジング、「今ビットコインを買うべきか」「BTCが天井をつけているか」「オンチェーン指標は何を示しているか」といった質問の際にこのスキルを活用します。
protein_solubility_optimization
タンパク質の溶解性最適化 - タンパク質の溶解性を最適化します。タンパク質の特性を計算し、溶解性と親水性を予測し、有効な変異を提案します。タンパク質配列の特性計算、タンパク質機能の予測、親水性計算、ゼロショット配列予測を含むタンパク質エンジニアリング業務に使用できます。3つのSCPサーバーから4つのツールを統合しています。
research-lookup
Parallel Chat APIまたはPerplexity sonar-pro-searchを使用して、最新の研究情報を検索できます。学術論文の検索にも対応しています。クエリは自動的に最適なバックエンドにルーティングされるため、論文の検索、研究データの収集、科学情報の検証に活用できます。
tree-formatting
ggtree(R)またはiTOL(ウェブ)を使用して、系統樹の可視化とフォーマットを行います。系統樹を図として描画する際、ツリーレイアウトの選択、分類学に基づく枝やラベルの色付け、クレードの折りたたみ、サポート値の表示、またはツリーへのオーバーレイ追加が必要な場合に使用してください。系統推定(protein-phylogenyスキルを使用)やドメイン注釈(今後の独立したスキル)には使用しないでください。
querying-indonesian-gov-data
インドネシア政府の50以上のAPIとデータソースに接続できます。BPJPH(ハラール認証)、BOM(食品安全)、OJK(金融適正性)、BPS(統計)、BMKG(気象・地震)、インドネシア中央銀行(為替レート)、IDX(株式)、CKAN公開データポータル、pasal.id(第三者法MCP)に対応しています。インドネシア政府データを活用したアプリ開発、.go.idウェブサイトのスクレイピング、ハラール認証の確認、企業の法的適正性の検証、金融機関ステータスの照会、またはインドネシアMCPサーバーへの接続時に使用できます。CSRF処理、CKAN API使用方法、IP制限回避など、すぐに実行可能なPythonパターンを含んでいます。