SQLDelight で View を使うべし

👉 Drive your UI with SQLDelight’s views | Leandro Favarin 
👉 GitHub - cashapp/sqldelight: SQLDelight - Generates typesafe Kotlin APIs from SQL 

SQLDelight は、すべてのクエリーに対して自動的にモデルオブジェクトを作成します。

以下シンプルな名前付きクエリー。


bandsOrderedByName:
SELECT id, name
FROM band
ORDER BY name DESC;

bandsOrderedByAge:
SELECT id, name
FROM band
ORDER BY age;

これから以下が作成される。


data class BandsOrderedByName(id: String, name: String)

data class BandsOrderedByAge(id: String, name: String)

実際は、もっと複雑になります。

以下、join句を使ったクエリーの場合。


SELECT
  band.id,
  band.name,
  album.*
FROM band
JOIN album ON band.id = album.band_id;

SQL View を使うとエレガントになります。


👉 SQLite Query Language: CREATE VIEW 


CREATE VIEW bandWithAlbum AS
SELECT
  band.id,
  band.name,
  album.*
FROM band
JOIN album ON band.id = album.band_id;

bandsOrderedByName:
SELECT *
FROM bandWithAlbum
ORDER BY name DESC;

bandsOrderedByAge:
SELECT *
FROM bandWithAlbum
ORDER BY age;

SQLDelight は、BandWithAlbum タイプを生成します。

続いて、ページネーションの例。


count:
SELECT count(*)
FROM bandWithAlbum;

paged:
SELECT *
FROM bandWithAlbum
LIMIT ?
OFFSET ?;

SQLDelight が生成するモデルは、data クラスなので、DiffUtil コールバックはすぐに書けます。


object BandItemCallback : ItemCallback<BandWithAlbum>() {
  override fun areItemsTheSame(oldItem: BandWithAlbum, newItem: BandWithAlbum): Boolean {
    return oldItem.id == newItem.id
  }

  override fun areContentsTheSame(oldItem: BandWithAlbum, newItem: BandWithAlbum): Boolean {
    return oldItem == newItem
  }
}

また、enum クラスを使ったソートオプション。


enum class Sort { NAME, AGE }

fun bandsSorted(by: Sort): Flow<List<BandWithAlbum>> = when (by) {
  NAME -> db.bandsOrderedByName()
  AGE -> db.bandsOrderedByAge()
}.asFlow().mapToList()

逆に、これらのようなSQL処理をプログラムで実行すると効率は落ちます。
👉 The Resurgence of SQL (Droidcon NYC 2017) - Speaker Deck 

まとめ

欲しいタイプを View にすると、少ないコードで実現できます。

ユーザーの要求は、技術が発達するにつれてますます激しくなることは明らかです。良きユーザエクスペリエンスのための簡単な実装方法を常に把握しておくことが重要になります。