wip departures + refactor
This commit is contained in:
parent
b31067992d
commit
41f3523a5a
43 changed files with 596 additions and 204 deletions
|
|
@ -25,9 +25,40 @@ kotlin {
|
|||
jvm()
|
||||
|
||||
sourceSets {
|
||||
val clientMain by creating {
|
||||
dependsOn(commonMain.get())
|
||||
}
|
||||
|
||||
androidMain.get().dependsOn(clientMain)
|
||||
iosArm64Main.get().dependsOn(clientMain)
|
||||
iosSimulatorArm64Main.get().dependsOn(clientMain)
|
||||
|
||||
commonMain.dependencies {
|
||||
implementation(libs.koin.core)
|
||||
implementation(projects.core)
|
||||
api(projects.core.data.stoptime)
|
||||
api(projects.core.stoptime)
|
||||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(libs.koin.compose)
|
||||
implementation(libs.ktor.client.okhttp)
|
||||
}
|
||||
commonMain.dependencies {
|
||||
implementation(libs.okio)
|
||||
implementation(libs.koin.core)
|
||||
implementation(libs.ktor.client.core)
|
||||
implementation(libs.ktor.client.contentnegotiation)
|
||||
implementation(libs.ktor.serialization.kotlinx.json)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.kotlinx.datetime)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(libs.kotlinx.serialization.protobuf)
|
||||
|
||||
implementation(projects.core)
|
||||
implementation(projects.core.sqld)
|
||||
}
|
||||
iosMain.dependencies {
|
||||
implementation(libs.ktor.client.darwin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
alias(libs.plugins.androidMultiplatformLibrary)
|
||||
alias(libs.plugins.ksp)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android {
|
||||
namespace = "moe.lava.banksia.core.data.client"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_11)
|
||||
}
|
||||
}
|
||||
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||
}
|
||||
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
jvm()
|
||||
|
||||
sourceSets {
|
||||
androidMain.dependencies {
|
||||
implementation(libs.koin.compose)
|
||||
implementation(libs.ktor.client.okhttp)
|
||||
}
|
||||
commonMain.dependencies {
|
||||
api(projects.core.data)
|
||||
|
||||
implementation(libs.okio)
|
||||
implementation(libs.koin.core)
|
||||
implementation(libs.ktor.client.core)
|
||||
implementation(libs.ktor.client.contentnegotiation)
|
||||
implementation(libs.ktor.serialization.kotlinx.json)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.kotlinx.datetime)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(libs.kotlinx.serialization.protobuf)
|
||||
|
||||
implementation(projects.core)
|
||||
implementation(projects.core.sqld)
|
||||
}
|
||||
iosMain.dependencies {
|
||||
implementation(libs.ktor.client.darwin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
plugins {
|
||||
alias(libs.plugins.kotlinJvm)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.okio)
|
||||
implementation(libs.koin.core)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.kotlinx.datetime)
|
||||
|
||||
api(projects.core.data)
|
||||
implementation(projects.core)
|
||||
}
|
||||
|
|
@ -16,17 +16,13 @@ import moe.lava.banksia.core.data.sources.route.RouteLocalDataSource
|
|||
import moe.lava.banksia.core.data.sources.route.RouteRemoteDataSource
|
||||
import moe.lava.banksia.core.data.sources.stop.StopLocalDataSource
|
||||
import moe.lava.banksia.core.data.sources.stop.StopRemoteDataSource
|
||||
import moe.lava.banksia.core.sqld.sqldDiModule
|
||||
import moe.lava.banksia.core.util.log
|
||||
import moe.lava.banksia.data.ptv.PtvService
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
val clientDataDiModule = module {
|
||||
includes(sqldDiModule)
|
||||
includes(stopTimeDataDiModule)
|
||||
|
||||
actual val platformModule = module {
|
||||
// HTTP Clients
|
||||
singleOf(::PtvService)
|
||||
single {
|
||||
|
|
@ -4,6 +4,7 @@ import kotlinx.coroutines.sync.Mutex
|
|||
import kotlinx.coroutines.sync.withLock
|
||||
import moe.lava.banksia.core.data.sources.route.RouteLocalDataSource
|
||||
import moe.lava.banksia.core.data.sources.route.RouteRemoteDataSource
|
||||
import moe.lava.banksia.core.model.Route
|
||||
import moe.lava.banksia.core.sqld.mappers.asModel
|
||||
|
||||
internal class ClientRouteRepository internal constructor(
|
||||
|
|
@ -22,5 +23,14 @@ internal class ClientRouteRepository internal constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val tripRouteMap = mutableMapOf<Long, Route>()
|
||||
|
||||
override suspend fun get(id: String) = mutex.withLock { local.get(id)?.asModel() ?: remote.get(id) }
|
||||
override suspend fun getByPattern(patternId: Long) = mutex.withLock {
|
||||
tripRouteMap[patternId]
|
||||
?: remote.getByPattern(patternId).also {
|
||||
local.save(it)
|
||||
tripRouteMap[patternId] = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import moe.lava.banksia.core.sqld.mappers.asDb
|
|||
internal class RouteLocalDataSource(private val queries: RouteQueries) {
|
||||
suspend fun get(id: String) = withContext(Dispatchers.IO) { queries.get(id).executeAsOneOrNull() }
|
||||
suspend fun getAll() = withContext(Dispatchers.IO) { queries.getAll().executeAsList() }
|
||||
// suspend fun getByTrip(tripId: String) = dao.getByTrip(tripId)
|
||||
suspend fun save(vararg routes: Route) {
|
||||
withContext(Dispatchers.IO) {
|
||||
queries.transaction {
|
||||
|
|
@ -7,5 +7,6 @@ import moe.lava.banksia.core.model.Route
|
|||
|
||||
internal class RouteRemoteDataSource(val client: HttpClient) {
|
||||
suspend fun get(id: String) = client.get("routes/${id}").body<Route>()
|
||||
suspend fun getByPattern(patternId: Long) = client.get("routes/by_pattern/${patternId}").body<Route>()
|
||||
suspend fun getAll() = client.get("routes").body<List<Route>>()
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package moe.lava.banksia.core.data
|
||||
|
||||
import moe.lava.banksia.core.sqld.sqldDiModule
|
||||
import org.koin.core.module.Module
|
||||
import org.koin.dsl.module
|
||||
|
||||
internal expect val platformModule: Module
|
||||
|
||||
val dataDiModule = module {
|
||||
includes(platformModule)
|
||||
includes(sqldDiModule)
|
||||
includes(stopTimeDataDiModule)
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package moe.lava.banksia.core.data.repositories
|
|||
import moe.lava.banksia.core.model.Route
|
||||
|
||||
interface RouteRepository {
|
||||
suspend fun get(id: String): Route
|
||||
suspend fun get(id: String): Route?
|
||||
suspend fun getByPattern(patternId: Long): Route?
|
||||
suspend fun getAll(): List<Route>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package moe.lava.banksia.core.data
|
||||
|
||||
import org.koin.dsl.module
|
||||
|
||||
internal actual val platformModule = module {
|
||||
|
||||
}
|
||||
|
|
@ -2,9 +2,10 @@ package moe.lava.banksia.core.sqld.mappers
|
|||
|
||||
import moe.lava.banksia.core.model.StopTime
|
||||
import moe.lava.banksia.core.model.StoppingPattern
|
||||
import moe.lava.banksia.core.model.TimeType
|
||||
import moe.lava.banksia.core.sqld.StoppingPattern as DbStoppingPattern
|
||||
|
||||
fun DbStoppingPattern.asModel(stoptimes: List<StopTime.Undated>) = StoppingPattern.Undated(
|
||||
fun <T: TimeType> DbStoppingPattern.asModel(stoptimes: List<StopTime<T>>) = StoppingPattern(
|
||||
id = id,
|
||||
routeId = routeId,
|
||||
shapeId = shapeId,
|
||||
|
|
@ -13,7 +14,7 @@ fun DbStoppingPattern.asModel(stoptimes: List<StopTime.Undated>) = StoppingPatte
|
|||
stoptimes = stoptimes,
|
||||
)
|
||||
|
||||
fun StoppingPattern.Undated.asDb() = DbStoppingPattern(
|
||||
fun StoppingPattern<*>.asDb() = DbStoppingPattern(
|
||||
id = id,
|
||||
routeId = routeId,
|
||||
shapeId = shapeId,
|
||||
|
|
|
|||
|
|
@ -11,5 +11,10 @@ SELECT * FROM Route;
|
|||
get:
|
||||
SELECT * FROM Route WHERE id == ?;
|
||||
|
||||
getByPattern:
|
||||
SELECT Route.* FROM Route
|
||||
INNER JOIN StoppingPattern ON Route.id == StoppingPattern.routeId
|
||||
WHERE StoppingPattern.id == :patternId;
|
||||
|
||||
insert:
|
||||
INSERT INTO Route VALUES ?;
|
||||
INSERT OR REPLACE INTO Route VALUES ?;
|
||||
|
|
|
|||
|
|
@ -22,3 +22,24 @@ INNER JOIN StoppingPattern ON StoppingPattern.id == Trip.patternId
|
|||
WHERE StopTime.patternId == StoppingPattern.id
|
||||
AND StopTime.stopId IN (SELECT Stop.id FROM Stop WHERE Stop.parent == :stopId OR Stop.id == :stopId)
|
||||
AND ServiceException.type IS NULL;
|
||||
|
||||
getExtendedForStop:
|
||||
SELECT DISTINCT
|
||||
StopTime.patternId,
|
||||
StopTime.arrivalDelta,
|
||||
StopTime.departureTime,
|
||||
StoppingPattern.headsign,
|
||||
Route.type AS routeType,
|
||||
Route.number AS routeNumber,
|
||||
Route.name AS routeName,
|
||||
Stop.platformCode AS stopPlatformCode
|
||||
FROM StopTime
|
||||
INNER JOIN Service ON Service.days & :days = :days AND :date BETWEEN Service.start AND Service.`end`
|
||||
LEFT JOIN ServiceException ON ServiceException.serviceId == Service.id AND ServiceException.date == :date
|
||||
INNER JOIN Trip ON Trip.serviceId == Service.id
|
||||
INNER JOIN StoppingPattern ON StoppingPattern.id == Trip.patternId
|
||||
INNER JOIN Route ON Route.id == StoppingPattern.routeId
|
||||
INNER JOIN Stop ON Stop.id == StopTime.stopId
|
||||
WHERE StopTime.patternId == StoppingPattern.id
|
||||
AND StopTime.stopId IN (SELECT Stop.id FROM Stop WHERE Stop.parent == :stopId OR Stop.id == :stopId)
|
||||
AND ServiceException.type IS NULL;
|
||||
|
|
|
|||
|
|
@ -8,3 +8,6 @@ CREATE TABLE StoppingPattern (
|
|||
|
||||
insert:
|
||||
INSERT OR REPLACE INTO StoppingPattern VALUES ?;
|
||||
|
||||
get:
|
||||
SELECT * FROM StoppingPattern WHERE id == :id;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
package moe.lava.banksia.core.endpoints
|
||||
|
||||
object Endpoint
|
||||
|
|
@ -31,13 +31,15 @@ sealed class TimeType {
|
|||
) : TimeType()
|
||||
}
|
||||
|
||||
fun TimeType.Undated.atDate(date: LocalDate) = TimeType.Dated(
|
||||
arrival = arrival.atDate(date),
|
||||
departure = departure.atDate(date),
|
||||
)
|
||||
|
||||
fun StopTime<TimeType.Undated>.atDate(date: LocalDate) = StopTime(
|
||||
patternId = patternId,
|
||||
stopId = stopId,
|
||||
time = TimeType.Dated(
|
||||
arrival = time.arrival.atDate(date),
|
||||
departure = time.departure.atDate(date),
|
||||
),
|
||||
time = time.atDate(date),
|
||||
pickupType = pickupType,
|
||||
dropOffType = dropOffType,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ plugins {
|
|||
|
||||
kotlin {
|
||||
android {
|
||||
namespace = "moe.lava.banksia.core.data.stoptime"
|
||||
namespace = "moe.lava.banksia.core.stoptime"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
compilerOptions {
|
||||
|
|
@ -56,5 +56,9 @@ kotlin {
|
|||
iosMain.dependencies {
|
||||
implementation(libs.ktor.client.darwin)
|
||||
}
|
||||
jvmMain.dependencies {
|
||||
implementation(libs.koin.ktor)
|
||||
implementation(libs.ktor.server.core)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,9 @@ import io.ktor.client.request.parameter
|
|||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.todayIn
|
||||
import moe.lava.banksia.core.model.StopTime
|
||||
import moe.lava.banksia.core.data.dto.ExtendedStopTime
|
||||
import moe.lava.banksia.core.endpoints.Endpoint
|
||||
import moe.lava.banksia.core.endpoints.stopTimeByStop
|
||||
import kotlin.time.Clock
|
||||
|
||||
internal class StopTimeRemoteDataSource(
|
||||
|
|
@ -16,9 +18,9 @@ internal class StopTimeRemoteDataSource(
|
|||
suspend fun getAtStop(
|
||||
stopId: String,
|
||||
date: LocalDate? = Clock.System.todayIn(TimeZone.currentSystemDefault()),
|
||||
): List<StopTime.Dated> {
|
||||
return client.get("stoptimes/by_stop/${stopId}") {
|
||||
): List<ExtendedStopTime> {
|
||||
return client.get(Endpoint.stopTimeByStop(stopId)) {
|
||||
parameter("date", date)
|
||||
}.body<List<StopTime.Dated>>()
|
||||
}.body<List<ExtendedStopTime>>()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package moe.lava.banksia.core.data.dto
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.serialization.Serializable
|
||||
import moe.lava.banksia.core.model.FutureTime
|
||||
import moe.lava.banksia.core.model.RouteType
|
||||
import moe.lava.banksia.core.model.TimeType
|
||||
import moe.lava.banksia.core.model.atDate
|
||||
import moe.lava.banksia.core.sqld.GetExtendedForStop
|
||||
|
||||
@Serializable
|
||||
data class ExtendedStopTime(
|
||||
val patternId: Long,
|
||||
val stopPlatformCode: String?,
|
||||
val time: TimeType.Dated,
|
||||
val headsign: String?,
|
||||
val routeType: RouteType,
|
||||
val routeNumber: String?,
|
||||
val routeName: String,
|
||||
)
|
||||
|
||||
// TODO: This probably doesn't belong here
|
||||
fun GetExtendedForStop.asModel(date: LocalDate) = ExtendedStopTime(
|
||||
patternId = patternId,
|
||||
stopPlatformCode = stopPlatformCode,
|
||||
time = TimeType.Undated(
|
||||
arrival = FutureTime.fromInt((departureTime + arrivalDelta).toInt()),
|
||||
departure = FutureTime.fromInt(departureTime.toInt()),
|
||||
).atDate(date),
|
||||
headsign = headsign,
|
||||
routeType = RouteType.from(routeType.toInt()),
|
||||
routeNumber = routeNumber,
|
||||
routeName = routeName,
|
||||
)
|
||||
|
|
@ -4,12 +4,12 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.todayIn
|
||||
import moe.lava.banksia.core.model.StopTime
|
||||
import moe.lava.banksia.core.data.dto.ExtendedStopTime
|
||||
import kotlin.time.Clock
|
||||
|
||||
expect class StopTimeRepository {
|
||||
suspend fun getForStop(
|
||||
id: String,
|
||||
date: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault()),
|
||||
): Flow<List<StopTime.Dated>>
|
||||
): Flow<List<ExtendedStopTime>>
|
||||
}
|
||||
|
|
@ -4,10 +4,9 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.datetime.LocalDate
|
||||
import moe.lava.banksia.core.model.StopTime
|
||||
import moe.lava.banksia.core.model.atDate
|
||||
import moe.lava.banksia.core.data.dto.ExtendedStopTime
|
||||
import moe.lava.banksia.core.data.dto.asModel
|
||||
import moe.lava.banksia.core.sqld.StopTimeQueries
|
||||
import moe.lava.banksia.core.sqld.mappers.asModel
|
||||
import moe.lava.banksia.core.util.serialise
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
|
|
@ -15,16 +14,16 @@ import org.koin.core.component.get
|
|||
internal class StopTimeLocalDataSource : KoinComponent {
|
||||
private val queries get() = get<StopTimeQueries>()
|
||||
|
||||
suspend fun getAtStop(stopId: String, date: LocalDate): List<StopTime.Dated> {
|
||||
suspend fun getAtStop(stopId: String, date: LocalDate): List<ExtendedStopTime> {
|
||||
return withContext(context = Dispatchers.IO) {
|
||||
queries
|
||||
.getForStopDated(
|
||||
.getExtendedForStop(
|
||||
listOf(date.dayOfWeek).serialise().toLong(),
|
||||
date.toEpochDays(),
|
||||
stopId,
|
||||
)
|
||||
.executeAsList()
|
||||
.map { it.asModel().atDate(date) }
|
||||
.map { it.asModel(date) }
|
||||
.sortedBy { it.time.departure }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package moe.lava.banksia.core.endpoints
|
||||
|
||||
fun Endpoint.stopTimeByStop(stopId: String) = "stoptimes/by_stop/${stopId}"
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package moe.lava.banksia.server.routes
|
||||
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.Route
|
||||
import io.ktor.server.routing.get
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.todayIn
|
||||
import moe.lava.banksia.core.data.repositories.StopTimeRepository
|
||||
import moe.lava.banksia.core.endpoints.Endpoint
|
||||
import moe.lava.banksia.core.endpoints.stopTimeByStop
|
||||
import org.koin.ktor.ext.inject
|
||||
import kotlin.time.Clock
|
||||
|
||||
fun Route.stopTimeRoutes() {
|
||||
val repo by inject<StopTimeRepository>()
|
||||
|
||||
get(Endpoint.stopTimeByStop("{stop_id}")) {
|
||||
val stopId = call.parameters["stop_id"]!!
|
||||
val date = call.queryParameters["date"]
|
||||
?.let { LocalDate.parse(it, LocalDate.Formats.ISO) }
|
||||
?: Clock.System.todayIn(TimeZone.currentSystemDefault())
|
||||
val data = repo.getForStop(stopId, date).first()
|
||||
call.respond(data)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue