【jOOQ】Recordからの値読み出しを省力化する【Kotlin】

定義したもの

import org.jooq.Field
import org.jooq.Record

inline fun <reified T> Record.read(field: Field<*>): T = this[field, T::class.java]

使い方

以下のように使います。

import org.jooq.Field
import org.jooq.Record

// FOOテーブルに定義された文字列型のFieldを想定
val field: Field<String?> = FOO.STRING_FIELD
// select結果などを保持するRecordを想定
val record: Record

// 以下のように、要求された型に応じた読み出しができる
val s1: String = record.read(field)
val s2: String? = record.read(field)
// エルビス演算子もよしなに判断してくれる
val s3: String = record.read(field) ?: ""
嬉しさ

jOOQがデフォルトで想定している読み出し方法の内最もシンプルなものは、Recordに定義された<T> T get(Field<T> field)を利用することです。
一方、KotlinGeneratorで生成されるコードではField(TableField)の型引数が常にnullableとなるため、non-nullな値として読み出す場合、一々!!で強制アンラップを行う必要が有ります。

// 単純にgetを用いた例
val s: String = record[field1]!!

また、Recordから何かしらの変換を伴う読み出しを行う場合は<U> U get(Field<?> field, Class<? extends U> type)を利用することになりますが、この関数はKClassを受け付けません。
このため、Kotlinから利用した際の見た目がよろしくありません。

// 変換を伴うgetを用いた例
import java.time.LocalDate

val d: LocalDate = record[field2, LocalDate::class.java]

今回定義した関数を使えば、両方ともシンプルかつ画一的な書き方ができます。
また、読み出し先がnullableになるような場合でも同様に書くことができます。

// 今回定義した関数を使った例
import java.time.LocalDate

val s: String = record.read(field1)
val d: LocalDate = record.read(field2)

// 要求される値がnullableな場合も同様に書ける
val s2: String? = record.read(field1)

クエリに対して期待される読み出し結果は基本的にマップ先の型に全て書かれているため、この関数を利用することで表現の重複を減らして機械的に書きやすくなります。

補足

関数の名前をreadにしているのは、getにするとjOOQデフォルトの内容と名前が被ってしまうためです。