feat: server-handled routes and stops
This commit is contained in:
parent
efba64ea90
commit
58ee095522
61 changed files with 1634 additions and 349 deletions
|
|
@ -1,28 +1,51 @@
|
|||
package moe.lava.banksia.room
|
||||
|
||||
import androidx.room.AutoMigration
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import moe.lava.banksia.model.Route
|
||||
import moe.lava.banksia.model.RouteType
|
||||
import moe.lava.banksia.model.Shape
|
||||
import moe.lava.banksia.room.converter.RouteTypeConverter
|
||||
import moe.lava.banksia.room.dao.RouteDao
|
||||
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.entity.RouteEntity
|
||||
import moe.lava.banksia.room.entity.ShapeEntity
|
||||
import moe.lava.banksia.room.entity.StopEntity
|
||||
import moe.lava.banksia.room.entity.StopTimeEntity
|
||||
import moe.lava.banksia.room.entity.TripEntity
|
||||
import androidx.room.Database as DatabaseAnnotation
|
||||
|
||||
@DatabaseAnnotation(entities = [Route::class, Shape::class], version = 1)
|
||||
@TypeConverters(RouteType.Companion::class)
|
||||
@DatabaseAnnotation(
|
||||
version = 2,
|
||||
entities = [
|
||||
RouteEntity::class,
|
||||
ShapeEntity::class,
|
||||
StopEntity::class,
|
||||
StopTimeEntity::class,
|
||||
TripEntity::class,
|
||||
],
|
||||
autoMigrations = [
|
||||
AutoMigration(from = 1, to = 2),
|
||||
]
|
||||
)
|
||||
@TypeConverters(RouteTypeConverter::class)
|
||||
abstract class Database : RoomDatabase() {
|
||||
abstract fun getRouteDao(): RouteDao
|
||||
abstract fun getShapeDao(): ShapeDao
|
||||
abstract val routeDao: RouteDao
|
||||
abstract val shapeDao: ShapeDao
|
||||
abstract val stopDao: StopDao
|
||||
abstract val stopTimeDao: StopTimeDao
|
||||
abstract val tripDao: TripDao
|
||||
|
||||
companion object {
|
||||
fun build(base: Builder<Database>) =
|
||||
base.fallbackToDestructiveMigrationOnDowngrade(true)
|
||||
base.fallbackToDestructiveMigration(true)
|
||||
.setDriver(BundledSQLiteDriver())
|
||||
.setQueryCoroutineContext(Dispatchers.IO)
|
||||
// .fallbackToDestructiveMigration(true)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package moe.lava.banksia.room.converter
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import moe.lava.banksia.model.RouteType
|
||||
|
||||
object RouteTypeConverter {
|
||||
@TypeConverter
|
||||
fun from(value: Int) = RouteType.entries.first { it.value == value }
|
||||
|
||||
@TypeConverter
|
||||
fun to(routeType: RouteType) = routeType.value
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import androidx.room.TypeConverter
|
|||
import moe.lava.banksia.model.ShapePath
|
||||
import moe.lava.banksia.util.Point
|
||||
|
||||
object ShapeConverter {
|
||||
object ShapePathConverter {
|
||||
@TypeConverter
|
||||
fun from(value: ByteArray): ShapePath {
|
||||
return value
|
||||
|
|
@ -3,23 +3,47 @@ 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.model.Route
|
||||
import moe.lava.banksia.room.entity.RouteEntity
|
||||
import moe.lava.banksia.room.entity.StopEntity
|
||||
|
||||
@Dao
|
||||
interface RouteDao {
|
||||
@Query("SELECT * FROM Route")
|
||||
suspend fun getAll(): List<Route>
|
||||
suspend fun getAll(): List<RouteEntity>
|
||||
|
||||
@Query("SELECT * FROM Route WHERE id == :id")
|
||||
suspend fun get(id: String): Route?
|
||||
suspend fun get(id: String): RouteEntity?
|
||||
|
||||
@Insert
|
||||
suspend fun insertAll(vararg routes: Route)
|
||||
suspend fun insertAll(vararg routes: RouteEntity)
|
||||
|
||||
@Insert(onConflict = REPLACE)
|
||||
suspend fun insertOrReplaceAll(vararg routes: RouteEntity)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(route: Route)
|
||||
suspend fun delete(route: RouteEntity)
|
||||
|
||||
@Query("DELETE FROM Route")
|
||||
suspend fun deleteAll()
|
||||
|
||||
@Query("""
|
||||
SELECT Stop.* FROM Stop
|
||||
INNER JOIN StopTime ON StopTime.stopId == Stop.id
|
||||
INNER JOIN Trip ON Trip.id == StopTime.tripId
|
||||
WHERE Trip.routeId == :id
|
||||
GROUP BY Stop.id
|
||||
""")
|
||||
suspend fun stops(id: String): List<StopEntity>
|
||||
|
||||
@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
|
||||
""")
|
||||
suspend fun stopsParent(id: String): List<StopEntity>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,18 +4,18 @@ import androidx.room.Dao
|
|||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import moe.lava.banksia.model.Shape
|
||||
import moe.lava.banksia.room.entity.ShapeEntity
|
||||
|
||||
@Dao
|
||||
interface ShapeDao {
|
||||
@Query("SELECT * FROM Shape WHERE id == :id")
|
||||
suspend fun get(id: String): Shape?
|
||||
suspend fun get(id: String): ShapeEntity?
|
||||
|
||||
@Insert
|
||||
suspend fun insertAll(vararg shapes: Shape)
|
||||
suspend fun insertAll(vararg shapes: ShapeEntity)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(shape: Shape)
|
||||
suspend fun delete(shape: ShapeEntity)
|
||||
|
||||
@Query("DELETE FROM Shape")
|
||||
suspend fun deleteAll()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
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.StopEntity
|
||||
|
||||
@Dao
|
||||
interface StopDao {
|
||||
@Query("SELECT * FROM Stop")
|
||||
suspend fun getAll(): List<StopEntity>
|
||||
|
||||
@Query("SELECT * FROM Stop WHERE id == :id")
|
||||
suspend fun get(id: String): StopEntity?
|
||||
|
||||
@Query("SELECT * FROM Stop WHERE id IN (:ids)")
|
||||
suspend fun get(ids: List<String>): List<StopEntity>
|
||||
|
||||
@Insert
|
||||
suspend fun insertAll(vararg stops: StopEntity)
|
||||
|
||||
@Insert(onConflict = REPLACE)
|
||||
suspend fun insertOrReplaceAll(vararg stops: StopEntity)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(stop: StopEntity)
|
||||
|
||||
@Query("DELETE FROM Stop")
|
||||
suspend fun deleteAll()
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
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.StopTimeEntity
|
||||
|
||||
@Dao
|
||||
interface StopTimeDao {
|
||||
@Query("SELECT * FROM StopTime")
|
||||
suspend fun getAll(): List<StopTimeEntity>
|
||||
|
||||
@Query("SELECT * FROM StopTime WHERE tripId == :tripId")
|
||||
suspend fun get(tripId: String): StopTimeEntity?
|
||||
|
||||
@Query("SELECT * FROM StopTime WHERE tripId IN (:tripIds)")
|
||||
suspend fun get(tripIds: List<String>): List<StopTimeEntity>
|
||||
|
||||
@Insert
|
||||
suspend fun insertAll(vararg stopTimes: StopTimeEntity)
|
||||
|
||||
@Insert(onConflict = REPLACE)
|
||||
suspend fun insertOrReplaceAll(vararg stopTimes: StopTimeEntity)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(stopTime: StopTimeEntity)
|
||||
|
||||
@Query("DELETE FROM StopTime")
|
||||
suspend fun deleteAll()
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
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.TripEntity
|
||||
|
||||
@Dao
|
||||
interface TripDao {
|
||||
@Query("SELECT * FROM Trip")
|
||||
suspend fun getAll(): List<TripEntity>
|
||||
|
||||
@Query("SELECT * FROM Trip WHERE id == :id")
|
||||
suspend fun get(id: String): TripEntity?
|
||||
|
||||
@Query("SELECT * FROM Trip WHERE routeId == :id")
|
||||
suspend fun getByRoute(id: String): List<TripEntity>
|
||||
|
||||
@Insert
|
||||
suspend fun insertAll(vararg trips: TripEntity)
|
||||
|
||||
@Insert(onConflict = REPLACE)
|
||||
suspend fun insertOrReplaceAll(vararg trips: TripEntity)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(trip: TripEntity)
|
||||
|
||||
@Query("DELETE FROM Trip")
|
||||
suspend fun deleteAll()
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package moe.lava.banksia.room.entity
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import moe.lava.banksia.model.Route
|
||||
import moe.lava.banksia.model.RouteType
|
||||
|
||||
@Entity("Route")
|
||||
data class RouteEntity(
|
||||
@PrimaryKey val id: String,
|
||||
val type: RouteType,
|
||||
val number: String?,
|
||||
val name: String,
|
||||
) {
|
||||
fun asModel() = Route(id, type, number, name)
|
||||
}
|
||||
|
||||
fun Route.asEntity() = RouteEntity(id, type, number, name)
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package moe.lava.banksia.room.entity
|
||||
|
||||
import kotlinx.datetime.DayOfWeek
|
||||
import kotlinx.datetime.LocalDate
|
||||
import moe.lava.banksia.model.Service
|
||||
|
||||
data class ServiceEntity(
|
||||
val id: String,
|
||||
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),
|
||||
LocalDate.fromEpochDays(start),
|
||||
LocalDate.fromEpochDays(end),
|
||||
)
|
||||
}
|
||||
|
||||
fun Service.asEntity() = ServiceEntity(
|
||||
id,
|
||||
ServiceEntity.Parser.serialiseDays(days),
|
||||
start.toEpochDays().toInt(),
|
||||
end.toEpochDays().toInt(),
|
||||
)
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package moe.lava.banksia.room.entity
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import androidx.room.TypeConverters
|
||||
import moe.lava.banksia.model.Shape
|
||||
import moe.lava.banksia.model.ShapePath
|
||||
import moe.lava.banksia.room.converter.ShapePathConverter
|
||||
|
||||
@Entity("Shape")
|
||||
@TypeConverters(ShapePathConverter::class)
|
||||
data class ShapeEntity(
|
||||
@PrimaryKey val id: String,
|
||||
val path: ShapePath,
|
||||
) {
|
||||
fun asModel() = Shape(id, path)
|
||||
}
|
||||
|
||||
fun Shape.asEntity() = ShapeEntity(id, path)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package moe.lava.banksia.room.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import moe.lava.banksia.model.Stop
|
||||
import moe.lava.banksia.util.Point
|
||||
|
||||
@Entity("Stop")
|
||||
data class StopEntity(
|
||||
@PrimaryKey val id: String,
|
||||
val name: String,
|
||||
val lat: Double,
|
||||
val lng: Double,
|
||||
@ColumnInfo(index = true) val parent: String,
|
||||
val hasWheelChairBoarding: Boolean,
|
||||
val level: String,
|
||||
val platformCode: String,
|
||||
) {
|
||||
fun asModel() = Stop(id, name, Point(lat, lng), parent, hasWheelChairBoarding, level, platformCode)
|
||||
}
|
||||
|
||||
fun Stop.asEntity() = StopEntity(id, name, pos.lat, pos.lng, parent, hasWheelChairBoarding, level, platformCode)
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package moe.lava.banksia.room.entity
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.ForeignKey.Companion.CASCADE
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import moe.lava.banksia.model.FutureTime
|
||||
import moe.lava.banksia.model.FutureTime.Companion.asInt
|
||||
import moe.lava.banksia.model.StopTime
|
||||
|
||||
@Entity(
|
||||
"StopTime",
|
||||
primaryKeys = ["tripId", "stopId"],
|
||||
foreignKeys = [
|
||||
ForeignKey(TripEntity::class, parentColumns = ["id"], childColumns = ["tripId"], onDelete = CASCADE),
|
||||
ForeignKey(StopEntity::class, parentColumns = ["id"], childColumns = ["stopId"], onDelete = CASCADE),
|
||||
]
|
||||
)
|
||||
data class StopTimeEntity(
|
||||
val tripId: String,
|
||||
val stopId: String,
|
||||
val arrivalTime: Int,
|
||||
val departureTime: Int,
|
||||
val headsign: String?,
|
||||
val pickupType: Int,
|
||||
val dropOffType: Int,
|
||||
) {
|
||||
fun asModel() = StopTime(
|
||||
tripId,
|
||||
stopId,
|
||||
FutureTime.fromInt(arrivalTime),
|
||||
FutureTime.fromInt(departureTime),
|
||||
headsign,
|
||||
pickupType,
|
||||
dropOffType,
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
fun StopTime.asEntity() = StopTimeEntity(
|
||||
tripId,
|
||||
stopId,
|
||||
arrivalTime.asInt(),
|
||||
departureTime.asInt(),
|
||||
headsign,
|
||||
pickupType,
|
||||
dropOffType,
|
||||
)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package moe.lava.banksia.room.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.ForeignKey.Companion.CASCADE
|
||||
import androidx.room.PrimaryKey
|
||||
import moe.lava.banksia.model.Trip
|
||||
|
||||
@Entity(
|
||||
"Trip",
|
||||
foreignKeys = [
|
||||
ForeignKey(RouteEntity::class, parentColumns = ["id"], childColumns = ["routeId"], onDelete = CASCADE),
|
||||
ForeignKey(ShapeEntity::class, parentColumns = ["id"], childColumns = ["shapeId"], onDelete = CASCADE),
|
||||
],
|
||||
)
|
||||
data class TripEntity(
|
||||
@PrimaryKey val id: String,
|
||||
@ColumnInfo(index = true) val routeId: String,
|
||||
val serviceId: String,
|
||||
val shapeId: String?,
|
||||
val tripHeadsign: String,
|
||||
val directionId: String,
|
||||
val blockId: String,
|
||||
val wheelchairAccessible: String,
|
||||
) {
|
||||
fun asModel() = Trip(id, routeId, serviceId, shapeId, tripHeadsign, directionId, blockId, wheelchairAccessible)
|
||||
}
|
||||
|
||||
fun Trip.asEntity() = TripEntity(id, routeId, serviceId, shapeId, tripHeadsign, directionId, blockId, wheelchairAccessible)
|
||||
Loading…
Add table
Add a link
Reference in a new issue