Kotlin で行う データベースマイグレーション

Kotlin でDBマイグレーションを行う方法を説明します。 
2019年2月時点ではバージョンが上がっていますので、記事追加します。(まだしてない)
それまでは [Spring Boot とデータベースマイグレーション](https://improve-future.com/spring-boot-with-db-migration.html) または [GitHub の Wiki](https://github.com/KenjiOhtsuka/harmonica/wiki/Jarmonica-Usage) を参考にしていただければ幸いです。

## 概要

ここで紹介する方法では、次のようなマイグレーションコードを用いてDBマイグレーションを行うことができます。
PostgreSQL, MySQL, Oracle Database, SQLite で使えます。

### マイグレーションのサンプル

`build.gradle` は後で記述します。
ここではマイグレーションファイルがどんな感じになるか見てみましょう。

```kotlin
package com.example.test.db.migration

import com.improve_future.harmonica.core.AbstractMigration

/**
 * HolloWorld
 */
class M20180624011127699_HolloWorld : AbstractMigration() {
    override fun up() {
        createTable("table_name") {
            integer("column_1", nullable = false)
            varchar("column_2")
        }
    }

    override fun down() {
        dropTable("table_name")
    }
}
```

`build.gradle` を設定すると、 `gradlew jarmonicaCreate` でマイグレーションファイルを作ることができます。

また、マイグレーションの中では Exposed を使うこともできます。

#### Exposed を使ったマイグレーションサンプル

```kotlin
package com.improve_future.test.db.migration

import com.improve_future.harmonica.core.AbstractMigration
import org.jetbrains.exposed.sql.SchemaUtils.create
import org.jetbrains.exposed.sql.SchemaUtils.drop
import org.jetbrains.exposed.sql.Table


object Cities : Table() {
    val id = integer("id").autoIncrement().primaryKey() // Column<Int>
    val name = varchar("name", 50) // Column<String>
}

class M20180624011127699_HolloWorld : AbstractMigration() {
    override fun up() {
        create(Cities)
    }

    override fun down() {
        drop(Cities)
    }
}
```

### マイグレーションの実行

次のコマンドでマイグレーションを実行できます。

* `gradlew jarmonicaCreate` : マイグレーションファイルを作る
    * `-PmigrationName=HelloWorld` とすると、マイグレーションの名前を指定できる。
* `gradlew jarmonicaUp` : すべてのマイグレーションを実行
    * `-Pstep=N`: 実行するマイグレーションの数を指定
    * `-Psql`: SQL の表示もする。
    * `-Psql=review`: SQL の表示のみ行い、マイグレーションは実行しない。 実行前にSQLを確認できる。
* `gradlew jarmonicaDown` : マイグレーションをひとつ戻す
    * `-Pstep=N`: 戻すマイグレーションの数を指定
    * `-Psql`: SQL の表示もする。
* `gradlew jarmonicaVersion` : マイグレーションのバージョンを表示する (どこまでマイグレーションが進んだか確認できる)

## 準備

このマイグレーションを実行するための準備です。 `build.gradle` のサンプルを紹介します。

### build.gradle

```gradle:build.gradle
buildscript {
    ext.kotlin_version = '1.2.41'

    repositories {
        jcenter()
        mavenCentral()
        maven { url 'https://jitpack.io' } // 必要
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.github.KenjiOhtsuka:harmonica:1.0.1' // 必要
    }
}

group 'yourgroup'
version 'yourversion'

apply plugin: 'kotlin'
apply plugin: 'jarmonica' // マイグレーションタスクを有効にする

// マイグレーションクラスのあるディレクトリを指定
extensions.extraProperties["directoryPath"] =
        "src/main/kotlin/com/example/test/db"
// マイグレーションクラスのパッケージを指定
extensions.extraProperties["migrationPackage"] =
        "com.example.test.db"

sourceCompatibility = 1.8

repositories {
    mavenCentral()
    maven { url 'https://jitpack.io' } // 必要
    maven {
        url  "https://dl.bintray.com/kotlin/exposed" // Exposed を使う場合
    }
}
dependencies {
    compile 'org.jetbrains.exposed:exposed:0.10.2' // Exposed を使う場合
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    compile group: 'org.reflections', name: 'reflections', version: '0.9.11' // 必要

    compile files('/lib/postgresql-42.2.2.jar') // 使用するJDBCドライバ
    compile 'com.github.KenjiOhtsuka:harmonica:1.0.1' // 必要

    /* 必要: ここはきっと改善可能 */
    compile group: 'org.jetbrains.kotlin', name: 'kotlin-script-runtime', version: kotlin_version
    compile group: 'org.jetbrains.kotlin', name: 'kotlin-script-util', version: kotlin_version
    compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlin_version
}

compileKotlin {
    kotlinOptions { jvmTarget = "1.8" }
}
compileTestKotlin {
    kotlinOptions { jvmTarget = "1.8" }
}
```

このように `build.gradle` を記述すると、 先に示した3種類のコマンドが実行可能です。

### DB Config

DB への 接続情報を記述します。
接続設定は下記のようになります。

```kotlin
package com.example.test.db.config

import com.improve_future.harmonica.core.DbConfig
import com.improve_future.harmonica.core.Dbms

class Default: DbConfig({
    dbms = Dbms.PostgreSQL
    user = "developer"
    password = "developer"
    host = "127.0.0.1"
    dbName = "migration_test"
})
```

このファイルを、特定の場所に配置します。

```gradle
// マイグレーションクラスのあるディレクトリを指定
extensions.extraProperties["directoryPath"] =
        "src/main/kotlin/com/example/test/db"
```

`build.gradle` で設定したディレクトリの下に config ディレクトリ を作成し、 その中に、 `Default.kt` という名前で作成します。

## さいごに

マイグレーションの Gradle Plugin のコードは [GitHub Harmonica](https://github.com/KenjiOhtsuka/harmonica) にあります。 Kotlin でマイグレーションを書くなにかいい方法がないかと思って作ったものです。

プロジェクト名が Harmonica で コマンドが jarmonicaXxxxx なのには理由があるのですがそれは [別のページ](https://qiita.com/KenjiOtsuka/items/f1d2b1896ff5d3652b63) に書きました。