🦜

Kotlin製ORMのexposedでWhere句の中でカスタム関数を使う

2023/10/08に公開

TL;DR

以下のような SQL を exposed を使って実行する方法を解説する。

select employee_id
from EMPLOYEE
where created_at >= TRUNC(SYSDATE-3)

3 日前以降に登録された従業員を抽出するクエリです。

ここで特殊なのは、

  • TRUNC という関数をどうやって呼び出すのか?
  • SYSDATE をどうやって使うのか?

かと思いますので、これらのやり方を説明します。

メンバー募集中!

サーバーサイド Kotlin コミュニティを作りました!

Kotlin ユーザーはぜひご参加ください!!

https://serverside-kt.connpass.com/

What's exposed ?

Kotlin 製の ORM(Object-Relational Mapping)ライブラリです。

wiki が提供されていますが結構情報が貧弱で、サブクエリを使った JOIN の方法などが書かれていないため、ハマりポイントになっています。

https://github.com/JetBrains/Exposed/wiki

使うテーブルの定義

EmployeeTable.kt
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.javatime.datetime

object EmployeeTable : Table("EMPLOYEE") {
    val employeeId = varchar("EMPLOYEE_ID", 10) //社員ID
    val departmentId = varchar("DEPARTMENT_ID", 10) //部署ID
    val created_at = datetime("CREATED_AT") // 作成日
}

TRUNC 関数を独自定義する

以下のように書くことで、TruncDateTime()をインスタンス化してTRUNCを扱うことが可能です。

TruncDateTime.kt
class TruncDateTime(
    private val dateTimeExp: Expression<*>,
    private val dayCount: Int? = null,
    private val isMinus: Boolean = false,
) : Expression<LocalDateTime>() {
    override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder {
        append("TRUNC(")
        append(dateTimeExp)
        if (dayCount != null) {
            if (isMinus) {
                append(" - ")
            } else {
                append(" + ")
            }
            append(dayCount.toString())
        }
        append(")")
    }
}

ここでは日付の加減算も一緒にできるようにしています。

SYSDATE の定義

同じ要領でSYSDATEも定義することが可能です。

class Sysdate : Expression<LocalDateTime>() {
    override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder {
        append("SYSDATE")
    }
}

呼び出し

EmployeeDataAccessor.kt
class EmployeeDataAccessor {
    fun getRecentRegistedEmployee(dayCount: Int) {
        val result = EmployeeTable.slice(
            EmployeeTable.employeeId,
        ).select{
            TruncDateTime(employee.created_at, dayCount) greaterEq TruncDateTime(Sysdate())
        }.toList()
    }
}

おわりに

ここまでくれば大分自由に exposed でクエリを書けるようになったはず。

メンバー募集中!

サーバーサイド Kotlin コミュニティを作りました!

Kotlin ユーザーはぜひご参加ください!!

https://serverside-kt.connpass.com/

また関西在住のソフトウェア開発者を中心に、関西エンジニアコミュニティを一緒に盛り上げてくださる方を募集しています。

よろしければ Conpass からメンバー登録よろしくお願いいたします。

https://blessingsoftware.connpass.com/

Discussion