🐕

SQLDelight で upsert する

2022/11/25に公開

SQLDelight は データベース操作を楽にしてくれるライブラリです。
CashApp ( Square 社 ) が開発しており、KMM を利用したプロジェクトでも導入できるのが利点だと思います。

https://cashapp.github.io/sqldelight/

今年 ( 2022年 ) の DroidKaigi でも採用されていました。

https://github.com/DroidKaigi/conference-app-2022/blob/c93babf6788fc828f9d5a988cd5c9697fe144275/gradle/libs.versions.toml#L132-L135

Upsert がしたい

Room では Upsert の機能が提供されています。
同様の動作を SQLDelight で実現したいです。

https://developer.android.com/reference/kotlin/androidx/room/Upsert

先に結論

こんな感じで記載するとうまく動作します。

HogeTable.sq
upsert {
    UPDATE hogeTable
    SET param1 = :param1,
        param2 = :param2,
        param3 = :param3
    WHERE id = :id;
  
    INSERT OR IGNORE INTO hogeTable (
        id,
        param1,
        param2,
        param3
    ) VALUES (
        :id,
        :param1,
        :param2,
        :param3
    );
  }

Grouping Statements を利用する

公式のドキュメントでしっかりとユースケースとして記載されていました。
Grouping Statements という機能を利用すれば実現できそうです。

https://cashapp.github.io/sqldelight/android_sqlite/grouping_statements/

INSERT 文で 疑問符 ( qmark スタイル) を使用していた場合は注意が必要

もともとこんな感じの INSERT 文を利用していたので、これを流用しようとしました。

HogeTable.sq
insert:
INSERT OR IGNORE INTO hogeTable (
  id,
  param1,
  param2,
  param3
) VALUES ?;

流用して記載したものがこちら。
INSERT 文で qmark スタイルを利用しています。

HogeTable.sq
upsert {
    UPDATE hogeTable
    SET param1 = :param1,
        param2 = :param2,
        param3 = :param3
    WHERE id = :id;
  
    INSERT OR IGNORE INTO hogeTable (
        id,
        param1,
        param2,
        param3
    ) VALUES ?;
  }

すると、こんなエラーが…。

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':core:database:generateCommonMainDatabaseInterface'.
> A failure occurred while executing com.squareup.sqldelight.gradle.SqlDelightTask$GenerateInterfaces
   > Failed to compile SqlDelightStmtClojureStmtListImpl(STMT_CLOJURE_STMT_LIST): [] :
     UPDATE hogeTable
       SET param1 = :param1,
           param2 = :param2,
           param3 = :param3
       WHERE id = :id;
     
       INSERT OR IGNORE INTO hogeTable (
           id,
           param1,
           param2,
           param3
       ) VALUES ?;

ぬぬ、よくわからん…。
おかしいところはなさそうだったのですが、公式が named スタイルで記載してあるなと思い、書き直してみました。

HogeTable.sq
upsert {
    UPDATE hogeTable
    SET param1 = :param1,
        param2 = :param2,
        param3 = :param3
    WHERE id = :id;
  
    INSERT OR IGNORE INTO hogeTable (
        id,
        param1,
        param2,
        param3
    ) VALUES (
        :id,
        :param1,
        :param2,
        :param3
    );
  }

これでビルドが通り、無事 Kotlin ファイルが生成されていることを確認できました 🎉

Discussion