SpringBoot(Maven)でFlywayMigrationとJOOQをPluginで導入する

# 対象読者
* Springまわりの技術について深掘りしたい
* JOOQに入門したい
* 型安全なクエリビルダーを利用したい
* FlywayをSpringに導入したい

# 環境
* SpringBoot 3.2
* Apache Maven 3.9.5 
* JOOQ 3.18.7
* Flyway 9.22.3
* Postgres 16

[備考] JOOQ & Flyawayは継承元のpomに定義されていたVersionを使用し、
MavenはSpringについているラッパーを使用する

# FlaywayとJOOQについて
### Flyway
Flywayはデータベースの移行を管理するオープンソースツールです。このツールの魅力は、そのシンプルさと設定よりも規約を重視するアプローチにあります。Flywayを使用することで、データベースのスキーマのバージョン管理が可能になり、スキーマの変更や移行を容易かつ確実に行うことができます。これはSQLやJavaコードで定義された移行を自動的に管理し、適用することができるため、データベーススキーマの進化をスムーズにコントロールするのに理想的です。(by chatgpt)

### JOOQ
jOOQはJavaにおけるデータベースアクセスを革新するライブラリです。このツールの特徴は、タイプセーフかつオブジェクト指向的な方法でSQLクエリを構築できる点にあります。jOOQは完全なORMではなく、SQLに特化しているため、より複雑なSQLクエリが必要な場合に非常に有効です。Javaの型システムとの統合により、文法エラーのリスクを減らしつつ、パワフルなSQL操作を提供します。また、データベーススキーマに基づいてJavaのクラスを自動生成する機能もあり、これにより開発者は煩雑なコーディング作業から解放され、より効率的にデータベース操作を行うことができます。(by chatgpt)

# 依存関係
JOOQとFlyqwayのstarterを依存関係に追加する。
JOOQでDBアクセスオブジェクトを自動生成するためには、  
jooq-metaとjooq-codegeが必要だが、starterには含まれていないので追加。

Versionを揃えるためにも継承元のspring-boot-starter-parentに含まれる
spring-boot-dependenciesの値を使用することが望ましい。
FlywayはPluginから実行する場合は、依存関係はいらない


```xml:pom.xml
        <!-- PostgreSQL -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- JOOQ -->
        <!-- jooqはstarterに含まれているので、それ以外の依存関係を追加 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jooq</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq-meta</artifactId>
            <version>${jooq.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq-codegen</artifactId>
            <version>${jooq.version}</version>
        </dependency>
```

# Plugin
### Flyaway DB Migration
実行方法は下記の２通りの方法がある。
* Spring起動時に実行されるMigration
* Maven Pluginを使用したMigration

SpringによるMigrationは手軽であるが、JOOQでテーブル定義からコードを生成するのに不向きのためコマンドラインからMigarationを実行できるようにしたいのでPluginを追加する。

```xml:pom.xml
    <build>
        <plugins>
            <!--     Flyway DB Migration       -->
            <plugin>
                <groupId>org.flywaydb</groupId>
                <artifactId>flyway-maven-plugin</artifactId>
                <version>${flyway.version}</version>
                
                <configuration>
                    <!-- DB接続情報  -->
                    <url>jdbc:postgresql://localhost:5432/sample</url>
                    <user>admin</user>
                    <password>password</password>
                    
                    <!-- baselineの設定。-->
                    <!-- どのバージョンからMigraitonを始めるかを定義 -->
                    <baselineVersion>0</baselineVersion>
                    <!-- baseline-version以前のバージョンのマイグレーションの実行の有無を定義 -->
                    <baselineOnMigrate>true</baselineOnMigrate>

                    <!-- PostgreSQLの場合デフォルトではPublicしか実行されないので-->
                    <!-- 別のスキーマを対象にしたい場合は別途ここで定義する-->
                    <schemas>
                        <schema>public</schema>
                        <schema>catalog</schema> 
                    </schemas>
                    
                    <!-- Migrationファイルが置かれているディレクトリを指定する-->
                    <locations>
                        <location>classpath:/db/migration</location>
                    </locations>
                </configuration>
                
                <!-- Driverを定義 -->
                <dependencies>
                    <dependency>
                        <groupId>org.postgresql</groupId>
                        <artifactId>postgresql</artifactId>
                        <version>${postgresql.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
```            
### 実行方法
下記のコマンドで実行。ゴールは[公式ドキュメント](https://documentation.red-gate.com/fd/maven-goal-184127408.html)を参考にしてください
```bash
./mvnw flyway:${goals}
```

### 備考
#### Spring起動時に実行されるMigration
flyway-coreが依存関係に含まれている際に、
`src/main/resources/db/migration`に配置されているmigarionファイルを実行する。
dbへの接続情報は`application.yaml`に定義されている値を使用する。
```xml: pom.xml
        <!--    DB Migration    -->
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>
```

```application.yml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/sample
    username: admin
    password: password
  flyway:
    # どのバージョンからMigraitonを始めるかを定義
    baseline-version: 0
    # baseline-version以前のバージョンのマイグレーションの実行の有無を定義
    baseline-on-migrate: true
    # マイグレーションスクリプトのエンコーディング方法
    encoding: UTF-8
    # Flywayを有効または無効にするための設定
    enabled: true
```


### JOOQ Codegen Plugin
```xml: pom.xml
    <build>
        <plugins>
            <!--    JOOQ Code gen        -->
            <plugin>
                <groupId>org.jooq</groupId>
                <artifactId>jooq-codegen-maven</artifactId>
                <version>${jooq.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.jooq</groupId>
                        <artifactId>jooq-meta</artifactId>
                        <version>${jooq.version}</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <!-- Driverと接続情報を定義-->
                    <jdbc>
                        <driver>org.postgresql.Driver</driver>
                        <url>jdbc:postgresql://localhost:5432/sample</url>
                        <user>admin</user>
                        <password>password</password>
                    </jdbc>
                    
                    <generator>
                        <database>
                            <name>org.jooq.meta.postgres.PostgresDatabase</name>
                            <schemata>
                                <!-- 複数のスキーマがある場合に定義する -->
                                <schema>
                                    <inputSchema>catalog</inputSchema>
                                </schema>
                                <schema>
                                    <inputSchema>catalog</inputSchema>
                                </schema>
                            </schemata>
                        </database>
                        <!-- 自動生成するコードの定義 -->
                        <generate>
                            <indexes>false</indexes>
                            <keys>false</keys>
                            <daos>false</daos>
                            <pojos>false</pojos>
                            <pojosAsJavaRecordClasses>true</pojosAsJavaRecordClasses>
                            <javaTimeTypes>true</javaTimeTypes>
                        </generate>
                        <!-- 自動生成したコードを配置するための設定 -->
                        <target>
                            <packageName>com.example.stocknavigator</packageName>
                            <directory>src/generate/java</directory>
                            <encoding>UTF-8</encoding>
                            <clean>true</clean>
                        </target>
                    </generator>
                </configuration>
            </plugin>
        </plugins>
    </build>

```

### 実行方法
下記のコマンドを実行
```bash
./mvnw jooq-codegen:generate
```

## まとめ
* FlywayはPluginからでもSpringからでも実行できる
* JOOQの自動生成はPluginを用いる

## 参考資料
https://poppingcarp.com/introduction-jooq/

https://poppingcarp.com/testdata-setup-by-flyway/

https://tech.excite.co.jp/entry/2023/03/07/122028

https://qiita.com/crml1206/items/f8a68945aa3a2cd19270