たかぎとねこの忘備録

プログラミングに関する忘備録を自分用に残しときます。マサカリ怖い。

KotlinのExposedで作成日に基づいて並び替えた値に対してページネーションを行いたい場合

ExposedのDAO APIを使って次のようなモデルを定義してみる。

object Posts : UUIDTable() {
    val text = varchar("text", 144)
    val createdAt = datetime("created_at")
}

class Post(id: EntityID<UUID>) : UUIDEntity(id) {
    companion object : UUIDEntityClass<Post>(Posts)

    var text by Posts.text
    var createdAt by Posts.createdAt
}

この時ページネーションを行いたいときに、次のような条件を考えてみる。

  • 取得数とオフセットを使って取得する範囲を特定する。
  • 日付を基に降順でデータを取得したい。

色々調べて思いついたのが、sortedByDescending()を使ってみること。

override suspend fun limitedPosts(n: Int, offset: Long): List<PostRecord> {
    return transaction {
        Post.all().limit(n, offset).sortedByDescending { post -> post.createdAt }.map { it.toPostRecord() }
    }
}

ExposedのDSL/DAOサンプル集 - Qiita

ただ、これだとlimit()で既に取得した値に対してソートを行った結果を取得することになってしまう。

これを回避するために、orderBy()limit()を組み合わせる。

override suspend fun limitedPosts(isActive: Boolean, n: Int, offset: Long): List<PostRecord> {
    return transaction {
        Post.all().orderBy(Posts.createdAt to SortOrder.DESC).limit(n, offset)
            .filter { post -> post.isActive == isActive }
            .map { it.toPostRecord() }
    }
}

これにより、ソートされた結果に基づいてlimit()を呼び出した内容を取得することができる。

参考

How does sorting work with limit in kotlin exposed model? - Stack Overflow