From 03f36c8c33fcb84e0cf9115a53239be1e31803f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20M=C3=A9a?= Date: Tue, 10 Dec 2024 16:18:56 -0500 Subject: [PATCH] mGTFS > add stop_times --- .../org/mtransit/commons/gtfs/sql/AllSQL.kt | 3 +- .../mtransit/commons/gtfs/sql/CommonSQL.kt | 23 ++-- .../mtransit/commons/gtfs/sql/SQLTableDef.kt | 2 +- .../mtransit/commons/gtfs/sql/StopTimeSQL.kt | 110 ++++++++++++++++++ 4 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/mtransit/commons/gtfs/sql/StopTimeSQL.kt diff --git a/src/main/java/org/mtransit/commons/gtfs/sql/AllSQL.kt b/src/main/java/org/mtransit/commons/gtfs/sql/AllSQL.kt index ae4a7e3..cbe8b61 100644 --- a/src/main/java/org/mtransit/commons/gtfs/sql/AllSQL.kt +++ b/src/main/java/org/mtransit/commons/gtfs/sql/AllSQL.kt @@ -6,8 +6,7 @@ val ALL_SQL_TABLES: List = listOf( StopSQL, CalendarDateSQL, TripSQL, - - // TODO stop_times + StopTimeSQL, FrequencySQL, // TODO directions (route_id, direction_id, direction_name) diff --git a/src/main/java/org/mtransit/commons/gtfs/sql/CommonSQL.kt b/src/main/java/org/mtransit/commons/gtfs/sql/CommonSQL.kt index 4113f86..33be085 100644 --- a/src/main/java/org/mtransit/commons/gtfs/sql/CommonSQL.kt +++ b/src/main/java/org/mtransit/commons/gtfs/sql/CommonSQL.kt @@ -38,9 +38,6 @@ abstract class CommonSQL() : TableSQL { open fun getOrInsertIdInt(statement: Statement, id: String): Int { this.cachedIds[id]?.let { - if (this is TripSQL) { - throw Exception("Re-using trip id $id") - } return it } val update = statement.executeUpdateMT(getSQLInsertIds(id), returnGeneratedKeys = true) @@ -67,7 +64,7 @@ abstract class CommonSQL() : TableSQL { fun getMainTableSQLCreate() = getMainTable()?.getSQLCreateTableQuery() - fun getMainTableSQLInsert() = getMainTable()?.getSQLInsertTableQuery() + fun getMainTableSQLInsert(allowUpdate: Boolean = false) = getMainTable()?.getSQLInsertTableQuery(allowUpdate) fun getMainTableInsertPreparedStatement(allowUpdate: Boolean = false) = getMainTable()?.let { buildString { @@ -84,31 +81,25 @@ abstract class CommonSQL() : TableSQL { } } - fun insertIntoMainTable(mainObject: MainType, statement: Statement, preparedStatement: PreparedStatement?): Boolean { + fun insertIntoMainTable(mainObject: MainType, statement: Statement, preparedStatement: PreparedStatement?, allowUpdate: Boolean = false): Boolean { preparedStatement?.apply { - val mainTable = getMainTable() ?: return false + val mainTableColumns = getMainTable()?.columns ?: return false val columnsValues = toInsertColumns(statement, mainObject) - val columnsDef = mainTable.columns columnsValues.forEachIndexed { i, columnValue -> if (columnValue == null) { setNull(i + 1, java.sql.Types.NULL) return@forEachIndexed } - when (columnsDef[i].columnType) { + when (mainTableColumns[i].columnType) { SQLUtils.INT -> setInt(i + 1, columnValue as Int) SQLUtils.TXT -> setString(i + 1, columnValue as String) - else -> TODO("Unexpected column type for ${columnsDef[i]}!") + else -> TODO("Unexpected column type for ${mainTableColumns[i]}!") } } addBatch() return true } - return statement.executeUpdateMT( - getSQLInsertOrReplace( - statement, - mainObject - ) - ) > 0 + return statement.executeUpdateMT(getSQLInsertOrReplace(statement, mainObject, allowUpdate)) > 0 } fun getMainTableSQLDrop() = getMainTable()?.getSQLDropIfExistsQuery() @@ -139,7 +130,7 @@ abstract class CommonSQL() : TableSQL { abstract fun toInsertColumns(statement: Statement, main: MainType): Array - open fun getSQLInsertOrReplace(statement: Statement, main: MainType) = getMainTableSQLInsert()?.let { + open fun getSQLInsertOrReplace(statement: Statement, main: MainType, allowUpdate: Boolean = false) = getMainTableSQLInsert(allowUpdate)?.let { SQLInsertBuilder.compile( it, *toInsertColumns(statement, main) diff --git a/src/main/java/org/mtransit/commons/gtfs/sql/SQLTableDef.kt b/src/main/java/org/mtransit/commons/gtfs/sql/SQLTableDef.kt index 8fe3305..23a4ef0 100644 --- a/src/main/java/org/mtransit/commons/gtfs/sql/SQLTableDef.kt +++ b/src/main/java/org/mtransit/commons/gtfs/sql/SQLTableDef.kt @@ -26,7 +26,7 @@ data class SQLTableDef( } }.build() - fun getSQLInsertTableQuery() = SQLInsertBuilder.getNew(tableName, insertAllowReplace).apply { + fun getSQLInsertTableQuery(overrideAllowUpdate: Boolean? = null) = SQLInsertBuilder.getNew(tableName, overrideAllowUpdate ?: insertAllowReplace).apply { columns.forEach { columnDef -> if (columnDef.columnType == SQLUtils.INT_PK_AUTO) { return@forEach // SKIP AUTOINCREMENT diff --git a/src/main/java/org/mtransit/commons/gtfs/sql/StopTimeSQL.kt b/src/main/java/org/mtransit/commons/gtfs/sql/StopTimeSQL.kt new file mode 100644 index 0000000..2b441fb --- /dev/null +++ b/src/main/java/org/mtransit/commons/gtfs/sql/StopTimeSQL.kt @@ -0,0 +1,110 @@ +package org.mtransit.commons.gtfs.sql + +import org.mtransit.commons.gtfs.data.StopId +import org.mtransit.commons.gtfs.data.StopTime +import org.mtransit.commons.gtfs.data.TripId +import org.mtransit.commons.sql.SQLUtils +import org.mtransit.commons.sql.executeUpdateMT +import java.sql.ResultSet +import java.sql.Statement + +object StopTimeSQL : CommonSQL(), TableSQL { + + const val T_STOP_TIME = "stop_time" + + const val T_STOP_TIME_K_TRIP_ID_INT = "trip_id_int" + const val T_STOP_TIME_K_STOP_ID_INT = "stop_id_int" + const val T_STOP_TIME_K_STOP_SEQUENCE = "stop_sequence" + const val T_STOP_TIME_K_ARRIVAL_TIME = "arrival_time" + const val T_STOP_TIME_K_DEPARTURE_TIME = "departure_time" + const val T_STOP_TIME_K_STOP_HEADSIGN = "stop_headsign" + const val T_STOP_TIME_K_PICKUP_TYPE = "pickup_type" + const val T_STOP_TIME_K_DROP_OFF_TYPE = "drop_off_type" + const val T_STOP_TIME_K_TIME_POINT = "time_point" + + override fun getMainTable() = SQLTableDef( + T_STOP_TIME, + listOf( + SQLColumDef(T_STOP_TIME_K_TRIP_ID_INT, SQLUtils.INT, primaryKey = true, foreignKey = SQLForeignKey(TripSQL.T_TRIP, TripSQL.T_TRIP_K_ID_INT)), + SQLColumDef(T_STOP_TIME_K_STOP_ID_INT, SQLUtils.INT, primaryKey = true, foreignKey = SQLForeignKey(StopSQL.T_STOP, StopSQL.T_STOP_K_ID_INT)), + SQLColumDef(T_STOP_TIME_K_STOP_SEQUENCE, SQLUtils.INT, primaryKey = true), + SQLColumDef(T_STOP_TIME_K_ARRIVAL_TIME, SQLUtils.TXT), // TODO int + SQLColumDef(T_STOP_TIME_K_DEPARTURE_TIME, SQLUtils.TXT), // TODO int + SQLColumDef(T_STOP_TIME_K_STOP_HEADSIGN, SQLUtils.TXT), + SQLColumDef(T_STOP_TIME_K_PICKUP_TYPE, SQLUtils.INT), + SQLColumDef(T_STOP_TIME_K_DROP_OFF_TYPE, SQLUtils.INT), + SQLColumDef(T_STOP_TIME_K_TIME_POINT, SQLUtils.INT), + ), + insertAllowReplace = false, + ) + + override fun toInsertColumns(statement: Statement, stopTime: StopTime) = with(stopTime) { + arrayOf( + TripSQL.getOrInsertIdInt(statement, stopTime.tripId), + StopSQL.getOrInsertIdInt(statement, stopTime.stopId), + stopSequence, + arrivalTime, + departureTime, + stopHeadsign, + pickupType, + dropOffType, + timePoint, + ) + } + + override fun fromResultSet(rs: ResultSet) = with(rs) { + StopTime( + tripId = rs.getString(TripSQL.T_TRIP_IDS_K_ID), + stopId = rs.getString(StopSQL.T_STOP_IDS_K_ID), + stopSequence = rs.getInt(T_STOP_TIME_K_STOP_SEQUENCE), + arrivalTime = rs.getString(T_STOP_TIME_K_ARRIVAL_TIME), + departureTime = rs.getString(T_STOP_TIME_K_DEPARTURE_TIME), + stopHeadsign = rs.getString(T_STOP_TIME_K_STOP_HEADSIGN), + pickupType = rs.getInt(T_STOP_TIME_K_PICKUP_TYPE), + dropOffType = rs.getInt(T_STOP_TIME_K_DROP_OFF_TYPE), + timePoint = rs.getInt(T_STOP_TIME_K_TIME_POINT), + ) + } + + fun select(statement: Statement, tripIds: Collection? = null, limitMaxNbRow: Int? = null, limitOffset: Int? = null): List { + val sql = buildString { + append("SELECT * ") + append("FROM $T_STOP_TIME ") + append("JOIN ${TripSQL.T_TRIP_IDS} ON $T_STOP_TIME.$T_STOP_TIME_K_TRIP_ID_INT = ${TripSQL.T_TRIP_IDS}.${TripSQL.T_TRIP_IDS_K_ID_INT} ") + append("JOIN ${StopSQL.T_STOP_IDS} ON $T_STOP_TIME.$T_STOP_TIME_K_STOP_ID_INT = ${StopSQL.T_STOP_IDS}.${StopSQL.T_STOP_IDS_K_ID_INT} ") + tripIds?.let { + append("WHERE ${TripSQL.T_TRIP_IDS}.${TripSQL.T_TRIP_IDS_K_ID} IN (${it.joinToString { "'$it'" }}) ") + } + append("ORDER BY ") + append("${TripSQL.T_TRIP_IDS_K_ID} ASC, ") + append("$T_STOP_TIME_K_STOP_SEQUENCE ASC, ") + append("$T_STOP_TIME_K_DEPARTURE_TIME ASC ") + limitMaxNbRow?.let { + append("LIMIT $limitMaxNbRow ") + limitOffset?.let { + append("OFFSET $limitOffset ") + } + } + } + return statement.executeQuery(sql).use { rs -> + buildList { + while (rs.next()) { + add(fromResultSet(rs)) + } + } + } + } + + fun delete(statement: Statement, tripId: TripId? = null, stopId: StopId? = null): Int { + val sql = buildString { + append("DELETE FROM $T_STOP_TIME") + tripId?.let { + append(" WHERE $T_STOP_TIME.$T_STOP_TIME_K_TRIP_ID_INT = ${TripSQL.getOrInsertIdInt(statement, tripId)}") + } + stopId?.let { + append(" WHERE $T_STOP_TIME.$T_STOP_TIME_K_STOP_ID_INT = ${StopSQL.getOrInsertIdInt(statement, stopId)}") + } + } + return statement.executeUpdateMT(sql) + } +} \ No newline at end of file