Skip to content

Commit 786a8ea

Browse files
committed
Migrate to Room for ease of setting up kotlin version
1 parent c1caafe commit 786a8ea

File tree

20 files changed

+296
-183
lines changed

20 files changed

+296
-183
lines changed

app/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ android {
104104
}
105105

106106
composeOptions {
107-
kotlinCompilerExtensionVersion = "1.4.4"
107+
kotlinCompilerExtensionVersion = "1.5.10"
108108
}
109109

110110
kotlinOptions {

app/src/main/java/dev/aungkyawpaing/ccdroidx/feature/MainViewModel.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@ package dev.aungkyawpaing.ccdroidx.feature
33
import androidx.lifecycle.ViewModel
44
import dagger.hilt.android.lifecycle.HiltViewModel
55
import dev.aungkyawpaing.ccdroidx.data.ProjectRepo
6-
import kotlinx.coroutines.flow.firstOrNull
76
import javax.inject.Inject
87

98
@HiltViewModel
109
class MainViewModel @Inject constructor(
1110
private val projectRepo: ProjectRepo
1211
) : ViewModel() {
1312

14-
suspend fun getProjectUrlById(projectId: Long): String? {
15-
return projectRepo.getById(projectId).firstOrNull()?.webUrl
13+
suspend fun getProjectUrlById(projectId: Long): String {
14+
return projectRepo.getById(projectId).webUrl
1615
}
1716

1817
}

data/build.gradle.kts

+6-16
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ plugins {
33
alias(libs.plugins.kotlin.android)
44
alias(libs.plugins.kotlin.ksp)
55
alias(libs.plugins.dagger.hilt)
6-
alias(libs.plugins.sqldelight)
76
alias(libs.plugins.android.junit5)
87
}
98

10-
val compileSdkVer : Int by rootProject.extra
11-
val minimumSdkVer : Int by rootProject.extra
9+
val compileSdkVer: Int by rootProject.extra
10+
val minimumSdkVer: Int by rootProject.extra
1211

1312
android {
1413
namespace = "dev.aungkyawpaing.ccdroidx.data"
@@ -52,15 +51,6 @@ android {
5251
}
5352
}
5453

55-
sqldelight {
56-
database("CCDroidXDb") {
57-
packageName = "dev.aungkyawpaing.ccdroidx"
58-
dialect = "sqlite:3.24"
59-
sourceFolders = listOf("sqldelight")
60-
schemaOutputDirectory = file("build/dbs")
61-
}
62-
}
63-
6454
dependencies {
6555
coreLibraryDesugaring(libs.desugar.jdk.libs)
6656
implementation(project(":common"))
@@ -82,10 +72,10 @@ dependencies {
8272
}
8373
testImplementation(libs.okhttp.mockWebServer)
8474

85-
implementation(libs.androidx.sqlite)
86-
implementation(libs.sqldelight.android)
87-
implementation(libs.sqldelight.coroutine)
88-
testImplementation(libs.sqldelight.jvm)
75+
implementation(libs.room.runtime)
76+
ksp(libs.room.compiler)
77+
implementation(libs.room.ktx)
78+
testImplementation(libs.room.testing)
8979

9080
implementation(libs.moshi.core)
9181
implementation(libs.moshi.adapters)

data/src/main/java/dev/aungkyawpaing/ccdroidx/data/ProjectRepo.kt

+10-18
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package dev.aungkyawpaing.ccdroidx.data
22

3-
import com.squareup.sqldelight.runtime.coroutines.asFlow
4-
import com.squareup.sqldelight.runtime.coroutines.mapToList
5-
import com.squareup.sqldelight.runtime.coroutines.mapToOne
6-
import dev.aungkyawpaing.ccdroidx.CCDroidXDb
73
import dev.aungkyawpaing.ccdroidx.common.Authentication
84
import dev.aungkyawpaing.ccdroidx.common.Project
95
import dev.aungkyawpaing.ccdroidx.common.coroutine.DispatcherProvider
106
import dev.aungkyawpaing.ccdroidx.data.api.FetchProject
7+
import dev.aungkyawpaing.ccdroidx.data.db.ProjectTableDao
118
import dev.aungkyawpaing.ccdroidx.data.db.ProjectTableToProjectMapper
129
import kotlinx.coroutines.flow.Flow
1310
import kotlinx.coroutines.flow.map
@@ -16,7 +13,7 @@ import javax.inject.Inject
1613

1714
class ProjectRepo @Inject constructor(
1815
private val fetchProject: FetchProject,
19-
private val db: CCDroidXDb,
16+
private val projectTableDao: ProjectTableDao,
2017
private val cryptography: Cryptography,
2118
private val projectTableToProjectMapper: ProjectTableToProjectMapper,
2219
private val dispatcherProvider: DispatcherProvider
@@ -52,7 +49,7 @@ class ProjectRepo @Inject constructor(
5249
suspend fun saveProject(project: Project) {
5350
withContext(dispatcherProvider.io()) {
5451
if (project.id == -1L) {
55-
db.projectTableQueries.insert(
52+
projectTableDao.insert(
5653
name = project.name,
5754
activity = project.activity,
5855
lastBuildStatus = project.lastBuildStatus,
@@ -65,7 +62,7 @@ class ProjectRepo @Inject constructor(
6562
password = if (project.authentication != null) cryptography.encrypt(project.authentication!!.password) else null
6663
)
6764
} else {
68-
db.projectTableQueries.update(
65+
projectTableDao.update(
6966
id = project.id,
7067
name = project.name,
7168
activity = project.activity,
@@ -83,37 +80,32 @@ class ProjectRepo @Inject constructor(
8380
}
8481

8582
fun getAll(): Flow<List<Project>> {
86-
return db.projectTableQueries.selectAll()
87-
.asFlow()
88-
.mapToList(dispatcherProvider.default())
83+
return projectTableDao.selectAll()
8984
.map { projectTables ->
9085
projectTables.map(projectTableToProjectMapper::mapProjectTable)
9186
}
9287
}
9388

9489

95-
fun getById(projectId: Long): Flow<Project> {
96-
return db.projectTableQueries.selectById(projectId)
97-
.asFlow()
98-
.mapToOne(dispatcherProvider.default())
99-
.map(projectTableToProjectMapper::mapProjectTable)
90+
fun getById(projectId: Long): Project {
91+
return projectTableToProjectMapper.mapProjectTable(projectTableDao.selectById(projectId))
10092
}
10193

10294
suspend fun delete(projectId: Long) {
10395
return withContext(dispatcherProvider.io()) {
104-
db.projectTableQueries.delete(projectId)
96+
projectTableDao.delete(projectId)
10597
}
10698
}
10799

108100
suspend fun unmuteProject(projectId: Long) {
109101
withContext(dispatcherProvider.io()) {
110-
db.projectTableQueries.updateMute(false, null, projectId)
102+
projectTableDao.updateMute(false, null, projectId)
111103
}
112104
}
113105

114106
suspend fun muteProject(projectId: Long) {
115107
withContext(dispatcherProvider.io()) {
116-
db.projectTableQueries.updateMute(true, null, projectId)
108+
projectTableDao.updateMute(true, null, projectId)
117109
}
118110
}
119111

data/src/main/java/dev/aungkyawpaing/ccdroidx/data/db/BuildStatusColumnAdapter.kt

-28
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package dev.aungkyawpaing.ccdroidx.data.db
2+
3+
import androidx.room.Database
4+
import androidx.room.RoomDatabase
5+
import androidx.room.TypeConverters
6+
import androidx.room.migration.Migration
7+
import androidx.sqlite.db.SupportSQLiteDatabase
8+
9+
val MIGRATION_1_2 = object : Migration(1, 2) {
10+
override fun migrate(database: SupportSQLiteDatabase) {
11+
database.execSQL("ALTER TABLE ProjectTable ADD isMuted INTEGER NOT NULL DEFAULT 0;")
12+
database.execSQL("ALTER TABLE ProjectTable ADD mutedUntil INTEGER")
13+
}
14+
}
15+
16+
val MIGRATION_2_3 = object : Migration(2, 3) {
17+
override fun migrate(database: SupportSQLiteDatabase) {
18+
database.execSQL("ALTER TABLE ProjectTable ADD username TEXT DEFAULT NULL;")
19+
database.execSQL("ALTER TABLE ProjectTable ADD password TEXT DEFAULT NULL;")
20+
}
21+
}
22+
23+
24+
@Database(entities = [ProjectTable::class], version = 3)
25+
@TypeConverters(Converters::class)
26+
abstract class CCDroidXDb : RoomDatabase() {
27+
abstract fun projectTableDao(): ProjectTableDao
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package dev.aungkyawpaing.ccdroidx.data.db
2+
3+
import androidx.room.TypeConverter
4+
import dev.aungkyawpaing.ccdroidx.common.BuildStatus
5+
import java.time.Instant
6+
import java.time.ZoneId
7+
import java.time.ZonedDateTime
8+
9+
internal class Converters {
10+
11+
@TypeConverter
12+
fun longToBaseStatus(databaseValue: Long): BuildStatus {
13+
return when (databaseValue) {
14+
1L -> BuildStatus.SUCCESS
15+
3L -> BuildStatus.EXCEPTION
16+
4L -> BuildStatus.FAILURE
17+
else -> BuildStatus.UNKNOWN
18+
}
19+
20+
}
21+
22+
@TypeConverter
23+
fun buildStatusToLong(value: BuildStatus): Long {
24+
return when (value) {
25+
BuildStatus.SUCCESS -> 1
26+
BuildStatus.UNKNOWN -> 2
27+
BuildStatus.EXCEPTION -> 3
28+
BuildStatus.FAILURE -> 4
29+
}
30+
}
31+
32+
@TypeConverter
33+
fun zonedDateTimeToLong(databaseValue: Long): ZonedDateTime {
34+
return Instant.ofEpochMilli(databaseValue).atZone(ZoneId.of("UTC"))
35+
}
36+
37+
@TypeConverter
38+
fun longToZonedDateTime(value: ZonedDateTime): Long {
39+
return value.toInstant().toEpochMilli()
40+
}
41+
42+
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package dev.aungkyawpaing.ccdroidx.data.db
22

33
import android.content.Context
4-
import com.squareup.sqldelight.android.AndroidSqliteDriver
5-
import com.squareup.sqldelight.db.SqlDriver
4+
import androidx.room.Room
65
import dagger.Module
76
import dagger.Provides
87
import dagger.hilt.InstallIn
98
import dagger.hilt.android.qualifiers.ApplicationContext
109
import dagger.hilt.components.SingletonComponent
11-
import dev.aungkyawpaing.ccdroidx.CCDroidXDb
1210
import javax.inject.Singleton
1311

1412
@Module
@@ -17,15 +15,16 @@ internal object DbModule {
1715

1816
@Provides
1917
@Singleton
20-
fun provideSqlDriver(@ApplicationContext context: Context): SqlDriver {
21-
return AndroidSqliteDriver(CCDroidXDb.Schema, context, "ccdroidx.db")
18+
fun database(@ApplicationContext context: Context): CCDroidXDb {
19+
return Room.databaseBuilder(
20+
context,
21+
CCDroidXDb::class.java, "ccdroidx.db"
22+
).addMigrations(MIGRATION_1_2, MIGRATION_2_3).build()
2223
}
2324

2425
@Provides
25-
@Singleton
26-
fun database(driver: SqlDriver): CCDroidXDb {
27-
return CCDroidXDb(
28-
driver = driver, ProjectTableAdapter = projectTableAdapter
29-
)
26+
fun projectTableDao(ccDroidXDb: CCDroidXDb): ProjectTableDao {
27+
return ccDroidXDb.projectTableDao()
3028
}
29+
3130
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package dev.aungkyawpaing.ccdroidx.data.db
2+
3+
import androidx.room.ColumnInfo
4+
import androidx.room.Entity
5+
import androidx.room.PrimaryKey
6+
import dev.aungkyawpaing.ccdroidx.common.BuildState
7+
import dev.aungkyawpaing.ccdroidx.common.BuildStatus
8+
import java.time.ZonedDateTime
9+
10+
@Entity(tableName = "ProjectTable")
11+
data class ProjectTable(
12+
// TODO: Have to put nullable for id because of sqldelight => room migration.
13+
// Add migration script to make id non nullable
14+
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Long?,
15+
@ColumnInfo(name = "name") val name: String,
16+
@ColumnInfo(name = "activity") val activity: BuildState,
17+
@ColumnInfo(name = "lastBuildStatus") val lastBuildStatus: BuildStatus,
18+
@ColumnInfo(name = "lastBuildLabel") val lastBuildLabel: String?,
19+
@ColumnInfo(name = "lastBuildTime") val lastBuildTime: ZonedDateTime,
20+
@ColumnInfo(name = "nextBuildTime") val nextBuildTime: ZonedDateTime?,
21+
@ColumnInfo(name = "webUrl") val webUrl: String,
22+
@ColumnInfo(name = "feedUrl") val feedUrl: String,
23+
@ColumnInfo(name = "isMuted", defaultValue = "0") val isMuted: Boolean = false,
24+
@ColumnInfo(name = "mutedUntil", defaultValue = "NULL") val mutedUntil: ZonedDateTime? = null,
25+
@ColumnInfo(name = "username", defaultValue = "NULL") val username: String? = null,
26+
@ColumnInfo(name = "password", defaultValue = "NULL") val password: String? = null,
27+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package dev.aungkyawpaing.ccdroidx.data.db
2+
3+
import androidx.room.Dao
4+
import androidx.room.Query
5+
import dev.aungkyawpaing.ccdroidx.common.BuildState
6+
import dev.aungkyawpaing.ccdroidx.common.BuildStatus
7+
import kotlinx.coroutines.flow.Flow
8+
import java.time.ZonedDateTime
9+
10+
@Dao
11+
interface ProjectTableDao {
12+
13+
@Query(
14+
"INSERT INTO ProjectTable(name, activity, lastBuildStatus, lastBuildLabel, lastBuildTime, nextBuildTime, webUrl, feedUrl, username, password) " +
15+
"VALUES (:name, :activity, :lastBuildStatus, :lastBuildLabel, :lastBuildTime, :nextBuildTime, :webUrl, :feedUrl, :username, :password);"
16+
)
17+
suspend fun insert(
18+
name: String,
19+
activity: BuildState,
20+
lastBuildStatus: BuildStatus,
21+
lastBuildLabel: String?,
22+
lastBuildTime: ZonedDateTime,
23+
nextBuildTime: ZonedDateTime?,
24+
webUrl: String,
25+
feedUrl: String,
26+
username: String?,
27+
password: String?
28+
)
29+
30+
@Query(
31+
"UPDATE ProjectTable SET name = :name, activity = :activity, " +
32+
"lastBuildStatus = :lastBuildStatus, lastBuildLabel = :lastBuildLabel, lastBuildTime = :lastBuildTime, nextBuildTime = :nextBuildTime, webUrl = :webUrl, feedUrl = :feedUrl,username = :username, password = :password WHERE id = :id"
33+
)
34+
suspend fun update(
35+
name: String,
36+
activity: BuildState,
37+
lastBuildStatus: BuildStatus,
38+
lastBuildLabel: String?,
39+
lastBuildTime: ZonedDateTime,
40+
nextBuildTime: ZonedDateTime?,
41+
webUrl: String,
42+
feedUrl: String,
43+
username: String?,
44+
password: String?,
45+
id: Long
46+
)
47+
48+
@Query("DELETE FROM ProjectTable WHERE id = :id;")
49+
suspend fun delete(id: Long)
50+
51+
@Query("UPDATE ProjectTable SET isMuted=:isMuted, mutedUntil=:mutedUntil WHERE id = :id;")
52+
suspend fun updateMute(isMuted: Boolean, mutedUntil: ZonedDateTime?, id: Long)
53+
54+
@Query("SELECT * FROM ProjectTable ORDER BY lastBuildStatus DESC, lastBuildTime DESC, id")
55+
fun selectAll(): Flow<List<ProjectTable>>
56+
57+
@Query("SELECT * FROM ProjectTable WHERE id = :id")
58+
fun selectById(id: Long): ProjectTable
59+
60+
}

0 commit comments

Comments
 (0)