Add SqlDelight Database

Used to test invalidations.

Bug: NA
Test: NA
Change-Id: If6c5682efab3846a325c3e7ce8f1a0c639d2071d
diff --git a/app-inspection/test-app/app/build.gradle.kts b/app-inspection/test-app/app/build.gradle.kts
index 858d4e1..7d69dab 100644
--- a/app-inspection/test-app/app/build.gradle.kts
+++ b/app-inspection/test-app/app/build.gradle.kts
@@ -5,6 +5,15 @@
   alias(libs.plugins.kotlin.kapt)
   alias(libs.plugins.kotlinAndroid)
   alias(libs.plugins.ksp)
+  alias(libs.plugins.sqldelight)
+}
+
+sqldelight {
+  databases {
+    create("SqlDelightDatabase") {
+      packageName.set("com.google.test.inspectors")
+    }
+  }
 }
 
 android {
@@ -58,6 +67,7 @@
   implementation(libs.lifecycle.runtime.ktx)
   implementation(libs.material3)
   implementation(libs.okhttp)
+  implementation(libs.sqldelight)
   implementation(libs.okhttp3)
   implementation(libs.ui)
   implementation(libs.ui.graphics)
diff --git a/app-inspection/test-app/app/src/main/java/com/google/test/inspectors/database/DatabaseViewModel.kt b/app-inspection/test-app/app/src/main/java/com/google/test/inspectors/database/DatabaseViewModel.kt
index ba356c2..d93dfd4 100644
--- a/app-inspection/test-app/app/src/main/java/com/google/test/inspectors/database/DatabaseViewModel.kt
+++ b/app-inspection/test-app/app/src/main/java/com/google/test/inspectors/database/DatabaseViewModel.kt
@@ -18,7 +18,6 @@
 
 import android.app.Application
 import android.content.Context
-import android.database.Cursor
 import android.database.sqlite.SQLiteDatabase
 import android.database.sqlite.SQLiteDatabase.OPEN_READONLY
 import android.database.sqlite.SQLiteDatabase.OpenParams
@@ -28,7 +27,11 @@
 import androidx.room.InvalidationTracker
 import androidx.room.Room
 import androidx.sqlite.db.SupportSQLiteDatabase
+import app.cash.sqldelight.Query
+import app.cash.sqldelight.db.QueryResult
+import app.cash.sqldelight.driver.android.AndroidSqliteDriver
 import com.google.test.inspectors.Logger
+import com.google.test.inspectors.SqlDelightDatabase
 import com.google.test.inspectors.database.room.RoomDatabase
 import com.google.test.inspectors.ui.scafold.AppScaffoldViewModel
 import dagger.hilt.android.lifecycle.HiltViewModel
@@ -71,6 +74,9 @@
   private val roomDatabase =
     Room.databaseBuilder(application, RoomDatabase::class.java, "room-database.db").build()
 
+  private val sqldelightDriver =
+    AndroidSqliteDriver(SqlDelightDatabase.Schema, application, "sqldelight-database.db")
+
   private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
     setSnack("Error: ${throwable.message}")
     Logger.error("Error: ${throwable.message}", throwable)
@@ -87,6 +93,10 @@
     scope.launch(IO) {
       val roomTables = roomDatabase.openHelper.readableDatabase.use { it.getTables() }
       roomDatabase.invalidationTracker.addObserver(RoomObserver(roomTables))
+
+      sqldelightDriver.getTables().forEach {
+        sqldelightDriver.addListener(it, listener = SqlDelightListener(it))
+      }
     }
   }
 
@@ -155,24 +165,45 @@
     override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {}
   }
 
-  private inner class RoomObserver(tables: Set<String>) :
+  private inner class RoomObserver(tables: List<String>) :
     InvalidationTracker.Observer(tables.toTypedArray()) {
 
     override fun onInvalidated(tables: Set<String>) {
       setSnack("Room tables [${tables.joinToString { it }}]  updated")
-      roomDatabase.openHelper.readableDatabase
+    }
+  }
+
+  private inner class SqlDelightListener(val table: String) : Query.Listener {
+    override fun queryResultsChanged() {
+      setSnack("SqlDelight table `$table` updated")
     }
   }
 }
 
-private fun SupportSQLiteDatabase.getTables() = query(QUERY_TABLES).getValues()
-
-private fun Cursor.getValues(): Set<String> {
-  return use { cursor ->
-    buildSet {
+private fun SupportSQLiteDatabase.getTables() =
+  query(QUERY_TABLES).use { cursor ->
+    buildList {
       while (cursor.moveToNext()) {
-        add(cursor.getString(0))
+        this.add(cursor.getString(0))
       }
     }
   }
-}
+
+private fun AndroidSqliteDriver.getTables() =
+  executeQuery(
+      null,
+      QUERY_TABLES,
+      { cursor ->
+        val tables = buildList {
+          while (cursor.next().value) {
+            val table = cursor.getString(0)
+            if (table != null) {
+              add(table)
+            }
+          }
+        }
+        QueryResult.Value(tables)
+      },
+      0,
+    )
+    .value
diff --git a/app-inspection/test-app/app/src/main/sqldelight/com/google/test/inspectors/database/sqldelight/SqlDelightDatabase.sq b/app-inspection/test-app/app/src/main/sqldelight/com/google/test/inspectors/database/sqldelight/SqlDelightDatabase.sq
new file mode 100644
index 0000000..fa0ddf1
--- /dev/null
+++ b/app-inspection/test-app/app/src/main/sqldelight/com/google/test/inspectors/database/sqldelight/SqlDelightDatabase.sq
@@ -0,0 +1,12 @@
+
+/**
+ * A simple SqlDelight database that we use to test invalidation code
+ *
+ * We don't do much with this database except register a query listener.
+ */
+CREATE TABLE users (
+  id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+  name TEXT NOT NULL
+);
+
+INSERT INTO users (name) VALUES ('Foo');
diff --git a/app-inspection/test-app/build.gradle.kts b/app-inspection/test-app/build.gradle.kts
index db2d47c..5a55a46 100644
--- a/app-inspection/test-app/build.gradle.kts
+++ b/app-inspection/test-app/build.gradle.kts
@@ -8,5 +8,6 @@
   alias(libs.plugins.kotlinAndroid) apply false
   alias(libs.plugins.ksp) apply false
   alias(libs.plugins.protobuf) apply false
+  alias(libs.plugins.sqldelight) apply false
 }
 true // Needed to make the Suppress annotation work for the plugins block
diff --git a/app-inspection/test-app/gradle/libs.versions.toml b/app-inspection/test-app/gradle/libs.versions.toml
index a73179f..5874b15 100644
--- a/app-inspection/test-app/gradle/libs.versions.toml
+++ b/app-inspection/test-app/gradle/libs.versions.toml
@@ -26,6 +26,7 @@
 protobuf-gradle-plugin = "0.9.4"
 protobuf-kotlin = "3.25.0"
 protoc = "3.25.0"
+sqldelight = "2.0.2"
 ui-tooling = "1.6.6"
 
 [libraries]
@@ -69,6 +70,7 @@
 protobuf-gradle-plugin = { module = "com.google.protobuf:protobuf-gradle-plugin", version.ref = "protobuf-gradle-plugin" }
 protobuf-kotlin = { module = "com.google.protobuf:protobuf-kotlin", version.ref = "protobuf-kotlin" }
 protoc = { module = "com.google.protobuf:protoc", version.ref = "protoc" }
+sqldelight = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
 ui = { group = "androidx.compose.ui", name = "ui" }
 ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
 ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
@@ -81,3 +83,4 @@
 kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
 ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
 protobuf = { id = "com.google.protobuf", version.ref = "protobuf" }
+sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }