feat(server/gtfs): service exception support
This commit is contained in:
parent
c9aeeb99c1
commit
58649b6171
10 changed files with 595 additions and 4 deletions
|
|
@ -21,12 +21,14 @@ 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.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
|
||||
|
|
@ -39,6 +41,7 @@ import kotlin.time.ExperimentalTime
|
|||
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()
|
||||
|
|
@ -77,7 +80,7 @@ class GtfsParser(
|
|||
.listFiles { it.isDirectory }
|
||||
.flatMap { d -> d.listFiles { f -> f.extension == "txt" }.toList() }
|
||||
.ifEmpty { extractAll(datasetPath) }
|
||||
.filter { it.parentFile.name == "2" }
|
||||
// .filter { it.parentFile.name == "2" }
|
||||
} else {
|
||||
extractAll(datasetPath)
|
||||
}
|
||||
|
|
@ -115,6 +118,10 @@ class GtfsParser(
|
|||
}
|
||||
.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 ->
|
||||
|
|
@ -207,6 +214,16 @@ class GtfsParser(
|
|||
)
|
||||
} }
|
||||
|
||||
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, services: Map<String, Service>) =
|
||||
fd.parseCsv<GtfsTrip>()
|
||||
.map { with(it) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -5,6 +5,7 @@ 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
|
||||
|
|
@ -25,6 +26,7 @@ class GtfsImporter(
|
|||
transactor.immediateTransaction {
|
||||
database.routeDao.deleteAll()
|
||||
database.serviceDao.deleteAll()
|
||||
database.serviceExceptionDao.deleteAll()
|
||||
database.shapeDao.deleteAll()
|
||||
database.stopDao.deleteAll()
|
||||
database.stopTimeDao.deleteAll()
|
||||
|
|
@ -34,6 +36,7 @@ class GtfsImporter(
|
|||
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)
|
||||
|
|
@ -67,6 +70,13 @@ class GtfsImporter(
|
|||
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...")
|
||||
|
|
|
|||
477
shared/schemas/moe.lava.banksia.room.Database/10.json
Normal file
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')"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ val CommonModules = module {
|
|||
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 }
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -9,6 +9,7 @@ import kotlinx.coroutines.IO
|
|||
import moe.lava.banksia.room.converter.RouteTypeConverter
|
||||
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
|
||||
|
|
@ -16,6 +17,7 @@ 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
|
||||
|
|
@ -24,10 +26,11 @@ import moe.lava.banksia.room.entity.VersionMetadataEntity
|
|||
import androidx.room.Database as DatabaseAnnotation
|
||||
|
||||
@DatabaseAnnotation(
|
||||
version = 9,
|
||||
version = 10,
|
||||
entities = [
|
||||
RouteEntity::class,
|
||||
ServiceEntity::class,
|
||||
ServiceExceptionEntity::class,
|
||||
ShapeEntity::class,
|
||||
StopEntity::class,
|
||||
StopTimeEntity::class,
|
||||
|
|
@ -37,6 +40,7 @@ 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)
|
||||
|
|
@ -44,6 +48,7 @@ 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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -22,11 +22,13 @@ interface StopTimeDao {
|
|||
suspend fun getForStop(stopId: String): List<StopTimeEntity>
|
||||
|
||||
@Query("""
|
||||
SELECT * FROM StopTime
|
||||
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 == :stopId
|
||||
AND ServiceException.type IS NULL
|
||||
""")
|
||||
suspend fun getForStopDated(stopId: String, days: Int, date: Int): List<StopTimeEntity>
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue