From 2acd857c2ba38e65c617907e39b0a504cd18bfe5 Mon Sep 17 00:00:00 2001 From: Olivier Patry Date: Sat, 14 Jun 2025 20:38:32 +0200 Subject: [PATCH 1/3] Isolate Room converters in tasks-core to allow reuse --- build.gradle.kts | 2 +- .../net/opatry/tasks/data/TasksAppDatabase.kt | 23 ++-------- .../net/opatry/tasks/data/CoreConverters.kt | 42 +++++++++++++++++++ 3 files changed, 46 insertions(+), 21 deletions(-) create mode 100644 tasks-core/src/commonMain/kotlin/net/opatry/tasks/data/CoreConverters.kt diff --git a/build.gradle.kts b/build.gradle.kts index 43cdd852..c9c94ad3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -85,7 +85,7 @@ val koverExcludedClasses = listOf( "net.opatry.tasks.app.ui.tooling.*", "net.opatry.tasks.data.*Dao", "net.opatry.tasks.data.*Dao\$DefaultImpls", - "net.opatry.tasks.data.Converters", + "net.opatry.tasks.data.CoreConverters", "net.opatry.tasks.data.entity.*", "net.opatry.tasks.data.model.*", "net.opatry.tasks.data.TasksAppDatabase*", diff --git a/tasks-app-shared/src/commonMain/kotlin/net/opatry/tasks/data/TasksAppDatabase.kt b/tasks-app-shared/src/commonMain/kotlin/net/opatry/tasks/data/TasksAppDatabase.kt index 87f72f55..eba47eb1 100644 --- a/tasks-app-shared/src/commonMain/kotlin/net/opatry/tasks/data/TasksAppDatabase.kt +++ b/tasks-app-shared/src/commonMain/kotlin/net/opatry/tasks/data/TasksAppDatabase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Olivier Patry + * Copyright (c) 2025 Olivier Patry * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -27,28 +27,13 @@ import androidx.room.ConstructedBy import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.RoomDatabaseConstructor -import androidx.room.TypeConverter import androidx.room.TypeConverters -import kotlinx.datetime.Instant import net.opatry.tasks.data.entity.TaskEntity import net.opatry.tasks.data.entity.TaskListEntity import net.opatry.tasks.data.entity.UserEntity - -object Converters { - @TypeConverter - fun instantFromString(value: String?): Instant? = value?.let(Instant::parse) - - @TypeConverter - fun instantToString(instant: Instant?): String? = instant?.toString() - - @TypeConverter - fun sortingFromString(value: String?): TaskListEntity.Sorting? = value?.let(TaskListEntity.Sorting::valueOf) - - @TypeConverter - fun sortingToString(sorting: TaskListEntity.Sorting?): String? = sorting?.name -} - +@ConstructedBy(TasksAppDatabaseConstructor::class) +@TypeConverters(CoreConverters::class) @Database( entities = [ TaskListEntity::class, @@ -61,8 +46,6 @@ object Converters { AutoMigration(from = 2, to = 3), // add sorting column in task_list table ], ) -@ConstructedBy(TasksAppDatabaseConstructor::class) -@TypeConverters(Converters::class) abstract class TasksAppDatabase : RoomDatabase() { abstract fun getTaskListDao(): TaskListDao abstract fun getTaskDao(): TaskDao diff --git a/tasks-core/src/commonMain/kotlin/net/opatry/tasks/data/CoreConverters.kt b/tasks-core/src/commonMain/kotlin/net/opatry/tasks/data/CoreConverters.kt new file mode 100644 index 00000000..14ef605b --- /dev/null +++ b/tasks-core/src/commonMain/kotlin/net/opatry/tasks/data/CoreConverters.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 Olivier Patry + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.opatry.tasks.data + +import androidx.room.TypeConverter +import kotlinx.datetime.Instant +import net.opatry.tasks.data.entity.TaskListEntity + + +object CoreConverters { + @TypeConverter + fun instantFromString(value: String?): Instant? = value?.let(Instant::parse) + + @TypeConverter + fun instantToString(instant: Instant?): String? = instant?.toString() + + @TypeConverter + fun sortingFromString(value: String?): TaskListEntity.Sorting? = value?.let(TaskListEntity.Sorting::valueOf) + + @TypeConverter + fun sortingToString(sorting: TaskListEntity.Sorting?): String? = sorting?.name +} \ No newline at end of file From 152ab8da1d43fd3c56763312f29ada7fb69f2a29 Mon Sep 17 00:00:00 2001 From: Olivier Patry Date: Sat, 14 Jun 2025 20:23:30 +0200 Subject: [PATCH 2/3] Move :tasks-core tests where they belong --- tasks-core/build.gradle.kts | 13 +++++- .../net/opatry/tasks/data/TaskDaoTest.kt | 7 ++- .../net/opatry/tasks/data/TaskListDaoTest.kt | 6 +-- .../tasks/data/TasksCoreTestDatabase.kt | 43 +++++++++++++++++++ 4 files changed, 61 insertions(+), 8 deletions(-) rename {tasks-app-shared/src/commonTest => tasks-core/src/jvmTest}/kotlin/net/opatry/tasks/data/TaskDaoTest.kt (99%) rename {tasks-app-shared/src/commonTest => tasks-core/src/jvmTest}/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt (98%) create mode 100644 tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt diff --git a/tasks-core/build.gradle.kts b/tasks-core/build.gradle.kts index febf3a64..b0c876f6 100644 --- a/tasks-core/build.gradle.kts +++ b/tasks-core/build.gradle.kts @@ -24,6 +24,7 @@ plugins { alias(libs.plugins.jetbrains.kotlin.multiplatform) alias(libs.plugins.jetbrains.kotlin.serialization) + alias(libs.plugins.ksp) } kotlin { @@ -46,5 +47,15 @@ kotlin { commonTest.dependencies { implementation(kotlin("test")) } + + jvmTest.dependencies { + implementation(libs.kotlinx.coroutines.test) + implementation(libs.androidx.room.testing) + implementation(libs.androidx.sqlite.bundled) + } } -} \ No newline at end of file +} + +dependencies { + add("kspJvm", libs.androidx.room.compiler) +} diff --git a/tasks-app-shared/src/commonTest/kotlin/net/opatry/tasks/data/TaskDaoTest.kt b/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TaskDaoTest.kt similarity index 99% rename from tasks-app-shared/src/commonTest/kotlin/net/opatry/tasks/data/TaskDaoTest.kt rename to tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TaskDaoTest.kt index 3ae40ff6..cacee05a 100644 --- a/tasks-app-shared/src/commonTest/kotlin/net/opatry/tasks/data/TaskDaoTest.kt +++ b/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TaskDaoTest.kt @@ -22,13 +22,13 @@ package net.opatry.tasks.data +import androidx.room.Room import androidx.sqlite.driver.bundled.BundledSQLiteDriver import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import kotlinx.datetime.Clock import kotlinx.datetime.Instant import net.opatry.tasks.data.entity.TaskEntity -import net.opatry.tasks.data.util.inMemoryTasksAppDatabaseBuilder import org.junit.After import kotlin.test.BeforeTest import kotlin.test.Test @@ -42,16 +42,15 @@ class TaskDaoTest { private val now: Instant get() = Clock.System.now() - private lateinit var db: TasksAppDatabase + private lateinit var db: TasksCoreTestDatabase private lateinit var taskDao: TaskDao @BeforeTest fun createDb() { - db = inMemoryTasksAppDatabaseBuilder() + db = Room.inMemoryDatabaseBuilder() .setDriver(BundledSQLiteDriver()) .build() taskDao = db.getTaskDao() - taskDao = db.getTaskDao() } @After diff --git a/tasks-app-shared/src/commonTest/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt b/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt similarity index 98% rename from tasks-app-shared/src/commonTest/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt rename to tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt index c8e832a4..e778430c 100644 --- a/tasks-app-shared/src/commonTest/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt +++ b/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt @@ -22,6 +22,7 @@ package net.opatry.tasks.data +import androidx.room.Room import androidx.sqlite.driver.bundled.BundledSQLiteDriver import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest @@ -29,7 +30,6 @@ import kotlinx.datetime.Clock import kotlinx.datetime.Instant import net.opatry.tasks.data.entity.TaskEntity import net.opatry.tasks.data.entity.TaskListEntity -import net.opatry.tasks.data.util.inMemoryTasksAppDatabaseBuilder import org.junit.After import kotlin.test.BeforeTest import kotlin.test.Test @@ -42,13 +42,13 @@ class TaskListDaoTest { private val now: Instant get() = Clock.System.now() - private lateinit var db: TasksAppDatabase + private lateinit var db: TasksCoreTestDatabase private lateinit var taskListDao: TaskListDao private lateinit var taskDao: TaskDao @BeforeTest fun createDb() { - db = inMemoryTasksAppDatabaseBuilder() + db = Room.inMemoryDatabaseBuilder() .setDriver(BundledSQLiteDriver()) .build() taskListDao = db.getTaskListDao() diff --git a/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt b/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt new file mode 100644 index 00000000..e6e759b1 --- /dev/null +++ b/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Olivier Patry + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.opatry.tasks.data + +import androidx.room.Database +import androidx.room.RoomDatabase +import androidx.room.TypeConverters +import net.opatry.tasks.data.entity.TaskEntity +import net.opatry.tasks.data.entity.TaskListEntity + +@TypeConverters(CoreConverters::class) +@Database( + entities = [ + TaskEntity::class, + TaskListEntity::class, + ], + version = 1, + exportSchema = false, +) +abstract class TasksCoreTestDatabase : RoomDatabase() { + abstract fun getTaskListDao(): TaskListDao + abstract fun getTaskDao(): TaskDao +} From 874d8bc85420638521103a2c81481d6a1b4a9ae3 Mon Sep 17 00:00:00 2001 From: Olivier Patry Date: Sat, 14 Jun 2025 21:00:26 +0200 Subject: [PATCH 3/3] WIP Need to have test database in main source sets --- tasks-core/build.gradle.kts | 2 ++ .../kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt | 2 +- .../kotlin/net/opatry/tasks/data/TaskDaoTest.kt | 0 .../kotlin/net/opatry/tasks/data/TaskListDaoTest.kt | 0 4 files changed, 3 insertions(+), 1 deletion(-) rename tasks-core/src/{jvmTest => commonMain}/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt (99%) rename tasks-core/src/{jvmTest => commonTest}/kotlin/net/opatry/tasks/data/TaskDaoTest.kt (100%) rename tasks-core/src/{jvmTest => commonTest}/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt (100%) diff --git a/tasks-core/build.gradle.kts b/tasks-core/build.gradle.kts index b0c876f6..f744a34a 100644 --- a/tasks-core/build.gradle.kts +++ b/tasks-core/build.gradle.kts @@ -42,6 +42,7 @@ kotlin { implementation(projects.google.tasks) implementation(libs.androidx.room.common) + implementation(libs.androidx.room.runtime) } commonTest.dependencies { @@ -51,6 +52,7 @@ kotlin { jvmTest.dependencies { implementation(libs.kotlinx.coroutines.test) implementation(libs.androidx.room.testing) + implementation(libs.androidx.room.runtime) implementation(libs.androidx.sqlite.bundled) } } diff --git a/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt b/tasks-core/src/commonMain/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt similarity index 99% rename from tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt rename to tasks-core/src/commonMain/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt index e6e759b1..7e2036ec 100644 --- a/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt +++ b/tasks-core/src/commonMain/kotlin/net/opatry/tasks/data/TasksCoreTestDatabase.kt @@ -40,4 +40,4 @@ import net.opatry.tasks.data.entity.TaskListEntity abstract class TasksCoreTestDatabase : RoomDatabase() { abstract fun getTaskListDao(): TaskListDao abstract fun getTaskDao(): TaskDao -} +} \ No newline at end of file diff --git a/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TaskDaoTest.kt b/tasks-core/src/commonTest/kotlin/net/opatry/tasks/data/TaskDaoTest.kt similarity index 100% rename from tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TaskDaoTest.kt rename to tasks-core/src/commonTest/kotlin/net/opatry/tasks/data/TaskDaoTest.kt diff --git a/tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt b/tasks-core/src/commonTest/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt similarity index 100% rename from tasks-core/src/jvmTest/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt rename to tasks-core/src/commonTest/kotlin/net/opatry/tasks/data/TaskListDaoTest.kt