Kotlin Multiplatform(android/iOS)でSQLDelightを使う

# SQLDelightとは
SQLDelightは、KotlinとSQLiteの間に型安全なインターフェースを提供するライブラリです。
.sqファイルにSQL文を記述すると、それに対応するKotlinのクラスが自動生成され、データベース操作が安全かつ簡潔に行えるようになります。

この記事では、SQLDelightを使ってデータベースを構築・操作する方法をステップごとに紹介します。

# SQLDelight導入の流れ
1. スキーマファイルの作成
1. Gradleの設定
1. コードの自動生成
1. プラットフォーム別のドライバ設定
1. データベース操作の実装

# 実装例：Userテーブルの作成と操作
ここでは、`AppDatabase`という名前のDBを作成し、`User`テーブルを操作する例を紹介します。
## 1. スキーマファイルの作成
`composeApp/src/commonMain/sqldelight/your-project/database/User.sq`に以下のように記述します
```SQL:composeApp/src/commonMain/sqldelight/your-project/database/User.sq
CREATE TABLE User (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    age INTEGER NOT NULL
);

selectAll:
SELECT * FROM User;

insertUser:
INSERT INTO User(name, age) VALUES (?, ?);

updateUser:
UPDATE User SET name = ?, age = ? WHERE id = ?;

deleteUser:
DELETE FROM User WHERE id = ?;
```
> 📁 `sqldelight`ディレクトリは、`kotlin`ディレクトリと同階層に作成してください。

## 2. Gradleの設定
composeApp/build.gradle.ktsに以下を追加
```kotlin:composeAppp/build.gradle.kts
plugins {
    id("app.cash.sqldelight") version "2.1.0"
}

kotlin {
	sourceSets {
		androidMain.dependencies {
			implementation("app.cash.sqldelight:android-driver:2.1.0")
		}
		commonMain.dependencies {
			implementation("app.cash.sqldelight:runtime:2.1.0")
		}
		iosMain.dependencies {
			implementation("app.cash.sqldelight:native-driver:2.1.0")
		}
	}
}

sqldelight {
    databases {
        // これがDB名になります
        create("AppDatabase") {
            // この部分は実際の階層と揃っている必要があります
            packageName.set("your-project.database")
        }
    }
}
```

## 3. コードの自動生成
以下のコマンドを実行すると、AppDatabase用のクラスが自動生成されます
```bash
./gradlew generateAppDatabaseInterface
```
生成されるファイルの一例
```
composeApp/build/generated/sqldelight/code/AppDatabase/commonMain/your-project/database/User.kt
```
## 4. プラットフォーム別のドライバ設定
### Android (`androidMain`)
アプリケーションコンテキストの初期化
```kotlin
lateinit var appContext: Context

fun initContext(context: Context) {
    appContext = context
}
```
MainActivityでの呼び出し
```kotlin: kotlin/your-project/MainActivity.kt
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        initContext(this)
        ...
    }
}
```
ドライバの生成
```kotlin
import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.driver.android.AndroidSqliteDriver

actual fun createDatabaseDriver(): SqlDriver =
    AndroidSqliteDriver(AppDatabase.Schema, appContext, "app.db")
```
### iOS (`iosMain`)
ドライバーの生成
```kotlin
import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.driver.native.NativeSqliteDriver
import your-project.database.AppDatabase

actual fun createDatabaseDriver(): SqlDriver = NativeSqliteDriver(AppDatabase.Schema, "app.db")
```
> 🔧 **Xcode設定**：
iosApp > Build Phases > Link Binary With Libraries にて libsqlite3.tbd を追加

### 共通処理 (`commonMain`)
ドライバー取得処理作成
```kotlin
import app.cash.sqldelight.db.SqlDriver

expect fun createDatabaseDriver(): SqlDriver
```

## 5. データベース操作の実装
```kotlin
import your-project.database.AppDatabase

func dbTrial() {
    val driver = createDatabaseDriver()
    val database = AppDatabase(driver)
    val queries = database.userQueries

    // 登録処理実行
    queries.insertUser("山田 太郎", 30)

    // 全件取得
    val userAll = queries.selectAll().executeAsList()
    println(userAll)

    // 更新
    queries.updateUser("鈴木 太郎", 31, 1)

    // 削除
    queries.deleteUser(1)
}
```

# 注意
- スキーマファイルを変更したら再生成コマンドを実行してください
- 動作しない場合の対処法：
    - エミュレータからアプリをアンインストール後、再ビルド
    - DB構成の変更が原因で正しく動作しないことがあります

# 最後に
Gradleの設定やiOSのドライバ設定、コード生成の手順で私自身つまずいた点が多々ありました。
この記事が、SQLDelightを始める方々の助けになれば嬉しいです。ご覧いただきありがとうございました！