diff --git a/build.gradle.kts b/build.gradle.kts index 0687328..9434477 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,6 +7,7 @@ plugins { alias(libs.plugins.composeCompiler) apply false alias(libs.plugins.kotlinJvm) apply false alias(libs.plugins.kotlinMultiplatform) apply false + alias(libs.plugins.sqldelight) apply false alias(libs.plugins.wire) apply false } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 99f7156..3dd2ee6 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -4,12 +4,6 @@ plugins { alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.kotlinSerialization) alias(libs.plugins.androidMultiplatformLibrary) - alias(libs.plugins.ksp) - alias(libs.plugins.room) -} - -room { - schemaDirectory("$projectDir/schemas") } kotlin { @@ -46,18 +40,9 @@ kotlin { implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.serialization.protobuf) - implementation(libs.room.runtime) - implementation(libs.sqlite.bundled) } iosMain.dependencies { implementation(libs.ktor.client.darwin) } } } - -dependencies { - add("kspAndroid", libs.room.compiler) - add("kspIosArm64", libs.room.compiler) - add("kspIosSimulatorArm64", libs.room.compiler) - add("kspJvm", libs.room.compiler) -} diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts index 6f78b5c..ecdba19 100644 --- a/core/data/build.gradle.kts +++ b/core/data/build.gradle.kts @@ -25,8 +25,40 @@ kotlin { jvm() sourceSets { + val clientMain by creating { + dependsOn(commonMain.get()) + } + + androidMain.get().dependsOn(clientMain) + iosArm64Main.get().dependsOn(clientMain) + iosSimulatorArm64Main.get().dependsOn(clientMain) + commonMain.dependencies { + implementation(libs.koin.core) implementation(projects.core) + api(projects.core.stoptime) + } + + androidMain.dependencies { + implementation(libs.koin.compose) + implementation(libs.ktor.client.okhttp) + } + commonMain.dependencies { + implementation(libs.okio) + implementation(libs.koin.core) + implementation(libs.ktor.client.core) + implementation(libs.ktor.client.contentnegotiation) + implementation(libs.ktor.serialization.kotlinx.json) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.datetime) + implementation(libs.kotlinx.serialization.json) + implementation(libs.kotlinx.serialization.protobuf) + + implementation(projects.core) + implementation(projects.core.sqld) + } + iosMain.dependencies { + implementation(libs.ktor.client.darwin) } } } diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/ClientStopTimeRepository.kt b/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/ClientStopTimeRepository.kt deleted file mode 100644 index aea3159..0000000 --- a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/ClientStopTimeRepository.kt +++ /dev/null @@ -1,16 +0,0 @@ -package moe.lava.banksia.core.data.repositories - -import moe.lava.banksia.core.data.sources.stoptime.StopTimeLocalDataSource -import moe.lava.banksia.core.data.sources.stoptime.StopTimeRemoteDataSource -import moe.lava.banksia.core.model.StopTimeDated - -internal class ClientStopTimeRepository internal constructor( - private val local: StopTimeLocalDataSource, - private val remote: StopTimeRemoteDataSource, -) : StopTimeRepository { - override suspend fun getForStop(id: String): List { - return local - .getAtStop(id) - .ifEmpty { remote.getAtStop(id) } - } -} diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteLocalDataSource.kt b/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteLocalDataSource.kt deleted file mode 100644 index ca267c3..0000000 --- a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteLocalDataSource.kt +++ /dev/null @@ -1,11 +0,0 @@ -package moe.lava.banksia.core.data.sources.route - -import moe.lava.banksia.core.model.Route -import moe.lava.banksia.core.room.dao.RouteDao -import moe.lava.banksia.core.room.entity.asEntity - -internal class RouteLocalDataSource(private val dao: RouteDao) { - suspend fun get(id: String) = dao.get(id) - suspend fun getAll() = dao.getAll() - suspend fun save(vararg routes: Route) = dao.insertOrReplaceAll(*routes.map { it.asEntity() }.toTypedArray()) -} diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stop/StopLocalDataSource.kt b/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stop/StopLocalDataSource.kt deleted file mode 100644 index 8e0d8ab..0000000 --- a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stop/StopLocalDataSource.kt +++ /dev/null @@ -1,12 +0,0 @@ -package moe.lava.banksia.core.data.sources.stop - -import moe.lava.banksia.core.model.Stop -import moe.lava.banksia.core.room.dao.RouteDao -import moe.lava.banksia.core.room.dao.StopDao -import moe.lava.banksia.core.room.entity.asEntity - -internal class StopLocalDataSource(private val dao: StopDao, private val routeDao: RouteDao) { - suspend fun get(id: String) = dao.get(id) - suspend fun getByRoute(id: String) = routeDao.stops(id) - suspend fun save(vararg stops: Stop) = dao.insertOrReplaceAll(*stops.map { it.asEntity() }.toTypedArray()) -} diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeLocalDataSource.kt b/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeLocalDataSource.kt deleted file mode 100644 index c5ce4e7..0000000 --- a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeLocalDataSource.kt +++ /dev/null @@ -1,28 +0,0 @@ -package moe.lava.banksia.core.data.sources.stoptime - -import kotlinx.datetime.LocalDate -import kotlinx.datetime.TimeZone -import kotlinx.datetime.todayIn -import moe.lava.banksia.core.model.StopTimeDated -import moe.lava.banksia.core.model.atDate -import moe.lava.banksia.core.room.dao.StopTimeDao -import moe.lava.banksia.core.util.serialise -import kotlin.time.Clock - -internal class StopTimeLocalDataSource( - private val stopTimeDao: StopTimeDao, -) { - suspend fun getAtStop( - stopId: String, - date: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault()), - ): List { - return stopTimeDao - .getForStopDated( - stopId, - listOf(date.dayOfWeek).serialise(), - date.toEpochDays().toInt(), - ) - .map { it.asModel().atDate(date) } - .sortedBy { it.departureTime } - } -} diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeRemoteDataSource.kt b/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeRemoteDataSource.kt deleted file mode 100644 index 0633a18..0000000 --- a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeRemoteDataSource.kt +++ /dev/null @@ -1,36 +0,0 @@ -package moe.lava.banksia.core.data.sources.stoptime - -import io.ktor.client.HttpClient -import io.ktor.client.call.body -import io.ktor.client.request.get -import io.ktor.client.request.parameter -import kotlinx.datetime.LocalDate -import kotlinx.datetime.TimeZone -import kotlinx.datetime.todayIn -import moe.lava.banksia.core.model.StopTimeDated -import kotlin.time.Clock - -internal class StopTimeRemoteDataSource( - private val client: HttpClient, -) { - suspend fun getAtStop( - stopId: String, - date: LocalDate? = Clock.System.todayIn(TimeZone.currentSystemDefault()), - ): List { - return client.get("stoptimes/by_stop/${stopId}") { - parameter("date", date) - }.body>() - } - - /*suspend fun get( - stop: String? = null, - trip: String? = null, - day: DayOfWeek? = Clock.System.todayIn(TimeZone.currentSystemDefault()).dayOfWeek, - ): List { - return client.get("stoptimes") { - stop?.let { parameter("stop", it) } - trip?.let { parameter("trip", it) } - day?.let { parameter("day", it) } - }.body>() - }*/ -} diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/trip/TripRemoteDataSource.kt b/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/trip/TripRemoteDataSource.kt deleted file mode 100644 index d1067d8..0000000 --- a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/trip/TripRemoteDataSource.kt +++ /dev/null @@ -1,18 +0,0 @@ -package moe.lava.banksia.core.data.sources.trip - -import io.ktor.client.HttpClient -import kotlinx.datetime.DayOfWeek -import kotlinx.datetime.TimeZone -import kotlinx.datetime.todayIn -import moe.lava.banksia.core.model.Trip -import kotlin.time.Clock - -internal class TripRemoteDataSource( - private val client: HttpClient, -) { - suspend fun get( - day: DayOfWeek? = Clock.System.todayIn(TimeZone.currentSystemDefault()).dayOfWeek, - ): List { - return listOf() - } -} diff --git a/core/data/server/build.gradle.kts b/core/data/server/build.gradle.kts deleted file mode 100644 index eaa309b..0000000 --- a/core/data/server/build.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -plugins { - alias(libs.plugins.kotlinJvm) - alias(libs.plugins.kotlinSerialization) -} - -kotlin { - compilerOptions { - freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime") - } -} - -dependencies { - implementation(libs.okio) - implementation(libs.koin.core) - implementation(libs.kotlinx.coroutines.core) - implementation(libs.kotlinx.datetime) - - api(projects.core.data) - implementation(projects.core) - implementation(projects.core.room) -} diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/ClientDataDiModule.kt b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/DataDiModule.client.kt similarity index 78% rename from core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/ClientDataDiModule.kt rename to core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/DataDiModule.client.kt index 01e961c..104c6bc 100644 --- a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/ClientDataDiModule.kt +++ b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/DataDiModule.client.kt @@ -10,26 +10,19 @@ import kotlinx.serialization.json.Json import moe.lava.banksia.core.Constants import moe.lava.banksia.core.data.repositories.ClientRouteRepository import moe.lava.banksia.core.data.repositories.ClientStopRepository -import moe.lava.banksia.core.data.repositories.ClientStopTimeRepository import moe.lava.banksia.core.data.repositories.RouteRepository import moe.lava.banksia.core.data.repositories.StopRepository -import moe.lava.banksia.core.data.repositories.StopTimeRepository import moe.lava.banksia.core.data.sources.route.RouteLocalDataSource import moe.lava.banksia.core.data.sources.route.RouteRemoteDataSource import moe.lava.banksia.core.data.sources.stop.StopLocalDataSource import moe.lava.banksia.core.data.sources.stop.StopRemoteDataSource -import moe.lava.banksia.core.data.sources.stoptime.StopTimeLocalDataSource -import moe.lava.banksia.core.data.sources.stoptime.StopTimeRemoteDataSource -import moe.lava.banksia.core.room.roomDiModule import moe.lava.banksia.core.util.log import moe.lava.banksia.data.ptv.PtvService import org.koin.core.module.dsl.singleOf import org.koin.dsl.bind import org.koin.dsl.module -val clientDataDiModule = module { - includes(roomDiModule) - +actual val platformModule = module { // HTTP Clients singleOf(::PtvService) single { @@ -56,11 +49,8 @@ val clientDataDiModule = module { singleOf(::RouteRemoteDataSource) singleOf(::StopLocalDataSource) singleOf(::StopRemoteDataSource) - singleOf(::StopTimeLocalDataSource) - singleOf(::StopTimeRemoteDataSource) // Repositories singleOf(::ClientRouteRepository) bind RouteRepository::class singleOf(::ClientStopRepository) bind StopRepository::class - singleOf(::ClientStopTimeRepository) bind StopTimeRepository::class } diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/ClientRouteRepository.kt b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/repositories/ClientRouteRepository.kt similarity index 67% rename from core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/ClientRouteRepository.kt rename to core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/repositories/ClientRouteRepository.kt index 70a8905..f46caac 100644 --- a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/ClientRouteRepository.kt +++ b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/repositories/ClientRouteRepository.kt @@ -4,6 +4,8 @@ import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import moe.lava.banksia.core.data.sources.route.RouteLocalDataSource import moe.lava.banksia.core.data.sources.route.RouteRemoteDataSource +import moe.lava.banksia.core.model.Route +import moe.lava.banksia.core.sqld.mappers.asModel internal class ClientRouteRepository internal constructor( private val local: RouteLocalDataSource, @@ -21,5 +23,14 @@ internal class ClientRouteRepository internal constructor( } } + private val tripRouteMap = mutableMapOf() + override suspend fun get(id: String) = mutex.withLock { local.get(id)?.asModel() ?: remote.get(id) } + override suspend fun getByPattern(patternId: Long) = mutex.withLock { + tripRouteMap[patternId] + ?: remote.getByPattern(patternId).also { + local.save(it) + tripRouteMap[patternId] = it + } + } } diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/ClientStopRepository.kt b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/repositories/ClientStopRepository.kt similarity index 94% rename from core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/ClientStopRepository.kt rename to core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/repositories/ClientStopRepository.kt index a5fd300..0aee84e 100644 --- a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/ClientStopRepository.kt +++ b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/repositories/ClientStopRepository.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import moe.lava.banksia.core.data.sources.stop.StopLocalDataSource import moe.lava.banksia.core.data.sources.stop.StopRemoteDataSource +import moe.lava.banksia.core.sqld.mappers.asModel internal class ClientStopRepository internal constructor( private val local: StopLocalDataSource, diff --git a/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteLocalDataSource.kt b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteLocalDataSource.kt new file mode 100644 index 0000000..8286b1f --- /dev/null +++ b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteLocalDataSource.kt @@ -0,0 +1,23 @@ +package moe.lava.banksia.core.data.sources.route + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.withContext +import moe.lava.banksia.core.model.Route +import moe.lava.banksia.core.sqld.RouteQueries +import moe.lava.banksia.core.sqld.mappers.asDb + +internal class RouteLocalDataSource(private val queries: RouteQueries) { + suspend fun get(id: String) = withContext(Dispatchers.IO) { queries.get(id).executeAsOneOrNull() } + suspend fun getAll() = withContext(Dispatchers.IO) { queries.getAll().executeAsList() } +// suspend fun getByTrip(tripId: String) = dao.getByTrip(tripId) + suspend fun save(vararg routes: Route) { + withContext(Dispatchers.IO) { + queries.transaction { + routes.forEach { + queries.insert(it.asDb()) + } + } + } + } +} diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteRemoteDataSource.kt b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteRemoteDataSource.kt similarity index 78% rename from core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteRemoteDataSource.kt rename to core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteRemoteDataSource.kt index bdcbfc1..15088fb 100644 --- a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteRemoteDataSource.kt +++ b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/route/RouteRemoteDataSource.kt @@ -7,5 +7,6 @@ import moe.lava.banksia.core.model.Route internal class RouteRemoteDataSource(val client: HttpClient) { suspend fun get(id: String) = client.get("routes/${id}").body() + suspend fun getByPattern(patternId: Long) = client.get("routes/by_pattern/${patternId}").body() suspend fun getAll() = client.get("routes").body>() } diff --git a/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/stop/StopLocalDataSource.kt b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/stop/StopLocalDataSource.kt new file mode 100644 index 0000000..524d123 --- /dev/null +++ b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/stop/StopLocalDataSource.kt @@ -0,0 +1,22 @@ +package moe.lava.banksia.core.data.sources.stop + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.withContext +import moe.lava.banksia.core.model.Stop +import moe.lava.banksia.core.sqld.StopQueries +import moe.lava.banksia.core.sqld.mappers.asDb + +internal class StopLocalDataSource(private val queries: StopQueries) { + suspend fun get(id: String) = withContext(Dispatchers.IO) { queries.get(id).executeAsOneOrNull() } + suspend fun getByRoute(id: String) = withContext(Dispatchers.IO) { queries.getByRoute(id).executeAsList() } + suspend fun save(vararg stops: Stop) { + withContext(Dispatchers.IO) { + queries.transaction { + stops.forEach { + queries.insert(it.asDb()) + } + } + } + } +} diff --git a/core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stop/StopRemoteDataSource.kt b/core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/stop/StopRemoteDataSource.kt similarity index 100% rename from core/data/client/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stop/StopRemoteDataSource.kt rename to core/data/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/stop/StopRemoteDataSource.kt diff --git a/core/data/src/commonMain/kotlin/moe/lava/banksia/core/data/DataDiModule.kt b/core/data/src/commonMain/kotlin/moe/lava/banksia/core/data/DataDiModule.kt new file mode 100644 index 0000000..eea6a0e --- /dev/null +++ b/core/data/src/commonMain/kotlin/moe/lava/banksia/core/data/DataDiModule.kt @@ -0,0 +1,13 @@ +package moe.lava.banksia.core.data + +import moe.lava.banksia.core.sqld.sqldDiModule +import org.koin.core.module.Module +import org.koin.dsl.module + +internal expect val platformModule: Module + +val dataDiModule = module { + includes(platformModule) + includes(sqldDiModule) + includes(stopTimeDataDiModule) +} diff --git a/core/data/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/RouteRepository.kt b/core/data/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/RouteRepository.kt index fbb663f..ef3d6f1 100644 --- a/core/data/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/RouteRepository.kt +++ b/core/data/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/RouteRepository.kt @@ -3,6 +3,7 @@ package moe.lava.banksia.core.data.repositories import moe.lava.banksia.core.model.Route interface RouteRepository { - suspend fun get(id: String): Route + suspend fun get(id: String): Route? + suspend fun getByPattern(patternId: Long): Route? suspend fun getAll(): List } diff --git a/core/data/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.kt b/core/data/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.kt deleted file mode 100644 index 87d01ac..0000000 --- a/core/data/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.kt +++ /dev/null @@ -1,7 +0,0 @@ -package moe.lava.banksia.core.data.repositories - -import moe.lava.banksia.core.model.StopTimeDated - -interface StopTimeRepository { - suspend fun getForStop(id: String): List -} diff --git a/core/data/src/jvmMain/kotlin/moe/lava/banksia/core/data/DataDiModule.jvm.kt b/core/data/src/jvmMain/kotlin/moe/lava/banksia/core/data/DataDiModule.jvm.kt new file mode 100644 index 0000000..78a44d1 --- /dev/null +++ b/core/data/src/jvmMain/kotlin/moe/lava/banksia/core/data/DataDiModule.jvm.kt @@ -0,0 +1,7 @@ +package moe.lava.banksia.core.data + +import org.koin.dsl.module + +internal actual val platformModule = module { + +} diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/1.json b/core/room/schemas/moe.lava.banksia.core.room.Database/1.json deleted file mode 100644 index 037062e..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/1.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 1, - "identityHash": "e536f5a9b1408377bcc449195169648c", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e536f5a9b1408377bcc449195169648c')" - ] - } -} \ No newline at end of file diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/10.json b/core/room/schemas/moe.lava.banksia.core.room.Database/10.json deleted file mode 100644 index 751e946..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/10.json +++ /dev/null @@ -1,477 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 10, - "identityHash": "5b90bc800bfae6d22124ea0a6a906ca7", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Service", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `days` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "days", - "columnName": "days", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "start", - "columnName": "start", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "end", - "columnName": "end", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Service_days", - "unique": false, - "columnNames": [ - "days" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Service_days` ON `${TABLE_NAME}` (`days`)" - } - ] - }, - { - "tableName": "ServiceException", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serviceId` TEXT NOT NULL, `date` INTEGER NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`serviceId`, `date`))", - "fields": [ - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "date", - "columnName": "date", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "serviceId", - "date" - ] - }, - "indices": [ - { - "name": "index_ServiceException_serviceId", - "unique": false, - "columnNames": [ - "serviceId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_ServiceException_serviceId` ON `${TABLE_NAME}` (`serviceId`)" - }, - { - "name": "index_ServiceException_type", - "unique": false, - "columnNames": [ - "type" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_ServiceException_type` ON `${TABLE_NAME}` (`type`)" - } - ] - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Stop", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "parent", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasWheelChairBoarding", - "columnName": "hasWheelChairBoarding", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "level", - "columnName": "level", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "platformCode", - "columnName": "platformCode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Stop_parent", - "unique": false, - "columnNames": [ - "parent" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)" - } - ] - }, - { - "tableName": "StopTime", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "stopId", - "columnName": "stopId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "arrivalTime", - "columnName": "arrivalTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "departureTime", - "columnName": "departureTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "headsign", - "columnName": "headsign", - "affinity": "TEXT" - }, - { - "fieldPath": "pickupType", - "columnName": "pickupType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dropOffType", - "columnName": "dropOffType", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tripId", - "stopId" - ] - }, - "indices": [ - { - "name": "index_StopTime_tripId", - "unique": false, - "columnNames": [ - "tripId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)" - }, - { - "name": "index_StopTime_stopId", - "unique": false, - "columnNames": [ - "stopId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)" - } - ], - "foreignKeys": [ - { - "table": "Trip", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Stop", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "stopId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "Trip", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`serviceId`) REFERENCES `Service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "routeId", - "columnName": "routeId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "shapeId", - "columnName": "shapeId", - "affinity": "TEXT" - }, - { - "fieldPath": "tripHeadsign", - "columnName": "tripHeadsign", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "directionId", - "columnName": "directionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "blockId", - "columnName": "blockId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wheelchairAccessible", - "columnName": "wheelchairAccessible", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Trip_shapeId", - "unique": false, - "columnNames": [ - "shapeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)" - }, - { - "name": "index_Trip_routeId", - "unique": false, - "columnNames": [ - "routeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)" - } - ], - "foreignKeys": [ - { - "table": "Route", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "routeId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Service", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "serviceId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Shape", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "shapeId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "VersionMetadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))", - "fields": [ - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastUpdated", - "columnName": "lastUpdated", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "type" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5b90bc800bfae6d22124ea0a6a906ca7')" - ] - } -} \ No newline at end of file diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/11.json b/core/room/schemas/moe.lava.banksia.core.room.Database/11.json deleted file mode 100644 index 6fc2976..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/11.json +++ /dev/null @@ -1,498 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 11, - "identityHash": "c4be3d0c2a25f8c5c33132646a070d0e", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Service", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `days` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "days", - "columnName": "days", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "start", - "columnName": "start", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "end", - "columnName": "end", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Service_days", - "unique": false, - "columnNames": [ - "days" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Service_days` ON `${TABLE_NAME}` (`days`)" - } - ] - }, - { - "tableName": "ServiceException", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serviceId` TEXT NOT NULL, `date` INTEGER NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`serviceId`, `date`))", - "fields": [ - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "date", - "columnName": "date", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "serviceId", - "date" - ] - }, - "indices": [ - { - "name": "index_ServiceException_serviceId", - "unique": false, - "columnNames": [ - "serviceId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_ServiceException_serviceId` ON `${TABLE_NAME}` (`serviceId`)" - }, - { - "name": "index_ServiceException_type", - "unique": false, - "columnNames": [ - "type" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_ServiceException_type` ON `${TABLE_NAME}` (`type`)" - } - ] - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Stop", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`parent`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "parent", - "affinity": "TEXT" - }, - { - "fieldPath": "hasWheelChairBoarding", - "columnName": "hasWheelChairBoarding", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "level", - "columnName": "level", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "platformCode", - "columnName": "platformCode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Stop_parent", - "unique": false, - "columnNames": [ - "parent" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)" - } - ], - "foreignKeys": [ - { - "table": "Stop", - "onDelete": "SET NULL", - "onUpdate": "NO ACTION", - "columns": [ - "parent" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "StopTime", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "stopId", - "columnName": "stopId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "arrivalTime", - "columnName": "arrivalTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "departureTime", - "columnName": "departureTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "headsign", - "columnName": "headsign", - "affinity": "TEXT" - }, - { - "fieldPath": "pickupType", - "columnName": "pickupType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dropOffType", - "columnName": "dropOffType", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tripId", - "stopId" - ] - }, - "indices": [ - { - "name": "index_StopTime_tripId", - "unique": false, - "columnNames": [ - "tripId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)" - }, - { - "name": "index_StopTime_stopId", - "unique": false, - "columnNames": [ - "stopId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)" - } - ], - "foreignKeys": [ - { - "table": "Trip", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Stop", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "stopId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "Trip", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`serviceId`) REFERENCES `Service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "routeId", - "columnName": "routeId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "shapeId", - "columnName": "shapeId", - "affinity": "TEXT" - }, - { - "fieldPath": "tripHeadsign", - "columnName": "tripHeadsign", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "directionId", - "columnName": "directionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "blockId", - "columnName": "blockId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wheelchairAccessible", - "columnName": "wheelchairAccessible", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Trip_shapeId", - "unique": false, - "columnNames": [ - "shapeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)" - }, - { - "name": "index_Trip_serviceId", - "unique": false, - "columnNames": [ - "serviceId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_serviceId` ON `${TABLE_NAME}` (`serviceId`)" - }, - { - "name": "index_Trip_routeId", - "unique": false, - "columnNames": [ - "routeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)" - } - ], - "foreignKeys": [ - { - "table": "Route", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "routeId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Service", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "serviceId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Shape", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "shapeId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "VersionMetadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))", - "fields": [ - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastUpdated", - "columnName": "lastUpdated", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "type" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c4be3d0c2a25f8c5c33132646a070d0e')" - ] - } -} \ No newline at end of file diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/2.json b/core/room/schemas/moe.lava.banksia.core.room.Database/2.json deleted file mode 100644 index 04a14e3..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/2.json +++ /dev/null @@ -1,315 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 2, - "identityHash": "83ece554400bb035c267dc2414c23293", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Stop", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "parent", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasWheelChairBoarding", - "columnName": "hasWheelChairBoarding", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "level", - "columnName": "level", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "platformCode", - "columnName": "platformCode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Stop_parent", - "unique": false, - "columnNames": [ - "parent" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)" - } - ] - }, - { - "tableName": "StopTime", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "stopId", - "columnName": "stopId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "arrivalTime", - "columnName": "arrivalTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "departureTime", - "columnName": "departureTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "headsign", - "columnName": "headsign", - "affinity": "TEXT" - }, - { - "fieldPath": "pickupType", - "columnName": "pickupType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dropOffType", - "columnName": "dropOffType", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tripId", - "stopId" - ] - }, - "foreignKeys": [ - { - "table": "Trip", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Stop", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "stopId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "Trip", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "routeId", - "columnName": "routeId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "shapeId", - "columnName": "shapeId", - "affinity": "TEXT" - }, - { - "fieldPath": "tripHeadsign", - "columnName": "tripHeadsign", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "directionId", - "columnName": "directionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "blockId", - "columnName": "blockId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wheelchairAccessible", - "columnName": "wheelchairAccessible", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Trip_routeId", - "unique": false, - "columnNames": [ - "routeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)" - } - ], - "foreignKeys": [ - { - "table": "Route", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "routeId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Shape", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "shapeId" - ], - "referencedColumns": [ - "id" - ] - } - ] - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '83ece554400bb035c267dc2414c23293')" - ] - } -} \ No newline at end of file diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/3.json b/core/room/schemas/moe.lava.banksia.core.room.Database/3.json deleted file mode 100644 index e769926..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/3.json +++ /dev/null @@ -1,339 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 3, - "identityHash": "5a7252ab3bcae4d0d0950024b19ba002", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Stop", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "parent", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasWheelChairBoarding", - "columnName": "hasWheelChairBoarding", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "level", - "columnName": "level", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "platformCode", - "columnName": "platformCode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Stop_parent", - "unique": false, - "columnNames": [ - "parent" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)" - } - ] - }, - { - "tableName": "StopTime", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "stopId", - "columnName": "stopId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "arrivalTime", - "columnName": "arrivalTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "departureTime", - "columnName": "departureTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "headsign", - "columnName": "headsign", - "affinity": "TEXT" - }, - { - "fieldPath": "pickupType", - "columnName": "pickupType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dropOffType", - "columnName": "dropOffType", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tripId", - "stopId" - ] - }, - "foreignKeys": [ - { - "table": "Trip", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Stop", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "stopId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "Trip", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "routeId", - "columnName": "routeId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "shapeId", - "columnName": "shapeId", - "affinity": "TEXT" - }, - { - "fieldPath": "tripHeadsign", - "columnName": "tripHeadsign", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "directionId", - "columnName": "directionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "blockId", - "columnName": "blockId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wheelchairAccessible", - "columnName": "wheelchairAccessible", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Trip_routeId", - "unique": false, - "columnNames": [ - "routeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)" - } - ], - "foreignKeys": [ - { - "table": "Route", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "routeId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Shape", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "shapeId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "VersionMetadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))", - "fields": [ - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastUpdated", - "columnName": "lastUpdated", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "type" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5a7252ab3bcae4d0d0950024b19ba002')" - ] - } -} \ No newline at end of file diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/4.json b/core/room/schemas/moe.lava.banksia.core.room.Database/4.json deleted file mode 100644 index 783b3ee..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/4.json +++ /dev/null @@ -1,368 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 4, - "identityHash": "4426fd2ccc826d9d9d9021546b105850", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Stop", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "parent", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasWheelChairBoarding", - "columnName": "hasWheelChairBoarding", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "level", - "columnName": "level", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "platformCode", - "columnName": "platformCode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Stop_parent", - "unique": false, - "columnNames": [ - "parent" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)" - } - ] - }, - { - "tableName": "StopTime", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "stopId", - "columnName": "stopId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "arrivalTime", - "columnName": "arrivalTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "departureTime", - "columnName": "departureTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "headsign", - "columnName": "headsign", - "affinity": "TEXT" - }, - { - "fieldPath": "pickupType", - "columnName": "pickupType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dropOffType", - "columnName": "dropOffType", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tripId", - "stopId" - ] - }, - "indices": [ - { - "name": "index_StopTime_tripId", - "unique": true, - "columnNames": [ - "tripId" - ], - "orders": [], - "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)" - }, - { - "name": "index_StopTime_stopId", - "unique": true, - "columnNames": [ - "stopId" - ], - "orders": [], - "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)" - } - ], - "foreignKeys": [ - { - "table": "Trip", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Stop", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "stopId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "Trip", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "routeId", - "columnName": "routeId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "shapeId", - "columnName": "shapeId", - "affinity": "TEXT" - }, - { - "fieldPath": "tripHeadsign", - "columnName": "tripHeadsign", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "directionId", - "columnName": "directionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "blockId", - "columnName": "blockId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wheelchairAccessible", - "columnName": "wheelchairAccessible", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Trip_shapeId", - "unique": false, - "columnNames": [ - "shapeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)" - }, - { - "name": "index_Trip_routeId", - "unique": false, - "columnNames": [ - "routeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)" - } - ], - "foreignKeys": [ - { - "table": "Route", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "routeId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Shape", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "shapeId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "VersionMetadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))", - "fields": [ - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastUpdated", - "columnName": "lastUpdated", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "type" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '4426fd2ccc826d9d9d9021546b105850')" - ] - } -} \ No newline at end of file diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/5.json b/core/room/schemas/moe.lava.banksia.core.room.Database/5.json deleted file mode 100644 index c4a786d..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/5.json +++ /dev/null @@ -1,368 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 5, - "identityHash": "4426fd2ccc826d9d9d9021546b105850", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Stop", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "parent", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasWheelChairBoarding", - "columnName": "hasWheelChairBoarding", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "level", - "columnName": "level", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "platformCode", - "columnName": "platformCode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Stop_parent", - "unique": false, - "columnNames": [ - "parent" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)" - } - ] - }, - { - "tableName": "StopTime", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "stopId", - "columnName": "stopId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "arrivalTime", - "columnName": "arrivalTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "departureTime", - "columnName": "departureTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "headsign", - "columnName": "headsign", - "affinity": "TEXT" - }, - { - "fieldPath": "pickupType", - "columnName": "pickupType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dropOffType", - "columnName": "dropOffType", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tripId", - "stopId" - ] - }, - "indices": [ - { - "name": "index_StopTime_tripId", - "unique": true, - "columnNames": [ - "tripId" - ], - "orders": [], - "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)" - }, - { - "name": "index_StopTime_stopId", - "unique": true, - "columnNames": [ - "stopId" - ], - "orders": [], - "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)" - } - ], - "foreignKeys": [ - { - "table": "Trip", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Stop", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "stopId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "Trip", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "routeId", - "columnName": "routeId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "shapeId", - "columnName": "shapeId", - "affinity": "TEXT" - }, - { - "fieldPath": "tripHeadsign", - "columnName": "tripHeadsign", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "directionId", - "columnName": "directionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "blockId", - "columnName": "blockId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wheelchairAccessible", - "columnName": "wheelchairAccessible", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Trip_shapeId", - "unique": false, - "columnNames": [ - "shapeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)" - }, - { - "name": "index_Trip_routeId", - "unique": false, - "columnNames": [ - "routeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)" - } - ], - "foreignKeys": [ - { - "table": "Route", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "routeId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Shape", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "shapeId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "VersionMetadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))", - "fields": [ - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastUpdated", - "columnName": "lastUpdated", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "type" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '4426fd2ccc826d9d9d9021546b105850')" - ] - } -} \ No newline at end of file diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/6.json b/core/room/schemas/moe.lava.banksia.core.room.Database/6.json deleted file mode 100644 index 5ab26dc..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/6.json +++ /dev/null @@ -1,368 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 6, - "identityHash": "5f52de4cc0ddbcf02a0d8be4cf4d4cfd", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Stop", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "parent", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasWheelChairBoarding", - "columnName": "hasWheelChairBoarding", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "level", - "columnName": "level", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "platformCode", - "columnName": "platformCode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Stop_parent", - "unique": false, - "columnNames": [ - "parent" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)" - } - ] - }, - { - "tableName": "StopTime", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "stopId", - "columnName": "stopId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "arrivalTime", - "columnName": "arrivalTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "departureTime", - "columnName": "departureTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "headsign", - "columnName": "headsign", - "affinity": "TEXT" - }, - { - "fieldPath": "pickupType", - "columnName": "pickupType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dropOffType", - "columnName": "dropOffType", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tripId", - "stopId" - ] - }, - "indices": [ - { - "name": "index_StopTime_tripId", - "unique": false, - "columnNames": [ - "tripId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)" - }, - { - "name": "index_StopTime_stopId", - "unique": false, - "columnNames": [ - "stopId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)" - } - ], - "foreignKeys": [ - { - "table": "Trip", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Stop", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "stopId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "Trip", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "routeId", - "columnName": "routeId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "shapeId", - "columnName": "shapeId", - "affinity": "TEXT" - }, - { - "fieldPath": "tripHeadsign", - "columnName": "tripHeadsign", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "directionId", - "columnName": "directionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "blockId", - "columnName": "blockId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wheelchairAccessible", - "columnName": "wheelchairAccessible", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Trip_shapeId", - "unique": false, - "columnNames": [ - "shapeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)" - }, - { - "name": "index_Trip_routeId", - "unique": false, - "columnNames": [ - "routeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)" - } - ], - "foreignKeys": [ - { - "table": "Route", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "routeId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Shape", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "shapeId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "VersionMetadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))", - "fields": [ - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastUpdated", - "columnName": "lastUpdated", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "type" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5f52de4cc0ddbcf02a0d8be4cf4d4cfd')" - ] - } -} \ No newline at end of file diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/7.json b/core/room/schemas/moe.lava.banksia.core.room.Database/7.json deleted file mode 100644 index d4c62b2..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/7.json +++ /dev/null @@ -1,415 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 7, - "identityHash": "15c94df0a62438ff28d451c074c94c59", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Service", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `days` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "days", - "columnName": "days", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "start", - "columnName": "start", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "end", - "columnName": "end", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Service_days", - "unique": false, - "columnNames": [ - "days" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Service_days` ON `${TABLE_NAME}` (`days`)" - } - ] - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Stop", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "parent", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasWheelChairBoarding", - "columnName": "hasWheelChairBoarding", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "level", - "columnName": "level", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "platformCode", - "columnName": "platformCode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Stop_parent", - "unique": false, - "columnNames": [ - "parent" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)" - } - ] - }, - { - "tableName": "StopTime", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "stopId", - "columnName": "stopId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "arrivalTime", - "columnName": "arrivalTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "departureTime", - "columnName": "departureTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "headsign", - "columnName": "headsign", - "affinity": "TEXT" - }, - { - "fieldPath": "pickupType", - "columnName": "pickupType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dropOffType", - "columnName": "dropOffType", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tripId", - "stopId" - ] - }, - "indices": [ - { - "name": "index_StopTime_tripId", - "unique": false, - "columnNames": [ - "tripId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)" - }, - { - "name": "index_StopTime_stopId", - "unique": false, - "columnNames": [ - "stopId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)" - } - ], - "foreignKeys": [ - { - "table": "Trip", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Stop", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "stopId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "Trip", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "routeId", - "columnName": "routeId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "shapeId", - "columnName": "shapeId", - "affinity": "TEXT" - }, - { - "fieldPath": "tripHeadsign", - "columnName": "tripHeadsign", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "directionId", - "columnName": "directionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "blockId", - "columnName": "blockId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wheelchairAccessible", - "columnName": "wheelchairAccessible", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Trip_shapeId", - "unique": false, - "columnNames": [ - "shapeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)" - }, - { - "name": "index_Trip_routeId", - "unique": false, - "columnNames": [ - "routeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)" - } - ], - "foreignKeys": [ - { - "table": "Route", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "routeId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Shape", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "shapeId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "VersionMetadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))", - "fields": [ - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastUpdated", - "columnName": "lastUpdated", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "type" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '15c94df0a62438ff28d451c074c94c59')" - ] - } -} \ No newline at end of file diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/8.json b/core/room/schemas/moe.lava.banksia.core.room.Database/8.json deleted file mode 100644 index 9240dd5..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/8.json +++ /dev/null @@ -1,426 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 8, - "identityHash": "6e0f07bf1af88b2e37b5ad7c38a3fb2a", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Service", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `days` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "days", - "columnName": "days", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "start", - "columnName": "start", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "end", - "columnName": "end", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Service_days", - "unique": false, - "columnNames": [ - "days" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Service_days` ON `${TABLE_NAME}` (`days`)" - } - ] - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Stop", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "parent", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasWheelChairBoarding", - "columnName": "hasWheelChairBoarding", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "level", - "columnName": "level", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "platformCode", - "columnName": "platformCode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Stop_parent", - "unique": false, - "columnNames": [ - "parent" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)" - } - ] - }, - { - "tableName": "StopTime", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "stopId", - "columnName": "stopId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "arrivalTime", - "columnName": "arrivalTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "departureTime", - "columnName": "departureTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "headsign", - "columnName": "headsign", - "affinity": "TEXT" - }, - { - "fieldPath": "pickupType", - "columnName": "pickupType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dropOffType", - "columnName": "dropOffType", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tripId", - "stopId" - ] - }, - "indices": [ - { - "name": "index_StopTime_tripId", - "unique": false, - "columnNames": [ - "tripId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)" - }, - { - "name": "index_StopTime_stopId", - "unique": false, - "columnNames": [ - "stopId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)" - } - ], - "foreignKeys": [ - { - "table": "Trip", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Stop", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "stopId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "Trip", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`serviceId`) REFERENCES `Service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "routeId", - "columnName": "routeId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "shapeId", - "columnName": "shapeId", - "affinity": "TEXT" - }, - { - "fieldPath": "tripHeadsign", - "columnName": "tripHeadsign", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "directionId", - "columnName": "directionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "blockId", - "columnName": "blockId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wheelchairAccessible", - "columnName": "wheelchairAccessible", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Trip_shapeId", - "unique": false, - "columnNames": [ - "shapeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)" - }, - { - "name": "index_Trip_routeId", - "unique": false, - "columnNames": [ - "routeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)" - } - ], - "foreignKeys": [ - { - "table": "Route", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "routeId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Service", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "serviceId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Shape", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "shapeId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "VersionMetadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))", - "fields": [ - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastUpdated", - "columnName": "lastUpdated", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "type" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6e0f07bf1af88b2e37b5ad7c38a3fb2a')" - ] - } -} \ No newline at end of file diff --git a/core/room/schemas/moe.lava.banksia.core.room.Database/9.json b/core/room/schemas/moe.lava.banksia.core.room.Database/9.json deleted file mode 100644 index 2359dbd..0000000 --- a/core/room/schemas/moe.lava.banksia.core.room.Database/9.json +++ /dev/null @@ -1,426 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 9, - "identityHash": "6e0f07bf1af88b2e37b5ad7c38a3fb2a", - "entities": [ - { - "tableName": "Route", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT" - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Service", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `days` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "days", - "columnName": "days", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "start", - "columnName": "start", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "end", - "columnName": "end", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Service_days", - "unique": false, - "columnNames": [ - "days" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Service_days` ON `${TABLE_NAME}` (`days`)" - } - ] - }, - { - "tableName": "Shape", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "path", - "columnName": "path", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "Stop", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lat", - "columnName": "lat", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "lng", - "columnName": "lng", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "parent", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasWheelChairBoarding", - "columnName": "hasWheelChairBoarding", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "level", - "columnName": "level", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "platformCode", - "columnName": "platformCode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Stop_parent", - "unique": false, - "columnNames": [ - "parent" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)" - } - ] - }, - { - "tableName": "StopTime", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "tripId", - "columnName": "tripId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "stopId", - "columnName": "stopId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "arrivalTime", - "columnName": "arrivalTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "departureTime", - "columnName": "departureTime", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "headsign", - "columnName": "headsign", - "affinity": "TEXT" - }, - { - "fieldPath": "pickupType", - "columnName": "pickupType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dropOffType", - "columnName": "dropOffType", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "tripId", - "stopId" - ] - }, - "indices": [ - { - "name": "index_StopTime_tripId", - "unique": false, - "columnNames": [ - "tripId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)" - }, - { - "name": "index_StopTime_stopId", - "unique": false, - "columnNames": [ - "stopId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)" - } - ], - "foreignKeys": [ - { - "table": "Trip", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "tripId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Stop", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "stopId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "Trip", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`serviceId`) REFERENCES `Service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "routeId", - "columnName": "routeId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "serviceId", - "columnName": "serviceId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "shapeId", - "columnName": "shapeId", - "affinity": "TEXT" - }, - { - "fieldPath": "tripHeadsign", - "columnName": "tripHeadsign", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "directionId", - "columnName": "directionId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "blockId", - "columnName": "blockId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wheelchairAccessible", - "columnName": "wheelchairAccessible", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_Trip_shapeId", - "unique": false, - "columnNames": [ - "shapeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)" - }, - { - "name": "index_Trip_routeId", - "unique": false, - "columnNames": [ - "routeId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)" - } - ], - "foreignKeys": [ - { - "table": "Route", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "routeId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Service", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "serviceId" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "Shape", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "shapeId" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "VersionMetadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))", - "fields": [ - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "lastUpdated", - "columnName": "lastUpdated", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "type" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6e0f07bf1af88b2e37b5ad7c38a3fb2a')" - ] - } -} \ No newline at end of file diff --git a/core/room/src/androidMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.android.kt b/core/room/src/androidMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.android.kt deleted file mode 100644 index 999ee4b..0000000 --- a/core/room/src/androidMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.android.kt +++ /dev/null @@ -1,22 +0,0 @@ -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() - - actual val database by lazy { - val ctx = get().applicationContext - val dbFile = ctx.getDatabasePath("room.db") - val builder = Room.databaseBuilder( - context = ctx, - name = dbFile.absolutePath, - ) - - Database.build(builder) - } -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/Database.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/Database.kt deleted file mode 100644 index 006b749..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/Database.kt +++ /dev/null @@ -1,83 +0,0 @@ -package moe.lava.banksia.core.room - -import androidx.room.AutoMigration -import androidx.room.RoomDatabase -import androidx.room.TypeConverters -import androidx.room.migration.Migration -import androidx.room.util.foreignKeyCheck -import androidx.sqlite.SQLiteConnection -import androidx.sqlite.driver.bundled.BundledSQLiteDriver -import androidx.sqlite.execSQL -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.IO -import moe.lava.banksia.core.room.converter.RouteTypeConverter -import moe.lava.banksia.core.room.dao.RouteDao -import moe.lava.banksia.core.room.dao.ServiceDao -import moe.lava.banksia.core.room.dao.ServiceExceptionDao -import moe.lava.banksia.core.room.dao.ShapeDao -import moe.lava.banksia.core.room.dao.StopDao -import moe.lava.banksia.core.room.dao.StopTimeDao -import moe.lava.banksia.core.room.dao.TripDao -import moe.lava.banksia.core.room.dao.VersionMetadataDao -import moe.lava.banksia.core.room.entity.RouteEntity -import moe.lava.banksia.core.room.entity.ServiceEntity -import moe.lava.banksia.core.room.entity.ServiceExceptionEntity -import moe.lava.banksia.core.room.entity.ShapeEntity -import moe.lava.banksia.core.room.entity.StopEntity -import moe.lava.banksia.core.room.entity.StopTimeEntity -import moe.lava.banksia.core.room.entity.TripEntity -import moe.lava.banksia.core.room.entity.VersionMetadataEntity -import androidx.room.Database as DatabaseAnnotation - -@DatabaseAnnotation( - version = 11, - entities = [ - RouteEntity::class, - ServiceEntity::class, - ServiceExceptionEntity::class, - ShapeEntity::class, - StopEntity::class, - StopTimeEntity::class, - TripEntity::class, - VersionMetadataEntity::class, - ], - autoMigrations = [ - AutoMigration(from = 1, to = 2), - AutoMigration(from = 2, to = 3), - AutoMigration(from = 9, to = 10), - ] -) -@TypeConverters(RouteTypeConverter::class) -abstract class Database : RoomDatabase() { - abstract val versionMetadataDao: VersionMetadataDao - abstract val routeDao: RouteDao - abstract val serviceDao: ServiceDao - abstract val serviceExceptionDao: ServiceExceptionDao - abstract val shapeDao: ShapeDao - abstract val stopDao: StopDao - abstract val stopTimeDao: StopTimeDao - abstract val tripDao: TripDao - - companion object { - fun build(base: Builder) = - base.fallbackToDestructiveMigration(true) - .setDriver(BundledSQLiteDriver()) - .setQueryCoroutineContext(Dispatchers.IO) - .addMigrations(MIGRATION_10_11) -// .fallbackToDestructiveMigration(true) - .build() - } -} - -val MIGRATION_10_11 = object : Migration(10, 11) { - override fun migrate(connection: SQLiteConnection) { - connection.execSQL("CREATE TABLE IF NOT EXISTS `_new_Stop` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`parent`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED)") - connection.execSQL("INSERT INTO `_new_Stop` (`id`,`name`,`lat`,`lng`,`parent`,`hasWheelChairBoarding`,`level`,`platformCode`) SELECT `id`,`name`,`lat`,`lng`,`parent`,`hasWheelChairBoarding`,`level`,`platformCode` FROM `Stop`") - connection.execSQL("UPDATE `_new_Stop` SET `parent` = NULL WHERE `parent` == \"\"") - connection.execSQL("DROP TABLE `Stop`") - connection.execSQL("ALTER TABLE `_new_Stop` RENAME TO `Stop`") - connection.execSQL("CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `Stop` (`parent`)") - connection.execSQL("CREATE INDEX IF NOT EXISTS `index_Trip_serviceId` ON `Trip` (`serviceId`)") - foreignKeyCheck(connection, "Stop") - } -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.kt deleted file mode 100644 index bfe32a9..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.kt +++ /dev/null @@ -1,7 +0,0 @@ -package moe.lava.banksia.core.room - -import org.koin.core.component.KoinComponent - -expect class DatabaseManager() : KoinComponent { - val database: Database -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/RoomDiModule.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/RoomDiModule.kt deleted file mode 100644 index 85c56fc..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/RoomDiModule.kt +++ /dev/null @@ -1,18 +0,0 @@ -package moe.lava.banksia.core.room - -import org.koin.core.module.dsl.singleOf -import org.koin.dsl.module - -val roomDiModule = module { - singleOf(::DatabaseManager) - factory { get().database } - - factory { get().versionMetadataDao } - factory { get().routeDao } - factory { get().serviceDao } - factory { get().serviceExceptionDao } - factory { get().shapeDao } - factory { get().stopDao } - factory { get().stopTimeDao } - factory { get().tripDao } -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/converter/RouteTypeConverter.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/converter/RouteTypeConverter.kt deleted file mode 100644 index f588a66..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/converter/RouteTypeConverter.kt +++ /dev/null @@ -1,12 +0,0 @@ -package moe.lava.banksia.core.room.converter - -import androidx.room.TypeConverter -import moe.lava.banksia.core.model.RouteType - -object RouteTypeConverter { - @TypeConverter - fun from(value: Int) = RouteType.from(value) - - @TypeConverter - fun to(routeType: RouteType) = routeType.value -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/converter/ShapePathConverter.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/converter/ShapePathConverter.kt deleted file mode 100644 index b914cff..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/converter/ShapePathConverter.kt +++ /dev/null @@ -1,43 +0,0 @@ -package moe.lava.banksia.core.room.converter - -import androidx.room.TypeConverter -import moe.lava.banksia.core.model.ShapePath -import moe.lava.banksia.core.util.Point - -object ShapePathConverter { - @TypeConverter - fun from(value: ByteArray): ShapePath { - return value - .asIterable() - .chunked(8) { - (it[0].toLong() and 0xFF) or - (it[1].toLong() and 0xFF shl 8) or - (it[2].toLong() and 0xFF shl 16) or - (it[3].toLong() and 0xFF shl 24) or - (it[4].toLong() and 0xFF shl 32) or - (it[5].toLong() and 0xFF shl 40) or - (it[6].toLong() and 0xFF shl 48) or - (it[7].toLong() and 0xFF shl 56) - } - .map { Double.fromBits(it) } - .chunked(2) - .map { (lat, lng) -> Point(lat, lng) } - } - - @TypeConverter - fun to(path: ShapePath): ByteArray { - return path - .flatMap { (lat, lng) -> listOf(lat.toBits(), lng.toBits()) } - .flatMap { i -> listOf( - i.toByte(), - (i shr 8).toByte(), - (i shr 16).toByte(), - (i shr 24).toByte(), - (i shr 32).toByte(), - (i shr 40).toByte(), - (i shr 48).toByte(), - (i shr 56).toByte(), - ) } - .toByteArray() - } -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/RouteDao.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/RouteDao.kt deleted file mode 100644 index c791f81..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/RouteDao.kt +++ /dev/null @@ -1,58 +0,0 @@ -package moe.lava.banksia.core.room.dao - -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.OnConflictStrategy.Companion.REPLACE -import androidx.room.Query -import moe.lava.banksia.core.room.entity.RouteEntity -import moe.lava.banksia.core.room.entity.StopEntity - -@Dao -interface RouteDao { - @Query("SELECT * FROM Route") - suspend fun getAll(): List - - @Query("SELECT * FROM Route WHERE id == :id") - suspend fun get(id: String): RouteEntity? - - @Insert - suspend fun insertAll(vararg routes: RouteEntity) - - @Insert(onConflict = REPLACE) - suspend fun insertOrReplaceAll(vararg routes: RouteEntity) - - @Delete - suspend fun delete(route: RouteEntity) - - @Query("DELETE FROM Route") - suspend fun deleteAll() - - @Query(""" - SELECT Stop.* FROM Stop - INNER JOIN StopTime ON StopTime.stopId == Stop.id - INNER JOIN Trip ON Trip.id == StopTime.tripId - WHERE Trip.routeId == :id - GROUP BY Stop.id - """) - suspend fun stops(id: String): List - - // I vibecoded this, sorry - @Query(""" - WITH Tree AS ( - SELECT Stop.* FROM Stop - INNER JOIN StopTime ON StopTime.stopId == Stop.id - INNER JOIN Trip ON Trip.id == StopTime.tripId - WHERE Trip.routeId == :id - GROUP BY Stop.id - - UNION ALL - - SELECT s.* - FROM Stop s - INNER JOIN Tree t ON s.id = t.parent - ) - SELECT DISTINCT * FROM Tree WHERE parent IS NULL; - """) - suspend fun stopsParent(id: String): List -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/ServiceDao.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/ServiceDao.kt deleted file mode 100644 index e459cdf..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/ServiceDao.kt +++ /dev/null @@ -1,29 +0,0 @@ -package moe.lava.banksia.core.room.dao - -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.OnConflictStrategy.Companion.REPLACE -import androidx.room.Query -import moe.lava.banksia.core.room.entity.ServiceEntity - -@Dao -interface ServiceDao { - @Query("SELECT * FROM Service") - suspend fun getAll(): List - - @Query("SELECT * FROM Service WHERE id == :id") - suspend fun get(id: String): ServiceEntity? - - @Insert - suspend fun insertAll(vararg services: ServiceEntity) - - @Insert(onConflict = REPLACE) - suspend fun insertOrReplaceAll(vararg services: ServiceEntity) - - @Delete - suspend fun delete(service: ServiceEntity) - - @Query("DELETE FROM Service") - suspend fun deleteAll() -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/ServiceExceptionDao.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/ServiceExceptionDao.kt deleted file mode 100644 index 86feb75..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/ServiceExceptionDao.kt +++ /dev/null @@ -1,29 +0,0 @@ -package moe.lava.banksia.core.room.dao - -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.OnConflictStrategy.Companion.REPLACE -import androidx.room.Query -import moe.lava.banksia.core.room.entity.ServiceExceptionEntity - -@Dao -interface ServiceExceptionDao { - @Query("SELECT * FROM ServiceException") - suspend fun getAll(): List - - @Query("SELECT * FROM ServiceException WHERE serviceId == :id") - suspend fun get(id: String): List - - @Insert - suspend fun insertAll(vararg exceptions: ServiceExceptionEntity) - - @Insert(onConflict = REPLACE) - suspend fun insertOrReplaceAll(vararg exceptions: ServiceExceptionEntity) - - @Delete - suspend fun delete(service: ServiceExceptionEntity) - - @Query("DELETE FROM ServiceException") - suspend fun deleteAll() -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/ShapeDao.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/ShapeDao.kt deleted file mode 100644 index 446a923..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/ShapeDao.kt +++ /dev/null @@ -1,26 +0,0 @@ -package moe.lava.banksia.core.room.dao - -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.OnConflictStrategy.Companion.REPLACE -import androidx.room.Query -import moe.lava.banksia.core.room.entity.ShapeEntity - -@Dao -interface ShapeDao { - @Query("SELECT * FROM Shape WHERE id == :id") - suspend fun get(id: String): ShapeEntity? - - @Insert - suspend fun insertAll(vararg shapes: ShapeEntity) - - @Insert(onConflict = REPLACE) - suspend fun insertOrReplaceAll(vararg shapes: ShapeEntity) - - @Delete - suspend fun delete(shape: ShapeEntity) - - @Query("DELETE FROM Shape") - suspend fun deleteAll() -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/StopDao.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/StopDao.kt deleted file mode 100644 index 7edb560..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/StopDao.kt +++ /dev/null @@ -1,42 +0,0 @@ -package moe.lava.banksia.core.room.dao - -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.OnConflictStrategy.Companion.REPLACE -import androidx.room.Query -import moe.lava.banksia.core.room.entity.StopEntity - -@Dao -interface StopDao { - @Query("SELECT * FROM Stop") - suspend fun getAll(): List - - @Query(""" - SELECT * FROM Stop - WHERE platformCode <> "" - AND parent IS NULL - """) - suspend fun getAllParentless(): List - - @Query("SELECT * FROM Stop WHERE id == :id") - suspend fun get(id: String): StopEntity? - - @Query("SELECT * FROM Stop WHERE id IN (:ids)") - suspend fun get(ids: List): List - - @Insert - suspend fun insertAll(vararg stops: StopEntity) - - @Insert(onConflict = REPLACE) - suspend fun insertOrReplaceAll(vararg stops: StopEntity) - - @Delete - suspend fun delete(stop: StopEntity) - - @Query("DELETE FROM Stop") - suspend fun deleteAll() - - @Query("UPDATE Stop SET parent = :parent WHERE id IN (:ids)") - suspend fun updateParents(ids: List, parent: String) -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/StopTimeDao.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/StopTimeDao.kt deleted file mode 100644 index 4670b6e..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/StopTimeDao.kt +++ /dev/null @@ -1,46 +0,0 @@ -package moe.lava.banksia.core.room.dao - -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.OnConflictStrategy.Companion.REPLACE -import androidx.room.Query -import moe.lava.banksia.core.room.entity.StopTimeEntity - -@Dao -interface StopTimeDao { - @Query("SELECT * FROM StopTime") - suspend fun getAll(): List - - @Query("SELECT * FROM StopTime WHERE tripId == :tripId") - suspend fun getForTrip(tripId: String): StopTimeEntity? - - @Query("SELECT * FROM StopTime WHERE tripId IN (:tripIds)") - suspend fun getForTrips(tripIds: List): List - - @Query("SELECT * FROM StopTime WHERE stopId == :stopId") - suspend fun getForStop(stopId: String): List - - @Query(""" - SELECT DISTINCT StopTime.* FROM StopTime - INNER JOIN Service ON Service.days & :days = :days AND :date BETWEEN Service.start AND Service.`end` - INNER JOIN Trip ON Trip.serviceId == Service.id - LEFT JOIN ServiceException ON ServiceException.serviceId == Service.id AND ServiceException.date == :date - WHERE StopTime.tripId == Trip.id - AND StopTime.stopId IN (SELECT Stop.id FROM Stop WHERE Stop.parent == :stopId OR Stop.id == :stopId) - AND ServiceException.type IS NULL - """) - suspend fun getForStopDated(stopId: String, days: Int, date: Int): List - - @Insert - suspend fun insertAll(vararg stopTimes: StopTimeEntity) - - @Insert(onConflict = REPLACE) - suspend fun insertOrReplaceAll(vararg stopTimes: StopTimeEntity) - - @Delete - suspend fun delete(stopTime: StopTimeEntity) - - @Query("DELETE FROM StopTime") - suspend fun deleteAll() -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/TripDao.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/TripDao.kt deleted file mode 100644 index 1798f61..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/TripDao.kt +++ /dev/null @@ -1,32 +0,0 @@ -package moe.lava.banksia.core.room.dao - -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.OnConflictStrategy.Companion.REPLACE -import androidx.room.Query -import moe.lava.banksia.core.room.entity.TripEntity - -@Dao -interface TripDao { - @Query("SELECT * FROM Trip") - suspend fun getAll(): List - - @Query("SELECT * FROM Trip WHERE id == :id") - suspend fun get(id: String): TripEntity? - - @Query("SELECT * FROM Trip WHERE routeId == :id") - suspend fun getByRoute(id: String): List - - @Insert - suspend fun insertAll(vararg trips: TripEntity) - - @Insert(onConflict = REPLACE) - suspend fun insertOrReplaceAll(vararg trips: TripEntity) - - @Delete - suspend fun delete(trip: TripEntity) - - @Query("DELETE FROM Trip") - suspend fun deleteAll() -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/VersionMetadataDao.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/VersionMetadataDao.kt deleted file mode 100644 index 357770d..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/dao/VersionMetadataDao.kt +++ /dev/null @@ -1,27 +0,0 @@ -package moe.lava.banksia.core.room.dao - -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy.Companion.REPLACE -import androidx.room.Query -import moe.lava.banksia.core.room.entity.VersionMetadataEntity - -@Dao -interface VersionMetadataDao { - @Query("SELECT * FROM VersionMetadata WHERE type == :type") - suspend fun get(type: String): VersionMetadataEntity? - - @Query("SELECT * FROM VersionMetadata") - suspend fun getAll(): List - - @Insert(onConflict = REPLACE) - suspend fun update(vararg data: VersionMetadataEntity) - - suspend fun update(vararg data: Pair) { - update(*data.map { (type, lastUpdated) -> VersionMetadataEntity(type, lastUpdated) }.toTypedArray()) - } - - suspend fun update(lastUpdated: Long, types: Collection) { - update(*types.map { VersionMetadataEntity(it, lastUpdated) }.toTypedArray()) - } -} diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/RouteEntity.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/RouteEntity.kt deleted file mode 100644 index 8feda0b..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/RouteEntity.kt +++ /dev/null @@ -1,18 +0,0 @@ -package moe.lava.banksia.core.room.entity - -import androidx.room.Entity -import androidx.room.PrimaryKey -import moe.lava.banksia.core.model.Route -import moe.lava.banksia.core.model.RouteType - -@Entity("Route") -data class RouteEntity( - @PrimaryKey val id: String, - val type: RouteType, - val number: String?, - val name: String, -) { - fun asModel() = Route(id, type, number, name) -} - -fun Route.asEntity() = RouteEntity(id, type, number, name) diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/ServiceEntity.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/ServiceEntity.kt deleted file mode 100644 index 4a1c8b7..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/ServiceEntity.kt +++ /dev/null @@ -1,31 +0,0 @@ -package moe.lava.banksia.core.room.entity - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.PrimaryKey -import kotlinx.datetime.LocalDate -import moe.lava.banksia.core.model.Service -import moe.lava.banksia.core.util.deserialiseDaysBitflag -import moe.lava.banksia.core.util.serialise - -@Entity("Service") -data class ServiceEntity( - @PrimaryKey val id: String, - @ColumnInfo(index = true) val days: Int, - val start: Int, - val end: Int, -) { - fun asModel() = Service( - id, - days.deserialiseDaysBitflag(), - LocalDate.fromEpochDays(start), - LocalDate.fromEpochDays(end), - ) -} - -fun Service.asEntity() = ServiceEntity( - id, - days.serialise(), - start.toEpochDays().toInt(), - end.toEpochDays().toInt(), -) diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/ServiceExceptionEntity.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/ServiceExceptionEntity.kt deleted file mode 100644 index 1ac45d3..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/ServiceExceptionEntity.kt +++ /dev/null @@ -1,28 +0,0 @@ -package moe.lava.banksia.core.room.entity - -import androidx.room.ColumnInfo -import androidx.room.Entity -import kotlinx.datetime.LocalDate -import moe.lava.banksia.core.model.ServiceException - -@Entity( - "ServiceException", - primaryKeys = ["serviceId", "date"] -) -data class ServiceExceptionEntity( - @ColumnInfo(index = true) val serviceId: String, - val date: Int, - @ColumnInfo(index = true) val type: Int, -) { - fun asModel() = ServiceException( - serviceId, - LocalDate.fromEpochDays(date), - type, - ) -} - -fun ServiceException.asEntity() = ServiceExceptionEntity( - serviceId, - date.toEpochDays().toInt(), - type, -) diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/ShapeEntity.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/ShapeEntity.kt deleted file mode 100644 index a19147d..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/ShapeEntity.kt +++ /dev/null @@ -1,19 +0,0 @@ -package moe.lava.banksia.core.room.entity - -import androidx.room.Entity -import androidx.room.PrimaryKey -import androidx.room.TypeConverters -import moe.lava.banksia.core.model.Shape -import moe.lava.banksia.core.model.ShapePath -import moe.lava.banksia.core.room.converter.ShapePathConverter - -@Entity("Shape") -@TypeConverters(ShapePathConverter::class) -data class ShapeEntity( - @PrimaryKey val id: String, - val path: ShapePath, -) { - fun asModel() = Shape(id, path) -} - -fun Shape.asEntity() = ShapeEntity(id, path) diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/StopEntity.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/StopEntity.kt deleted file mode 100644 index f59c5da..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/StopEntity.kt +++ /dev/null @@ -1,36 +0,0 @@ -package moe.lava.banksia.core.room.entity - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.ForeignKey -import androidx.room.ForeignKey.Companion.SET_NULL -import androidx.room.PrimaryKey -import moe.lava.banksia.core.model.Stop -import moe.lava.banksia.core.util.Point - -@Entity( - "Stop", - foreignKeys = [ - ForeignKey( - StopEntity::class, - parentColumns = ["id"], - childColumns = ["parent"], - onDelete = SET_NULL, - deferred = true, - ), - ] -) -data class StopEntity( - @PrimaryKey val id: String, - val name: String, - val lat: Double, - val lng: Double, - @ColumnInfo(index = true) val parent: String?, - val hasWheelChairBoarding: Boolean, - val level: String, - val platformCode: String, -) { - fun asModel() = Stop(id, name, Point(lat, lng), parent, hasWheelChairBoarding, level, platformCode) -} - -fun Stop.asEntity() = StopEntity(id, name, pos.lat, pos.lng, parent, hasWheelChairBoarding, level, platformCode) diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/StopTimeEntity.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/StopTimeEntity.kt deleted file mode 100644 index d96036d..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/StopTimeEntity.kt +++ /dev/null @@ -1,53 +0,0 @@ -package moe.lava.banksia.core.room.entity - -import androidx.room.Entity -import androidx.room.ForeignKey -import androidx.room.ForeignKey.Companion.CASCADE -import androidx.room.Index -import kotlinx.serialization.ExperimentalSerializationApi -import moe.lava.banksia.core.model.FutureTime -import moe.lava.banksia.core.model.FutureTime.Companion.asInt -import moe.lava.banksia.core.model.StopTime - -@Entity( - "StopTime", - primaryKeys = ["tripId", "stopId"], - indices = [ - Index("tripId", unique = false), - Index("stopId", unique = false), - ], - foreignKeys = [ - ForeignKey(TripEntity::class, parentColumns = ["id"], childColumns = ["tripId"], onDelete = CASCADE), - ForeignKey(StopEntity::class, parentColumns = ["id"], childColumns = ["stopId"], onDelete = CASCADE), - ] -) -data class StopTimeEntity( - val tripId: String, - val stopId: String, - val arrivalTime: Int, - val departureTime: Int, - val headsign: String?, - val pickupType: Int, - val dropOffType: Int, -) { - fun asModel() = StopTime( - tripId, - stopId, - FutureTime.fromInt(arrivalTime), - FutureTime.fromInt(departureTime), - headsign, - pickupType, - dropOffType, - ) -} - -@OptIn(ExperimentalSerializationApi::class) -fun StopTime.asEntity() = StopTimeEntity( - tripId, - stopId, - arrivalTime.asInt(), - departureTime.asInt(), - headsign, - pickupType, - dropOffType, -) diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/TripEntity.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/TripEntity.kt deleted file mode 100644 index 7928c60..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/TripEntity.kt +++ /dev/null @@ -1,49 +0,0 @@ -package moe.lava.banksia.core.room.entity - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.ForeignKey -import androidx.room.ForeignKey.Companion.CASCADE -import androidx.room.Index -import androidx.room.PrimaryKey -import moe.lava.banksia.core.model.Trip - -@Entity( - "Trip", - foreignKeys = [ - ForeignKey(RouteEntity::class, parentColumns = ["id"], childColumns = ["routeId"], onDelete = CASCADE), - ForeignKey(ServiceEntity::class, parentColumns = ["id"], childColumns = ["serviceId"], onDelete = CASCADE), - ForeignKey(ShapeEntity::class, parentColumns = ["id"], childColumns = ["shapeId"], onDelete = CASCADE), - ], - indices = [Index("shapeId"), Index("serviceId")], -) -data class TripEntity( - @PrimaryKey val id: String, - @ColumnInfo(index = true) val routeId: String, - val serviceId: String, - val shapeId: String?, - val tripHeadsign: String, - val directionId: String, - val blockId: String, - val wheelchairAccessible: String, -) - -fun Trip.Companion.from(tripEntity: TripEntity, serviceEntity: ServiceEntity): Trip { - if (tripEntity.serviceId != serviceEntity.id) { - throw IllegalArgumentException("trip and service id mismatch (${tripEntity.serviceId} != ${serviceEntity.id})") - } - return with(tripEntity) { - Trip( - id = id, - routeId = routeId, - service = serviceEntity.asModel(), - shapeId = shapeId, - tripHeadsign = tripHeadsign, - directionId = directionId, - blockId = blockId, - wheelchairAccessible = wheelchairAccessible - ) - } -} - -fun Trip.asEntity() = TripEntity(id, routeId, service.id, shapeId, tripHeadsign, directionId, blockId, wheelchairAccessible) diff --git a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/VersionMetadataEntity.kt b/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/VersionMetadataEntity.kt deleted file mode 100644 index 1e7cab9..0000000 --- a/core/room/src/commonMain/kotlin/moe/lava/banksia/core/room/entity/VersionMetadataEntity.kt +++ /dev/null @@ -1,19 +0,0 @@ -package moe.lava.banksia.core.room.entity - -import androidx.room.Entity -import androidx.room.PrimaryKey -import moe.lava.banksia.core.model.VersionMetadata - -@Entity( - "VersionMetadata", -) -data class VersionMetadataEntity( - /** Entity type this metadata applies to */ - @PrimaryKey val type: String, - /** Last updated */ - val lastUpdated: Long, -) { - fun asModel() = VersionMetadata(type, lastUpdated) -} - -fun VersionMetadata.asEntity() = VersionMetadataEntity(type, lastUpdated) diff --git a/core/room/src/iosMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.ios.kt b/core/room/src/iosMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.ios.kt deleted file mode 100644 index 34e370e..0000000 --- a/core/room/src/iosMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.ios.kt +++ /dev/null @@ -1,8 +0,0 @@ -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") -} diff --git a/core/room/src/jvmMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.jvm.kt b/core/room/src/jvmMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.jvm.kt deleted file mode 100644 index 360d2dd..0000000 --- a/core/room/src/jvmMain/kotlin/moe/lava/banksia/core/room/DatabaseManager.jvm.kt +++ /dev/null @@ -1,69 +0,0 @@ -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 { - val dbFile = File(path) - return Room.databaseBuilder( - 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.takeIf { it.exists() }?.delete() - val r2 = File(file.parentFile, file.name + ".lck").takeIf { it.exists() }?.delete() - val r3 = File(file.parentFile, file.name + "-journal").takeIf { it.exists() }?.delete() - return r1 != false && r2 != false && r3 != false - } - - private fun renameAll(from: File, to: File): Boolean { - val r1 = from.takeIf { it.exists() }?.renameTo(to) - val r2 = File(from.parentFile, from.name + ".lck").takeIf { it.exists() }?.renameTo(File(to.parentFile, to.name + ".lck")) - val r3 = File(from.parentFile, from.name + "-journal").takeIf { it.exists() }?.renameTo(File(to.parentFile, to.name + "-journal")) - return r1 != false && r2 != false && r3 != false - } - - 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() - } - } -} diff --git a/core/room/build.gradle.kts b/core/sqld/build.gradle.kts similarity index 55% rename from core/room/build.gradle.kts rename to core/sqld/build.gradle.kts index 31a7393..472a908 100644 --- a/core/room/build.gradle.kts +++ b/core/sqld/build.gradle.kts @@ -4,17 +4,12 @@ plugins { alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.kotlinSerialization) alias(libs.plugins.androidMultiplatformLibrary) - alias(libs.plugins.ksp) - alias(libs.plugins.room) -} - -room { - schemaDirectory("$projectDir/schemas") + alias(libs.plugins.sqldelight) } kotlin { android { - namespace = "moe.lava.banksia.core.room" + namespace = "moe.lava.banksia.core.sqld" compileSdk = libs.versions.android.compileSdk.get().toInt() compilerOptions { @@ -22,33 +17,37 @@ kotlin { } } - compilerOptions { - freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime") - } - iosArm64() iosSimulatorArm64() jvm() sourceSets { + androidMain.dependencies { + implementation(libs.sqldelight.driver.android) + } commonMain.dependencies { implementation(libs.okio) implementation(libs.koin.core) implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.datetime) - implementation(libs.kotlinx.serialization.json) - implementation(libs.room.runtime) - implementation(libs.sqlite.bundled) implementation(projects.core) } + nativeMain.dependencies { + implementation(libs.sqldelight.driver.native) + } + jvmMain.dependencies { + implementation(libs.sqldelight.driver.jvm) + } } } -dependencies { - add("kspAndroid", libs.room.compiler) - add("kspIosArm64", libs.room.compiler) - add("kspIosSimulatorArm64", libs.room.compiler) - add("kspJvm", libs.room.compiler) +sqldelight { + databases { + register("BanksiaDatabase") { + packageName.set("moe.lava.banksia.core.sqld") + schemaOutputDirectory.set(file("src/commonMain/sqldelight/schema")) + } + } } diff --git a/core/sqld/src/androidMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.android.kt b/core/sqld/src/androidMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.android.kt new file mode 100644 index 0000000..c47613c --- /dev/null +++ b/core/sqld/src/androidMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.android.kt @@ -0,0 +1,14 @@ +package moe.lava.banksia.core.sqld + +import android.content.Context +import app.cash.sqldelight.driver.android.AndroidSqliteDriver +import org.koin.core.component.KoinComponent +import org.koin.core.component.get + +actual class DatabaseManager : KoinComponent { + actual val database by lazy { + val ctx = get().applicationContext + val driver = AndroidSqliteDriver(BanksiaDatabase.Schema, ctx, "${DBNAME}.db") + BanksiaDatabase(driver) + } +} diff --git a/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.kt b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.kt new file mode 100644 index 0000000..983eb58 --- /dev/null +++ b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.kt @@ -0,0 +1,7 @@ +package moe.lava.banksia.core.sqld + +internal const val DBNAME = "timetable" + +expect class DatabaseManager() { + val database: BanksiaDatabase +} diff --git a/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/SqldDiModule.kt b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/SqldDiModule.kt new file mode 100644 index 0000000..deee453 --- /dev/null +++ b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/SqldDiModule.kt @@ -0,0 +1,17 @@ +package moe.lava.banksia.core.sqld + +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module + +val sqldDiModule = module { + singleOf(::DatabaseManager) + factory { get().database } + factory { get().routeQueries } + factory { get().serviceQueries } + factory { get().serviceExceptionQueries } + factory { get().shapeQueries } + factory { get().stopQueries } + factory { get().stoppingPatternQueries } + factory { get().stopTimeQueries } + factory { get().tripQueries } +} diff --git a/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Route.kt b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Route.kt new file mode 100644 index 0000000..f3a5521 --- /dev/null +++ b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Route.kt @@ -0,0 +1,14 @@ +package moe.lava.banksia.core.sqld.mappers + +import moe.lava.banksia.core.model.Route +import moe.lava.banksia.core.model.RouteType +import moe.lava.banksia.core.sqld.Route as DbRoute + +fun DbRoute.asModel() = Route( + id = id, + type = RouteType.from(type.toInt()), + number = number, + name = name, +) + +fun Route.asDb() = DbRoute(id, type.value.toLong(), number, name) diff --git a/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Service.kt b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Service.kt new file mode 100644 index 0000000..dbda5ea --- /dev/null +++ b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Service.kt @@ -0,0 +1,21 @@ +package moe.lava.banksia.core.sqld.mappers + +import kotlinx.datetime.LocalDate +import moe.lava.banksia.core.model.Service +import moe.lava.banksia.core.util.deserialiseDaysBitflag +import moe.lava.banksia.core.util.serialise +import moe.lava.banksia.core.sqld.Service as DbService + +fun DbService.asModel() = Service( + id = id, + days = days.toInt().deserialiseDaysBitflag(), + start = LocalDate.fromEpochDays(start), + end = LocalDate.fromEpochDays(end), +) + +fun Service.asDb() = DbService( + id = id, + days = days.serialise().toLong(), + start = start.toEpochDays(), + end = end.toEpochDays(), +) diff --git a/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/ServiceException.kt b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/ServiceException.kt new file mode 100644 index 0000000..ef0d201 --- /dev/null +++ b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/ServiceException.kt @@ -0,0 +1,17 @@ +package moe.lava.banksia.core.sqld.mappers + +import kotlinx.datetime.LocalDate +import moe.lava.banksia.core.model.ServiceException +import moe.lava.banksia.core.sqld.ServiceException as DbServiceException + +fun DbServiceException.asModel() = ServiceException( + serviceId = serviceId, + date = LocalDate.fromEpochDays(date), + type = type.toInt(), +) + +fun ServiceException.asDb() = DbServiceException( + serviceId = serviceId, + type = date.toEpochDays(), + date = type.toLong(), +) diff --git a/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Shape.kt b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Shape.kt new file mode 100644 index 0000000..4a8d7db --- /dev/null +++ b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Shape.kt @@ -0,0 +1,52 @@ +package moe.lava.banksia.core.sqld.mappers + +import moe.lava.banksia.core.model.Shape +import moe.lava.banksia.core.model.ShapePath +import moe.lava.banksia.core.util.Point +import moe.lava.banksia.core.sqld.Shape as DbShape + +fun DbShape.asModel() = Shape( + id = id, + path = bytesToPath(path), +) + +fun Shape.asDb() = DbShape( + id = id, + path = bytesFromPath(path), +) + +private fun bytesToPath(value: ByteArray): ShapePath { + return value + .asSequence() + .asIterable() + .chunked(8) { + (it[0].toLong() and 0xFF) or + (it[1].toLong() and 0xFF shl 8) or + (it[2].toLong() and 0xFF shl 16) or + (it[3].toLong() and 0xFF shl 24) or + (it[4].toLong() and 0xFF shl 32) or + (it[5].toLong() and 0xFF shl 40) or + (it[6].toLong() and 0xFF shl 48) or + (it[7].toLong() and 0xFF shl 56) + } + .map { Double.fromBits(it) } + .chunked(2) + .map { (lat, lng) -> Point(lat, lng) } + .toList() +} + +private fun bytesFromPath(path: ShapePath): ByteArray { + return path + .flatMap { (lat, lng) -> listOf(lat.toBits(), lng.toBits()) } + .flatMap { i -> listOf( + i.toByte(), + (i shr 8).toByte(), + (i shr 16).toByte(), + (i shr 24).toByte(), + (i shr 32).toByte(), + (i shr 40).toByte(), + (i shr 48).toByte(), + (i shr 56).toByte(), + ) } + .toByteArray() +} diff --git a/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Stop.kt b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Stop.kt new file mode 100644 index 0000000..3bf6b54 --- /dev/null +++ b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Stop.kt @@ -0,0 +1,26 @@ +package moe.lava.banksia.core.sqld.mappers + +import moe.lava.banksia.core.model.Stop +import moe.lava.banksia.core.util.Point +import moe.lava.banksia.core.sqld.Stop as DbStop + +fun DbStop.asModel() = Stop( + id = id, + name = name, + pos = Point(lat, lng), + parent = parent, + hasWheelChairBoarding = hasWheelChairBoarding == 1L, + level = level, + platformCode = platformCode, +) + +fun Stop.asDb() = DbStop( + id = id, + name = name, + lat = pos.lat, + lng = pos.lng, + parent = parent, + hasWheelChairBoarding = if (hasWheelChairBoarding) 1L else 0L, + level = level, + platformCode = platformCode +) diff --git a/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/StopTime.kt b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/StopTime.kt new file mode 100644 index 0000000..26d5390 --- /dev/null +++ b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/StopTime.kt @@ -0,0 +1,27 @@ +package moe.lava.banksia.core.sqld.mappers + +import moe.lava.banksia.core.model.FutureTime +import moe.lava.banksia.core.model.FutureTime.Companion.asInt +import moe.lava.banksia.core.model.StopTime +import moe.lava.banksia.core.model.TimeType +import moe.lava.banksia.core.sqld.StopTime as DbStopTime + +fun DbStopTime.asModel() = StopTime( + patternId = patternId, + stopId = stopId, + time = TimeType.Undated( + arrival = FutureTime.fromInt((departureTime + arrivalDelta).toInt()), + departure = FutureTime.fromInt(departureTime.toInt()), + ), + pickupType = pickupType.toInt(), + dropOffType = dropOffType.toInt(), +) + +fun StopTime.Undated.asDb() = DbStopTime( + patternId = patternId, + stopId = stopId, + arrivalDelta = (time.arrival.asInt() - time.departure.asInt()).toLong(), + departureTime = time.departure.asInt().toLong(), + pickupType = pickupType.toLong(), + dropOffType = dropOffType.toLong(), +) diff --git a/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/StoppingPattern.kt b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/StoppingPattern.kt new file mode 100644 index 0000000..d1409a2 --- /dev/null +++ b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/StoppingPattern.kt @@ -0,0 +1,23 @@ +package moe.lava.banksia.core.sqld.mappers + +import moe.lava.banksia.core.model.StopTime +import moe.lava.banksia.core.model.StoppingPattern +import moe.lava.banksia.core.model.TimeType +import moe.lava.banksia.core.sqld.StoppingPattern as DbStoppingPattern + +fun DbStoppingPattern.asModel(stoptimes: List>) = StoppingPattern( + id = id, + routeId = routeId, + shapeId = shapeId, + headsign = headsign, + wheelchairAccessible = wheelchairAccessible == 1L, + stoptimes = stoptimes, +) + +fun StoppingPattern<*>.asDb() = DbStoppingPattern( + id = id, + routeId = routeId, + shapeId = shapeId, + headsign = headsign, + wheelchairAccessible = if (wheelchairAccessible) 1L else 0L, +) diff --git a/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Trip.kt b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Trip.kt new file mode 100644 index 0000000..b3443fb --- /dev/null +++ b/core/sqld/src/commonMain/kotlin/moe/lava/banksia/core/sqld/mappers/Trip.kt @@ -0,0 +1,27 @@ +package moe.lava.banksia.core.sqld.mappers + +import moe.lava.banksia.core.model.Service +import moe.lava.banksia.core.model.StoppingPattern +import moe.lava.banksia.core.model.Trip +import moe.lava.banksia.core.sqld.Trip as DbTrip + +fun DbTrip.asModel(pattern: StoppingPattern.Undated, service: Service): Trip.Undated { + if (serviceId != service.id) { + throw IllegalArgumentException("trip and service id mismatch (${serviceId} != ${service.id})") + } + return Trip( + id = gtfsId, + pattern = pattern, + service = service, + directionId = directionId.toInt(), + blockId = blockId.toString(), + ) +} + +fun Trip.Undated.asDb() = DbTrip( + gtfsId = id, + patternId = pattern.id, + serviceId = service.id, + directionId = directionId.toLong(), + blockId = blockId?.toLong(), +) diff --git a/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Route.sq b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Route.sq new file mode 100644 index 0000000..e607975 --- /dev/null +++ b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Route.sq @@ -0,0 +1,20 @@ +CREATE TABLE Route ( + id TEXT PRIMARY KEY NOT NULL, + type INTEGER NOT NULL, + number TEXT, + name TEXT NOT NULL +); + +getAll: +SELECT * FROM Route; + +get: +SELECT * FROM Route WHERE id == ?; + +getByPattern: +SELECT Route.* FROM Route +INNER JOIN StoppingPattern ON Route.id == StoppingPattern.routeId +WHERE StoppingPattern.id == :patternId; + +insert: +INSERT OR REPLACE INTO Route VALUES ?; diff --git a/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Service.sq b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Service.sq new file mode 100644 index 0000000..a1c5fad --- /dev/null +++ b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Service.sq @@ -0,0 +1,11 @@ +CREATE TABLE Service ( + id TEXT PRIMARY KEY NOT NULL, + days INTEGER NOT NULL, + start INTEGER NOT NULL, + end INTEGER NOT NULL +); + +CREATE INDEX idx_Service_days ON Service (days); + +insert: +INSERT INTO Service VALUES ?; diff --git a/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/ServiceException.sq b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/ServiceException.sq new file mode 100644 index 0000000..332f198 --- /dev/null +++ b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/ServiceException.sq @@ -0,0 +1,9 @@ +CREATE TABLE ServiceException ( + serviceId TEXT NOT NULL, + type INTEGER NOT NULL, + date INTEGER NOT NULL, + PRIMARY KEY (serviceId, type) +); + +insert: +INSERT INTO ServiceException VALUES ?; diff --git a/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Shape.sq b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Shape.sq new file mode 100644 index 0000000..8734200 --- /dev/null +++ b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Shape.sq @@ -0,0 +1,7 @@ +CREATE TABLE Shape ( + id TEXT PRIMARY KEY NOT NULL, + path BLOB NOT NULL +); + +insert: +INSERT INTO Shape VALUES ?; diff --git a/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Stop.sq b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Stop.sq new file mode 100644 index 0000000..4af5c50 --- /dev/null +++ b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Stop.sq @@ -0,0 +1,54 @@ +CREATE TABLE Stop ( + id TEXT PRIMARY KEY NOT NULL, + name TEXT NOT NULL, + lat REAL NOT NULL, + lng REAL NOT NULL, + parent TEXT REFERENCES Stop(id), + hasWheelChairBoarding INTEGER NOT NULL, + level TEXT, + platformCode TEXT +); + +CREATE INDEX idx_Stop_parent ON Stop (parent); + +getAll: +SELECT * FROM Stop; + +getAllParentless: +SELECT * FROM Stop WHERE platformCode IS NOT NULL AND parent IS NULL; + +get: +SELECT * FROM Stop WHERE id == ?; + +getMany: +SELECT * FROM Stop WHERE id IN ?; + +insert: +INSERT INTO Stop VALUES ?; + +updateParents: +UPDATE Stop SET parent = ? WHERE id IN ?; + +getByRoute: +SELECT Stop.* FROM Stop +INNER JOIN StopTime ON StopTime.stopId == Stop.id +INNER JOIN StoppingPattern ON StoppingPattern.id == StopTime.patternId +WHERE StoppingPattern.routeId == :id +GROUP BY Stop.id; + +-- I vibecoded this, sorry +getParentsByRoute: +WITH RECURSIVE Tree AS ( + SELECT Stop.* FROM Stop + INNER JOIN StopTime ON StopTime.stopId == Stop.id + INNER JOIN StoppingPattern ON StoppingPattern.id == StopTime.patternId + WHERE StoppingPattern.routeId == :id + GROUP BY Stop.id + + UNION ALL + + SELECT s.* + FROM Stop s + INNER JOIN Tree t ON s.id = t.parent +) +SELECT DISTINCT * FROM Tree WHERE parent IS NULL; diff --git a/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/StopTime.sq b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/StopTime.sq new file mode 100644 index 0000000..06bd76b --- /dev/null +++ b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/StopTime.sq @@ -0,0 +1,45 @@ +CREATE TABLE StopTime ( + patternId INTEGER NOT NULL REFERENCES StoppingPattern (id), + stopId TEXT NOT NULL REFERENCES Stop (id), + arrivalDelta INTEGER NOT NULL, + departureTime INTEGER NOT NULL, + pickupType INTEGER NOT NULL, + dropOffType INTEGER NOT NULL, + PRIMARY KEY (patternId, stopId) +) WITHOUT ROWID; + +CREATE INDEX idx_StopTime_stopId ON StopTime (stopId); + +insert: +INSERT OR REPLACE INTO StopTime VALUES ?; + +getForStopDated: +SELECT DISTINCT StopTime.* FROM StopTime +INNER JOIN Service ON Service.days & :days = :days AND :date BETWEEN Service.start AND Service.`end` +LEFT JOIN ServiceException ON ServiceException.serviceId == Service.id AND ServiceException.date == :date +INNER JOIN Trip ON Trip.serviceId == Service.id +INNER JOIN StoppingPattern ON StoppingPattern.id == Trip.patternId +WHERE StopTime.patternId == StoppingPattern.id + AND StopTime.stopId IN (SELECT Stop.id FROM Stop WHERE Stop.parent == :stopId OR Stop.id == :stopId) + AND ServiceException.type IS NULL; + +getExtendedForStop: +SELECT DISTINCT + StopTime.patternId, + StopTime.arrivalDelta, + StopTime.departureTime, + StoppingPattern.headsign, + Route.type AS routeType, + Route.number AS routeNumber, + Route.name AS routeName, + Stop.platformCode AS stopPlatformCode +FROM StopTime +INNER JOIN Service ON Service.days & :days = :days AND :date BETWEEN Service.start AND Service.`end` +LEFT JOIN ServiceException ON ServiceException.serviceId == Service.id AND ServiceException.date == :date +INNER JOIN Trip ON Trip.serviceId == Service.id +INNER JOIN StoppingPattern ON StoppingPattern.id == Trip.patternId +INNER JOIN Route ON Route.id == StoppingPattern.routeId +INNER JOIN Stop ON Stop.id == StopTime.stopId +WHERE StopTime.patternId == StoppingPattern.id + AND StopTime.stopId IN (SELECT Stop.id FROM Stop WHERE Stop.parent == :stopId OR Stop.id == :stopId) + AND ServiceException.type IS NULL; diff --git a/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/StoppingPattern.sq b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/StoppingPattern.sq new file mode 100644 index 0000000..9a09e69 --- /dev/null +++ b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/StoppingPattern.sq @@ -0,0 +1,13 @@ +CREATE TABLE StoppingPattern ( + id INTEGER PRIMARY KEY NOT NULL, + routeId TEXT NOT NULL REFERENCES Route (id), + shapeId TEXT NOT NULL REFERENCES Shape (id), + headsign TEXT NOT NULL, + wheelchairAccessible INTEGER NOT NULL +); + +insert: +INSERT OR REPLACE INTO StoppingPattern VALUES ?; + +get: +SELECT * FROM StoppingPattern WHERE id == :id; diff --git a/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Trip.sq b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Trip.sq new file mode 100644 index 0000000..c53b62a --- /dev/null +++ b/core/sqld/src/commonMain/sqldelight/moe/lava/banksia/core/sqld/Trip.sq @@ -0,0 +1,13 @@ +CREATE TABLE Trip ( + gtfsId TEXT PRIMARY KEY NOT NULL, + patternId INTEGER NOT NULL REFERENCES StoppingPattern (id), + serviceId TEXT NOT NULL REFERENCES Service (id), + blockId INTEGER, + directionId INTEGER NOT NULL +); + +CREATE INDEX idx_Trip_patternId ON Trip (patternId); +CREATE INDEX idx_Trip_serviceId ON Trip (serviceId); + +insert: +INSERT OR REPLACE INTO Trip VALUES ?; diff --git a/core/sqld/src/commonMain/sqldelight/schema/1.db b/core/sqld/src/commonMain/sqldelight/schema/1.db new file mode 100644 index 0000000..feaacb3 Binary files /dev/null and b/core/sqld/src/commonMain/sqldelight/schema/1.db differ diff --git a/core/sqld/src/iosMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.ios.kt b/core/sqld/src/iosMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.ios.kt new file mode 100644 index 0000000..9ce0627 --- /dev/null +++ b/core/sqld/src/iosMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.ios.kt @@ -0,0 +1,11 @@ +package moe.lava.banksia.core.sqld + +import app.cash.sqldelight.driver.native.NativeSqliteDriver +import org.koin.core.component.KoinComponent + +actual class DatabaseManager : KoinComponent { + actual val database by lazy { + val driver = NativeSqliteDriver(BanksiaDatabase.Schema, "${DBNAME}.db") + BanksiaDatabase(driver) + } +} diff --git a/core/sqld/src/jvmMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.jvm.kt b/core/sqld/src/jvmMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.jvm.kt new file mode 100644 index 0000000..61d9e95 --- /dev/null +++ b/core/sqld/src/jvmMain/kotlin/moe/lava/banksia/core/sqld/DatabaseManager.jvm.kt @@ -0,0 +1,56 @@ +package moe.lava.banksia.core.sqld + +import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver +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 java.util.Properties +import kotlin.system.exitProcess + +actual class DatabaseManager : KoinComponent { + private var driver = connect() + actual val database get() = BanksiaDatabase(driver) + + private fun connect(path: String = "./data/${DBNAME}.db") = + JdbcSqliteDriver("jdbc:sqlite:${path}", Properties(), BanksiaDatabase.Schema) + .apply { execute(null, "PRAGMA journal_mode = OFF;", 0) } + + fun makeAlt() = run { + File("./data/${DBNAME}_alt.db").takeIf { it.exists() }?.delete() + val driver = connect("./data/${DBNAME}_alt.db") + BanksiaDatabase(driver) to { driver.close() } + } + + fun swap(scope: CoroutineScope = CoroutineScope(Dispatchers.IO)) { + val live = File("./data/${DBNAME}.db") + val alt = File("./data/${DBNAME}_alt.db") + val old = File("./data/${DBNAME}_old.db") + + if (live.takeIf { it.exists() }?.renameTo(old) == false) { + error("DatabaseManager", "Failed to rename database from live to old (${live.absolutePath} -> ${old.absolutePath})") + return + } + if (alt.takeIf { it.exists() }?.renameTo(live) == false) { + 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 oldDriver = driver + driver = connect() + + scope.launch { + delay(5000) + if (old.takeIf { it.exists() }?.delete() == false) { + error("DatabaseManager", "Failed to unlink old database, stray files! (${old.absolutePath})") + } + oldDriver.close() + } + } +} diff --git a/core/src/commonMain/kotlin/moe/lava/banksia/core/Constants.kt.skeleton b/core/src/commonMain/kotlin/moe/lava/banksia/core/Constants.kt.skeleton index 15b3c58..909f642 100644 --- a/core/src/commonMain/kotlin/moe/lava/banksia/core/Constants.kt.skeleton +++ b/core/src/commonMain/kotlin/moe/lava/banksia/core/Constants.kt.skeleton @@ -6,7 +6,7 @@ object Constants { const val opendataKey: String = "" const val serverUrl: String = "https://banksia.lava.moe/api/" // TODO - const val devMode: Boolean = false + var devMode: Boolean = false const val updateKey: String = "" const val protomapsKey: String = "" } diff --git a/core/src/commonMain/kotlin/moe/lava/banksia/core/endpoints/Endpoint.kt b/core/src/commonMain/kotlin/moe/lava/banksia/core/endpoints/Endpoint.kt new file mode 100644 index 0000000..7e23b5d --- /dev/null +++ b/core/src/commonMain/kotlin/moe/lava/banksia/core/endpoints/Endpoint.kt @@ -0,0 +1,3 @@ +package moe.lava.banksia.core.endpoints + +object Endpoint diff --git a/core/src/commonMain/kotlin/moe/lava/banksia/core/model/Stop.kt b/core/src/commonMain/kotlin/moe/lava/banksia/core/model/Stop.kt index 73e6f02..bbe6fbf 100644 --- a/core/src/commonMain/kotlin/moe/lava/banksia/core/model/Stop.kt +++ b/core/src/commonMain/kotlin/moe/lava/banksia/core/model/Stop.kt @@ -10,6 +10,6 @@ data class Stop( val pos: Point, val parent: String?, val hasWheelChairBoarding: Boolean, - val level: String, - val platformCode: String, + val level: String?, + val platformCode: String?, ) diff --git a/core/src/commonMain/kotlin/moe/lava/banksia/core/model/StopTime.kt b/core/src/commonMain/kotlin/moe/lava/banksia/core/model/StopTime.kt index 70657dc..edd7c51 100644 --- a/core/src/commonMain/kotlin/moe/lava/banksia/core/model/StopTime.kt +++ b/core/src/commonMain/kotlin/moe/lava/banksia/core/model/StopTime.kt @@ -1,14 +1,45 @@ package moe.lava.banksia.core.model +import kotlinx.datetime.LocalDate +import kotlinx.datetime.LocalDateTime import kotlinx.serialization.Serializable @Serializable -data class StopTime( - val tripId: String, +data class StopTime( + val patternId: Long, val stopId: String, - val arrivalTime: FutureTime, - val departureTime: FutureTime, - val headsign: String?, + val time: T, val pickupType: Int, val dropOffType: Int, +) { + typealias Dated = StopTime + typealias Undated = StopTime +} + +@Serializable +sealed class TimeType { + @Serializable + data class Undated( + val arrival: FutureTime, + val departure: FutureTime, + ) : TimeType() + + @Serializable + data class Dated( + val arrival: LocalDateTime, + val departure: LocalDateTime, + ) : TimeType() +} + +fun TimeType.Undated.atDate(date: LocalDate) = TimeType.Dated( + arrival = arrival.atDate(date), + departure = departure.atDate(date), +) + +fun StopTime.atDate(date: LocalDate) = StopTime( + patternId = patternId, + stopId = stopId, + time = time.atDate(date), + pickupType = pickupType, + dropOffType = dropOffType, ) diff --git a/core/src/commonMain/kotlin/moe/lava/banksia/core/model/StopTimeDated.kt b/core/src/commonMain/kotlin/moe/lava/banksia/core/model/StopTimeDated.kt deleted file mode 100644 index 1bd75c6..0000000 --- a/core/src/commonMain/kotlin/moe/lava/banksia/core/model/StopTimeDated.kt +++ /dev/null @@ -1,26 +0,0 @@ -package moe.lava.banksia.core.model - -import kotlinx.datetime.LocalDate -import kotlinx.datetime.LocalDateTime -import kotlinx.serialization.Serializable - -@Serializable -data class StopTimeDated( - val tripId: String, - val stopId: String, - val arrivalTime: LocalDateTime, - val departureTime: LocalDateTime, - val headsign: String?, - val pickupType: Int, - val dropOffType: Int, -) - -fun StopTime.atDate(date: LocalDate) = StopTimeDated( - tripId = tripId, - stopId = stopId, - arrivalTime = arrivalTime.atDate(date), - departureTime = departureTime.atDate(date), - headsign = headsign, - pickupType = pickupType, - dropOffType = dropOffType, -) diff --git a/core/src/commonMain/kotlin/moe/lava/banksia/core/model/StoppingPattern.kt b/core/src/commonMain/kotlin/moe/lava/banksia/core/model/StoppingPattern.kt new file mode 100644 index 0000000..1374cff --- /dev/null +++ b/core/src/commonMain/kotlin/moe/lava/banksia/core/model/StoppingPattern.kt @@ -0,0 +1,16 @@ +package moe.lava.banksia.core.model + +import kotlinx.serialization.Serializable + +@Serializable +data class StoppingPattern( + val id: Long, + val routeId: String, + val shapeId: String, + val headsign: String, + val wheelchairAccessible: Boolean, + val stoptimes: List>, +) { + typealias Dated = StoppingPattern + typealias Undated = StoppingPattern +} diff --git a/core/src/commonMain/kotlin/moe/lava/banksia/core/model/Trip.kt b/core/src/commonMain/kotlin/moe/lava/banksia/core/model/Trip.kt index 753f653..752d6d2 100644 --- a/core/src/commonMain/kotlin/moe/lava/banksia/core/model/Trip.kt +++ b/core/src/commonMain/kotlin/moe/lava/banksia/core/model/Trip.kt @@ -3,13 +3,13 @@ package moe.lava.banksia.core.model import kotlinx.serialization.Serializable @Serializable -data class Trip( +data class Trip( val id: String, - val routeId: String, + val pattern: StoppingPattern, val service: Service, - val shapeId: String?, - val tripHeadsign: String, - val directionId: String, - val blockId: String, - val wheelchairAccessible: String, -) + val directionId: Int, + val blockId: String?, +) { + typealias Dated = Trip + typealias Undated = Trip +} diff --git a/core/data/client/build.gradle.kts b/core/stoptime/build.gradle.kts similarity index 71% rename from core/data/client/build.gradle.kts rename to core/stoptime/build.gradle.kts index e9848f3..44cf072 100644 --- a/core/data/client/build.gradle.kts +++ b/core/stoptime/build.gradle.kts @@ -9,7 +9,7 @@ plugins { kotlin { android { - namespace = "moe.lava.banksia.core.data.client" + namespace = "moe.lava.banksia.core.stoptime" compileSdk = libs.versions.android.compileSdk.get().toInt() compilerOptions { @@ -19,6 +19,7 @@ kotlin { compilerOptions { freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime") + freeCompilerArgs.add("-Xexpect-actual-classes") } iosArm64() @@ -27,13 +28,18 @@ kotlin { jvm() sourceSets { + val clientMain by creating { + dependsOn(commonMain.get()) + } + + androidMain.get().dependsOn(clientMain) + iosArm64Main.get().dependsOn(clientMain) + iosSimulatorArm64Main.get().dependsOn(clientMain) + androidMain.dependencies { - implementation(libs.koin.compose) implementation(libs.ktor.client.okhttp) } commonMain.dependencies { - api(projects.core.data) - implementation(libs.okio) implementation(libs.koin.core) implementation(libs.ktor.client.core) @@ -45,10 +51,14 @@ kotlin { implementation(libs.kotlinx.serialization.protobuf) implementation(projects.core) - implementation(projects.core.room) + implementation(projects.core.sqld) } iosMain.dependencies { implementation(libs.ktor.client.darwin) } + jvmMain.dependencies { + implementation(libs.koin.ktor) + implementation(libs.ktor.server.core) + } } } diff --git a/core/stoptime/src/clientMain/kotlin/moe/lava/banksia/core/data/StopTimeDataDiModule.client.kt b/core/stoptime/src/clientMain/kotlin/moe/lava/banksia/core/data/StopTimeDataDiModule.client.kt new file mode 100644 index 0000000..2f83304 --- /dev/null +++ b/core/stoptime/src/clientMain/kotlin/moe/lava/banksia/core/data/StopTimeDataDiModule.client.kt @@ -0,0 +1,11 @@ +package moe.lava.banksia.core.data + +import moe.lava.banksia.core.data.repositories.StopTimeRepository +import moe.lava.banksia.core.data.sources.stoptime.StopTimeRemoteDataSource +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module + +internal actual val platformModule = module { + singleOf(::StopTimeRepository) + singleOf(::StopTimeRemoteDataSource) +} diff --git a/core/stoptime/src/clientMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.client.kt b/core/stoptime/src/clientMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.client.kt new file mode 100644 index 0000000..ecaff8e --- /dev/null +++ b/core/stoptime/src/clientMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.client.kt @@ -0,0 +1,19 @@ +package moe.lava.banksia.core.data.repositories + +import kotlinx.coroutines.flow.flow +import kotlinx.datetime.LocalDate +import moe.lava.banksia.core.data.sources.stoptime.StopTimeLocalDataSource +import moe.lava.banksia.core.data.sources.stoptime.StopTimeRemoteDataSource + +actual class StopTimeRepository internal constructor( + private val local: StopTimeLocalDataSource, + private val remote: StopTimeRemoteDataSource, +) { + actual suspend fun getForStop(id: String, date: LocalDate) = flow { + emit(local.getAtStop(id, date)) + + remote.getAtStop(id, date) + .takeIf { it.isNotEmpty() } + ?.let { emit(it) } + } +} diff --git a/core/stoptime/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeRemoteDataSource.kt b/core/stoptime/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeRemoteDataSource.kt new file mode 100644 index 0000000..0c38f64 --- /dev/null +++ b/core/stoptime/src/clientMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeRemoteDataSource.kt @@ -0,0 +1,26 @@ +package moe.lava.banksia.core.data.sources.stoptime + +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.request.get +import io.ktor.client.request.parameter +import kotlinx.datetime.LocalDate +import kotlinx.datetime.TimeZone +import kotlinx.datetime.todayIn +import moe.lava.banksia.core.data.dto.ExtendedStopTime +import moe.lava.banksia.core.endpoints.Endpoint +import moe.lava.banksia.core.endpoints.stopTimeByStop +import kotlin.time.Clock + +internal class StopTimeRemoteDataSource( + private val client: HttpClient, +) { + suspend fun getAtStop( + stopId: String, + date: LocalDate? = Clock.System.todayIn(TimeZone.currentSystemDefault()), + ): List { + return client.get(Endpoint.stopTimeByStop(stopId)) { + parameter("date", date) + }.body>() + } +} diff --git a/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/StopTimeDataDiModule.kt b/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/StopTimeDataDiModule.kt new file mode 100644 index 0000000..d46affa --- /dev/null +++ b/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/StopTimeDataDiModule.kt @@ -0,0 +1,13 @@ +package moe.lava.banksia.core.data + +import moe.lava.banksia.core.data.sources.stoptime.StopTimeLocalDataSource +import org.koin.core.module.Module +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module + +internal expect val platformModule: Module; + +val stopTimeDataDiModule = module { + includes(platformModule) + singleOf(::StopTimeLocalDataSource) +} diff --git a/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/dto/ExtendedStopTime.kt b/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/dto/ExtendedStopTime.kt new file mode 100644 index 0000000..38de29d --- /dev/null +++ b/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/dto/ExtendedStopTime.kt @@ -0,0 +1,34 @@ +package moe.lava.banksia.core.data.dto + +import kotlinx.datetime.LocalDate +import kotlinx.serialization.Serializable +import moe.lava.banksia.core.model.FutureTime +import moe.lava.banksia.core.model.RouteType +import moe.lava.banksia.core.model.TimeType +import moe.lava.banksia.core.model.atDate +import moe.lava.banksia.core.sqld.GetExtendedForStop + +@Serializable +data class ExtendedStopTime( + val patternId: Long, + val stopPlatformCode: String?, + val time: TimeType.Dated, + val headsign: String?, + val routeType: RouteType, + val routeNumber: String?, + val routeName: String, +) + +// TODO: This probably doesn't belong here +fun GetExtendedForStop.asModel(date: LocalDate) = ExtendedStopTime( + patternId = patternId, + stopPlatformCode = stopPlatformCode, + time = TimeType.Undated( + arrival = FutureTime.fromInt((departureTime + arrivalDelta).toInt()), + departure = FutureTime.fromInt(departureTime.toInt()), + ).atDate(date), + headsign = headsign, + routeType = RouteType.from(routeType.toInt()), + routeNumber = routeNumber, + routeName = routeName, +) diff --git a/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.kt b/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.kt new file mode 100644 index 0000000..6a81c09 --- /dev/null +++ b/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.kt @@ -0,0 +1,15 @@ +package moe.lava.banksia.core.data.repositories + +import kotlinx.coroutines.flow.Flow +import kotlinx.datetime.LocalDate +import kotlinx.datetime.TimeZone +import kotlinx.datetime.todayIn +import moe.lava.banksia.core.data.dto.ExtendedStopTime +import kotlin.time.Clock + +expect class StopTimeRepository { + suspend fun getForStop( + id: String, + date: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault()), + ): Flow> +} diff --git a/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeLocalDataSource.kt b/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeLocalDataSource.kt new file mode 100644 index 0000000..f22dc09 --- /dev/null +++ b/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/data/sources/stoptime/StopTimeLocalDataSource.kt @@ -0,0 +1,30 @@ +package moe.lava.banksia.core.data.sources.stoptime + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.withContext +import kotlinx.datetime.LocalDate +import moe.lava.banksia.core.data.dto.ExtendedStopTime +import moe.lava.banksia.core.data.dto.asModel +import moe.lava.banksia.core.sqld.StopTimeQueries +import moe.lava.banksia.core.util.serialise +import org.koin.core.component.KoinComponent +import org.koin.core.component.get + +internal class StopTimeLocalDataSource : KoinComponent { + private val queries get() = get() + + suspend fun getAtStop(stopId: String, date: LocalDate): List { + return withContext(context = Dispatchers.IO) { + queries + .getExtendedForStop( + listOf(date.dayOfWeek).serialise().toLong(), + date.toEpochDays(), + stopId, + ) + .executeAsList() + .map { it.asModel(date) } + .sortedBy { it.time.departure } + } + } +} diff --git a/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/endpoints/StopTimeEndpoints.kt b/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/endpoints/StopTimeEndpoints.kt new file mode 100644 index 0000000..f689b2d --- /dev/null +++ b/core/stoptime/src/commonMain/kotlin/moe/lava/banksia/core/endpoints/StopTimeEndpoints.kt @@ -0,0 +1,3 @@ +package moe.lava.banksia.core.endpoints + +fun Endpoint.stopTimeByStop(stopId: String) = "stoptimes/by_stop/${stopId}" diff --git a/core/stoptime/src/jvmMain/kotlin/moe/lava/banksia/core/data/StopTimeDataDiModule.jvm.kt b/core/stoptime/src/jvmMain/kotlin/moe/lava/banksia/core/data/StopTimeDataDiModule.jvm.kt new file mode 100644 index 0000000..70ef406 --- /dev/null +++ b/core/stoptime/src/jvmMain/kotlin/moe/lava/banksia/core/data/StopTimeDataDiModule.jvm.kt @@ -0,0 +1,9 @@ +package moe.lava.banksia.core.data + +import moe.lava.banksia.core.data.repositories.StopTimeRepository +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module + +internal actual val platformModule = module { + singleOf(::StopTimeRepository) +} diff --git a/core/stoptime/src/jvmMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.jvm.kt b/core/stoptime/src/jvmMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.jvm.kt new file mode 100644 index 0000000..b4c37a6 --- /dev/null +++ b/core/stoptime/src/jvmMain/kotlin/moe/lava/banksia/core/data/repositories/StopTimeRepository.jvm.kt @@ -0,0 +1,13 @@ +package moe.lava.banksia.core.data.repositories + +import kotlinx.coroutines.flow.flow +import kotlinx.datetime.LocalDate +import moe.lava.banksia.core.data.sources.stoptime.StopTimeLocalDataSource + +actual class StopTimeRepository internal constructor( + private val local: StopTimeLocalDataSource, +) { + actual suspend fun getForStop(id: String, date: LocalDate) = flow { + emit(local.getAtStop(id, date)) + } +} diff --git a/core/stoptime/src/jvmMain/kotlin/moe/lava/banksia/server/routes/StopTimeRoute.kt b/core/stoptime/src/jvmMain/kotlin/moe/lava/banksia/server/routes/StopTimeRoute.kt new file mode 100644 index 0000000..5791855 --- /dev/null +++ b/core/stoptime/src/jvmMain/kotlin/moe/lava/banksia/server/routes/StopTimeRoute.kt @@ -0,0 +1,27 @@ +package moe.lava.banksia.server.routes + +import io.ktor.server.response.respond +import io.ktor.server.routing.Route +import io.ktor.server.routing.get +import kotlinx.coroutines.flow.first +import kotlinx.datetime.LocalDate +import kotlinx.datetime.TimeZone +import kotlinx.datetime.todayIn +import moe.lava.banksia.core.data.repositories.StopTimeRepository +import moe.lava.banksia.core.endpoints.Endpoint +import moe.lava.banksia.core.endpoints.stopTimeByStop +import org.koin.ktor.ext.inject +import kotlin.time.Clock + +fun Route.stopTimeRoutes() { + val repo by inject() + + get(Endpoint.stopTimeByStop("{stop_id}")) { + val stopId = call.parameters["stop_id"]!! + val date = call.queryParameters["date"] + ?.let { LocalDate.parse(it, LocalDate.Formats.ISO) } + ?: Clock.System.todayIn(TimeZone.currentSystemDefault()) + val data = repo.getForStop(stopId, date).first() + call.respond(data) + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e171b55..483c5d5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,11 +1,11 @@ [versions] agp = "9.1.0" -android-compileSdk = "36" +android-compileSdk = "37" android-minSdk = "24" -android-targetSdk = "36" +android-targetSdk = "37" androidx-activity= "1.13.0" androidx-lifecycle = "2.10.0" -compose-multiplatform = "1.11.0-alpha04" +compose-multiplatform = "1.12.0-alpha02" composeunstyled = "1.49.6" coroutines = "1.10.2" geo = "0.8.0" @@ -19,12 +19,11 @@ ktor = "3.4.1" logback = "1.5.32" maplibre = "0.12.1" material = "1.7.3" -material3 = "1.11.0-alpha04" +material3 = "1.11.0-alpha07" okio = "3.17.0" playServicesLocation = "21.3.0" -sqlite = "2.6.2" -room = "2.8.4" secretsGradlePlugin = "2.0.1" +sqldelight = "2.3.2" wire = "6.1.0" [libraries] @@ -67,10 +66,10 @@ moko-geo = { module = "dev.icerock.moko:geo", version.ref = "geo" } moko-geo-compose = { module = "dev.icerock.moko:geo-compose", version.ref = "geo" } okio = { module = "com.squareup.okio:okio", version.ref = "okio" } play-services-location = { module = "com.google.android.gms:play-services-location", version.ref = "playServicesLocation" } -room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } -room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } -sqlite-bundled = { group = "androidx.sqlite", name = "sqlite-bundled", version.ref = "sqlite" } secrets-gradle-plugin = { module = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin", version.ref = "secretsGradlePlugin" } +sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } +sqldelight-driver-jvm = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" } +sqldelight-driver-native = { module = "app.cash.sqldelight:native-driver", version.ref = "sqldelight" } ui-backhandler = { module = "org.jetbrains.compose.ui:ui-backhandler", version.ref = "compose-multiplatform" } [plugins] @@ -83,6 +82,6 @@ kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } ktor = { id = "io.ktor.plugin", version.ref = "ktor" } -room = { id = "androidx.room", version.ref = "room" } secretsGradle = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin" } +sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" } wire = { id = "com.squareup.wire", version.ref = "wire" } diff --git a/server/build.gradle.kts b/server/build.gradle.kts index 4150bb2..9d2cb78 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -20,7 +20,9 @@ kotlin { dependencies { implementation(projects.core) - implementation(projects.core.room) + implementation(projects.core.data) + implementation(projects.core.sqld) + implementation(projects.core.stoptime) implementation(projects.server.gtfs) implementation(projects.server.gtfsRt) @@ -36,8 +38,6 @@ dependencies { implementation(libs.ktor.server.contentnegotiation) implementation(libs.ktor.server.core) implementation(libs.ktor.server.netty) - implementation(libs.room.runtime) - implementation(libs.sqlite.bundled) testImplementation(libs.ktor.server.tests) testImplementation(libs.kotlin.test.junit) } diff --git a/server/gtfs/src/main/kotlin/moe/lava/banksia/server/gtfs/GtfsParser.kt b/server/gtfs/src/main/kotlin/moe/lava/banksia/server/gtfs/GtfsParser.kt index f8d9832..c844499 100644 --- a/server/gtfs/src/main/kotlin/moe/lava/banksia/server/gtfs/GtfsParser.kt +++ b/server/gtfs/src/main/kotlin/moe/lava/banksia/server/gtfs/GtfsParser.kt @@ -18,6 +18,7 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.modules.EmptySerializersModule import kotlinx.serialization.serializer import moe.lava.banksia.core.Constants +import moe.lava.banksia.core.model.FutureTime.Companion.asInt import moe.lava.banksia.core.model.Route import moe.lava.banksia.core.model.RouteType import moe.lava.banksia.core.model.Service @@ -25,6 +26,8 @@ import moe.lava.banksia.core.model.ServiceException import moe.lava.banksia.core.model.Shape import moe.lava.banksia.core.model.Stop import moe.lava.banksia.core.model.StopTime +import moe.lava.banksia.core.model.StoppingPattern +import moe.lava.banksia.core.model.TimeType import moe.lava.banksia.core.model.Trip import moe.lava.banksia.core.util.Point import moe.lava.banksia.server.gtfs.structures.GtfsRoute @@ -35,6 +38,8 @@ import moe.lava.banksia.server.gtfs.structures.GtfsStop import moe.lava.banksia.server.gtfs.structures.GtfsStopTime import moe.lava.banksia.server.gtfs.structures.GtfsTrip import java.io.File +import java.nio.ByteBuffer +import java.security.MessageDigest import java.util.zip.ZipFile import kotlin.time.ExperimentalTime @@ -46,8 +51,7 @@ sealed class GtfsData { data class ServiceExceptionChunk(val exceptions: List) : GtfsData() data class ShapeChunk(val shapes: List) : GtfsData() data class StopChunk(val stops: List) : GtfsData() - data class StopTimeChunk(val stopTimes: List) : GtfsData() - data class TripChunk(val trips: List) : GtfsData() + data class TripChunk(val trips: List) : GtfsData() } class GtfsParser( @@ -129,7 +133,6 @@ class GtfsParser( .filter { it.name == "trips.txt" } .flatMap { fd -> parseTrips(fd, services) - .also { emit(GtfsData.TripChunk(it)) } } .associateBy { it.id } @@ -137,13 +140,53 @@ class GtfsParser( .filter { it.name == "stop_times.txt" } .forEach { fd -> log.info("parsing stop times for ${fd.parent}...") - parseStopTimes(fd, trips) { seq -> - seq.chunked(1000000) - .forEach { emit(GtfsData.StopTimeChunk(it)) } + parseStopTimes(fd) { seq -> + val times = ArrayList>(1000100) + seq.forEach { pair -> + val (_, stoptime) = pair + if (times.size > 1000000 && stoptime.patternId == 1L) { + emit(GtfsData.TripChunk(processStoptimes(trips, times))) + times.clear() + } + + times.add(pair) + } + emit(GtfsData.TripChunk(processStoptimes(trips, times))) } } } + private fun hashCalc(headsign: String, stops: List): Long { + val inst = MessageDigest.getInstance("SHA-256") + inst.update(headsign.toByteArray()) + stops.forEach { + inst.update(it.stopId.toByteArray()) + val dint = it.time.departure.asInt() + inst.update((dint).toByte()) + inst.update((dint shr 8).toByte()) + val aint = it.time.arrival.asInt() + inst.update((aint).toByte()) + inst.update((aint shr 8).toByte()) + } + + val buf = inst.digest().slice(0..7).toByteArray() + buf[0] = 0 + buf[1] = 0 + return ByteBuffer.wrap(buf).long + } + + private fun processStoptimes(trips: Map, times: ArrayList>) = + times.groupBy { it.first } + .map { (tripId, pairs) -> + val trip = trips[tripId]!! + val stoptimes = pairs.map { it.second } + val hash = hashCalc(trip.pattern.headsign, stoptimes) + trip.copy(pattern = trip.pattern.copy( + id = hash, + stoptimes = stoptimes.map { it.copy(patternId = hash) } + )) + } + private fun parseRoutes(fd: File) = fd.parseCsv() .map { with(it) { @@ -175,21 +218,22 @@ class GtfsParser( pos = Point(stop_lat, stop_lon), parent = parent_station.ifEmpty { null }, hasWheelChairBoarding = wheelchair_boarding == "1", - level = level_id, - platformCode = platform_code, + level = level_id.ifEmpty { null }, + platformCode = platform_code.ifEmpty { null }, ) } } - private inline fun parseStopTimes(fd: File, trips: Map, block: (Sequence) -> Unit) = + private inline fun parseStopTimes(fd: File, block: (Sequence>) -> Unit) = fd.parseCsvSequence { seq -> seq .map { with(it) { - StopTime( - tripId = trip_id, + it.trip_id to StopTime( + patternId = stop_sequence, stopId = stop_id, - arrivalTime = GtfsStopTime.parseGtfsTime(arrival_time), - departureTime = GtfsStopTime.parseGtfsTime(departure_time), - headsign = stop_headsign.ifEmpty { trips[trip_id]!!.tripHeadsign }, + time = TimeType.Undated( + arrival = GtfsStopTime.parseGtfsTime(arrival_time), + departure = GtfsStopTime.parseGtfsTime(departure_time), + ), pickupType = pickup_type, dropOffType = drop_off_type, ) @@ -210,7 +254,7 @@ class GtfsParser( if (sunday == 1) add(DayOfWeek.SUNDAY) } Service( - id = service_id, + id = "${fd.parentFile.name}_${service_id}", days = days, start = LocalDate.parse(start_date, LocalDate.Formats.ISO_BASIC), end = LocalDate.parse(end_date, LocalDate.Formats.ISO_BASIC), @@ -221,7 +265,7 @@ class GtfsParser( fd.parseCsv() .map { with(it) { ServiceException( - serviceId = service_id, + serviceId = "${fd.parentFile.name}_${service_id}", date = LocalDate.parse(date, LocalDate.Formats.ISO_BASIC), type = exception_type, ) @@ -230,15 +274,19 @@ class GtfsParser( private fun parseTrips(fd: File, services: Map) = fd.parseCsv() .map { with(it) { - Trip( + Trip.Undated( id = trip_id, - routeId = route_id, - service = services[service_id]!!, - shapeId = shape_id.ifEmpty { null }, - tripHeadsign = trip_headsign, - directionId = direction_id, - blockId = block_id, - wheelchairAccessible = wheelchair_accessible, + pattern = StoppingPattern( + id = 0, + routeId = route_id, + shapeId = shape_id, + headsign = trip_headsign, + wheelchairAccessible = wheelchair_accessible == "1", + stoptimes = listOf() + ), + service = services["${fd.parentFile.name}_${service_id}"]!!, + directionId = direction_id.toInt(), + blockId = block_id.ifEmpty { null }, ) } } diff --git a/server/gtfs/src/main/kotlin/moe/lava/banksia/server/gtfs/structures/GtfsStopTime.kt b/server/gtfs/src/main/kotlin/moe/lava/banksia/server/gtfs/structures/GtfsStopTime.kt index 33da78f..c0bbaf2 100644 --- a/server/gtfs/src/main/kotlin/moe/lava/banksia/server/gtfs/structures/GtfsStopTime.kt +++ b/server/gtfs/src/main/kotlin/moe/lava/banksia/server/gtfs/structures/GtfsStopTime.kt @@ -10,7 +10,7 @@ internal data class GtfsStopTime( val arrival_time: String, val departure_time: String, val stop_id: String, - val stop_sequence: Int, + val stop_sequence: Long, val stop_headsign: String, val pickup_type: Int, val drop_off_type: Int, diff --git a/server/gtfs_rt/src/main/kotlin/moe/lava/banksia/server/gtfsrt/GtfsrtArchiver.kt b/server/gtfs_rt/src/main/kotlin/moe/lava/banksia/server/gtfsrt/GtfsrtArchiver.kt index 7b9229b..aaee0a9 100644 --- a/server/gtfs_rt/src/main/kotlin/moe/lava/banksia/server/gtfsrt/GtfsrtArchiver.kt +++ b/server/gtfs_rt/src/main/kotlin/moe/lava/banksia/server/gtfsrt/GtfsrtArchiver.kt @@ -41,13 +41,19 @@ internal class GtfsrtArchiver { val time = Instant.fromEpochSeconds(timestamp).toLocalDateTime(TimeZone.currentSystemDefault()) + val (prevWeek, prevDay) = (time.dayOfYear - 1) / 7 to (time.dayOfYear - 1) % 7 + val (nextWeek, nextDay) = time.dayOfYear / 7 to time.dayOfYear % 7 + val base = File(BASE_DIR, type) - val previousParent = File(base, "${time.year}-${((time.dayOfYear - 1) / 7).toString().padStart(2, '0')}") - val currentParent = File(base, "${time.year}-${((time.dayOfYear - 1) / 7 + 1).toString().padStart(2, '0')}") + val previousParent = File(base, "${time.year}-${prevWeek.toString().padStart(2, '0')}/${prevDay}") + val currentParent = File(base, "${time.year}-${nextWeek.toString().padStart(2, '0')}/${nextDay}") val target = File(currentParent, "${timestamp}.proto") if (previousParent.isDirectory) { enqueueCompression(previousParent) + if (prevWeek != nextWeek) { + enqueueCompression(previousParent.parentFile) + } } if (!target.exists()) { @@ -90,6 +96,7 @@ internal class GtfsrtArchiver { ).start() val exitCode = proc.waitFor() if (exitCode == 0) { + log("CompressJob", "Compressed ${next.absolutePath} to ${next.absolutePath}.tar.zst") if (next.deleteRecursively()) { cmut.withLock { cqueue.remove(next) } } else { diff --git a/server/src/main/kotlin/moe/lava/banksia/server/Application.kt b/server/src/main/kotlin/moe/lava/banksia/server/Application.kt index 0981b80..dedffe5 100644 --- a/server/src/main/kotlin/moe/lava/banksia/server/Application.kt +++ b/server/src/main/kotlin/moe/lava/banksia/server/Application.kt @@ -15,29 +15,26 @@ import io.ktor.server.routing.routing import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import kotlinx.datetime.LocalDate -import kotlinx.datetime.TimeZone -import kotlinx.datetime.todayIn import moe.lava.banksia.core.Constants -import moe.lava.banksia.core.model.atDate -import moe.lava.banksia.core.room.dao.RouteDao -import moe.lava.banksia.core.room.dao.StopDao -import moe.lava.banksia.core.room.dao.StopTimeDao -import moe.lava.banksia.core.room.dao.VersionMetadataDao -import moe.lava.banksia.core.util.serialise +import moe.lava.banksia.core.sqld.RouteQueries +import moe.lava.banksia.core.sqld.StopQueries +import moe.lava.banksia.core.sqld.mappers.asModel import moe.lava.banksia.server.di.ServerModules import moe.lava.banksia.server.gtfsrt.GtfsrtService +import moe.lava.banksia.server.routes.stopTimeRoutes import org.koin.dsl.module import org.koin.ktor.ext.get import org.koin.ktor.plugin.Koin -import kotlin.time.Clock fun main() { + if (System.getenv("BANKSIA_PRODUCTION") == "1") Constants.devMode = false + embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module) .start(wait = true) } fun Application.module() { + log.info("devMode: ${Constants.devMode}") install(ContentNegotiation) { json() } @@ -50,6 +47,8 @@ fun Application.module() { launch { get().start(this, !Constants.devMode) } routing { + stopTimeRoutes() + if (Constants.devMode) { get("/fixup") { call.respondText("received") @@ -85,25 +84,9 @@ fun Application.module() { } } - get("/metadata/{type?}") { - val dao = get() - val type = call.parameters["type"] - if (type == null) { - call.respond(dao.getAll().map { it.asModel() }) - return@get - } - - val data = dao.get(type)?.asModel() - if (data == null) { - call.respond(HttpStatusCode.NotFound) - } else { - call.respond(data) - } - } - get("/routes") { val routes = withContext(context = Dispatchers.IO) { - get().getAll() + get().getAll().executeAsList() } val res = routes.map { it.asModel() } call.respond(res) @@ -111,16 +94,17 @@ fun Application.module() { get("/routes/{route_id}") { val routeId = call.parameters["route_id"]!! val route = withContext(context = Dispatchers.IO) { - get().get(routeId) + get().get(routeId).executeAsOneOrNull() } - if (route != null) + if (route != null) { call.respond(route.asModel()) - else + } else { call.respond(HttpStatusCode.NotFound) + } } get("/stops") { val routes = withContext(context = Dispatchers.IO) { - get().getAll() + get().getAll().executeAsList() } val res = routes.map { it.asModel() } call.respond(res) @@ -128,41 +112,26 @@ fun Application.module() { get("/stops/{stop_id}") { val stopId = call.parameters["stop_id"]!! val stop = withContext(context = Dispatchers.IO) { - get().get(stopId) + get().get(stopId).executeAsOneOrNull() } - if (stop != null) + if (stop != null) { call.respond(stop.asModel()) - else + } else { call.respond(HttpStatusCode.NotFound) + } } get("/route_stops/{route_id}") { val routeId = call.parameters["route_id"]!! val useParent = call.queryParameters["parent"] !in listOf("false", "0") val stops = withContext(Dispatchers.IO) { - val routeDao = get() - if (useParent) - routeDao.stopsParent(routeId) - else - routeDao.stops(routeId) + val queries = get() + if (useParent) { + queries.getParentsByRoute(routeId).executeAsList() + } else { + queries.getByRoute(routeId).executeAsList() + } } call.respond(stops.map { it.asModel() }) } - get("/stoptimes/by_stop/{stop_id}") { - val stopId = call.parameters["stop_id"]!! - val date = call.queryParameters["date"] - ?.let { LocalDate.parse(it, LocalDate.Formats.ISO) } - ?: Clock.System.todayIn(TimeZone.currentSystemDefault()) - val times = withContext(context = Dispatchers.IO) { - get() - .getForStopDated( - stopId, - listOf(date.dayOfWeek).serialise(), - date.toEpochDays().toInt(), - ) - .map { it.asModel().atDate(date) } - .sortedBy { it.departureTime } - } - call.respond(times) - } } } diff --git a/server/src/main/kotlin/moe/lava/banksia/server/GtfsDataFixer.kt b/server/src/main/kotlin/moe/lava/banksia/server/GtfsDataFixer.kt index c74930d..97892e0 100644 --- a/server/src/main/kotlin/moe/lava/banksia/server/GtfsDataFixer.kt +++ b/server/src/main/kotlin/moe/lava/banksia/server/GtfsDataFixer.kt @@ -1,16 +1,16 @@ package moe.lava.banksia.server -import moe.lava.banksia.core.room.Database -import moe.lava.banksia.core.room.entity.StopEntity +import moe.lava.banksia.core.sqld.BanksiaDatabase import moe.lava.banksia.core.util.log import java.security.MessageDigest +import moe.lava.banksia.core.sqld.Stop as DbStop class GtfsDataFixer( - private val database: Database, + private val database: BanksiaDatabase, ) { - suspend fun addParentsToStops() { - val dao = database.stopDao - val stops = dao.getAllParentless() + fun addParentsToStops() { + val queries = database.stopQueries + val stops = queries.getAllParentless().executeAsList() stops .groupBy { it.name.split("/")[0] } .filter { (_, stops) -> stops.size > 1 } @@ -19,19 +19,21 @@ class GtfsDataFixer( val avgLng = stops.map { it.lng }.average() val hash = name.sha256().substring(0, 7) val parentId = "bsia:df1:$hash" - val parent = StopEntity( + val parent = DbStop( id = parentId, name = name, lat = avgLat, lng = avgLng, parent = null, - hasWheelChairBoarding = stops.all { it.hasWheelChairBoarding }, + hasWheelChairBoarding = if (stops.all { it.hasWheelChairBoarding == 1L }) 1L else 0L, level = "", platformCode = "", ) log("datafixer", "inserting ${parentId} for ${stops.size} children") - dao.insertAll(parent) - dao.updateParents(stops.map { it.id }, parentId) + queries.transaction { + queries.insert(parent) + queries.updateParents(parentId, stops.map { it.id }) + } } } } diff --git a/server/src/main/kotlin/moe/lava/banksia/server/GtfsImporter.kt b/server/src/main/kotlin/moe/lava/banksia/server/GtfsImporter.kt index 5c8dc37..84fae70 100644 --- a/server/src/main/kotlin/moe/lava/banksia/server/GtfsImporter.kt +++ b/server/src/main/kotlin/moe/lava/banksia/server/GtfsImporter.kt @@ -6,14 +6,13 @@ import moe.lava.banksia.core.model.Service import moe.lava.banksia.core.model.ServiceException import moe.lava.banksia.core.model.Shape import moe.lava.banksia.core.model.Stop -import moe.lava.banksia.core.model.StopTime import moe.lava.banksia.core.model.Trip -import moe.lava.banksia.core.room.Database -import moe.lava.banksia.core.room.DatabaseManager -import moe.lava.banksia.core.room.entity.asEntity +import moe.lava.banksia.core.sqld.DatabaseManager +import moe.lava.banksia.core.sqld.mappers.asDb import moe.lava.banksia.server.gtfs.GtfsData import moe.lava.banksia.server.gtfs.GtfsParser import kotlin.time.Clock +import moe.lava.banksia.core.sqld.BanksiaDatabase as Database class GtfsImporter( private val parser: GtfsParser, @@ -21,7 +20,7 @@ class GtfsImporter( private val log: Logger, ) { suspend fun import(url: String, date: Long = Clock.System.now().epochSeconds) { - val database = dbm.makeAlt() + val (database, close) = dbm.makeAlt() parser.update(url).collect { chunk -> when (chunk) { @@ -30,53 +29,55 @@ class GtfsImporter( is GtfsData.ServiceExceptionChunk -> database.addServiceExceptions(chunk.exceptions) is GtfsData.ShapeChunk -> database.addShapes(chunk.shapes) is GtfsData.StopChunk -> database.addStops(chunk.stops) - is GtfsData.StopTimeChunk -> database.addStopTimes(chunk.stopTimes) is GtfsData.TripChunk -> database.addTrips(chunk.trips) } } - database.updateMetadata(date) - database.close() + close() dbm.swap() } - private suspend fun Database.updateMetadata(date: Long) { - val dao = versionMetadataDao - log.info("updating metadata...") - dao.update(date, listOf("routes", "stops", "shapes", "trips", "stop_times")) - log.info("done") - } - - private suspend fun Database.addRoutes(routes: List) { - val dao = routeDao + private fun Database.addRoutes(routes: List) { log.info("inserting routes...") - dao.insertOrReplaceAll(*routes.map { it.asEntity() }.toTypedArray()) + routeQueries.transaction { + routes.forEach { + routeQueries.insert(it.asDb()) + } + } log.info("done") } - private suspend fun Database.addServices(services: List) { - val dao = serviceDao + private fun Database.addServices(services: List) { log.info("inserting services...") - dao.insertOrReplaceAll(*services.map { it.asEntity() }.toTypedArray()) + serviceQueries.transaction { + services.forEach { + serviceQueries.insert(it.asDb()) + } + } log.info("done") } - private suspend fun Database.addServiceExceptions(exceptions: List) { - val dao = serviceExceptionDao + private fun Database.addServiceExceptions(exceptions: List) { log.info("inserting exceptions...") - dao.insertOrReplaceAll(*exceptions.map { it.asEntity() }.toTypedArray()) + serviceExceptionQueries.transaction { + exceptions.forEach { + serviceExceptionQueries.insert(it.asDb()) + } + } log.info("done") } - private suspend fun Database.addShapes(shapes: List) { - val dao = shapeDao + private fun Database.addShapes(shapes: List) { log.info("inserting shapes...") - dao.insertOrReplaceAll(*shapes.map { it.asEntity() }.toTypedArray()) + shapeQueries.transaction { + shapes.forEach { + shapeQueries.insert(it.asDb()) + } + } log.info("done") } - private suspend fun Database.addStops(stops: List) { - val dao = stopDao + private fun Database.addStops(stops: List) { log.info("inserting stops...") stops .groupBy { it.id } @@ -89,21 +90,26 @@ class GtfsImporter( } } } - dao.insertOrReplaceAll(*stops.map { it.asEntity() }.toTypedArray()) + + stopQueries.transaction { + stops.forEach { + stopQueries.insert(it.asDb()) + } + } log.info("done") } - private suspend fun Database.addStopTimes(stopTimes: List) { - val dao = stopTimeDao - log.info("inserting ${stopTimes.size} stoptimes...") - dao.insertOrReplaceAll(*stopTimes.map { it.asEntity() }.toTypedArray()) - log.info("done") - } - - private suspend fun Database.addTrips(trips: List) { - val dao = tripDao + private fun Database.addTrips(trips: List) { log.info("inserting ${trips.size} trips...") - dao.insertOrReplaceAll(*trips.map { it.asEntity() }.toTypedArray()) + transaction { + trips.forEach { trip -> + stoppingPatternQueries.insert(trip.pattern.asDb()) + trip.pattern.stoptimes.forEach { stoptime -> + stopTimeQueries.insert(stoptime.asDb()) + } + tripQueries.insert(trip.asDb()) + } + } log.info("done") } } diff --git a/server/src/main/kotlin/moe/lava/banksia/server/di/ServerModules.kt b/server/src/main/kotlin/moe/lava/banksia/server/di/ServerModules.kt index a8a7541..b2593b3 100644 --- a/server/src/main/kotlin/moe/lava/banksia/server/di/ServerModules.kt +++ b/server/src/main/kotlin/moe/lava/banksia/server/di/ServerModules.kt @@ -1,7 +1,7 @@ package moe.lava.banksia.server.di import io.ktor.client.HttpClient -import moe.lava.banksia.core.room.roomDiModule +import moe.lava.banksia.core.data.dataDiModule import moe.lava.banksia.server.GtfsDataFixer import moe.lava.banksia.server.GtfsImporter import moe.lava.banksia.server.gtfs.GtfsParser @@ -11,7 +11,7 @@ import org.koin.core.module.dsl.singleOf import org.koin.dsl.module val ServerModules = module { - includes(roomDiModule) + includes(dataDiModule) single { HttpClient() } singleOf(::GtfsParser) diff --git a/server/src/main/resources/logback.xml b/server/src/main/resources/logback.xml index de5d8bf..6519371 100644 --- a/server/src/main/resources/logback.xml +++ b/server/src/main/resources/logback.xml @@ -14,7 +14,7 @@ %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - + diff --git a/settings.gradle.kts b/settings.gradle.kts index 9abcf7f..bdb499e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -37,9 +37,8 @@ include(":server:gtfs") include(":server:gtfs_rt") include(":core") include(":core:data") -include(":core:data:client") -include(":core:data:server") -include(":core:room") +include(":core:stoptime") +include(":core:sqld") include(":ui") include(":ui:maps") include(":ui:shared") diff --git a/ui/build.gradle.kts b/ui/build.gradle.kts index 9c5c7bd..b599bc6 100644 --- a/ui/build.gradle.kts +++ b/ui/build.gradle.kts @@ -41,7 +41,9 @@ kotlin { sourceSets { androidMain.dependencies { + implementation(libs.compose.ui.tooling.preview) implementation(libs.play.services.location) + implementation(projects.ui.shared) } commonMain.dependencies { implementation(libs.compose.components.resources) @@ -68,7 +70,8 @@ kotlin { implementation(libs.ui.backhandler) implementation(projects.core) - implementation(projects.core.data.client) + implementation(projects.core.data) + implementation(projects.core.stoptime) implementation(projects.ui.maps) implementation(projects.ui.shared) } diff --git a/ui/shared/build.gradle.kts b/ui/shared/build.gradle.kts index e379840..2a78572 100644 --- a/ui/shared/build.gradle.kts +++ b/ui/shared/build.gradle.kts @@ -16,6 +16,10 @@ kotlin { compilerOptions { jvmTarget.set(JvmTarget.JVM_11) } + + androidResources { + enable = true + } } compilerOptions { @@ -47,4 +51,5 @@ dependencies { compose.resources { publicResClass = true packageOfResClass = "moe.lava.banksia.resources" + generateResClass = always } diff --git a/ui/shared/src/commonMain/composeResources/drawable/arrow_drop_down.xml b/ui/shared/src/commonMain/composeResources/drawable/arrow_drop_down.xml new file mode 100644 index 0000000..ac49572 --- /dev/null +++ b/ui/shared/src/commonMain/composeResources/drawable/arrow_drop_down.xml @@ -0,0 +1,9 @@ + + + diff --git a/ui/shared/src/commonMain/composeResources/drawable/arrow_drop_up.xml b/ui/shared/src/commonMain/composeResources/drawable/arrow_drop_up.xml new file mode 100644 index 0000000..322fa56 --- /dev/null +++ b/ui/shared/src/commonMain/composeResources/drawable/arrow_drop_up.xml @@ -0,0 +1,9 @@ + + + diff --git a/ui/src/commonMain/kotlin/moe/lava/banksia/ui/di/AppModule.kt b/ui/src/commonMain/kotlin/moe/lava/banksia/ui/di/AppModule.kt index a2b4d7e..cff36fb 100644 --- a/ui/src/commonMain/kotlin/moe/lava/banksia/ui/di/AppModule.kt +++ b/ui/src/commonMain/kotlin/moe/lava/banksia/ui/di/AppModule.kt @@ -1,12 +1,12 @@ package moe.lava.banksia.ui.di -import moe.lava.banksia.core.data.clientDataDiModule +import moe.lava.banksia.core.data.dataDiModule import moe.lava.banksia.ui.screens.map.MapScreenViewModel import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.module val AppModule = module { - includes(clientDataDiModule) + includes(dataDiModule) // ViewModel viewModelOf(::MapScreenViewModel) diff --git a/ui/src/commonMain/kotlin/moe/lava/banksia/ui/layout/info/InfoPanel.kt b/ui/src/commonMain/kotlin/moe/lava/banksia/ui/layout/info/InfoPanel.kt index 55eac69..9fb37d7 100644 --- a/ui/src/commonMain/kotlin/moe/lava/banksia/ui/layout/info/InfoPanel.kt +++ b/ui/src/commonMain/kotlin/moe/lava/banksia/ui/layout/info/InfoPanel.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeContent import androidx.compose.foundation.layout.size @@ -27,7 +28,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.coerceAtMost import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay import kotlin.time.Duration.Companion.milliseconds @@ -45,6 +45,7 @@ sealed class InfoPanelState { @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun InfoPanel( + modifier: Modifier = Modifier, state: InfoPanelState, onEvent: (InfoPanelEvent) -> Unit, onPeekHeightChange: (Dp) -> Unit, @@ -65,11 +66,13 @@ fun InfoPanel( } Column( - Modifier + modifier = modifier .fillMaxWidth() .padding(horizontal = 24.dp) + .heightIn(min = 350.dp) .onSizeChanged { - onPeekHeightChange(with(localDensity) { it.height.toDp().coerceAtMost(250.dp) }) +// onPeekHeightChange(with(localDensity) { it.height.toDp().coerceAtMost(250.dp) }) + onPeekHeightChange(350.dp) } ) { Box { diff --git a/ui/src/commonMain/kotlin/moe/lava/banksia/ui/layout/info/StopInfoPanel.kt b/ui/src/commonMain/kotlin/moe/lava/banksia/ui/layout/info/StopInfoPanel.kt index dbe3b29..369721c 100644 --- a/ui/src/commonMain/kotlin/moe/lava/banksia/ui/layout/info/StopInfoPanel.kt +++ b/ui/src/commonMain/kotlin/moe/lava/banksia/ui/layout/info/StopInfoPanel.kt @@ -1,75 +1,358 @@ package moe.lava.banksia.ui.layout.info +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Edit +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SegmentedListItem +import androidx.compose.material3.ShapeDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import moe.lava.banksia.resources.Res +import moe.lava.banksia.resources.arrow_drop_down +import moe.lava.banksia.resources.arrow_drop_up +import moe.lava.banksia.ui.extensions.BUS_ORANGE +import moe.lava.banksia.ui.extensions.TRAIN_BLUE +import moe.lava.banksia.ui.platform.BanksiaTheme +import org.jetbrains.compose.resources.painterResource +import kotlin.time.Clock +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Instant -sealed class StopInfoPanelEvent : InfoPanelEvent() +sealed class StopInfoPanelEvent : InfoPanelEvent() { + data object ToggleGrouping : StopInfoPanelEvent() +} data class StopInfoPanelState( val id: String, val name: String, val subname: String? = null, - val departures: List? = null, + val departures: List? = null, ) : InfoPanelState() { override val loading: Boolean - get() = departures == null + get() = departures.isNullOrEmpty() - data class Departure(val directionName: String, val formattedTimes: String) + data class DeparturePlatforms( + val platform: String, + val departures: List, + ) + + data class DepartureInfo( + val routeName: String, + val routeColour: Color?, + val headsign: String, + val description: String?, + val time: Instant, + ) } @Composable -internal fun StopInfoPanel( - state: StopInfoPanelState, - onEvent: (StopInfoPanelEvent) -> Unit, +private fun listColors() = ListItemDefaults.colors( + containerColor = MaterialTheme.colorScheme.surfaceContainer, + selectedContainerColor = MaterialTheme.colorScheme.primary, + selectedContentColor = MaterialTheme.colorScheme.onPrimary, +) + +@Composable +@OptIn(ExperimentalMaterial3ExpressiveApi::class) +private fun MonoPlatform( + state: StopInfoPanelState.DeparturePlatforms ) { - Column(Modifier.fillMaxWidth()) { - Text( - state.name, - style = MaterialTheme.typography.titleLarge, - fontWeight = FontWeight.SemiBold, - textAlign = TextAlign.Start - ) - state.subname?.let { - Text( - "/ $it", - modifier = Modifier.padding(start = 5.dp), - style = MaterialTheme.typography.titleSmall, - color = Color.Gray, - fontWeight = FontWeight.SemiBold, - textAlign = TextAlign.Start - ) - } - state.departures?.let { - Spacer(Modifier.height(5.dp)) - it.forEach { (name, formatted) -> - Row(verticalAlignment = Alignment.CenterVertically) { + val departures = state.departures + val lazyState = LazyListState(firstVisibleItemIndex = + departures.indexOfFirst { + it.time > Clock.System.now() + }.coerceAtLeast(0) + ) + LazyColumn( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(ListItemDefaults.SegmentedGap), + state = lazyState, + ) { + itemsIndexed(departures) { idx, dep -> + SegmentedListItem( + onClick = {}, + colors = listColors(), + shapes = ListItemDefaults.segmentedShapes( + idx, + departures.size, + ), + supportingContent = { + dep.description?.let { Text(dep.description) } + }, + trailingContent = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy((-4).dp) + ) { + Text( + text = (dep.time - Clock.System.now()).inWholeMinutes.toString(), + style = MaterialTheme.typography.headlineSmallEmphasized, + ) + Text( + text = "mn", + style = MaterialTheme.typography.labelSmallEmphasized, + ) + } + }, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(6.dp) + ) { + Box( + Modifier + .clip(ShapeDefaults.ExtraSmall) + .background(dep.routeColour ?: MaterialTheme.colorScheme.surface) + .padding(vertical = 2.dp, horizontal = 4.dp) + ) { + Text( + text = dep.routeName, + style = MaterialTheme.typography.labelSmallEmphasized, + color = MaterialTheme.colorScheme.surface, + ) + } Text( - name, - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.SemiBold - ) - Text( - formatted, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - modifier = Modifier.padding(horizontal = 5.dp) + text = dep.headsign, + style = MaterialTheme.typography.labelLargeEmphasized, ) } } } } } + +@Composable +@OptIn(ExperimentalMaterial3ExpressiveApi::class) +private fun ManyPlatforms( + state: List, +) { + val expandedList = remember { mutableStateListOf(*Array(state.size) { true }) } + LazyColumn( + modifier = Modifier.fillMaxSize(), + ) { + state.forEachIndexed { idx, depInfo -> + val (platform, departures) = depInfo + val expanded = expandedList[idx] + stickyHeader(key = "header_${depInfo.hashCode()}") { + val base = ListItemDefaults.segmentedShapes(0, 2) + val large = MaterialTheme.shapes.large + + Box( + Modifier + .animateItem() + .background(MaterialTheme.colorScheme.surfaceContainerLow) + .padding(bottom = ListItemDefaults.SegmentedGap) + ) { + SegmentedListItem( + onClick = { expandedList[idx] = !expandedList[idx] }, + colors = listColors(), + shapes = if (expanded) base else base.copy(shape = large), + trailingContent = { + Icon( + painterResource(if (expanded) Res.drawable.arrow_drop_up else Res.drawable.arrow_drop_down), + contentDescription = null, + modifier = Modifier + .background( + if (expanded) MaterialTheme.colorScheme.surface else Color.Transparent, + shape = RoundedCornerShape(100) + ) + .padding(6.dp), + tint = MaterialTheme.colorScheme.onSurface, + ) + }, + ) { + Text( + text = platform, + style = MaterialTheme.typography.labelLarge, + ) + } + } + } + + if (expanded) { + item(key = "items_${depInfo.hashCode()}") { + Column( + modifier = Modifier.animateItem(), + verticalArrangement = Arrangement.spacedBy(ListItemDefaults.SegmentedGap), + ) { + departures.filter { it.time > Clock.System.now() }.take(5) + .forEachIndexed { idx, dep -> + SegmentedListItem( + onClick = {}, + colors = listColors(), + shapes = ListItemDefaults.segmentedShapes( + idx + 1, + (departures.size + 1).coerceAtMost(6), + ), + supportingContent = { + dep.description?.let { Text(dep.description) } + }, + trailingContent = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy((-4).dp) + ) { + Text( + text = (dep.time - Clock.System.now()).inWholeMinutes.toString(), + style = MaterialTheme.typography.headlineSmallEmphasized, + ) + Text( + text = "mn", + style = MaterialTheme.typography.labelSmallEmphasized, + ) + } + }, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(6.dp) + ) { + Box( + Modifier + .clip(ShapeDefaults.ExtraSmall) + .background( + dep.routeColour + ?: MaterialTheme.colorScheme.surface + ) + .padding(vertical = 2.dp, horizontal = 4.dp) + ) { + Text( + text = dep.routeName, + style = MaterialTheme.typography.labelSmallEmphasized, + color = MaterialTheme.colorScheme.surface, + ) + } + Text( + text = dep.headsign, + style = MaterialTheme.typography.labelLargeEmphasized, + ) + } + } + } + } + } + } + item(key = "spacer_${depInfo.hashCode()}") { + Spacer( + modifier = Modifier.animateItem().height(10.dp) + ) + } + } + } +} + +@OptIn(ExperimentalMaterial3ExpressiveApi::class) +@Composable +internal fun StopInfoPanel( + state: StopInfoPanelState, + onEvent: (StopInfoPanelEvent) -> Unit, +) { + val spec = fadeIn(tween(300, 300)) togetherWith fadeOut(tween(300)) + + AnimatedContent( + targetState = state, + contentKey = { it.id }, + transitionSpec = { spec }, + ) { state -> + Column(Modifier.fillMaxWidth().fillMaxHeight()) { + Row { + Column { + Text( + state.name, + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.SemiBold, + textAlign = TextAlign.Start + ) + state.subname?.let { + Text( + "/ $it", + modifier = Modifier.padding(start = 5.dp), + style = MaterialTheme.typography.titleSmall, + color = Color.Gray, + fontWeight = FontWeight.SemiBold, + textAlign = TextAlign.Start + ) + } + } + IconButton( + onClick = { onEvent(StopInfoPanelEvent.ToggleGrouping) }, + ) { Icon(Icons.Default.Edit, null) } + } + Spacer(Modifier.height(10.dp)) + AnimatedContent( + targetState = state.departures, + transitionSpec = { spec }, + ) { departures -> + departures?.let { departurePlatforms -> + if (departurePlatforms.size > 1) { + ManyPlatforms(departurePlatforms) + } else if (departurePlatforms.size == 1) { + MonoPlatform(departurePlatforms[0]) + } + } + } + } + } +} + +@Preview +@Composable +internal fun StopInfoPanelPreview() { + fun dateIn(dur: Duration) = (Clock.System.now() + dur) + + InfoPanel( + modifier = Modifier.background(BanksiaTheme.colors.background), + state = StopInfoPanelState( + id = "id", + name = "name", + subname = "sub", + departures = listOf( + StopInfoPanelState.DeparturePlatforms("Platform 1", listOf( + StopInfoPanelState.DepartureInfo("Sunbury", Color(TRAIN_BLUE), "Sunbury", "··· Malvern -> Anzac ··· Sunbury", dateIn(2.minutes)), + StopInfoPanelState.DepartureInfo("Sunbury", Color(TRAIN_BLUE), "West Footscray", "Express via Metro Tunnel", dateIn(8.minutes)), + )), + StopInfoPanelState.DeparturePlatforms("Platform 2", listOf( + StopInfoPanelState.DepartureInfo("237", Color(BUS_ORANGE), "Westall", null, dateIn(7.minutes)), + StopInfoPanelState.DepartureInfo("442", Color(BUS_ORANGE), "Dandenong", null, dateIn(8.minutes)), + )), + ), + ), + onEvent = {}, + onPeekHeightChange = {}, + ) +} diff --git a/ui/src/commonMain/kotlin/moe/lava/banksia/ui/screens/map/MapScreenViewModel.kt b/ui/src/commonMain/kotlin/moe/lava/banksia/ui/screens/map/MapScreenViewModel.kt index c4bd768..de06381 100644 --- a/ui/src/commonMain/kotlin/moe/lava/banksia/ui/screens/map/MapScreenViewModel.kt +++ b/ui/src/commonMain/kotlin/moe/lava/banksia/ui/screens/map/MapScreenViewModel.kt @@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.datetime.TimeZone import kotlinx.datetime.toInstant +import moe.lava.banksia.core.data.dto.ExtendedStopTime import moe.lava.banksia.core.data.repositories.RouteRepository import moe.lava.banksia.core.data.repositories.StopRepository import moe.lava.banksia.core.data.repositories.StopTimeRepository @@ -26,9 +27,11 @@ import moe.lava.banksia.core.util.LoopFlow.Companion.waitUntilSubscribed import moe.lava.banksia.core.util.Point import moe.lava.banksia.core.util.log import moe.lava.banksia.data.ptv.PtvService +import moe.lava.banksia.ui.extensions.getUIProperties import moe.lava.banksia.ui.layout.info.InfoPanelEvent import moe.lava.banksia.ui.layout.info.InfoPanelState import moe.lava.banksia.ui.layout.info.RouteInfoPanelState +import moe.lava.banksia.ui.layout.info.StopInfoPanelEvent import moe.lava.banksia.ui.layout.info.StopInfoPanelState import moe.lava.banksia.ui.layout.info.TripInfoPanelState import moe.lava.banksia.ui.map.util.CameraPosition @@ -36,8 +39,6 @@ import moe.lava.banksia.ui.map.util.CameraPositionBounds import moe.lava.banksia.ui.map.util.Marker import moe.lava.banksia.ui.state.MapState import moe.lava.banksia.ui.state.SearchState -import kotlin.time.Clock -import kotlin.time.Duration.Companion.minutes sealed class MapScreenEvent { data object DismissState : MapScreenEvent() @@ -53,6 +54,9 @@ private data class InternalState( val route: String? = null, val stop: String? = null, val run: String? = null, + + val lastStopDepartures: List? = null, + val stopsGrouped: Boolean = true, ) class MapScreenViewModel( @@ -69,6 +73,10 @@ class MapScreenViewModel( viewModelScope.launch { switchRoute(value.route) } if (value.stop != last.stop) viewModelScope.launch { switchStop(value.stop) } + if (value.lastStopDepartures != last.lastStopDepartures) + viewModelScope.launch { buildDepartures() } + if (value.stopsGrouped != last.stopsGrouped) + viewModelScope.launch { buildDepartures() } if (value.run != last.run) switchRun(value.run) } @@ -105,7 +113,9 @@ class MapScreenViewModel( fun handleEvent(event: InfoPanelEvent) { viewModelScope.launch { -// when (event) { } + when (event) { + StopInfoPanelEvent.ToggleGrouping -> state = state.copy(stopsGrouped = !state.stopsGrouped) + } } } @@ -165,7 +175,7 @@ class MapScreenViewModel( } val route = routeRepository.get(routeId) -// val gtfsRoute = ptvService.route(routeId) + ?: return iInfoState.update { RouteInfoPanelState( name = route.name, @@ -215,11 +225,11 @@ class MapScreenViewModel( private suspend fun switchStop(id: String?) { if (id == null) { iInfoState.update { InfoPanelState.None } + state = state.copy(lastStopDepartures = null) return } val stop = stopRepository.get(id) -// val stop = ptvService.stop(routeType, stopId) val split = stop.name.split("/") val name = split[0] val subname = split.getOrNull(1) @@ -231,29 +241,61 @@ class MapScreenViewModel( ) } - val departures = stopTimeRepository.getForStop(id) - .filter { !it.headsign.isNullOrBlank() } - .groupBy { it.headsign!! } - .map { (headsign, stopTimes) -> - val now = Clock.System.now() - val times = stopTimes - .map { it.arrivalTime.toInstant(TimeZone.currentSystemDefault()) } - .filter { it >= (now - 1.minutes) } - .joinToString(" | ") { - val diff = (it - now).inWholeMinutes.coerceAtLeast(0) - if (diff >= 65) { - "${((diff + 30.0) / 60.0).toInt()}hr" - } else { - "${diff}mn" - } - } - StopInfoPanelState.Departure(headsign, times) + stopTimeRepository.getForStop(id) + .onEach { departures -> + state = state.copy( + lastStopDepartures = departures + ) + } + .launchIn(viewModelScope) + } + + private fun friendlyPlatform(platform: String) = + platform.takeUnless { it.firstOrNull()?.isDigit() == true } + ?: "Platform $platform" + private fun buildDepartures() { + val rawDepartures = state.lastStopDepartures ?: return + val departures = if (state.stopsGrouped) { + rawDepartures + .groupBy { it.stopPlatformCode } + .mapKeys { (platform) -> platform?.let { friendlyPlatform(it) } } + .entries + .sortedBy { (platform) -> platform } + .map { (platform, deps) -> + StopInfoPanelState.DeparturePlatforms( + platform = platform ?: "", + departures = deps.map { + StopInfoPanelState.DepartureInfo( + routeName = it.routeNumber ?: it.routeName, + routeColour = it.routeType.getUIProperties().colour, + headsign = it.headsign ?: it.routeName, + description = null, + time = it.time.departure.toInstant(TimeZone.currentSystemDefault()), + ) + } + ) + } + } else if (rawDepartures.isEmpty()) { + listOf() + } else { + listOf(StopInfoPanelState.DeparturePlatforms(platform = "", departures = rawDepartures.map { dep -> + StopInfoPanelState.DepartureInfo( + routeName = dep.routeNumber ?: dep.routeName, + routeColour = dep.routeType.getUIProperties().colour, + headsign = dep.headsign ?: dep.routeName, + description = dep.stopPlatformCode?.let { friendlyPlatform(it) }, + time = dep.time.departure.toInstant(TimeZone.currentSystemDefault()), + ) + })) + } + + departures.let { departures -> + iInfoState.update { + if (it !is StopInfoPanelState) + it + else + it.copy(departures = departures) } - iInfoState.update { - if (it !is StopInfoPanelState) - it - else - it.copy(departures = departures) } }