概要
この記事では、Kotlin で Exposed と Flyway を使用して、Prisma に似たデータベーススキーマ管理とマイグレーションの開発体験を作る方法を紹介します。
必要なもの
-
Exposed: Kotlin 用の JetBrains 製 ORM フレームワーク(
org.jetbrains.exposed:exposed-core
、org.jetbrains.exposed:exposed-migration
などの依存関係) -
Flyway: データベースバージョン管理用のマイグレーションツール(
org.flywaydb:flyway-core
などの依存関係) - データベースドライバ: 選択したデータベース用の JDBC ドライバ
1. テーブルの定義
Exposed を使うと、データベーススキーマを Kotlin オブジェクトとして定義でき、コンパイル時の安全性と IDE 支援が得られます。以下は顧客テーブルの定義例です:
// ...
import org.jetbrains.exposed.dao.id.UUIDTable
// ...
object CustomerTable : Table("customers") {
val id = integer("id").autoIncrement()
val name = text("name")
val email = text("email")
override val primaryKey = PrimaryKey(id)
}
詳しくはExposed のドキュメントをご覧ください。
2. 必要なマイグレーションの確認
マイグレーションを適用する前に、データベースをテーブル定義と同期するために必要な SQL ステートメントを確認すると便利です。これは特に開発中にスキーマ変更の影響を確認するのに役立ちます:
// ...
import MigrationUtils
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.StdOutSqlLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.transactions.transaction
import org.slf4j.LoggerFactory
// ...
fun checkForRequiredMigrations() {
Database.connect(
...
)
transaction {
addLogger(StdOutSqlLogger)
val statements = MigrationUtils.statementsRequiredForDatabaseMigration(
tables = arrayOf(CustomerTable, ...) // ここに全てのテーブルを追加
)
if (statements.isNotEmpty()) {
val combinedStatements = statements.joinToString("\n")
println("\n=== データベースマイグレーションが必要です! ===\n$combinedStatements\n=== マイグレーション終了 ===")
}
}
}
この関数は以下を行います:
- Exposed のテーブル定義と実際のデータベーススキーマを比較
- データベースを同期するために必要な SQL ステートメントを生成
- レビュー用に出力
例えば、CustomerTable
を追加した後にこのチェックを実行すると、次のような出力が表示されます:
=== データベースマイグレーションが必要です! ===
CREATE TABLE IF NOT EXISTS customers (id SERIAL PRIMARY KEY, "name" TEXT NOT NULL, email TEXT NOT NULL)
CREATE SEQUENCE IF NOT EXISTS customers_id_seq START WITH 1 MINVALUE 1 MAXVALUE 9223372036854775807
=== マイグレーション終了 ===
この出力が表示されたら、src/main/resources/db/migration
に有効な Flyway マイグレーションファイル名で新しいファイルを作成してください。
CREATE TABLE IF NOT EXISTS customers (id SERIAL PRIMARY KEY, "name" TEXT NOT NULL, email TEXT NOT NULL)
CREATE SEQUENCE IF NOT EXISTS customers_id_seq START WITH 1 MINVALUE 1 MAXVALUE 9223372036854775807
詳しくはFlyway のドキュメントをご覧ください。
3. Flyway によるマイグレーションの適用
Exposed はマイグレーション用の SQL を生成できますが、Flyway はそれらのマイグレーションをバージョン管理し適用する堅牢な方法を提供します:
// ...
import org.flywaydb.core.Flyway
// ...
fun applyMigrations() {
Flyway.configure().dataSource(
...
).load().migrate()
}
この関数は以下を行います:
- デフォルトの場所(
db/migration
)からマイグレーションスクリプトを見つける - 保留中のマイグレーションを順番に適用する
- Flyway のメタデータテーブルでマイグレーション履歴を追跡する
こちらもFlyway のドキュメントで詳細を確認してください。
おまけ:マイグレーションファイルの自動生成
マイグレーションファイルを自動生成することもできます:
MigrationUtils.generateMigrationScript(
tables = arrayOf(CustomerTable, OrderTable, ProductTable),
"./src/main/resources/db/migration",
"V1__add_customer_table"
)
これにより Flyway のマイグレーションディレクトリに SQL ファイルが作成されます。
まとめ
ExposedとFlywayを組み合わせることで、型安全なスキーマ定義とシンプルで確実なマイグレーション管理が可能になります。これにより、Prismaのような直感的な開発体験をKotlinでも実現でき、データベーススキーマの変更を簡潔で効率的に進めることができます。
ほなまた!