feat(core/room): swappable databases
This commit is contained in:
parent
e7caeca356
commit
959b022cf9
8 changed files with 117 additions and 73 deletions
|
|
@ -0,0 +1,22 @@
|
|||
package moe.lava.banksia.core.room
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
import org.koin.core.component.inject
|
||||
|
||||
actual class DatabaseManager actual constructor() : KoinComponent {
|
||||
private val ctx by inject<Context>()
|
||||
|
||||
actual val database by lazy {
|
||||
val ctx = get<Context>().applicationContext
|
||||
val dbFile = ctx.getDatabasePath("room.db")
|
||||
val builder = Room.databaseBuilder<Database>(
|
||||
context = ctx,
|
||||
name = dbFile.absolutePath,
|
||||
)
|
||||
|
||||
Database.build(builder)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package moe.lava.banksia.core.room
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import org.koin.core.parameter.ParametersHolder
|
||||
import org.koin.core.scope.Scope
|
||||
|
||||
class AndroidDatabaseBuilder(val ctx: Context) : PlatformDatabaseBuilder {
|
||||
override fun getBuilder(): RoomDatabase.Builder<Database> {
|
||||
val appContext = ctx.applicationContext
|
||||
val dbFile = appContext.getDatabasePath("room.db")
|
||||
return Room.databaseBuilder<Database>(
|
||||
context = appContext,
|
||||
name = dbFile.absolutePath
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal actual fun Scope.provideDatabaseBuilder(p: ParametersHolder): PlatformDatabaseBuilder =
|
||||
AndroidDatabaseBuilder(get())
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package moe.lava.banksia.core.room
|
||||
|
||||
import org.koin.core.component.KoinComponent
|
||||
|
||||
expect class DatabaseManager() : KoinComponent {
|
||||
val database: Database
|
||||
}
|
||||
|
|
@ -1,26 +1,18 @@
|
|||
package moe.lava.banksia.core.room
|
||||
|
||||
import androidx.room.RoomDatabase
|
||||
import org.koin.core.parameter.ParametersHolder
|
||||
import org.koin.core.scope.Scope
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val roomDiModule = module {
|
||||
single { provideDatabaseBuilder(it) }
|
||||
single { Database.build(get<PlatformDatabaseBuilder>().getBuilder()) }
|
||||
singleOf(::DatabaseManager)
|
||||
factory { get<DatabaseManager>().database }
|
||||
|
||||
single { get<Database>().versionMetadataDao }
|
||||
single { get<Database>().routeDao }
|
||||
single { get<Database>().serviceDao }
|
||||
single { get<Database>().serviceExceptionDao }
|
||||
single { get<Database>().shapeDao }
|
||||
single { get<Database>().stopDao }
|
||||
single { get<Database>().stopTimeDao }
|
||||
single { get<Database>().tripDao }
|
||||
factory { get<Database>().versionMetadataDao }
|
||||
factory { get<Database>().routeDao }
|
||||
factory { get<Database>().serviceDao }
|
||||
factory { get<Database>().serviceExceptionDao }
|
||||
factory { get<Database>().shapeDao }
|
||||
factory { get<Database>().stopDao }
|
||||
factory { get<Database>().stopTimeDao }
|
||||
factory { get<Database>().tripDao }
|
||||
}
|
||||
|
||||
internal interface PlatformDatabaseBuilder {
|
||||
fun getBuilder(): RoomDatabase.Builder<Database>
|
||||
}
|
||||
|
||||
internal expect fun Scope.provideDatabaseBuilder(p: ParametersHolder): PlatformDatabaseBuilder
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
package moe.lava.banksia.core.room
|
||||
|
||||
import org.koin.core.component.KoinComponent
|
||||
|
||||
actual class DatabaseManager actual constructor() : KoinComponent {
|
||||
actual val database: Database
|
||||
get() = TODO("Not yet implemented")
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package moe.lava.banksia.core.room
|
||||
|
||||
import androidx.room.RoomDatabase
|
||||
import org.koin.core.parameter.ParametersHolder
|
||||
import org.koin.core.scope.Scope
|
||||
|
||||
class IosDatabaseBuilder() : PlatformDatabaseBuilder {
|
||||
override fun getBuilder(): RoomDatabase.Builder<Database> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
internal actual fun Scope.provideDatabaseBuilder(p: ParametersHolder): PlatformDatabaseBuilder =
|
||||
IosDatabaseBuilder()
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package moe.lava.banksia.core.room
|
||||
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import moe.lava.banksia.core.util.error
|
||||
import org.koin.core.component.KoinComponent
|
||||
import java.io.File
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
actual class DatabaseManager : KoinComponent {
|
||||
private var liveDatabase: Database = Database.build(getBuilder())
|
||||
actual val database get() = liveDatabase
|
||||
|
||||
private fun getBuilder(path: String = "./data/room.db"): RoomDatabase.Builder<Database> {
|
||||
val dbFile = File(path)
|
||||
return Room.databaseBuilder<Database>(
|
||||
name = dbFile.absolutePath,
|
||||
).setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
|
||||
}
|
||||
|
||||
fun makeAlt() = Database.build(getBuilder("./data/room_alt.db"))
|
||||
|
||||
private fun deleteAll(file: File): Boolean {
|
||||
val r1 = file.delete()
|
||||
val r2 = File(file.parentFile, file.name + ".lck").delete()
|
||||
val r3 = File(file.parentFile, file.name + "-journal").delete()
|
||||
return r1 && r2 && r3
|
||||
}
|
||||
|
||||
private fun renameAll(from: File, to: File): Boolean {
|
||||
val r1 = from.renameTo(to)
|
||||
val r2 = File(from.parentFile, from.name + ".lck").renameTo(File(to.parentFile, to.name + ".lck"))
|
||||
val r3 = File(from.parentFile, from.name + "-journal").renameTo(File(to.parentFile, to.name + "-journal"))
|
||||
return r1 && r2 && r3
|
||||
}
|
||||
|
||||
fun swap(scope: CoroutineScope = CoroutineScope(Dispatchers.IO)) {
|
||||
val live = File("./data/room.db")
|
||||
val alt = File("./data/room_alt.db")
|
||||
val old = File("./data/room_old.db")
|
||||
|
||||
if (!renameAll(live, old)) {
|
||||
error("DatabaseManager", "Failed to rename database from live to old (${live.absolutePath} -> ${old.absolutePath})")
|
||||
return
|
||||
}
|
||||
if (!renameAll(alt, live)) {
|
||||
error("DatabaseManager", "Failed to rename database from alt to live, trying to undo.. (${alt.absolutePath} -> ${live.absolutePath})")
|
||||
if (!live.renameTo(old)) {
|
||||
error("DatabaseManager", "Failed to undo, critical failure, exiting..")
|
||||
exitProcess(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
val oldDatabase = liveDatabase
|
||||
liveDatabase = Database.build(getBuilder())
|
||||
|
||||
scope.launch {
|
||||
delay(5000)
|
||||
if (!deleteAll(old)) {
|
||||
error("DatabaseManager", "Failed to unlink old database, stray files! (${old.absolutePath})")
|
||||
}
|
||||
oldDatabase.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package moe.lava.banksia.core.room
|
||||
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import org.koin.core.parameter.ParametersHolder
|
||||
import org.koin.core.scope.Scope
|
||||
import java.io.File
|
||||
|
||||
class JvmDatabaseBuilder() : PlatformDatabaseBuilder {
|
||||
override fun getBuilder(): RoomDatabase.Builder<Database> {
|
||||
val dbFile = File("./data/room.db")
|
||||
return Room.databaseBuilder<Database>(
|
||||
name = dbFile.absolutePath,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal actual fun Scope.provideDatabaseBuilder(p: ParametersHolder): PlatformDatabaseBuilder =
|
||||
JvmDatabaseBuilder()
|
||||
Loading…
Add table
Add a link
Reference in a new issue