Compare commits
16 commits
74338d6dce
...
c55e3a3232
| Author | SHA1 | Date | |
|---|---|---|---|
| c55e3a3232 | |||
| 58649b6171 | |||
| c9aeeb99c1 | |||
| 91d4fe25a6 | |||
| b568ed547a | |||
| ed9d294afc | |||
| 0181497420 | |||
| aad5ae4024 | |||
| f0ce780bba | |||
| 72b9fb2757 | |||
| b5f2ec102d | |||
| 8925c943ab | |||
| a79c95829e | |||
| aab03ced07 | |||
| 758f9cea01 | |||
| 2b64fdcda9 |
1
.gitignore
vendored
|
|
@ -20,3 +20,4 @@ captures
|
|||
secrets.properties
|
||||
shared/src/commonMain/kotlin/moe/lava/banksia/Constants.kt
|
||||
/data/
|
||||
/data
|
||||
|
|
|
|||
57
androidApp/build.gradle.kts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.androidApplication)
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.composeCompiler)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
target {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_11)
|
||||
}
|
||||
}
|
||||
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.ui)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.compose.ui.tooling.preview)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
debugImplementation(libs.compose.ui.tooling)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "moe.lava.banksia"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "moe.lava.banksia"
|
||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||
targetSdk = libs.versions.android.targetSdk.get().toInt()
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
}
|
||||
packaging {
|
||||
resources {
|
||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
getByName("release") {
|
||||
isMinifyEnabled = false
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
|
@ -13,9 +13,6 @@
|
|||
android:enableOnBackInvokedCallback="true"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:theme="@android:style/Theme.Material.Light.NoActionBar">
|
||||
<meta-data
|
||||
android:name="com.google.android.geo.API_KEY"
|
||||
android:value="${MAPS_API_KEY}" />
|
||||
<activity
|
||||
android:exported="true"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -2,7 +2,7 @@ plugins {
|
|||
// this is necessary to avoid the plugins to be loaded multiple times
|
||||
// in each subproject's classloader
|
||||
alias(libs.plugins.androidApplication) apply false
|
||||
alias(libs.plugins.androidLibrary) apply false
|
||||
alias(libs.plugins.androidMultiplatformLibrary) apply false
|
||||
alias(libs.plugins.composeMultiplatform) apply false
|
||||
alias(libs.plugins.composeCompiler) apply false
|
||||
alias(libs.plugins.kotlinJvm) apply false
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
alias(libs.plugins.androidLibrary)
|
||||
alias(libs.plugins.androidMultiplatformLibrary)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
androidTarget {
|
||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
||||
android {
|
||||
namespace = "moe.lava.banksia.client"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_11)
|
||||
}
|
||||
|
|
@ -19,7 +20,6 @@ kotlin {
|
|||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||
}
|
||||
|
||||
iosX64()
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
|
|
@ -41,15 +41,3 @@ kotlin {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "moe.lava.banksia.client"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
defaultConfig {
|
||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package moe.lava.banksia.client.data.stoptime
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.todayIn
|
||||
import moe.lava.banksia.model.StopTimeDated
|
||||
import moe.lava.banksia.model.atDate
|
||||
import moe.lava.banksia.room.dao.StopTimeDao
|
||||
import moe.lava.banksia.util.serialise
|
||||
import kotlin.time.Clock
|
||||
|
||||
class StopTimeLocalDataSource(
|
||||
private val stopTimeDao: StopTimeDao,
|
||||
) {
|
||||
suspend fun getAtStop(
|
||||
stopId: String,
|
||||
date: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault()),
|
||||
): List<StopTimeDated> {
|
||||
return stopTimeDao
|
||||
.getForStopDated(
|
||||
stopId,
|
||||
listOf(date.dayOfWeek).serialise(),
|
||||
date.toEpochDays().toInt(),
|
||||
)
|
||||
.map { it.asModel().atDate(date) }
|
||||
.sortedBy { it.departureTime }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package moe.lava.banksia.client.data.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.model.StopTimeDated
|
||||
import kotlin.time.Clock
|
||||
|
||||
class StopTimeRemoteDataSource(
|
||||
private val client: HttpClient,
|
||||
) {
|
||||
suspend fun getAtStop(
|
||||
stopId: String,
|
||||
date: LocalDate? = Clock.System.todayIn(TimeZone.currentSystemDefault()),
|
||||
): List<StopTimeDated> {
|
||||
return client.get("stoptimes/by_stop/${stopId}") {
|
||||
parameter("date", date)
|
||||
}.body<List<StopTimeDated>>()
|
||||
}
|
||||
|
||||
/*suspend fun get(
|
||||
stop: String? = null,
|
||||
trip: String? = null,
|
||||
day: DayOfWeek? = Clock.System.todayIn(TimeZone.currentSystemDefault()).dayOfWeek,
|
||||
): List<StopTime> {
|
||||
return client.get("stoptimes") {
|
||||
stop?.let { parameter("stop", it) }
|
||||
trip?.let { parameter("trip", it) }
|
||||
day?.let { parameter("day", it) }
|
||||
}.body<List<StopTime>>()
|
||||
}*/
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package moe.lava.banksia.client.data.trip
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import kotlinx.datetime.DayOfWeek
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.todayIn
|
||||
import moe.lava.banksia.model.Trip
|
||||
import kotlin.time.Clock
|
||||
|
||||
class TripRemoteDataSource(
|
||||
private val client: HttpClient,
|
||||
) {
|
||||
suspend fun get(
|
||||
day: DayOfWeek? = Clock.System.todayIn(TimeZone.currentSystemDefault()).dayOfWeek,
|
||||
): List<Trip> {
|
||||
return listOf()
|
||||
}
|
||||
}
|
||||
|
|
@ -12,8 +12,11 @@ import moe.lava.banksia.client.data.route.RouteLocalDataSource
|
|||
import moe.lava.banksia.client.data.route.RouteRemoteDataSource
|
||||
import moe.lava.banksia.client.data.stop.StopLocalDataSource
|
||||
import moe.lava.banksia.client.data.stop.StopRemoteDataSource
|
||||
import moe.lava.banksia.client.data.stoptime.StopTimeLocalDataSource
|
||||
import moe.lava.banksia.client.data.stoptime.StopTimeRemoteDataSource
|
||||
import moe.lava.banksia.client.repository.RouteRepository
|
||||
import moe.lava.banksia.client.repository.StopRepository
|
||||
import moe.lava.banksia.client.repository.StopTimeRepository
|
||||
import moe.lava.banksia.data.ptv.PtvService
|
||||
import moe.lava.banksia.util.log
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
|
|
@ -46,8 +49,11 @@ val ClientModule = module {
|
|||
singleOf(::RouteRemoteDataSource)
|
||||
singleOf(::StopLocalDataSource)
|
||||
singleOf(::StopRemoteDataSource)
|
||||
singleOf(::StopTimeLocalDataSource)
|
||||
singleOf(::StopTimeRemoteDataSource)
|
||||
|
||||
// Repositories
|
||||
singleOf(::RouteRepository)
|
||||
singleOf(::StopRepository)
|
||||
singleOf(::StopTimeRepository)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package moe.lava.banksia.client.repository
|
||||
|
||||
import moe.lava.banksia.client.data.stoptime.StopTimeLocalDataSource
|
||||
import moe.lava.banksia.client.data.stoptime.StopTimeRemoteDataSource
|
||||
import moe.lava.banksia.model.StopTimeDated
|
||||
|
||||
class StopTimeRepository(
|
||||
private val local: StopTimeLocalDataSource,
|
||||
private val remote: StopTimeRemoteDataSource,
|
||||
) {
|
||||
suspend fun getForStop(id: String): List<StopTimeDated> {
|
||||
return local
|
||||
.getAtStop(id)
|
||||
.ifEmpty { remote.getAtStop(id) }
|
||||
}
|
||||
}
|
||||
13
gradle/gradle-daemon-jvm.properties
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#This file is generated by updateDaemonJvm
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/ecd23fd7707c683afbcd6052998cb6a9/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/398ffe3949748bfb1d5636f023d228fd/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e99bae143b75f9a10ead10248f02055e/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/04e088f8677de3b384108493cc9481d0/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/398ffe3949748bfb1d5636f023d228fd/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e55dccbfe27cb97945148c61a39c89c5/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/dbd05c4936d573642f94cd149e1356c8/redirect
|
||||
toolchainVendor=JETBRAINS
|
||||
toolchainVersion=21
|
||||
|
|
@ -1,40 +1,37 @@
|
|||
[versions]
|
||||
agp = "8.13.1"
|
||||
agp = "9.1.0"
|
||||
android-compileSdk = "36"
|
||||
android-minSdk = "24"
|
||||
android-targetSdk = "36"
|
||||
androidx-activityCompose = "1.12.4"
|
||||
androidx-appcompat = "1.7.0"
|
||||
androidx-constraintlayout = "2.2.1"
|
||||
androidx-core-ktx = "1.15.0"
|
||||
androidx-espresso-core = "3.6.1"
|
||||
androidx-lifecycle = "2.9.6"
|
||||
androidx-material = "1.12.0"
|
||||
androidx-test-junit = "1.2.1"
|
||||
compose-multiplatform = "1.11.0-alpha02"
|
||||
androidx-activity= "1.13.0"
|
||||
androidx-lifecycle = "2.10.0"
|
||||
compose-multiplatform = "1.11.0-alpha04"
|
||||
composeunstyled = "1.49.6"
|
||||
coroutines = "1.10.2"
|
||||
geo = "0.8.0"
|
||||
junit = "4.13.2"
|
||||
koin = "4.1.1"
|
||||
kotlin = "2.3.10"
|
||||
koin = "4.2.0"
|
||||
kotlin = "2.3.20"
|
||||
kotlinxDatetime = "0.7.1"
|
||||
kotlinxSerializationCsv = "0.2.18"
|
||||
kotlinxSerialization = "1.10.0"
|
||||
ksp = "2.3.4"
|
||||
ktor = "3.4.0"
|
||||
ktor = "3.4.1"
|
||||
logback = "1.5.32"
|
||||
maplibre = "0.12.1"
|
||||
material = "1.7.3"
|
||||
material3 = "1.11.0-alpha02"
|
||||
okio = "3.16.4"
|
||||
material3 = "1.11.0-alpha04"
|
||||
okio = "3.17.0"
|
||||
playServicesLocation = "21.3.0"
|
||||
sqlite = "2.6.2"
|
||||
room = "2.8.4"
|
||||
secretsGradlePlugin = "2.0.1"
|
||||
wire = "5.5.0"
|
||||
wire = "6.1.0"
|
||||
|
||||
[libraries]
|
||||
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
|
||||
androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
|
||||
androidx-lifecycle-viewmodel-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" }
|
||||
androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
|
||||
compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "compose-multiplatform" }
|
||||
compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "compose-multiplatform" }
|
||||
compose-material-icons-core = { module = "org.jetbrains.compose.material:material-icons-core", version.ref = "material" }
|
||||
|
|
@ -44,18 +41,11 @@ compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-mu
|
|||
compose-ui-tooling = { module = "org.jetbrains.compose.ui:ui-tooling", version.ref = "compose-multiplatform" }
|
||||
compose-ui-tooling-preview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "compose-multiplatform" }
|
||||
composeunstyled = { module = "com.composables:composeunstyled", version.ref = "composeunstyled" }
|
||||
moko-geo = { module = "dev.icerock.moko:geo", version.ref = "geo" }
|
||||
moko-geo-compose = { module = "dev.icerock.moko:geo-compose", version.ref = "geo" }
|
||||
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
|
||||
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
|
||||
androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
|
||||
androidx-lifecycle-viewmodel-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" }
|
||||
androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
|
||||
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" }
|
||||
koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" }
|
||||
koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin" }
|
||||
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
|
||||
koin-ktor = { module = "io.insert-koin:koin-ktor", version.ref = "koin" }
|
||||
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
|
||||
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
|
||||
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" }
|
||||
|
|
@ -73,11 +63,11 @@ ktor-server-netty = { module = "io.ktor:ktor-server-netty-jvm", version.ref = "k
|
|||
ktor-server-tests = { module = "io.ktor:ktor-server-test-host", version.ref = "ktor" }
|
||||
logback = { module = "ch.qos.logback:logback-classic", version.ref = "logback" }
|
||||
maplibre-compose = { module = "org.maplibre.compose:maplibre-compose", version.ref = "maplibre" }
|
||||
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-common = { group = "androidx.room", name = "room-common", version.ref = "room" }
|
||||
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
|
||||
room-ktx = { group = "androidx.room", name = "room-ktx", 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" }
|
||||
|
|
@ -85,7 +75,7 @@ ui-backhandler = { module = "org.jetbrains.compose.ui:ui-backhandler", version.r
|
|||
|
||||
[plugins]
|
||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||
androidLibrary = { id = "com.android.library", version.ref = "agp" }
|
||||
androidMultiplatformLibrary = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
|
||||
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
|
||||
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
|
|
|
|||
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
|||
|
|
@ -12,8 +12,17 @@ application {
|
|||
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=${extra["io.ktor.development"] ?: "false"}")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.shared)
|
||||
implementation(projects.server.gtfs)
|
||||
implementation(projects.server.gtfsRt)
|
||||
|
||||
implementation(libs.logback)
|
||||
implementation(libs.koin.core)
|
||||
implementation(libs.koin.ktor)
|
||||
|
|
|
|||
20
server/gtfs/build.gradle.kts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
plugins {
|
||||
alias(libs.plugins.kotlinJvm)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.shared)
|
||||
implementation(libs.kotlinx.serialization.csv)
|
||||
implementation(libs.kotlinx.datetime)
|
||||
implementation(libs.ktor.client.contentnegotiation)
|
||||
implementation(libs.ktor.client.core)
|
||||
implementation(libs.ktor.client.okhttp)
|
||||
}
|
||||
|
|
@ -9,19 +9,26 @@ import io.ktor.client.statement.bodyAsChannel
|
|||
import io.ktor.util.cio.writeChannel
|
||||
import io.ktor.util.logging.Logger
|
||||
import io.ktor.utils.io.copyAndClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onCompletion
|
||||
import kotlinx.datetime.DayOfWeek
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.modules.EmptySerializersModule
|
||||
import kotlinx.serialization.serializer
|
||||
import moe.lava.banksia.Constants
|
||||
import moe.lava.banksia.model.Route
|
||||
import moe.lava.banksia.model.RouteType
|
||||
import moe.lava.banksia.model.Service
|
||||
import moe.lava.banksia.model.ServiceException
|
||||
import moe.lava.banksia.model.Shape
|
||||
import moe.lava.banksia.model.Stop
|
||||
import moe.lava.banksia.model.StopTime
|
||||
import moe.lava.banksia.model.Trip
|
||||
import moe.lava.banksia.room.Database
|
||||
import moe.lava.banksia.room.converter.RouteTypeConverter
|
||||
import moe.lava.banksia.room.entity.asEntity
|
||||
import moe.lava.banksia.server.gtfs.structures.GtfsRoute
|
||||
import moe.lava.banksia.server.gtfs.structures.GtfsService
|
||||
import moe.lava.banksia.server.gtfs.structures.GtfsServiceException
|
||||
import moe.lava.banksia.server.gtfs.structures.GtfsShape
|
||||
import moe.lava.banksia.server.gtfs.structures.GtfsStop
|
||||
import moe.lava.banksia.server.gtfs.structures.GtfsStopTime
|
||||
|
|
@ -29,19 +36,27 @@ import moe.lava.banksia.server.gtfs.structures.GtfsTrip
|
|||
import moe.lava.banksia.util.Point
|
||||
import java.io.File
|
||||
import java.util.zip.ZipFile
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.ExperimentalTime
|
||||
|
||||
class GtfsHandler(
|
||||
sealed class GtfsData {
|
||||
data class RouteChunk(val routes: List<Route>) : GtfsData()
|
||||
data class ServiceChunk(val services: List<Service>) : GtfsData()
|
||||
data class ServiceExceptionChunk(val exceptions: List<ServiceException>) : GtfsData()
|
||||
data class ShapeChunk(val shapes: List<Shape>) : GtfsData()
|
||||
data class StopChunk(val stops: List<Stop>) : GtfsData()
|
||||
data class StopTimeChunk(val stopTimes: List<StopTime>) : GtfsData()
|
||||
data class TripChunk(val trips: List<Trip>) : GtfsData()
|
||||
}
|
||||
|
||||
class GtfsParser(
|
||||
private val log: Logger,
|
||||
private val client: HttpClient,
|
||||
private val db: Database,
|
||||
) {
|
||||
private val csv = CsvFormat(StringDeferringConfig(EmptySerializersModule()))
|
||||
private val datasetPath = File("/tmp/banksia", "dataset.zip")
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
suspend fun update(datasetUrl: String, date: Long? = null) {
|
||||
suspend fun update(datasetUrl: String): Flow<GtfsData> {
|
||||
val parentDir = datasetPath.parentFile
|
||||
@Suppress("SimplifyBooleanWithConstants", "KotlinConstantConditions")
|
||||
if (parentDir.exists() && !Constants.devMode)
|
||||
|
|
@ -65,42 +80,65 @@ class GtfsHandler(
|
|||
.listFiles { it.isDirectory }
|
||||
.flatMap { d -> d.listFiles { f -> f.extension == "txt" }.toList() }
|
||||
.ifEmpty { extractAll(datasetPath) }
|
||||
// .filter { it.parentFile.name == "2" }
|
||||
} else {
|
||||
extractAll(datasetPath)
|
||||
}
|
||||
|
||||
addRoutes(files)
|
||||
addStops(files)
|
||||
addShapes(files)
|
||||
addTrips(files)
|
||||
addStopTimes(files)
|
||||
log.info("parsing...")
|
||||
return parse(files)
|
||||
.onCompletion {
|
||||
@Suppress("KotlinConstantConditions")
|
||||
if (!Constants.devMode) {
|
||||
parentDir.deleteRecursively()
|
||||
}
|
||||
|
||||
updateMetadata(date ?: Clock.System.now().epochSeconds)
|
||||
|
||||
@Suppress("KotlinConstantConditions")
|
||||
if (!Constants.devMode) {
|
||||
parentDir.deleteRecursively()
|
||||
}
|
||||
|
||||
log.info("done!")
|
||||
log.info("done!")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateMetadata(date: Long) {
|
||||
val dao = db.versionMetadataDao
|
||||
log.info("updating metadata...")
|
||||
dao.update(date, listOf("routes", "stops", "shapes", "trips", "stop_times"))
|
||||
}
|
||||
|
||||
private suspend fun addRoutes(files: List<File>) {
|
||||
val dao = db.routeDao
|
||||
log.info("parsing routes...")
|
||||
val routes = files
|
||||
private fun parse(files: List<File>) = flow {
|
||||
files
|
||||
.filter { it.name == "routes.txt" }
|
||||
.flatMap { fd -> parseRoutes(fd) }
|
||||
.forEach { emit(GtfsData.RouteChunk(parseRoutes(it))) }
|
||||
|
||||
log.info("inserting routes...")
|
||||
dao.deleteAll()
|
||||
dao.insertAll(*routes.map { it.asEntity() }.toTypedArray())
|
||||
files
|
||||
.filter { it.name == "stops.txt" }
|
||||
.forEach { emit(GtfsData.StopChunk(parseStops(it))) }
|
||||
|
||||
files
|
||||
.filter { it.name == "shapes.txt" }
|
||||
.forEach { emit(GtfsData.ShapeChunk(parseShapes(it))) }
|
||||
|
||||
val services = files
|
||||
.filter { it.name == "calendar.txt" }
|
||||
.flatMap { fd ->
|
||||
parseServices(fd)
|
||||
.also { emit(GtfsData.ServiceChunk(it)) }
|
||||
}
|
||||
.associateBy { it.id }
|
||||
|
||||
files
|
||||
.filter { it.name == "calendar_dates.txt" }
|
||||
.forEach { emit(GtfsData.ServiceExceptionChunk(parseServiceExceptions(it))) }
|
||||
|
||||
val trips = files
|
||||
.filter { it.name == "trips.txt" }
|
||||
.flatMap { fd ->
|
||||
parseTrips(fd, services)
|
||||
.also { emit(GtfsData.TripChunk(it)) }
|
||||
}
|
||||
.associateBy { it.id }
|
||||
|
||||
files
|
||||
.filter { it.name == "stop_times.txt" }
|
||||
.forEach { fd ->
|
||||
log.info("parsing stop times for ${fd.parent}...")
|
||||
parseStopTimes(fd, trips) { seq ->
|
||||
seq.chunked(10000)
|
||||
.forEach { emit(GtfsData.StopTimeChunk(it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseRoutes(fd: File) =
|
||||
|
|
@ -108,24 +146,12 @@ class GtfsHandler(
|
|||
.map { with(it) {
|
||||
Route(
|
||||
id = route_id,
|
||||
type = RouteTypeConverter.from(fd.parentFile.name.toInt()),
|
||||
type = RouteType.from(fd.parentFile.name.toInt()),
|
||||
number = route_short_name,
|
||||
name = route_long_name,
|
||||
)
|
||||
} }
|
||||
|
||||
private suspend fun addShapes(files: List<File>) {
|
||||
val dao = db.shapeDao
|
||||
log.info("parsing shapes...")
|
||||
val shapes = files
|
||||
.filter { it.name == "shapes.txt" }
|
||||
.flatMap { fd -> parseShapes(fd) }
|
||||
|
||||
log.info("inserting shapes...")
|
||||
dao.deleteAll()
|
||||
dao.insertAll(*shapes.map { it.asEntity() }.toTypedArray())
|
||||
}
|
||||
|
||||
private fun parseShapes(fd: File) =
|
||||
fd.parseCsv<GtfsShape>()
|
||||
.groupBy { it.shape_id }
|
||||
|
|
@ -137,29 +163,6 @@ class GtfsHandler(
|
|||
Shape(id, points)
|
||||
}
|
||||
|
||||
private suspend fun addStops(files: List<File>) {
|
||||
val dao = db.stopDao
|
||||
log.info("parsing stops...")
|
||||
val stops = files
|
||||
.filter { it.name == "stops.txt" }
|
||||
.flatMap { fd -> parseStops(fd) }
|
||||
|
||||
log.info("inserting stops...")
|
||||
dao.deleteAll()
|
||||
stops
|
||||
.groupBy { it.id }
|
||||
.forEach { (id, gstops) ->
|
||||
if (gstops.size > 1) {
|
||||
if (gstops.withIndex().any { (i, stop) -> i != 0 && stop != gstops[i - 1] }) {
|
||||
gstops.forEach {
|
||||
log.info("duplicate $id: $it")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.insertOrReplaceAll(*stops.map { it.asEntity() }.toTypedArray())
|
||||
}
|
||||
|
||||
private fun parseStops(fd: File) =
|
||||
fd.parseCsv<GtfsStop>()
|
||||
.map { with(it) {
|
||||
|
|
@ -174,27 +177,7 @@ class GtfsHandler(
|
|||
)
|
||||
} }
|
||||
|
||||
private suspend fun addStopTimes(files: List<File>) {
|
||||
val dao = db.stopTimeDao
|
||||
dao.deleteAll()
|
||||
log.info("parsing stop times...")
|
||||
files
|
||||
.filter { it.name == "stop_times.txt" }
|
||||
.forEach { fd ->
|
||||
log.info("parsing stop times for ${fd.parent}...")
|
||||
parseStopTimes(fd) { seq ->
|
||||
seq.chunked(1000000)
|
||||
.forEach { queue ->
|
||||
log.info("converting stop times (${queue.size}) for ${fd.parent}...")
|
||||
val conv = queue.map { it.asEntity() }.toTypedArray()
|
||||
log.info("inserting stop times (${conv.size}) for ${fd.parent}...")
|
||||
dao.insertOrReplaceAll(*conv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun parseStopTimes(fd: File, block: (Sequence<StopTime>) -> Unit) =
|
||||
private inline fun parseStopTimes(fd: File, trips: Map<String, Trip>, block: (Sequence<StopTime>) -> Unit) =
|
||||
fd.parseCsvSequence<GtfsStopTime> { seq ->
|
||||
seq
|
||||
.map { with(it) {
|
||||
|
|
@ -203,7 +186,7 @@ class GtfsHandler(
|
|||
stopId = stop_id,
|
||||
arrivalTime = GtfsStopTime.parseGtfsTime(arrival_time),
|
||||
departureTime = GtfsStopTime.parseGtfsTime(departure_time),
|
||||
headsign = stop_headsign,
|
||||
headsign = stop_headsign.ifEmpty { trips[trip_id]!!.tripHeadsign },
|
||||
pickupType = pickup_type,
|
||||
dropOffType = drop_off_type,
|
||||
)
|
||||
|
|
@ -211,25 +194,43 @@ class GtfsHandler(
|
|||
.let { block(it) }
|
||||
}
|
||||
|
||||
private suspend fun addTrips(files: List<File>) {
|
||||
val dao = db.tripDao
|
||||
log.info("parsing trips...")
|
||||
val trips = files
|
||||
.filter { it.name == "trips.txt" }
|
||||
.flatMap { fd -> parseTrips(fd) }
|
||||
private fun parseServices(fd: File) =
|
||||
fd.parseCsv<GtfsService>()
|
||||
.map { with(it) {
|
||||
val days = buildList {
|
||||
if (monday == 1) add(DayOfWeek.MONDAY)
|
||||
if (tuesday == 1) add(DayOfWeek.TUESDAY)
|
||||
if (wednesday == 1) add(DayOfWeek.WEDNESDAY)
|
||||
if (thursday == 1) add(DayOfWeek.THURSDAY)
|
||||
if (friday == 1) add(DayOfWeek.FRIDAY)
|
||||
if (saturday == 1) add(DayOfWeek.SATURDAY)
|
||||
if (sunday == 1) add(DayOfWeek.SUNDAY)
|
||||
}
|
||||
Service(
|
||||
id = service_id,
|
||||
days = days,
|
||||
start = LocalDate.parse(start_date, LocalDate.Formats.ISO_BASIC),
|
||||
end = LocalDate.parse(end_date, LocalDate.Formats.ISO_BASIC),
|
||||
)
|
||||
} }
|
||||
|
||||
log.info("inserting trips...")
|
||||
dao.deleteAll()
|
||||
dao.insertOrReplaceAll(*trips.map { it.asEntity() }.toTypedArray())
|
||||
}
|
||||
private fun parseServiceExceptions(fd: File) =
|
||||
fd.parseCsv<GtfsServiceException>()
|
||||
.map { with(it) {
|
||||
ServiceException(
|
||||
serviceId = service_id,
|
||||
date = LocalDate.parse(date, LocalDate.Formats.ISO_BASIC),
|
||||
type = exception_type,
|
||||
)
|
||||
} }
|
||||
|
||||
private fun parseTrips(fd: File) =
|
||||
private fun parseTrips(fd: File, services: Map<String, Service>) =
|
||||
fd.parseCsv<GtfsTrip>()
|
||||
.map { with(it) {
|
||||
Trip(
|
||||
id = trip_id,
|
||||
routeId = route_id,
|
||||
serviceId = service_id,
|
||||
service = services[service_id]!!,
|
||||
shapeId = shape_id.ifEmpty { null },
|
||||
tripHeadsign = trip_headsign,
|
||||
directionId = direction_id,
|
||||
|
|
@ -4,7 +4,7 @@ import kotlinx.serialization.Serializable
|
|||
|
||||
@Suppress("PropertyName")
|
||||
@Serializable
|
||||
data class GtfsRoute(
|
||||
internal data class GtfsRoute(
|
||||
val route_id: String,
|
||||
val agency_id: String,
|
||||
val route_short_name: String,
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package moe.lava.banksia.server.gtfs.structures
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Suppress("PropertyName")
|
||||
@Serializable
|
||||
internal data class GtfsService(
|
||||
val service_id: String,
|
||||
val monday: Int,
|
||||
val tuesday: Int,
|
||||
val wednesday: Int,
|
||||
val thursday: Int,
|
||||
val friday: Int,
|
||||
val saturday: Int,
|
||||
val sunday: Int,
|
||||
val start_date: String,
|
||||
val end_date: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package moe.lava.banksia.server.gtfs.structures
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Suppress("PropertyName")
|
||||
@Serializable
|
||||
internal data class GtfsServiceException(
|
||||
val service_id: String,
|
||||
val date: String,
|
||||
val exception_type: Int,
|
||||
)
|
||||
|
|
@ -4,7 +4,7 @@ import kotlinx.serialization.Serializable
|
|||
|
||||
@Suppress("PropertyName")
|
||||
@Serializable
|
||||
data class GtfsShape(
|
||||
internal data class GtfsShape(
|
||||
val shape_id: String,
|
||||
val shape_pt_lat: Double,
|
||||
val shape_pt_lon: Double,
|
||||
|
|
@ -4,7 +4,7 @@ import kotlinx.serialization.Serializable
|
|||
|
||||
@Suppress("PropertyName")
|
||||
@Serializable
|
||||
data class GtfsStop(
|
||||
internal data class GtfsStop(
|
||||
val stop_id: String,
|
||||
val stop_name: String,
|
||||
val stop_lat: Double,
|
||||
|
|
@ -5,7 +5,7 @@ import moe.lava.banksia.model.FutureTime
|
|||
|
||||
@Suppress("PropertyName")
|
||||
@Serializable
|
||||
data class GtfsStopTime(
|
||||
internal data class GtfsStopTime(
|
||||
val trip_id: String,
|
||||
val arrival_time: String,
|
||||
val departure_time: String,
|
||||
|
|
@ -4,7 +4,7 @@ import kotlinx.serialization.Serializable
|
|||
|
||||
@Suppress("PropertyName")
|
||||
@Serializable
|
||||
data class GtfsTrip(
|
||||
internal data class GtfsTrip(
|
||||
val route_id: String,
|
||||
val service_id: String,
|
||||
val trip_id: String,
|
||||
32
server/gtfs_rt/build.gradle.kts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
plugins {
|
||||
alias(libs.plugins.kotlinJvm)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
alias(libs.plugins.wire)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.shared)
|
||||
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)
|
||||
}
|
||||
|
||||
wire {
|
||||
sourcePath {
|
||||
srcDir("src/main/proto")
|
||||
}
|
||||
kotlin {}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package moe.lava.banksia.data.gtfsr
|
||||
package moe.lava.banksia.server.gtfsrt
|
||||
|
||||
import com.google.transit.realtime.FeedMessage
|
||||
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package moe.lava.banksia.server.gtfsrt
|
||||
|
||||
import com.google.transit.realtime.FeedMessage
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import moe.lava.banksia.util.log
|
||||
import java.io.File
|
||||
import kotlin.time.Instant
|
||||
|
||||
private const val BASE_DIR = "./data/gtfsr-archive/"
|
||||
|
||||
internal class GtfsrtArchiver {
|
||||
private var started = false
|
||||
|
||||
suspend fun start(flow: SharedFlow<Pair<String, ByteArray>>) {
|
||||
if (started) {
|
||||
log("GtfsrtArchiver", "Tried to start when already started")
|
||||
return
|
||||
}
|
||||
started = true
|
||||
coroutineScope {
|
||||
launch { compressJob() }
|
||||
|
||||
flow.collect { (type, rawData) ->
|
||||
val data = try {
|
||||
FeedMessage.ADAPTER.decode(rawData)
|
||||
} catch (e: Throwable) {
|
||||
log("gtfsr $type", "Failed to parse proto: $e")
|
||||
return@collect
|
||||
}
|
||||
val timestamp = data.header_.timestamp
|
||||
?: return@collect log("gtfsr $type", "Failed to read proto timestamp")
|
||||
|
||||
val time = Instant.fromEpochSeconds(timestamp).toLocalDateTime(TimeZone.currentSystemDefault())
|
||||
|
||||
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 target = File(currentParent, "${timestamp}.proto")
|
||||
|
||||
if (previousParent.isDirectory) {
|
||||
enqueueCompression(previousParent)
|
||||
}
|
||||
|
||||
if (!target.exists()) {
|
||||
try {
|
||||
if (!target.parentFile.isDirectory) {
|
||||
target.parentFile.mkdirs()
|
||||
}
|
||||
target.writeBytes(rawData)
|
||||
} catch (e: Throwable) {
|
||||
log("gtfsr $type", "Failed to write ${target}: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val cqueue = mutableSetOf<File>()
|
||||
private val ignore = mutableSetOf<File>()
|
||||
private val cmut = Mutex()
|
||||
private suspend fun enqueueCompression(fd: File) {
|
||||
cmut.withLock { cqueue.add(fd) }
|
||||
}
|
||||
|
||||
private suspend fun compressJob() {
|
||||
while(true) {
|
||||
while(true) {
|
||||
val next = cmut.withLock { cqueue.firstOrNull() }
|
||||
?: break
|
||||
if (!next.isDirectory) {
|
||||
cmut.withLock { cqueue.remove(next) }
|
||||
continue
|
||||
}
|
||||
if (next in ignore) continue
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
val proc = ProcessBuilder(
|
||||
"tar", "-acf",
|
||||
"${next.absolutePath}.tar.zst",
|
||||
next.absolutePath
|
||||
).start()
|
||||
val exitCode = proc.waitFor()
|
||||
if (exitCode == 0) {
|
||||
if (next.deleteRecursively()) {
|
||||
cmut.withLock { cqueue.remove(next) }
|
||||
} else {
|
||||
log("CompressJob", "Failed to delete $next")
|
||||
ignore.add(next)
|
||||
}
|
||||
} else {
|
||||
val msg = proc.errorStream.readAllBytes().decodeToString()
|
||||
log("CompressJob", "Failed to delete $next (exit code $exitCode")
|
||||
log("CompressJob", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
delay(30000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package moe.lava.banksia.server.gtfsrt
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.url
|
||||
import io.ktor.client.statement.bodyAsText
|
||||
import io.ktor.client.statement.readRawBytes
|
||||
import io.ktor.http.isSuccess
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.joinAll
|
||||
import kotlinx.coroutines.launch
|
||||
import moe.lava.banksia.Constants
|
||||
import moe.lava.banksia.util.LogScope
|
||||
import moe.lava.banksia.util.log
|
||||
|
||||
private val types = arrayOf(
|
||||
"metro/trip-updates",
|
||||
"metro/vehicle-positions",
|
||||
"metro/service-alerts",
|
||||
"tram/trip-updates",
|
||||
"tram/vehicle-positions",
|
||||
"tram/service-alerts",
|
||||
"bus/trip-updates",
|
||||
"bus/vehicle-positions",
|
||||
"vline/trip-updates",
|
||||
"vline/vehicle-positions",
|
||||
)
|
||||
|
||||
class GtfsrtService(
|
||||
private val client: HttpClient,
|
||||
) {
|
||||
private val archiver = GtfsrtArchiver()
|
||||
private var started = false
|
||||
|
||||
internal val rawMessages: SharedFlow<Pair<String, ByteArray>>
|
||||
field = MutableSharedFlow<Pair<String, ByteArray>>()
|
||||
|
||||
fun start(
|
||||
scope: CoroutineScope,
|
||||
enableArchiving: Boolean = false,
|
||||
) {
|
||||
if (started) {
|
||||
log("GtfsrtService", "Tried to start when already started")
|
||||
return
|
||||
}
|
||||
|
||||
if (enableArchiving) {
|
||||
scope.launch { archiver.start(rawMessages) }
|
||||
}
|
||||
|
||||
scope.launch { fetch() }
|
||||
}
|
||||
|
||||
private suspend fun fetch() {
|
||||
coroutineScope {
|
||||
types.map { type ->
|
||||
launch(context = Dispatchers.IO) {
|
||||
val logger = LogScope("gtfsr $type")
|
||||
try {
|
||||
val res = client.get {
|
||||
url("https://api.opendata.transport.vic.gov.au/opendata/public-transport/gtfs/realtime/v1/${type}")
|
||||
header("KeyId", Constants.opendataKey)
|
||||
}
|
||||
if (!res.status.isSuccess()) {
|
||||
logger.log("${res.status} | ${res.bodyAsText()}")
|
||||
} else {
|
||||
val bytes = res.readRawBytes()
|
||||
rawMessages.emit(type to bytes)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logger.log("$e")
|
||||
logger.log(e.stackTraceToString())
|
||||
}
|
||||
}
|
||||
}.joinAll()
|
||||
}
|
||||
|
||||
delay(10000)
|
||||
fetch()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package moe.lava.banksia.data.gtfsr
|
||||
package moe.lava.banksia.server.gtfsrt
|
||||
|
||||
import com.google.transit.realtime.FeedMessage
|
||||
import moe.lava.banksia.util.Point
|
||||
|
|
@ -15,17 +15,23 @@ 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.Constants
|
||||
import moe.lava.banksia.di.CommonModules
|
||||
import moe.lava.banksia.model.atDate
|
||||
import moe.lava.banksia.room.dao.RouteDao
|
||||
import moe.lava.banksia.room.dao.StopDao
|
||||
import moe.lava.banksia.room.dao.StopTimeDao
|
||||
import moe.lava.banksia.room.dao.VersionMetadataDao
|
||||
import moe.lava.banksia.server.di.ServerModules
|
||||
import moe.lava.banksia.server.gtfs.GtfsHandler
|
||||
import moe.lava.banksia.server.gtfsr.GtfsrService
|
||||
import moe.lava.banksia.server.gtfsrt.GtfsrtService
|
||||
import moe.lava.banksia.util.serialise
|
||||
import org.koin.dsl.module
|
||||
import org.koin.ktor.ext.inject
|
||||
import org.koin.ktor.plugin.Koin
|
||||
import kotlin.time.Clock
|
||||
|
||||
fun main() {
|
||||
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
|
||||
|
|
@ -41,10 +47,20 @@ fun Application.module() {
|
|||
modules(CommonModules, ServerModules)
|
||||
}
|
||||
|
||||
val gtfsr by inject<GtfsrService>()
|
||||
launch { gtfsr.start() }
|
||||
@Suppress("KotlinConstantConditions")
|
||||
if (!Constants.devMode) {
|
||||
val gtfsr by inject<GtfsrtService>()
|
||||
launch { gtfsr.start(this, true) }
|
||||
}
|
||||
|
||||
routing {
|
||||
if (Constants.devMode) {
|
||||
get("/fixup") {
|
||||
call.respondText("received")
|
||||
val fixer by inject<GtfsDataFixer>()
|
||||
fixer.addParentsToStops()
|
||||
}
|
||||
}
|
||||
get("/update") {
|
||||
val key = call.parameters["key"]
|
||||
if (key != Constants.updateKey) {
|
||||
|
|
@ -57,8 +73,11 @@ fun Application.module() {
|
|||
?: "https://opendata.transport.vic.gov.au/dataset/3f4e292e-7f8a-4ffe-831f-1953be0fe448/resource/${datasetUuid}/download/gtfs.zip"
|
||||
call.respondText("received")
|
||||
launch(context = Dispatchers.IO) {
|
||||
val handler by inject<GtfsHandler>()
|
||||
handler.update(datasetUrl)
|
||||
val fixer by inject<GtfsDataFixer>()
|
||||
val importer by inject<GtfsImporter>()
|
||||
importer.import(datasetUrl)
|
||||
|
||||
fixer.addParentsToStops()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +133,7 @@ fun Application.module() {
|
|||
}
|
||||
get("/route_stops/{route_id}") {
|
||||
val routeId = call.parameters["route_id"]!!
|
||||
val useParent = call.queryParameters["parent"] in listOf("true", "1")
|
||||
val useParent = call.queryParameters["parent"] !in listOf("false", "0")
|
||||
val stops = withContext(Dispatchers.IO) {
|
||||
val routeDao by inject<RouteDao>()
|
||||
if (useParent)
|
||||
|
|
@ -123,20 +142,23 @@ fun Application.module() {
|
|||
routeDao.stops(routeId)
|
||||
}
|
||||
call.respond(stops.map { it.asModel() })
|
||||
// val stops = withContext(Dispatchers.IO) {
|
||||
// val stopDao by inject<StopDao>()
|
||||
// val stopTimeDao by inject<StopTimeDao>()
|
||||
// val tripDao by inject<TripDao>()
|
||||
//
|
||||
// tripDao.getByRoute(routeId)
|
||||
// .map { it.id }
|
||||
// .let { stopTimeDao.get(it) }
|
||||
// .flatMap { it.asModel().stopInfos }
|
||||
// .map { it.stopId }
|
||||
// .let { stopDao.get(it) }
|
||||
// .map { it.asModel() }
|
||||
// }
|
||||
// call.respond(stops)
|
||||
}
|
||||
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) {
|
||||
inject<StopTimeDao>().value
|
||||
.getForStopDated(
|
||||
stopId,
|
||||
listOf(date.dayOfWeek).serialise(),
|
||||
date.toEpochDays().toInt(),
|
||||
)
|
||||
.map { it.asModel().atDate(date) }
|
||||
.sortedBy { it.departureTime }
|
||||
}
|
||||
call.respond(times)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
package moe.lava.banksia.server
|
||||
|
||||
import moe.lava.banksia.room.Database
|
||||
import moe.lava.banksia.room.entity.StopEntity
|
||||
import moe.lava.banksia.util.log
|
||||
import java.security.MessageDigest
|
||||
|
||||
class GtfsDataFixer(
|
||||
private val database: Database,
|
||||
) {
|
||||
suspend fun addParentsToStops() {
|
||||
val dao = database.stopDao
|
||||
val stops = dao.getAllParentless()
|
||||
stops
|
||||
.groupBy { it.name.split("/")[0] }
|
||||
.filter { (_, stops) -> stops.size > 1 }
|
||||
.forEach { (name, stops) ->
|
||||
val avgLat = stops.map { it.lat }.average()
|
||||
val avgLng = stops.map { it.lng }.average()
|
||||
val hash = name.sha256().substring(0, 7)
|
||||
val parentId = "bsia:df1:$hash"
|
||||
val parent = StopEntity(
|
||||
id = parentId,
|
||||
name = name,
|
||||
lat = avgLat,
|
||||
lng = avgLng,
|
||||
parent = "",
|
||||
hasWheelChairBoarding = stops.all { it.hasWheelChairBoarding },
|
||||
level = "",
|
||||
platformCode = "",
|
||||
)
|
||||
log("datafixer", "inserting ${parentId} for ${stops.size} children")
|
||||
dao.insertAll(parent)
|
||||
database.stopDao.updateParents(stops.map { it.id }, parentId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.sha256() =
|
||||
MessageDigest
|
||||
.getInstance("SHA-256")
|
||||
.digest(this.toByteArray())
|
||||
.joinToString("") { "%02x".format(it) }
|
||||
118
server/src/main/kotlin/moe/lava/banksia/server/GtfsImporter.kt
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
package moe.lava.banksia.server
|
||||
|
||||
import androidx.room.immediateTransaction
|
||||
import androidx.room.useWriterConnection
|
||||
import io.ktor.util.logging.Logger
|
||||
import moe.lava.banksia.model.Route
|
||||
import moe.lava.banksia.model.Service
|
||||
import moe.lava.banksia.model.ServiceException
|
||||
import moe.lava.banksia.model.Shape
|
||||
import moe.lava.banksia.model.Stop
|
||||
import moe.lava.banksia.model.StopTime
|
||||
import moe.lava.banksia.model.Trip
|
||||
import moe.lava.banksia.room.Database
|
||||
import moe.lava.banksia.room.entity.asEntity
|
||||
import moe.lava.banksia.server.gtfs.GtfsData
|
||||
import moe.lava.banksia.server.gtfs.GtfsParser
|
||||
import kotlin.time.Clock
|
||||
|
||||
class GtfsImporter(
|
||||
private val parser: GtfsParser,
|
||||
private val database: Database,
|
||||
private val log: Logger,
|
||||
) {
|
||||
suspend fun import(url: String, date: Long = Clock.System.now().epochSeconds) {
|
||||
database.useWriterConnection { transactor ->
|
||||
transactor.immediateTransaction {
|
||||
database.routeDao.deleteAll()
|
||||
database.serviceDao.deleteAll()
|
||||
database.serviceExceptionDao.deleteAll()
|
||||
database.shapeDao.deleteAll()
|
||||
database.stopDao.deleteAll()
|
||||
database.stopTimeDao.deleteAll()
|
||||
database.tripDao.deleteAll()
|
||||
|
||||
parser.update(url).collect { chunk ->
|
||||
when (chunk) {
|
||||
is GtfsData.RouteChunk -> addRoutes(chunk.routes)
|
||||
is GtfsData.ServiceChunk -> addServices(chunk.services)
|
||||
is GtfsData.ServiceExceptionChunk -> addServiceExceptions(chunk.exceptions)
|
||||
is GtfsData.ShapeChunk -> addShapes(chunk.shapes)
|
||||
is GtfsData.StopChunk -> addStops(chunk.stops)
|
||||
is GtfsData.StopTimeChunk -> addStopTimes(chunk.stopTimes)
|
||||
is GtfsData.TripChunk -> addTrips(chunk.trips)
|
||||
}
|
||||
}
|
||||
|
||||
updateMetadata(date)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateMetadata(date: Long) {
|
||||
val dao = database.versionMetadataDao
|
||||
log.info("updating metadata...")
|
||||
dao.update(date, listOf("routes", "stops", "shapes", "trips", "stop_times"))
|
||||
log.info("done")
|
||||
}
|
||||
|
||||
private suspend fun addRoutes(routes: List<Route>) {
|
||||
val dao = database.routeDao
|
||||
log.info("inserting routes...")
|
||||
dao.insertOrReplaceAll(*routes.map { it.asEntity() }.toTypedArray())
|
||||
log.info("done")
|
||||
}
|
||||
|
||||
private suspend fun addServices(services: List<Service>) {
|
||||
val dao = database.serviceDao
|
||||
log.info("inserting services...")
|
||||
dao.insertOrReplaceAll(*services.map { it.asEntity() }.toTypedArray())
|
||||
log.info("done")
|
||||
}
|
||||
|
||||
private suspend fun addServiceExceptions(exceptions: List<ServiceException>) {
|
||||
val dao = database.serviceExceptionDao
|
||||
log.info("inserting exceptions...")
|
||||
dao.insertOrReplaceAll(*exceptions.map { it.asEntity() }.toTypedArray())
|
||||
log.info("done")
|
||||
}
|
||||
|
||||
private suspend fun addShapes(shapes: List<Shape>) {
|
||||
val dao = database.shapeDao
|
||||
log.info("inserting shapes...")
|
||||
dao.insertOrReplaceAll(*shapes.map { it.asEntity() }.toTypedArray())
|
||||
log.info("done")
|
||||
}
|
||||
|
||||
private suspend fun addStops(stops: List<Stop>) {
|
||||
val dao = database.stopDao
|
||||
log.info("inserting stops...")
|
||||
stops
|
||||
.groupBy { it.id }
|
||||
.forEach { (id, gstops) ->
|
||||
if (gstops.size > 1) {
|
||||
if (gstops.withIndex().any { (i, stop) -> i != 0 && stop != gstops[i - 1] }) {
|
||||
gstops.forEach {
|
||||
log.warn("duplicate $id: $it")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.insertOrReplaceAll(*stops.map { it.asEntity() }.toTypedArray())
|
||||
log.info("done")
|
||||
}
|
||||
|
||||
private suspend fun addStopTimes(stopTimes: List<StopTime>) {
|
||||
val dao = database.stopTimeDao
|
||||
log.info("inserting ${stopTimes.size} stoptimes...")
|
||||
dao.insertOrReplaceAll(*stopTimes.map { it.asEntity() }.toTypedArray())
|
||||
log.info("done")
|
||||
}
|
||||
|
||||
private suspend fun addTrips(trips: List<Trip>) {
|
||||
val dao = database.tripDao
|
||||
log.info("inserting ${trips.size} trips...")
|
||||
dao.insertOrReplaceAll(*trips.map { it.asEntity() }.toTypedArray())
|
||||
log.info("done")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,18 @@
|
|||
package moe.lava.banksia.server.di
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import moe.lava.banksia.server.gtfs.GtfsHandler
|
||||
import moe.lava.banksia.server.gtfsr.GtfsrService
|
||||
import moe.lava.banksia.server.GtfsDataFixer
|
||||
import moe.lava.banksia.server.GtfsImporter
|
||||
import moe.lava.banksia.server.gtfs.GtfsParser
|
||||
import moe.lava.banksia.server.gtfsrt.GtfsrtService
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val ServerModules = module {
|
||||
single { HttpClient() }
|
||||
singleOf(::GtfsHandler)
|
||||
singleOf(::GtfsrService)
|
||||
singleOf(::GtfsParser)
|
||||
singleOf(::GtfsrtService)
|
||||
|
||||
singleOf(::GtfsDataFixer)
|
||||
singleOf(::GtfsImporter)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,164 +0,0 @@
|
|||
package moe.lava.banksia.server.gtfsr
|
||||
|
||||
import com.google.transit.realtime.FeedMessage
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.url
|
||||
import io.ktor.client.statement.bodyAsText
|
||||
import io.ktor.client.statement.readRawBytes
|
||||
import io.ktor.http.isSuccess
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.joinAll
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import moe.lava.banksia.Constants
|
||||
import moe.lava.banksia.util.LogScope
|
||||
import moe.lava.banksia.util.log
|
||||
import java.io.File
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
|
||||
private const val BASE_DIR = "./data/gtfsr-archive/"
|
||||
|
||||
class GtfsrService(private val client: HttpClient) {
|
||||
private var started = false
|
||||
private val latest = mutableMapOf<String, FeedMessage>()
|
||||
|
||||
fun latestFor(type: String) = latest[type]
|
||||
|
||||
private val iFlow = MutableSharedFlow<Pair<String, FeedMessage>>()
|
||||
val flow = iFlow.asSharedFlow()
|
||||
|
||||
companion object {
|
||||
val types = arrayOf(
|
||||
"metro/trip-updates",
|
||||
"metro/vehicle-positions",
|
||||
"metro/service-alerts",
|
||||
"tram/trip-updates",
|
||||
"tram/vehicle-positions",
|
||||
"tram/service-alerts",
|
||||
"bus/trip-updates",
|
||||
"bus/vehicle-positions",
|
||||
"vline/trip-updates",
|
||||
"vline/vehicle-positions",
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun start() {
|
||||
if (started) {
|
||||
log("GtfsrService", "Tried to start when already started")
|
||||
return
|
||||
}
|
||||
started = true
|
||||
coroutineScope {
|
||||
launch { compressJob() }
|
||||
|
||||
while (true) {
|
||||
val results = mutableMapOf<String, ByteArray>()
|
||||
types.map { type ->
|
||||
launch(context = Dispatchers.IO) {
|
||||
val logger = LogScope("gtfsr $type")
|
||||
try {
|
||||
val res = client.get {
|
||||
url("https://api.opendata.transport.vic.gov.au/opendata/public-transport/gtfs/realtime/v1/${type}")
|
||||
header("KeyId", Constants.opendataKey)
|
||||
}
|
||||
if (!res.status.isSuccess()) {
|
||||
logger.log("${res.status} | ${res.bodyAsText()}")
|
||||
} else {
|
||||
results[type] = res.readRawBytes()
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logger.log("$e")
|
||||
logger.log(e.stackTraceToString())
|
||||
}
|
||||
}
|
||||
}.joinAll()
|
||||
|
||||
results.forEach { (type, data) ->
|
||||
val dec = try {
|
||||
FeedMessage.ADAPTER.decode(data)
|
||||
} catch (e: Throwable) {
|
||||
log("gtfsr $type", "Failed to parse proto: $e")
|
||||
return@forEach
|
||||
}
|
||||
val timestamp = dec.header_.timestamp
|
||||
?: return@forEach log("gtfsr $type", "Failed to read proto timestamp")
|
||||
|
||||
val time = Instant.ofEpochSecond(timestamp).atZone(ZoneId.systemDefault())
|
||||
|
||||
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 target = File(currentParent, "${timestamp}.proto")
|
||||
|
||||
if (previousParent.isDirectory) {
|
||||
enqueueCompression(previousParent)
|
||||
}
|
||||
|
||||
if (!target.exists()) {
|
||||
try {
|
||||
if (!target.parentFile.isDirectory) {
|
||||
target.parentFile.mkdirs()
|
||||
}
|
||||
target.writeBytes(data)
|
||||
} catch (e: Throwable) {
|
||||
log("gtfsr $type", "Failed to write ${target}: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
delay(10000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val cqueue = mutableSetOf<File>()
|
||||
private val ignore = mutableSetOf<File>()
|
||||
private val cmut = Mutex()
|
||||
private suspend fun enqueueCompression(fd: File) {
|
||||
cmut.withLock { cqueue.add(fd) }
|
||||
}
|
||||
|
||||
private suspend fun compressJob() {
|
||||
while(true) {
|
||||
while(true) {
|
||||
val next = cmut.withLock { cqueue.firstOrNull() }
|
||||
?: break
|
||||
if (!next.isDirectory) {
|
||||
cmut.withLock { cqueue.remove(next) }
|
||||
continue
|
||||
}
|
||||
if (next in ignore) continue
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
val proc = ProcessBuilder(
|
||||
"tar", "-acf",
|
||||
"${next.absolutePath}.tar.zst",
|
||||
next.absolutePath
|
||||
).start()
|
||||
val exitCode = proc.waitFor()
|
||||
if (exitCode == 0) {
|
||||
if (next.deleteRecursively()) {
|
||||
cmut.withLock { cqueue.remove(next) }
|
||||
} else {
|
||||
log("CompressJob", "Failed to delete $next")
|
||||
ignore.add(next)
|
||||
}
|
||||
} else {
|
||||
val msg = proc.errorStream.readAllBytes().decodeToString()
|
||||
log("CompressJob", "Failed to delete $next (exit code $exitCode")
|
||||
log("CompressJob", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
delay(30000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,9 @@ pluginManagement {
|
|||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||
}
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
|
|
@ -28,7 +31,12 @@ dependencyResolutionManagement {
|
|||
}
|
||||
}
|
||||
|
||||
include(":androidApp")
|
||||
include(":client")
|
||||
include(":server")
|
||||
include(":server:gtfs")
|
||||
include(":server:gtfs_rt")
|
||||
include(":shared")
|
||||
include(":ui")
|
||||
include(":ui:maps")
|
||||
include(":ui:shared")
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
alias(libs.plugins.androidLibrary)
|
||||
alias(libs.plugins.androidMultiplatformLibrary)
|
||||
alias(libs.plugins.ksp)
|
||||
alias(libs.plugins.room)
|
||||
alias(libs.plugins.wire)
|
||||
}
|
||||
|
||||
room {
|
||||
|
|
@ -15,8 +13,10 @@ room {
|
|||
}
|
||||
|
||||
kotlin {
|
||||
androidTarget {
|
||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
||||
android {
|
||||
namespace = "moe.lava.banksia.shared"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_11)
|
||||
}
|
||||
|
|
@ -26,7 +26,6 @@ kotlin {
|
|||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||
}
|
||||
|
||||
iosX64()
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
|
|
@ -58,27 +57,7 @@ kotlin {
|
|||
|
||||
dependencies {
|
||||
add("kspAndroid", libs.room.compiler)
|
||||
add("kspIosX64", libs.room.compiler)
|
||||
add("kspIosArm64", libs.room.compiler)
|
||||
add("kspIosSimulatorArm64", libs.room.compiler)
|
||||
add("kspJvm", libs.room.compiler)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "moe.lava.banksia.shared"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
defaultConfig {
|
||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||
}
|
||||
}
|
||||
|
||||
wire {
|
||||
sourcePath {
|
||||
srcDir("src/commonMain/proto")
|
||||
}
|
||||
kotlin {}
|
||||
}
|
||||
477
shared/schemas/moe.lava.banksia.room.Database/10.json
Normal file
|
|
@ -0,0 +1,477 @@
|
|||
{
|
||||
"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')"
|
||||
]
|
||||
}
|
||||
}
|
||||
498
shared/schemas/moe.lava.banksia.room.Database/11.json
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
{
|
||||
"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')"
|
||||
]
|
||||
}
|
||||
}
|
||||
368
shared/schemas/moe.lava.banksia.room.Database/4.json
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
{
|
||||
"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')"
|
||||
]
|
||||
}
|
||||
}
|
||||
368
shared/schemas/moe.lava.banksia.room.Database/5.json
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
{
|
||||
"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')"
|
||||
]
|
||||
}
|
||||
}
|
||||
368
shared/schemas/moe.lava.banksia.room.Database/6.json
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
{
|
||||
"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')"
|
||||
]
|
||||
}
|
||||
}
|
||||
415
shared/schemas/moe.lava.banksia.room.Database/7.json
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
{
|
||||
"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')"
|
||||
]
|
||||
}
|
||||
}
|
||||
426
shared/schemas/moe.lava.banksia.room.Database/8.json
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
{
|
||||
"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')"
|
||||
]
|
||||
}
|
||||
}
|
||||
426
shared/schemas/moe.lava.banksia.room.Database/9.json
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
{
|
||||
"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')"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -8,4 +8,5 @@ object Constants {
|
|||
// TODO
|
||||
const val devMode: Boolean = false
|
||||
const val updateKey: String = ""
|
||||
const val protomapsKey: String = ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import kotlinx.serialization.encoding.Decoder
|
|||
import kotlinx.serialization.encoding.Encoder
|
||||
import moe.lava.banksia.model.RouteType
|
||||
|
||||
private object PtvRouteTypeSerialiser : KSerializer<PtvRouteType> {
|
||||
object PtvRouteTypeSerialiser : KSerializer<PtvRouteType> {
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
|
||||
PtvRouteType::class.qualifiedName!!,
|
||||
PrimitiveKind.INT)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ val CommonModules = module {
|
|||
single { Database.build(get<PlatformDatabaseBuilder>().getBuilder()) }
|
||||
single { get<Database>().versionMetadataDao }
|
||||
single { get<Database>().routeDao }
|
||||
single { get<Database>().serviceDao }
|
||||
single { get<Database>().serviceExceptionDao }
|
||||
single { get<Database>().shapeDao }
|
||||
single { get<Database>().stopDao }
|
||||
single { get<Database>().stopTimeDao }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
package moe.lava.banksia.model
|
||||
|
||||
import kotlinx.datetime.DateTimeUnit
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.LocalTime
|
||||
import kotlinx.datetime.atTime
|
||||
import kotlinx.datetime.plus
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
|
|
@ -39,6 +43,10 @@ data class FutureTime(
|
|||
val minute = time.minute
|
||||
val second = time.second
|
||||
val trueHour = time.hour + (if (dayOffset) 24 else 0)
|
||||
|
||||
fun atDate(date: LocalDate) = date
|
||||
.let { if (dayOffset) date.plus(1, DateTimeUnit.DAY) else date }
|
||||
.atTime(time)
|
||||
}
|
||||
|
||||
object FutureTimeSerialiser: KSerializer<FutureTime> {
|
||||
|
|
|
|||
|
|
@ -13,4 +13,8 @@ enum class RouteType(val value: Int) {
|
|||
SkyBus(11),
|
||||
Interstate(10),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun from(value: Int) = RouteType.entries.first { it.value == value }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package moe.lava.banksia.model
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ServiceException(
|
||||
val serviceId: String,
|
||||
val date: LocalDate,
|
||||
val type: Int,
|
||||
)
|
||||
|
|
@ -8,7 +8,7 @@ data class Stop(
|
|||
val id: String,
|
||||
val name: String,
|
||||
val pos: Point,
|
||||
val parent: String,
|
||||
val parent: String?,
|
||||
val hasWheelChairBoarding: Boolean,
|
||||
val level: String,
|
||||
val platformCode: String,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package moe.lava.banksia.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,
|
||||
)
|
||||
|
|
@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable
|
|||
data class Trip(
|
||||
val id: String,
|
||||
val routeId: String,
|
||||
val serviceId: String,
|
||||
val service: Service,
|
||||
val shapeId: String?,
|
||||
val tripHeadsign: String,
|
||||
val directionId: String,
|
||||
|
|
|
|||
|
|
@ -3,17 +3,25 @@ package moe.lava.banksia.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.room.converter.RouteTypeConverter
|
||||
import moe.lava.banksia.room.dao.VersionMetadataDao
|
||||
import moe.lava.banksia.room.dao.RouteDao
|
||||
import moe.lava.banksia.room.dao.ServiceDao
|
||||
import moe.lava.banksia.room.dao.ServiceExceptionDao
|
||||
import moe.lava.banksia.room.dao.ShapeDao
|
||||
import moe.lava.banksia.room.dao.StopDao
|
||||
import moe.lava.banksia.room.dao.StopTimeDao
|
||||
import moe.lava.banksia.room.dao.TripDao
|
||||
import moe.lava.banksia.room.dao.VersionMetadataDao
|
||||
import moe.lava.banksia.room.entity.RouteEntity
|
||||
import moe.lava.banksia.room.entity.ServiceEntity
|
||||
import moe.lava.banksia.room.entity.ServiceExceptionEntity
|
||||
import moe.lava.banksia.room.entity.ShapeEntity
|
||||
import moe.lava.banksia.room.entity.StopEntity
|
||||
import moe.lava.banksia.room.entity.StopTimeEntity
|
||||
|
|
@ -22,9 +30,11 @@ import moe.lava.banksia.room.entity.VersionMetadataEntity
|
|||
import androidx.room.Database as DatabaseAnnotation
|
||||
|
||||
@DatabaseAnnotation(
|
||||
version = 3,
|
||||
version = 11,
|
||||
entities = [
|
||||
RouteEntity::class,
|
||||
ServiceEntity::class,
|
||||
ServiceExceptionEntity::class,
|
||||
ShapeEntity::class,
|
||||
StopEntity::class,
|
||||
StopTimeEntity::class,
|
||||
|
|
@ -34,12 +44,15 @@ import androidx.room.Database as DatabaseAnnotation
|
|||
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
|
||||
|
|
@ -50,7 +63,21 @@ abstract class Database : RoomDatabase() {
|
|||
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")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import moe.lava.banksia.model.RouteType
|
|||
|
||||
object RouteTypeConverter {
|
||||
@TypeConverter
|
||||
fun from(value: Int) = RouteType.entries.first { it.value == value }
|
||||
fun from(value: Int) = RouteType.from(value)
|
||||
|
||||
@TypeConverter
|
||||
fun to(routeType: RouteType) = routeType.value
|
||||
|
|
|
|||
|
|
@ -37,13 +37,22 @@ interface RouteDao {
|
|||
""")
|
||||
suspend fun stops(id: String): List<StopEntity>
|
||||
|
||||
// I vibecoded this, sorry
|
||||
@Query("""
|
||||
SELECT Stop.* FROM Stop
|
||||
INNER JOIN Stop Child ON Child.parent == Stop.id
|
||||
INNER JOIN StopTime ON StopTime.stopId == Child.id
|
||||
INNER JOIN Trip ON Trip.id == StopTime.tripId
|
||||
WHERE Trip.routeId == :id
|
||||
GROUP BY Stop.id
|
||||
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<StopEntity>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
package moe.lava.banksia.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.room.entity.ServiceEntity
|
||||
|
||||
@Dao
|
||||
interface ServiceDao {
|
||||
@Query("SELECT * FROM Service")
|
||||
suspend fun getAll(): List<ServiceEntity>
|
||||
|
||||
@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()
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package moe.lava.banksia.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.room.entity.ServiceExceptionEntity
|
||||
|
||||
@Dao
|
||||
interface ServiceExceptionDao {
|
||||
@Query("SELECT * FROM ServiceException")
|
||||
suspend fun getAll(): List<ServiceExceptionEntity>
|
||||
|
||||
@Query("SELECT * FROM ServiceException WHERE serviceId == :id")
|
||||
suspend fun get(id: String): List<ServiceExceptionEntity>
|
||||
|
||||
@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()
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package moe.lava.banksia.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.room.entity.ShapeEntity
|
||||
|
||||
|
|
@ -14,6 +15,9 @@ interface ShapeDao {
|
|||
@Insert
|
||||
suspend fun insertAll(vararg shapes: ShapeEntity)
|
||||
|
||||
@Insert(onConflict = REPLACE)
|
||||
suspend fun insertOrReplaceAll(vararg shapes: ShapeEntity)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(shape: ShapeEntity)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,13 @@ interface StopDao {
|
|||
@Query("SELECT * FROM Stop")
|
||||
suspend fun getAll(): List<StopEntity>
|
||||
|
||||
@Query("""
|
||||
SELECT * FROM Stop
|
||||
WHERE platformCode <> ""
|
||||
AND parent == ""
|
||||
""")
|
||||
suspend fun getAllParentless(): List<StopEntity>
|
||||
|
||||
@Query("SELECT * FROM Stop WHERE id == :id")
|
||||
suspend fun get(id: String): StopEntity?
|
||||
|
||||
|
|
@ -29,4 +36,7 @@ interface StopDao {
|
|||
|
||||
@Query("DELETE FROM Stop")
|
||||
suspend fun deleteAll()
|
||||
|
||||
@Query("UPDATE Stop SET parent = :parent WHERE id IN (:ids)")
|
||||
suspend fun updateParents(ids: List<String>, parent: String)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,24 @@ interface StopTimeDao {
|
|||
suspend fun getAll(): List<StopTimeEntity>
|
||||
|
||||
@Query("SELECT * FROM StopTime WHERE tripId == :tripId")
|
||||
suspend fun get(tripId: String): StopTimeEntity?
|
||||
suspend fun getForTrip(tripId: String): StopTimeEntity?
|
||||
|
||||
@Query("SELECT * FROM StopTime WHERE tripId IN (:tripIds)")
|
||||
suspend fun get(tripIds: List<String>): List<StopTimeEntity>
|
||||
suspend fun getForTrips(tripIds: List<String>): List<StopTimeEntity>
|
||||
|
||||
@Query("SELECT * FROM StopTime WHERE stopId == :stopId")
|
||||
suspend fun getForStop(stopId: String): List<StopTimeEntity>
|
||||
|
||||
@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<StopTimeEntity>
|
||||
|
||||
@Insert
|
||||
suspend fun insertAll(vararg stopTimes: StopTimeEntity)
|
||||
|
|
|
|||
|
|
@ -1,50 +1,23 @@
|
|||
package moe.lava.banksia.room.entity
|
||||
|
||||
import kotlinx.datetime.DayOfWeek
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.datetime.LocalDate
|
||||
import moe.lava.banksia.model.Service
|
||||
import moe.lava.banksia.util.deserialiseDaysBitflag
|
||||
import moe.lava.banksia.util.serialise
|
||||
|
||||
@Entity("Service")
|
||||
data class ServiceEntity(
|
||||
val id: String,
|
||||
val days: Int,
|
||||
@PrimaryKey val id: String,
|
||||
@ColumnInfo(index = true) val days: Int,
|
||||
val start: Int,
|
||||
val end: Int,
|
||||
) {
|
||||
object Parser {
|
||||
private fun Int.check(other: Int) = (this and other) != 0
|
||||
|
||||
fun deserialiseDays(days: Int): List<DayOfWeek> = buildList {
|
||||
if (days.check(1))
|
||||
add(DayOfWeek.MONDAY)
|
||||
if (days.check(1 shl 1))
|
||||
add(DayOfWeek.TUESDAY)
|
||||
if (days.check(1 shl 2))
|
||||
add(DayOfWeek.WEDNESDAY)
|
||||
if (days.check(1 shl 3))
|
||||
add(DayOfWeek.THURSDAY)
|
||||
if (days.check(1 shl 4))
|
||||
add(DayOfWeek.FRIDAY)
|
||||
if (days.check(1 shl 5))
|
||||
add(DayOfWeek.SATURDAY)
|
||||
if (days.check(1 shl 6))
|
||||
add(DayOfWeek.SUNDAY)
|
||||
}
|
||||
fun serialiseDays(days: List<DayOfWeek>): Int =
|
||||
days.fold(0) { vl, n ->
|
||||
vl + when (n) {
|
||||
DayOfWeek.MONDAY -> 1
|
||||
DayOfWeek.TUESDAY -> 1 shl 1
|
||||
DayOfWeek.WEDNESDAY -> 1 shl 2
|
||||
DayOfWeek.THURSDAY -> 1 shl 3
|
||||
DayOfWeek.FRIDAY -> 1 shl 4
|
||||
DayOfWeek.SATURDAY -> 1 shl 5
|
||||
DayOfWeek.SUNDAY -> 1 shl 6
|
||||
}
|
||||
}
|
||||
}
|
||||
fun asModel() = Service(
|
||||
id,
|
||||
Parser.deserialiseDays(days),
|
||||
days.deserialiseDaysBitflag(),
|
||||
LocalDate.fromEpochDays(start),
|
||||
LocalDate.fromEpochDays(end),
|
||||
)
|
||||
|
|
@ -52,7 +25,7 @@ data class ServiceEntity(
|
|||
|
||||
fun Service.asEntity() = ServiceEntity(
|
||||
id,
|
||||
ServiceEntity.Parser.serialiseDays(days),
|
||||
days.serialise(),
|
||||
start.toEpochDays().toInt(),
|
||||
end.toEpochDays().toInt(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package moe.lava.banksia.room.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import kotlinx.datetime.LocalDate
|
||||
import moe.lava.banksia.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,
|
||||
)
|
||||
|
|
@ -2,17 +2,30 @@ package moe.lava.banksia.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.model.Stop
|
||||
import moe.lava.banksia.util.Point
|
||||
|
||||
@Entity("Stop")
|
||||
@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,
|
||||
@ColumnInfo(index = true) val parent: String?,
|
||||
val hasWheelChairBoarding: Boolean,
|
||||
val level: String,
|
||||
val platformCode: String,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package moe.lava.banksia.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.model.FutureTime
|
||||
import moe.lava.banksia.model.FutureTime.Companion.asInt
|
||||
|
|
@ -11,6 +12,10 @@ import moe.lava.banksia.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),
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ 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.model.Trip
|
||||
|
||||
|
|
@ -11,8 +12,10 @@ import moe.lava.banksia.model.Trip
|
|||
"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,
|
||||
|
|
@ -23,8 +26,24 @@ data class TripEntity(
|
|||
val directionId: String,
|
||||
val blockId: String,
|
||||
val wheelchairAccessible: String,
|
||||
) {
|
||||
fun asModel() = Trip(id, routeId, serviceId, shapeId, tripHeadsign, directionId, blockId, wheelchairAccessible)
|
||||
)
|
||||
|
||||
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, serviceId, shapeId, tripHeadsign, directionId, blockId, wheelchairAccessible)
|
||||
fun Trip.asEntity() = TripEntity(id, routeId, service.id, shapeId, tripHeadsign, directionId, blockId, wheelchairAccessible)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package moe.lava.banksia.util
|
||||
|
||||
/** Wraps an arbitrary value, such that equality checks are forced to be done by reference */
|
||||
class BoxedValue<T>(val value: T) {
|
||||
operator fun component1() = value
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package moe.lava.banksia.util
|
||||
|
||||
import kotlinx.datetime.DayOfWeek
|
||||
|
||||
private fun Int.check(other: Int) = (this and other) != 0
|
||||
|
||||
fun Int.deserialiseDaysBitflag(): List<DayOfWeek> = buildList {
|
||||
val days = this@deserialiseDaysBitflag
|
||||
if (days.check(1))
|
||||
add(DayOfWeek.MONDAY)
|
||||
if (days.check(1 shl 1))
|
||||
add(DayOfWeek.TUESDAY)
|
||||
if (days.check(1 shl 2))
|
||||
add(DayOfWeek.WEDNESDAY)
|
||||
if (days.check(1 shl 3))
|
||||
add(DayOfWeek.THURSDAY)
|
||||
if (days.check(1 shl 4))
|
||||
add(DayOfWeek.FRIDAY)
|
||||
if (days.check(1 shl 5))
|
||||
add(DayOfWeek.SATURDAY)
|
||||
if (days.check(1 shl 6))
|
||||
add(DayOfWeek.SUNDAY)
|
||||
}
|
||||
|
||||
fun List<DayOfWeek>.serialise(): Int =
|
||||
this.fold(0) { vl, n ->
|
||||
vl + when (n) {
|
||||
DayOfWeek.MONDAY -> 1
|
||||
DayOfWeek.TUESDAY -> 1 shl 1
|
||||
DayOfWeek.WEDNESDAY -> 1 shl 2
|
||||
DayOfWeek.THURSDAY -> 1 shl 3
|
||||
DayOfWeek.FRIDAY -> 1 shl 4
|
||||
DayOfWeek.SATURDAY -> 1 shl 5
|
||||
DayOfWeek.SUNDAY -> 1 shl 6
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +1,31 @@
|
|||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
alias(libs.plugins.androidApplication)
|
||||
alias(libs.plugins.androidMultiplatformLibrary)
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.composeCompiler)
|
||||
alias(libs.plugins.secretsGradle)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
androidTarget {
|
||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
||||
android {
|
||||
namespace = "moe.lava.banksia.ui"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_11)
|
||||
}
|
||||
|
||||
androidResources {
|
||||
enable = true
|
||||
}
|
||||
}
|
||||
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||
}
|
||||
|
||||
listOf(
|
||||
|
|
@ -35,9 +41,6 @@ kotlin {
|
|||
|
||||
sourceSets {
|
||||
androidMain.dependencies {
|
||||
implementation(libs.compose.ui.tooling.preview)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
implementation(libs.play.services.location)
|
||||
}
|
||||
commonMain.dependencies {
|
||||
|
|
@ -66,47 +69,16 @@ kotlin {
|
|||
|
||||
implementation(projects.client)
|
||||
implementation(projects.shared)
|
||||
implementation(projects.ui.maps)
|
||||
implementation(projects.ui.shared)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "moe.lava.banksia"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "moe.lava.banksia"
|
||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||
targetSdk = libs.versions.android.targetSdk.get().toInt()
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
}
|
||||
packaging {
|
||||
resources {
|
||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
getByName("release") {
|
||||
isMinifyEnabled = false
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
debugImplementation(compose.uiTooling)
|
||||
androidRuntimeClasspath(libs.compose.ui.tooling)
|
||||
}
|
||||
|
||||
secrets {
|
||||
propertiesFileName = "secrets.properties"
|
||||
}
|
||||
|
||||
compose.resources {
|
||||
publicResClass = true
|
||||
packageOfResClass = "moe.lava.banksia.resources"
|
||||
}
|
||||
|
|
|
|||
56
ui/maps/build.gradle.kts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
alias(libs.plugins.androidMultiplatformLibrary)
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.composeCompiler)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android {
|
||||
namespace = "moe.lava.banksia.ui.map"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_11)
|
||||
}
|
||||
}
|
||||
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||
}
|
||||
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
sourceSets {
|
||||
androidMain.dependencies {
|
||||
implementation(libs.compose.ui.tooling.preview)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
implementation(libs.play.services.location)
|
||||
}
|
||||
commonMain.dependencies {
|
||||
implementation(libs.koin.core)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.kotlinx.datetime)
|
||||
implementation(libs.ktor.serialization.kotlinx.json)
|
||||
|
||||
implementation(libs.maplibre.compose)
|
||||
implementation(libs.moko.geo)
|
||||
implementation(libs.moko.geo.compose)
|
||||
|
||||
implementation(libs.compose.components.resources)
|
||||
implementation(libs.compose.runtime)
|
||||
implementation(libs.compose.foundation)
|
||||
implementation(libs.compose.material3)
|
||||
implementation(libs.compose.ui)
|
||||
|
||||
implementation(projects.shared)
|
||||
implementation(projects.ui.shared)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package moe.lava.banksia.ui.map
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.add
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import moe.lava.banksia.Constants
|
||||
import moe.lava.banksia.ui.map.mappers.routeColorExpression
|
||||
import moe.lava.banksia.ui.platform.BanksiaTheme
|
||||
import org.maplibre.compose.camera.CameraPosition
|
||||
import org.maplibre.compose.camera.rememberCameraState
|
||||
import org.maplibre.compose.expressions.dsl.const
|
||||
import org.maplibre.compose.layers.CircleLayer
|
||||
import org.maplibre.compose.map.MapOptions
|
||||
import org.maplibre.compose.map.MaplibreMap
|
||||
import org.maplibre.compose.map.OrnamentOptions
|
||||
import org.maplibre.compose.sources.GeoJsonData
|
||||
import org.maplibre.compose.sources.rememberGeoJsonSource
|
||||
import org.maplibre.compose.style.BaseStyle
|
||||
import org.maplibre.compose.util.ClickResult
|
||||
import org.maplibre.spatialk.geojson.Feature
|
||||
import org.maplibre.spatialk.geojson.Geometry
|
||||
|
||||
@Composable
|
||||
internal fun MapLibreMaps(
|
||||
modifier: Modifier,
|
||||
insets: WindowInsets,
|
||||
positionState: MapsPositionState,
|
||||
stops: GeoJsonData.Features?,
|
||||
// vehicles: GeoJsonData.Features?,
|
||||
stopInnerColor: Color,
|
||||
onStopClicked: (Feature<Geometry, JsonObject?>) -> Unit,
|
||||
) {
|
||||
val camPos = rememberCameraState(
|
||||
CameraPosition(
|
||||
zoom = 16.0,
|
||||
target = MELBOURNE_POS
|
||||
)
|
||||
)
|
||||
|
||||
val variant = if (isSystemInDarkTheme()) "dark" else "light"
|
||||
|
||||
MaplibreMap(
|
||||
modifier = modifier,
|
||||
baseStyle = BaseStyle.Uri("https://api.protomaps.com/styles/v5/$variant/en.json?key=${Constants.protomapsKey}"),
|
||||
cameraState = camPos,
|
||||
options = MapOptions(
|
||||
ornamentOptions = OrnamentOptions(
|
||||
padding = WindowInsets.safeDrawing.add(insets).asPaddingValues(),
|
||||
isScaleBarEnabled = false,
|
||||
isAttributionEnabled = false,
|
||||
)
|
||||
)
|
||||
) {
|
||||
if (stops != null) {
|
||||
val stopsSource = rememberGeoJsonSource(stops)
|
||||
CircleLayer(
|
||||
id = "maps-stops0",
|
||||
source = stopsSource,
|
||||
color = const(BanksiaTheme.colors.surface),
|
||||
radius = const(3.dp),
|
||||
strokeWidth = const(2.dp),
|
||||
strokeColor = routeColorExpression,
|
||||
)
|
||||
CircleLayer(
|
||||
id = "maps-stops0-clickhandler",
|
||||
source = stopsSource,
|
||||
color = const(Color.Transparent),
|
||||
radius = const(12.dp),
|
||||
onClick = { features ->
|
||||
// onEvent(MapScreenEvent.SelectStop(marker.type to feature.id!!.content))
|
||||
// val marker = Json.decodeFromJsonElement<T>(feature.properties!!)
|
||||
onStopClicked(features[0])
|
||||
ClickResult.Consume
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package moe.lava.banksia.ui.map
|
||||
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import moe.lava.banksia.ui.map.mappers.asFeatures
|
||||
import moe.lava.banksia.ui.map.mappers.toPosition
|
||||
import moe.lava.banksia.ui.map.util.Marker
|
||||
import moe.lava.banksia.ui.platform.BanksiaTheme
|
||||
import moe.lava.banksia.util.Point
|
||||
|
||||
internal val MELBOURNE = Point(-37.8136, 144.9631)
|
||||
internal val MELBOURNE_POS = MELBOURNE.toPosition()
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Maps(
|
||||
modifier: Modifier = Modifier,
|
||||
insets: WindowInsets = WindowInsets(),
|
||||
stops: List<Marker.Stop> = listOf(),
|
||||
// vehicles: List<Marker.Vehicle> = listOf(),
|
||||
positionState: MapsPositionState = rememberMapsPositionState(),
|
||||
onStopClicked: (id: String) -> Unit = {},
|
||||
// onVehicleClicked: (id: String) -> Unit = {},
|
||||
) {
|
||||
MapLibreMaps(
|
||||
modifier = modifier,
|
||||
insets = insets,
|
||||
positionState = positionState,
|
||||
stops = stops.takeIf { it.isNotEmpty() }?.asFeatures(),
|
||||
// vehicles = vehicles.takeIf { it.isNotEmpty() }?.asFeatures(),
|
||||
stopInnerColor = BanksiaTheme.colors.surface,
|
||||
onStopClicked = { feature -> onStopClicked(feature.id!!.content) },
|
||||
// onVehicleClicked = {},
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package moe.lava.banksia.ui.map
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import moe.lava.banksia.util.Point
|
||||
|
||||
class MapsPositionState internal constructor(
|
||||
private val scope: CoroutineScope
|
||||
) {
|
||||
internal val updates: SharedFlow<Point>
|
||||
field = MutableSharedFlow()
|
||||
|
||||
fun update(position: Point) {
|
||||
scope.launch { updates.emit(position) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberMapsPositionState(): MapsPositionState {
|
||||
val scope = rememberCoroutineScope()
|
||||
return remember { MapsPositionState(scope) }
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package moe.lava.banksia.ui.map.mappers
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import moe.lava.banksia.model.RouteType
|
||||
import moe.lava.banksia.ui.map.util.Marker
|
||||
import org.maplibre.compose.sources.GeoJsonData
|
||||
import org.maplibre.spatialk.geojson.FeatureCollection
|
||||
import org.maplibre.spatialk.geojson.dsl.addFeature
|
||||
import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection
|
||||
import org.maplibre.spatialk.geojson.Point as MLPoint
|
||||
|
||||
@Serializable
|
||||
data class MarkerProps(
|
||||
val type: RouteType,
|
||||
)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun Iterable<Marker>.asFeatures() = GeoJsonData.Features(asFeatureCollection())
|
||||
|
||||
internal fun Iterable<Marker>.asFeatureCollection(): FeatureCollection<MLPoint, MarkerProps> {
|
||||
val markers = this
|
||||
return buildFeatureCollection {
|
||||
markers.forEach { marker ->
|
||||
val type = when (marker) {
|
||||
is Marker.Stop -> marker.type
|
||||
is Marker.Vehicle -> marker.type
|
||||
}
|
||||
val id = when (marker) {
|
||||
is Marker.Stop -> marker.id
|
||||
is Marker.Vehicle -> marker.ref
|
||||
}
|
||||
addFeature(
|
||||
geometry = MLPoint(marker.point.toPosition()),
|
||||
properties = MarkerProps(type),
|
||||
) {
|
||||
setId(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package moe.lava.banksia.ui.map.mappers
|
||||
|
||||
import moe.lava.banksia.util.Point
|
||||
import org.maplibre.spatialk.geojson.Position
|
||||
|
||||
internal fun Point.toPosition() = Position(lng, lat)
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package moe.lava.banksia.ui.map.mappers
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import moe.lava.banksia.model.RouteType
|
||||
import moe.lava.banksia.ui.extensions.getUIProperties
|
||||
import moe.lava.banksia.ui.platform.BanksiaTheme
|
||||
import org.maplibre.compose.expressions.dsl.case
|
||||
import org.maplibre.compose.expressions.dsl.const
|
||||
import org.maplibre.compose.expressions.dsl.convertToString
|
||||
import org.maplibre.compose.expressions.dsl.feature
|
||||
import org.maplibre.compose.expressions.dsl.switch
|
||||
|
||||
internal val routeColorExpression @Composable get() = switch(
|
||||
input = feature["type"].convertToString(),
|
||||
cases = RouteType.entries.map {
|
||||
case(label = it.name, output = const(it.getUIProperties().colour))
|
||||
}.toTypedArray(),
|
||||
fallback = const(BanksiaTheme.colors.surface),
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package moe.lava.banksia.ui.utils.map
|
||||
package moe.lava.banksia.ui.map.util
|
||||
|
||||
import moe.lava.banksia.util.Point
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package moe.lava.banksia.ui.utils.map
|
||||
package moe.lava.banksia.ui.map.util
|
||||
|
||||
import moe.lava.banksia.util.Point
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package moe.lava.banksia.ui.map.util
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import moe.lava.banksia.model.RouteType
|
||||
import moe.lava.banksia.util.Point
|
||||
|
||||
@Serializable
|
||||
sealed class Marker {
|
||||
abstract val point: Point
|
||||
|
||||
sealed class Typed : Marker() {
|
||||
abstract val type: RouteType
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Stop(
|
||||
override val point: Point,
|
||||
override val type: RouteType,
|
||||
val id: String,
|
||||
) : Typed()
|
||||
|
||||
@Serializable
|
||||
data class Vehicle(
|
||||
override val point: Point,
|
||||
override val type: RouteType,
|
||||
val ref: String,
|
||||
) : Typed()
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package moe.lava.banksia.ui.utils.map
|
||||
package moe.lava.banksia.ui.map.util
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import moe.lava.banksia.util.Point
|
||||
50
ui/shared/build.gradle.kts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
alias(libs.plugins.androidMultiplatformLibrary)
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.composeCompiler)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android {
|
||||
namespace = "moe.lava.banksia.ui.shared"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_11)
|
||||
}
|
||||
}
|
||||
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||
}
|
||||
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(libs.compose.components.resources)
|
||||
implementation(libs.compose.runtime)
|
||||
implementation(libs.compose.foundation)
|
||||
implementation(libs.compose.material3)
|
||||
implementation(libs.compose.ui)
|
||||
implementation(libs.compose.ui.tooling.preview)
|
||||
|
||||
implementation(projects.shared)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
androidRuntimeClasspath(libs.compose.ui.tooling)
|
||||
}
|
||||
|
||||
compose.resources {
|
||||
publicResClass = true
|
||||
packageOfResClass = "moe.lava.banksia.resources"
|
||||
}
|
||||