Room¶
Why¶
Have the DB request working properly (no thread exception, etc.)
Prerequisites¶
- If it is the first database of the module, read the standard 🚧
Control points¶
- The DB request must work on its own (no API call or anything else)
Key steps¶
- In core/database, create the entities, DAO interface, and room DAO
interface MyDao {
// We use single because it returns only one value
fun upsert(element: MyElementEntity): Single<Unit>
// We use flowable because it watches changes and the DB and send new values
// It can be converted to Observable
// http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html
fun getAll(): Flowable<List<MyElementEntity>>
}
interface RoomMyDao: MyDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
override fun upsert(element: MyElementEntity): Single<Unit>
@Query("SELECT * FROM my_element")
override fun getAll(): Flowable<List<MyElementEntity>>
}
@Entity(tableName = "my_element")
data class MyElementEntity {
@PrimaryKey val id: String = UUID.randomUUID().toString(),
@ColumnInfo(name = "my_value")
val myValue: String,
}
- Register in Room the new entity and DAO (increase version)
@Database(
entities = [
A::class, B::class, C::class,
MyElementEntity::class // New
],
version = 6 // New
)
@TypeConverters(Converters::class)
abstract class MyDatabase : RoomDatabase() {
abstract fun aDao(): RoomADao
abstract fun bDao(): RoomBDao
abstract fun cDao(): RoomCDao
abstract fun myDao(): RoomMyDao // New
}
- Register in Koin the new DAO
object CoreDatabaseModule {
val module =
module {
single { MyStorageService.db.aDao() } binds arrayOf(ADao::class)
single { MyStorageService.db.bDao() } binds arrayOf(BDao::class)
single { MyStorageService.db.cDao() } binds arrayOf(CDao::class)
single { MyStorageService.db.myDao() } binds arrayOf(MyDao::class) // New
}
}
Warning
For non-one-to-one relations between tables, check the room documentation
-
In the lib, create a folder "repository", here you should have
-
Adapters between domain and DB (these are different types)
fun MyElement.toEntity(): MyElementEntity {
// Implementation here
}
fun MyElementEntity.toDomain(): MyElement {
// Implementation here
}
- Calls to the DB
class MyRepository(private val myDao: MyDao) {
fun upsertElement(element: MyElement): Single<Unit> {
return myDao
.upsert(element.toEntity())
// We can't do db operations on main thread
.subscribeOn(Schedulers.io())
}
fun getAll(): Observable<List<MyElement>> {
return myDao
.getAll()
// Get all is an flowable but we are used to observable in the code
.toObservable()
.map { elements -> elements.map { it.toDomain() } }
// We can't do db operations on main thread
.subscribeOn(Schedulers.io())
}
}
- You can now use the calls from "repository" inside your cqrs
Mistakes to avoid¶
- Forget to do a migration when affecting an existing table
- Forget to register in room and in koin
- Forget to be on an io thread
Last update: August 24, 2021