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
|
package moe.lava.banksia.core.room
|
||||||
|
|
||||||
import androidx.room.RoomDatabase
|
import org.koin.core.module.dsl.singleOf
|
||||||
import org.koin.core.parameter.ParametersHolder
|
|
||||||
import org.koin.core.scope.Scope
|
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val roomDiModule = module {
|
val roomDiModule = module {
|
||||||
single { provideDatabaseBuilder(it) }
|
singleOf(::DatabaseManager)
|
||||||
single { Database.build(get<PlatformDatabaseBuilder>().getBuilder()) }
|
factory { get<DatabaseManager>().database }
|
||||||
|
|
||||||
single { get<Database>().versionMetadataDao }
|
factory { get<Database>().versionMetadataDao }
|
||||||
single { get<Database>().routeDao }
|
factory { get<Database>().routeDao }
|
||||||
single { get<Database>().serviceDao }
|
factory { get<Database>().serviceDao }
|
||||||
single { get<Database>().serviceExceptionDao }
|
factory { get<Database>().serviceExceptionDao }
|
||||||
single { get<Database>().shapeDao }
|
factory { get<Database>().shapeDao }
|
||||||
single { get<Database>().stopDao }
|
factory { get<Database>().stopDao }
|
||||||
single { get<Database>().stopTimeDao }
|
factory { get<Database>().stopTimeDao }
|
||||||
single { get<Database>().tripDao }
|
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