diff --git a/src/Database/Database.ts b/src/Database/Database.ts index ff632f8..7aea479 100644 --- a/src/Database/Database.ts +++ b/src/Database/Database.ts @@ -7,7 +7,7 @@ export const Knex = knex({ user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, - port: 5432 + port: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 5432 }, pool: { min: 0, diff --git a/src/Interfaces/DatabaseRitInfoUpdate.ts b/src/Interfaces/DatabaseRitInfoUpdate.ts index d3615be..9646d7b 100644 --- a/src/Interfaces/DatabaseRitInfoUpdate.ts +++ b/src/Interfaces/DatabaseRitInfoUpdate.ts @@ -44,4 +44,5 @@ export interface IRitInfoStopUpdate extends IDatabaseStopUpdate { plannedTrack: string | null; actualTrack: string | null; stationCode: string; + name: string; } \ No newline at end of file diff --git a/src/Models/RitInfoUpdate.ts b/src/Models/RitInfoUpdate.ts index eed91a4..07ddb51 100644 --- a/src/Models/RitInfoUpdate.ts +++ b/src/Models/RitInfoUpdate.ts @@ -4,13 +4,14 @@ * Questions? Email: tristantriest@gmail.com */ -import {IDatabaseRitInfoUpdate} from '../Interfaces/DatabaseRitInfoUpdate' +import {IDatabaseRitInfoUpdate, IRitInfoStopUpdate} from '../Interfaces/DatabaseRitInfoUpdate' import {ExtendedStopTimeUpdate} from "./GTFS/StopTimeUpdate"; import {RitInfoStopUpdate} from "./StopUpdates/RitinfoStopUpdate"; import {StopUpdateCollection} from "./StopUpdateCollection"; import {InternationalAgencys, InternationalTrainSeries} from '../Utilities/InternationalAgencys'; import {IJourneyChange} from "../Shared/src/Types/Infoplus/V2/JourneyChange"; import {LogicalJourneyChangeType} from "../Shared/src/Types/Infoplus/V2/Changes/LogicalJourneyChangeType"; +import {TrainType} from "../Shared/src/Types/API/V2/InfoPlus/TrainType"; export class RitInfoUpdate { private readonly _agency: string; @@ -50,12 +51,36 @@ export class RitInfoUpdate { this._timestamp = update.timestamp; this._routeType = update.routeType; - this._routeLongName = update.routeLongName; + this._routeLongName = this.getRouteLongName(update); this._agencyId = update.agencyId; this._isInternationalTrain = this.setInternationalTrain(); } + private getRouteLongName(update: IDatabaseRitInfoUpdate): string { + if(update.routeLongName) + return update.routeLongName; + + const firstStop = this.stops.first(); + const lastStop = this.stops.last(); + + //The trainseries of e.g. 1234 is 1200, 570 is 500, 29290 is 29000 + const trainSeries = update.trainNumber - (update.trainNumber % 100); + const trainType = update.trainType; + const longTrainType = TrainType.shortToLong(TrainType.fromStringToShort(trainType)); + + //Haarlem <-> Amsterdam Sloterdijk BST26000 + //Nachtnettrein Amsterdam Bijlmer ArenA <-> Leiden Centraal + + //Rotterdam Centraal <-> Amsterdam Centraal ICD1100 + if(firstStop.name && lastStop.name) { + return `${firstStop.name} <-> ${lastStop.name} ${trainType}${trainSeries}`; + } + + return `${longTrainType} ${trainSeries}`; + + } + private setInternationalTrain(): boolean { let isInternationalTrain = false; diff --git a/src/Models/StopUpdateCollection.ts b/src/Models/StopUpdateCollection.ts index c54218c..8b1e4c6 100644 --- a/src/Models/StopUpdateCollection.ts +++ b/src/Models/StopUpdateCollection.ts @@ -24,6 +24,12 @@ export class StopUpdateCollection extends Collection { //Make sure all times are increasing this.checkIncreasingTimes(); + + /* + @InfoPlaza - Specific to Infoplaza IFF GTFS + Set all stop sequences sequentually irrespective of the sequence in InfoPlus + */ + this.setSequenceNumbers(); } private setFirstStop() { @@ -101,6 +107,18 @@ export class StopUpdateCollection extends Collection { } } + /** + * Set the sequence number of each stop to its index in the array + 1 + * @private + */ + private setSequenceNumbers() { + for (let i = 0; i < this.length; i++) { + const stop = this.get(i); + stop.sequence = i + 1; + this.set(i, stop); + } + } + /** * Fix the current stop time by setting the arrival time to the planned arrival time + min(delay at previous stop, delay at next stop) * @param previousStop The previous stop in the sequence @@ -136,7 +154,7 @@ export class StopUpdateCollection extends Collection { if (stopToFix.plannedArrivalTime === null) return; // Calculate the new arrival time by adding the departure delay at the previous stop to the planned arrival time at the current stop - const newArrivalTime = stopToFix.plannedArrivalTime.getTime() + previousStop.departureDelay; + const newArrivalTime = (stopToFix.plannedArrivalTime.getTime() / 1000) + previousStop.departureDelay; // If the new arrival time is not increasing, we can't fix the arrival time if (newArrivalTime < previousStop.departureTime) { diff --git a/src/Models/StopUpdates/RitinfoStopUpdate.ts b/src/Models/StopUpdates/RitinfoStopUpdate.ts index c9fd76c..60ce688 100644 --- a/src/Models/StopUpdates/RitinfoStopUpdate.ts +++ b/src/Models/StopUpdates/RitinfoStopUpdate.ts @@ -25,6 +25,8 @@ export class RitInfoStopUpdate extends StopUpdate { public readonly stationCode: string; + public readonly name: string; + constructor(update: IRitInfoStopUpdate) { super(update); @@ -40,6 +42,9 @@ export class RitInfoStopUpdate extends StopUpdate { this.platform = update.platform; this.track = update.track; + + this.name = update.name; + if(this.platform !== this.track) console.log(`[RitInfoStopUpdate] Platform and Track are not the same for stop ${this.stationCode}! Platform: ${this.platform}, Track: ${this.track}`) } diff --git a/src/Repositories/InfoplusRepository.ts b/src/Repositories/InfoplusRepository.ts index e41dc36..d582c80 100644 --- a/src/Repositories/InfoplusRepository.ts +++ b/src/Repositories/InfoplusRepository.ts @@ -15,114 +15,106 @@ export class InfoplusRepository extends Repository implements IInfoPlusRepositor console.time('getCurrentRealtimeTripUpdates'); return this.database.raw(` WITH cal_dates AS (SELECT DISTINCT "serviceId", "date" - FROM "StaticData-NL".calendar_dates - WHERE "date" >= ?::date - AND date <= ?::date), - trips AS (SELECT "tripId", "routeId", "directionId", "tripShortName", "shapeId", "serviceId" - FROM "StaticData-NL".trips - WHERE agency = 'IFF' - AND "serviceId" IN (SELECT DISTINCT "serviceId" - FROM cal_dates)), - stops AS (SELECT "stopId", "stationCode", "platformCode" - FROM "StaticData-NL".stops - WHERE "stationCode" IS NOT NULL) - SELECT jpjl."journeyPartNumber" AS "trainNumber", - jpjl."shortJourneyPartNumber" AS "shortTrainNumber", - r."trainType"->>'code' AS "trainType", - r.agency, - r."operationDate", - r."showsInTravelPlanner" AS "showsInTripPlanner", - r."timestamp", - coalesce(lj."journeyChanges", jpjl."journeyPartChanges") AS "changes", - t."tripId" AS "tripId", - coalesce(t."routeId", t_short."routeId") AS "routeId", - rt."routeType" AS "routeType", - rt."agencyId" AS "agencyId", - rt."routeLongName" AS "routeLongName", - coalesce(t."directionId", t_short."directionId") AS "directionId", - coalesce(t."shapeId", t_short."shapeId") AS "shapeId", - jsonb_agg( - jsonb_build_object( - 'stationCode', - si."stationCode", - 'plannedWillStop', - si."plannedWillStop", - 'actualWillStop', - si."actualWillStop", - 'plannedArrivalTime', - si."plannedArrivalTime", - 'plannedDepartureTime', - si."plannedDepartureTime", - 'departureTime', - coalesce(si."actualDepartureTime", si."plannedDepartureTime"), - 'arrivalTime', - coalesce(si."actualArrivalTime", si."plannedArrivalTime"), - 'departureDelay', - si."actualDepartureTime" - si."plannedDepartureTime", - 'arrivalDelay', - si."actualArrivalTime" - si."plannedArrivalTime", - 'changes', - si.changes, - 'stopId', - COALESCE(s."stopId", lateral_stop."stopId", si."stationCode"), - 'platform', - s."platformCode", - 'plannedTrack', - coalesce(si."plannedArrivalTracks", si."plannedDepartureTracks"), - 'actualTrack', - coalesce(si."actualArrivalTracks", si."actualDepartureTracks"), - 'track', - coalesce(si."actualArrivalTracks", si."actualDepartureTracks", si."plannedArrivalTracks", - si."plannedDepartureTracks"), - 'sequence', - si."stopOrder" - ) ORDER BY si."stopOrder") stops - FROM "InfoPlus-new".ritinfo r - JOIN "InfoPlus-new".logical_journeys lj - ON r."trainNumber" = lj."trainNumber" AND r."operationDate" = lj."operationDate" - JOIN "InfoPlus-new".logical_journey_parts jpjl - ON lj."journeyNumber" = jpjl."journeyNumber" AND - r."operationDate" = jpjl."operationDate" - JOIN "InfoPlus-new".stop_information si - ON jpjl."journeyPartNumber" = si."journeyPartNumber" AND - jpjl."operationDate" = si."operationDate" AND - ("plannedWillStop" = true OR "actualWillStop" = true) AND - (coalesce("plannedDepartureTime", "actualArrivalTime") IS NOT NULL OR - coalesce("plannedArrivalTime", "actualArrivalTime") IS NOT NULL) - LEFT JOIN trips t - ON jpjl."journeyPartNumber" = t."tripShortName"::int + FROM "StaticData-NL".calendar_dates + WHERE "date" >= ?::date + AND date <= ?::date), + trips AS (SELECT "tripId", "routeId", "directionId", "tripShortName", "shapeId", "serviceId" + FROM "StaticData-NL".trips + WHERE agency = 'IFF' + AND "serviceId" IN (SELECT DISTINCT "serviceId" + FROM cal_dates)), + stops AS (SELECT "stopId", "stationCode", "platformCode", "stopName" + FROM "StaticData-NL".stops + WHERE "stationCode" IS NOT NULL) +SELECT jpjl."journeyPartNumber" AS "trainNumber", + jpjl."shortJourneyPartNumber" AS "shortTrainNumber", + r."trainType" ->> 'code' AS "trainType", + r.agency, + r."operationDate", + r."showsInTravelPlanner" AS "showsInTripPlanner", + r."timestamp", + coalesce(lj."journeyChanges", jpjl."journeyPartChanges") AS "changes", + t."tripId" AS "tripId", + coalesce(t."routeId", t_short."routeId") AS "routeId", + rt."routeType" AS "routeType", + rt."agencyId" AS "agencyId", + rt."routeLongName" AS "routeLongName", + coalesce(t."directionId", t_short."directionId") AS "directionId", + coalesce(t."shapeId", t_short."shapeId") AS "shapeId", + jsonb_agg( + CASE + WHEN s."stopId" IS NOT NULL OR lateral_stop."stopId" IS NOT NULL THEN + jsonb_build_object( + 'stationCode', si."stationCode", + 'plannedWillStop', si."plannedWillStop", + 'actualWillStop', si."actualWillStop", + 'plannedArrivalTime', si."plannedArrivalTime", + 'plannedDepartureTime', si."plannedDepartureTime", + 'departureTime', coalesce(si."actualDepartureTime", si."plannedDepartureTime"), + 'arrivalTime', coalesce(si."actualArrivalTime", si."plannedArrivalTime"), + 'departureDelay', si."actualDepartureTime" - si."plannedDepartureTime", + 'arrivalDelay', si."actualArrivalTime" - si."plannedArrivalTime", + 'changes', si.changes, + 'stopId', COALESCE(s."stopId", lateral_stop."stopId"), + 'platform', s."platformCode", + 'plannedTrack', coalesce(si."plannedArrivalTracks", si."plannedDepartureTracks"), + 'actualTrack', coalesce(si."actualArrivalTracks", si."actualDepartureTracks"), + 'track', + coalesce(si."actualArrivalTracks", si."actualDepartureTracks", si."plannedArrivalTracks", + si."plannedDepartureTracks"), + 'sequence', si."stopOrder", + 'name', COALESCE(s."stopName", lateral_stop."stopName", si."stationCode") + ) + END + ORDER BY si."stopOrder" + ) FILTER (WHERE s."stopId" IS NOT NULL OR lateral_stop."stopId" IS NOT NULL) AS stops +FROM "InfoPlus-new".ritinfo r + JOIN "InfoPlus-new".logical_journeys lj + ON r."trainNumber" = lj."trainNumber" AND r."operationDate" = lj."operationDate" + JOIN "InfoPlus-new".logical_journey_parts jpjl + ON lj."journeyNumber" = jpjl."journeyNumber" AND + r."operationDate" = jpjl."operationDate" + JOIN "InfoPlus-new".stop_information si + ON jpjl."journeyPartNumber" = si."journeyPartNumber" AND + jpjl."operationDate" = si."operationDate" AND + ("plannedWillStop" = true OR "actualWillStop" = true) AND + (coalesce("plannedDepartureTime", "actualArrivalTime") IS NOT NULL OR + coalesce("plannedArrivalTime", "actualArrivalTime") IS NOT NULL) + LEFT JOIN trips t + ON jpjl."journeyPartNumber" = t."tripShortName"::int AND EXISTS (SELECT 1 FROM cal_dates cd WHERE cd."serviceId" = t."serviceId" AND cd."date" = r."operationDate") LEFT JOIN trips t_short ON t."tripId" IS NULL AND jpjl."shortJourneyPartNumber" = t_short."tripShortName"::int - AND EXISTS (SELECT 1 + AND EXISTS (SELECT 1 FROM cal_dates cd WHERE cd."serviceId" = t_short."serviceId" - AND cd."date" = r."operationDate") - LEFT JOIN stops s ON (s."stationCode" = lower(si."stationCode") AND - s."platformCode" = - coalesce(si."actualArrivalTracks", si."actualDepartureTracks", si."plannedArrivalTracks", - si."plannedDepartureTracks")) - LEFT JOIN LATERAL ( - SELECT "stopId" - FROM stops lax - WHERE lax."stationCode" = lower(si."stationCode") - LIMIT 1 - ) AS lateral_stop ON s."stopId" IS NULL - LEFT JOIN "StaticData-NL".routes rt ON rt."routeId" = coalesce(t."routeId", t_short."routeId") - WHERE r."operationDate" >= ?::date - AND NOT ( - r."operationDate" > ?::date - AND lj."journeyChanges" IS NULL - ) - GROUP BY r."trainNumber", jpjl."journeyPartNumber", r."shortTrainNumber", jpjl."shortJourneyPartNumber", - r."trainType", r.agency, - r."showsInTravelPlanner", r.timestamp, r."operationDate", t."tripId", coalesce(t."tripId", t_short."tripId"), - coalesce(lj."journeyChanges", jpjl."journeyPartChanges"), - t."tripId", coalesce(t."routeId", t_short."routeId"), - coalesce(t."directionId", t_short."directionId"), coalesce(t."shapeId", t_short."shapeId"), rt."routeType", rt."agencyId", rt."routeLongName"; + AND cd."date" = r."operationDate") + LEFT JOIN stops s ON (s."stationCode" = lower(si."stationCode") AND + s."platformCode" = + coalesce(si."actualArrivalTracks", si."actualDepartureTracks", si."plannedArrivalTracks", + si."plannedDepartureTracks")) + LEFT JOIN LATERAL ( + SELECT "stopId", "stopName" + FROM stops lax + WHERE lax."stationCode" = lower(si."stationCode") + LIMIT 1 + ) AS lateral_stop ON s."stopId" IS NULL + LEFT JOIN "StaticData-NL".routes rt ON rt."routeId" = coalesce(t."routeId", t_short."routeId") +WHERE r."operationDate" >= ?::date + AND NOT ( + r."operationDate" > ?::date + AND lj."journeyChanges" IS NULL + ) +GROUP BY r."trainNumber", jpjl."journeyPartNumber", r."shortTrainNumber", jpjl."shortJourneyPartNumber", + r."trainType", r.agency, + r."showsInTravelPlanner", r.timestamp, r."operationDate", t."tripId", coalesce(t."tripId", t_short."tripId"), + coalesce(lj."journeyChanges", jpjl."journeyPartChanges"), + t."tripId", coalesce(t."routeId", t_short."routeId"), + coalesce(t."directionId", t_short."directionId"), coalesce(t."shapeId", t_short."shapeId"), rt."routeType", + rt."agencyId", rt."routeLongName"; `, [operationDateOfTodayOrYesterday, endOperationDate, operationDateOfTodayOrYesterday, operationDateOfTodayOrTomorrow]).then(result => { console.timeEnd('getCurrentRealtimeTripUpdates'); return result.rows;