feat: Add platforms to stations

This commit is contained in:
2025-09-18 18:57:36 +02:00
parent 050badbd85
commit 19a178bbd2
5 changed files with 80 additions and 12 deletions
@@ -33,8 +33,7 @@ interface BahnStationMapper {
return Station( return Station(
StationId.of(NonEmptyString(countryCode + "-" + db.eva.value.toString())), StationId.of(NonEmptyString(countryCode + "-" + db.eva.value.toString())),
CountryCode(NonEmptyString(countryCode)), CountryCode(NonEmptyString(countryCode)),
db.name, db.name
listOf()
) )
} }
} }
@@ -2,5 +2,16 @@ package de.twomartens.timetable.model.common
data class Platform( data class Platform(
var name: String, var name: String,
var sections: MutableList<Section> ) {
) private var sectionsInternal: MutableSet<Section> = mutableSetOf()
val sections: Set<Section> get() = sectionsInternal
fun addSection(section: Section) {
sectionsInternal.add(section)
}
fun addAllSections(sections: Collection<Section>) {
sectionsInternal.addAll(sections)
}
}
@@ -18,7 +18,6 @@ data class Station(
var stationId: StationId, var stationId: StationId,
var countryCode: CountryCode, var countryCode: CountryCode,
var name: NonEmptyString, var name: NonEmptyString,
var platforms: List<Platform>
) { ) {
@Id @Id
lateinit var id: ObjectId lateinit var id: ObjectId
@@ -28,4 +27,24 @@ data class Station(
@LastModifiedDate @LastModifiedDate
lateinit var lastModified: Instant lateinit var lastModified: Instant
private var platformsInternal: MutableMap<String, Platform> = mutableMapOf()
val platforms: List<Platform> get() = platformsInternal.values.toList()
fun addPlatform(platform: Platform?) {
if (platform == null) {
return
}
if (!platformsInternal.containsKey(platform.name)) {
platformsInternal[platform.name] = platform
} else {
platformsInternal[platform.name]?.addAllSections(platform.sections)
}
}
fun addAllPlatforms(platforms: Collection<Platform>) {
platforms.forEach { addPlatform(it) }
}
} }
@@ -16,12 +16,13 @@ interface StationMapper {
@Mapping(target = "created", ignore = true) @Mapping(target = "created", ignore = true)
@Mapping(target = "lastModified", ignore = true) @Mapping(target = "lastModified", ignore = true)
fun mapToDB(countryCode: CountryCode, dto: Station): de.twomartens.timetable.model.db.Station { fun mapToDB(countryCode: CountryCode, dto: Station): de.twomartens.timetable.model.db.Station {
return de.twomartens.timetable.model.db.Station( val station = de.twomartens.timetable.model.db.Station(
StationId.of(NonEmptyString(countryCode.countryCode.value + "-" + dto.id)), StationId.of(NonEmptyString(countryCode.countryCode.value + "-" + dto.id)),
countryCode, countryCode,
NonEmptyString(dto.name), NonEmptyString(dto.name)
dto.platforms
) )
station.addAllPlatforms(dto.platforms)
return station
} }
fun mapStationsToDto(stations: List<de.twomartens.timetable.model.db.Station>): List<Station> fun mapStationsToDto(stations: List<de.twomartens.timetable.model.db.Station>): List<Station>
@@ -2,14 +2,14 @@ package de.twomartens.timetable.service
import de.twomartens.timetable.bahnApi.model.db.BahnTimetable import de.twomartens.timetable.bahnApi.model.db.BahnTimetable
import de.twomartens.timetable.bahnApi.repository.BahnTimetableRepository import de.twomartens.timetable.bahnApi.repository.BahnTimetableRepository
import de.twomartens.timetable.model.common.ServiceId import de.twomartens.timetable.model.common.*
import de.twomartens.timetable.model.common.TimetableId
import de.twomartens.timetable.model.common.UserId
import de.twomartens.timetable.model.db.Service import de.twomartens.timetable.model.db.Service
import de.twomartens.timetable.model.db.ServiceRepository import de.twomartens.timetable.model.db.ServiceRepository
import de.twomartens.timetable.model.db.ServiceStop import de.twomartens.timetable.model.db.ServiceStop
import de.twomartens.timetable.model.db.Timetable import de.twomartens.timetable.model.db.Timetable
import de.twomartens.timetable.model.dto.TimetableState import de.twomartens.timetable.model.dto.TimetableState
import de.twomartens.timetable.model.repository.StationRepository
import de.twomartens.timetable.route.TswRouteRepository
import de.twomartens.timetable.timetable.TimetableRepository import de.twomartens.timetable.timetable.TimetableRepository
import de.twomartens.timetable.types.NonEmptyString import de.twomartens.timetable.types.NonEmptyString
import org.springframework.batch.core.Job import org.springframework.batch.core.Job
@@ -112,6 +112,9 @@ class BatchProcessTimetableConfiguration {
transactionManager: PlatformTransactionManager, transactionManager: PlatformTransactionManager,
stopStorageRequestRepository: StopStorageRequestRepository, stopStorageRequestRepository: StopStorageRequestRepository,
serviceRepository: ServiceRepository, serviceRepository: ServiceRepository,
stationRepository: StationRepository,
timetableRepository: TimetableRepository,
routeRepository: TswRouteRepository,
@Value("#{jobParameters}") jobParameters: JobParameters): Step { @Value("#{jobParameters}") jobParameters: JobParameters): Step {
val userId = UserId.of(NonEmptyString(jobParameters.getString("userId")!!)) val userId = UserId.of(NonEmptyString(jobParameters.getString("userId")!!))
val timetableId = TimetableId.of(NonEmptyString(jobParameters.getString("timetableId")!!)) val timetableId = TimetableId.of(NonEmptyString(jobParameters.getString("timetableId")!!))
@@ -125,7 +128,6 @@ class BatchProcessTimetableConfiguration {
.saveState(true) .saveState(true)
.build() .build()
val processor = ItemProcessor<StopStorageRequest, Service> { val processor = ItemProcessor<StopStorageRequest, Service> {
val serviceId = ServiceId.of(NonEmptyString(it.trainNumber)) val serviceId = ServiceId.of(NonEmptyString(it.trainNumber))
val serviceExists = serviceRepository.existsServiceByUserIdAndTimetableIdAndServiceId( val serviceExists = serviceRepository.existsServiceByUserIdAndTimetableIdAndServiceId(
@@ -136,6 +138,18 @@ class BatchProcessTimetableConfiguration {
} else { } else {
Service(userId, timetableId, serviceId) Service(userId, timetableId, serviceId)
} }
val timetable = timetableRepository.findByUserIdAndTimetableId(userId, timetableId)!!
val route = routeRepository.findByUserIdAndRouteId(userId, timetable.routeId)!!
val station = stationRepository.findByCountryCodeAndStationId(
route.country.code,
StationId.of(NonEmptyString(route.country.code + "-" + it.eva)))!!
val arrivalPlatform = buildPlatform(it.plannedArrivalPlatform)
station.addPlatform(arrivalPlatform)
val departurePlatform = buildPlatform(it.plannedDeparturePlatform)
station.addPlatform(departurePlatform)
stationRepository.save(station) // yes, this violates the pure function principle
service.addStop(ServiceStop( service.addStop(ServiceStop(
it.eva, it.eva,
it.plannedArrivalTime, it.plannedArrivalTime,
@@ -192,4 +206,28 @@ class BatchProcessTimetableConfiguration {
.writer(writer) .writer(writer)
.build() .build()
} }
private fun buildPlatform(platformString: String?): Platform? {
if (platformString == null) {
return null
}
val platformFormat = Regex("(<track>\\d+)(?:\\s+(<sections>[\\w-]+))?")
val matchResult = platformFormat.matchEntire(platformString) ?: return null
val track = matchResult.groups["track"]?.value ?: return null
val platform = Platform(track)
val sectionsString = matchResult.groups["sections"]?.value ?: return platform
val sectionRangeEndpoints = sectionsString.split("-")
val sections = if (sectionRangeEndpoints.size == 1) {
setOf(Section.of(NonEmptyString(sectionRangeEndpoints[0])))
} else {
(sectionRangeEndpoints[0].toCharArray()[0]..
sectionRangeEndpoints[1].toCharArray()[0]).map {
Section.of(NonEmptyString(it.toString()))
}
}
platform.addAllSections(sections)
return platform
}
} }