aboutsummaryrefslogtreecommitdiff
path: root/src/Costasdev.Busurbano.Sources.OpenTripPlannerGql
diff options
context:
space:
mode:
authorAriel Costas Guerrero <ariel@costas.dev>2025-12-27 16:39:09 +0100
committerAriel Costas Guerrero <ariel@costas.dev>2025-12-27 16:39:28 +0100
commitf81ff82f2a07f87f6eb4f43de49ede64215519e5 (patch)
tree67b4f9ef1c94184e2e1a9878c6feed8dc30ebcb3 /src/Costasdev.Busurbano.Sources.OpenTripPlannerGql
parentef2df90ffb195edcddd701511dc5953c7baa63af (diff)
Refactor route planner to use new GraphQL backend
Diffstat (limited to 'src/Costasdev.Busurbano.Sources.OpenTripPlannerGql')
-rw-r--r--src/Costasdev.Busurbano.Sources.OpenTripPlannerGql/Queries/ArrivalsAtStop.cs18
-rw-r--r--src/Costasdev.Busurbano.Sources.OpenTripPlannerGql/Queries/PlanConnectionContent.cs238
2 files changed, 256 insertions, 0 deletions
diff --git a/src/Costasdev.Busurbano.Sources.OpenTripPlannerGql/Queries/ArrivalsAtStop.cs b/src/Costasdev.Busurbano.Sources.OpenTripPlannerGql/Queries/ArrivalsAtStop.cs
index bbf2c08..bce35a2 100644
--- a/src/Costasdev.Busurbano.Sources.OpenTripPlannerGql/Queries/ArrivalsAtStop.cs
+++ b/src/Costasdev.Busurbano.Sources.OpenTripPlannerGql/Queries/ArrivalsAtStop.cs
@@ -46,6 +46,11 @@ public class ArrivalsAtStopContent : IGraphRequest<ArrivalsAtStopContent.Args>
departureStoptime {{
scheduledDeparture
}}
+ arrivalStoptime {{
+ stop {{
+ gtfsId
+ }}
+ }}
{geometryField}
stoptimes {{
stop {{
@@ -110,6 +115,9 @@ public class ArrivalsAtStopResponse : AbstractGraphResponse
[JsonPropertyName("departureStoptime")]
public required DepartureStoptime DepartureStoptime { get; set; }
+ [JsonPropertyName("arrivalStoptime")]
+ public required ArrivalStoptime ArrivalStoptime { get; set; }
+
[JsonPropertyName("route")] public required RouteDetails Route { get; set; }
[JsonPropertyName("tripGeometry")] public GeometryDetails? Geometry { get; set; }
@@ -141,6 +149,16 @@ public class ArrivalsAtStopResponse : AbstractGraphResponse
public int ScheduledDeparture { get; set; }
}
+ public class ArrivalStoptime
+ {
+ [JsonPropertyName("stop")] public ArrivalStoptimeStop Stop { get; set; }
+ }
+
+ public class ArrivalStoptimeStop
+ {
+ [JsonPropertyName("gtfsId")] public required string GtfsId { get; set; }
+ }
+
public class RouteDetails
{
[JsonPropertyName("gtfsId")] public required string GtfsId { get; set; }
diff --git a/src/Costasdev.Busurbano.Sources.OpenTripPlannerGql/Queries/PlanConnectionContent.cs b/src/Costasdev.Busurbano.Sources.OpenTripPlannerGql/Queries/PlanConnectionContent.cs
new file mode 100644
index 0000000..a4bf8d1
--- /dev/null
+++ b/src/Costasdev.Busurbano.Sources.OpenTripPlannerGql/Queries/PlanConnectionContent.cs
@@ -0,0 +1,238 @@
+using System.Globalization;
+using System.Text.Json.Serialization;
+
+namespace Costasdev.Busurbano.Sources.OpenTripPlannerGql.Queries;
+
+#pragma warning disable CS8618
+
+public class PlanConnectionContent : IGraphRequest<PlanConnectionContent.Args>
+{
+ public record Args(
+ double StartLatitude,
+ double StartLongitude,
+ double EndLatitude,
+ double EndLongitude,
+ DateTimeOffset ReferenceTime,
+ bool ReferenceIsArrival = false
+ );
+
+ public static string Query(Args args)
+ {
+ var madridTz = TimeZoneInfo.FindSystemTimeZoneById("Europe/Madrid");
+
+ // Treat incoming DateTime as Madrid local wall-clock time
+ var localMadridTime =
+ DateTime.SpecifyKind(args.ReferenceTime.UtcDateTime, DateTimeKind.Unspecified);
+
+ var offset = madridTz.GetUtcOffset(localMadridTime);
+ var actualTimeOfQuery = new DateTimeOffset(localMadridTime, offset);
+
+ var dateTimeParameter = args.ReferenceIsArrival ? $"latestArrival:\"{actualTimeOfQuery:O}\"" : $"earliestDeparture:\"{actualTimeOfQuery:O}\"";
+
+ return string.Create(CultureInfo.InvariantCulture,
+ $$"""
+ query Query {
+ planConnection(
+ first: 4
+ origin: {
+ location:{
+ coordinate:{
+ latitude:{{args.StartLatitude}}
+ longitude:{{args.StartLongitude}}
+ }
+ }
+ }
+ destination:{
+ location:{
+ coordinate:{
+ latitude:{{args.EndLatitude}}
+ longitude:{{args.EndLongitude}}
+ }
+ }
+ }
+ dateTime:{
+ {{dateTimeParameter}}
+ }
+ ) {
+ edges {
+ node {
+ duration
+ start
+ end
+ walkTime
+ walkDistance
+ waitingTime
+ legs {
+ start {
+ scheduledTime
+ }
+ end {
+ scheduledTime
+ }
+ mode
+ route {
+ shortName
+ longName
+ agency {
+ name
+ }
+ color
+ textColor
+ }
+ from {
+ name
+ lat
+ lon
+ stop {
+ gtfsId
+ code
+ name
+ lat
+ lon
+ }
+ }
+ to {
+ name
+ lat
+ lon
+ stop {
+ gtfsId
+ code
+ name
+ lat
+ lon
+ }
+ }
+ stopCalls {
+ stopLocation {
+ ... on Stop {
+ gtfsId
+ code
+ name
+ lat
+ lon
+ }
+ }
+ }
+ legGeometry {
+ points
+ }
+ steps {
+ distance
+ relativeDirection
+ streetName
+ absoluteDirection
+ lat
+ lon
+ }
+ headsign
+ distance
+ }
+ }
+ }
+ }
+ }
+ """);
+ }
+}
+
+public class PlanConnectionResponse : AbstractGraphResponse
+{
+ public PlanConnectionItem PlanConnection { get; set; }
+
+ public class PlanConnectionItem
+ {
+ [JsonPropertyName("edges")]
+ public Edge[] Edges { get; set; }
+ }
+
+ public class Edge
+ {
+ [JsonPropertyName("node")]
+ public Node Node { get; set; }
+ }
+
+ public class Node
+ {
+ [JsonPropertyName("duration")] public int DurationSeconds { get; set; }
+ [JsonPropertyName("start")] public string Start8601 { get; set; }
+ [JsonPropertyName("end")] public string End8601 { get; set; }
+ [JsonPropertyName("walkTime")] public int WalkSeconds { get; set; }
+ [JsonPropertyName("walkDistance")] public double WalkDistance { get; set; }
+ [JsonPropertyName("waitingTime")] public int WaitingSeconds { get; set; }
+ [JsonPropertyName("legs")] public Leg[] Legs { get; set; }
+ }
+
+ public class Leg
+ {
+ [JsonPropertyName("start")] public ScheduledTimeContainer Start { get; set; }
+ [JsonPropertyName("end")] public ScheduledTimeContainer End { get; set; }
+ [JsonPropertyName("mode")] public string Mode { get; set; } // TODO: Make enum, maybe
+ [JsonPropertyName("route")] public TransitRoute? Route { get; set; }
+ [JsonPropertyName("from")] public LegPosition From { get; set; }
+ [JsonPropertyName("to")] public LegPosition To { get; set; }
+ [JsonPropertyName("stopCalls")] public StopCall[] StopCalls { get; set; }
+ [JsonPropertyName("legGeometry")] public LegGeometry LegGeometry { get; set; }
+ [JsonPropertyName("steps")] public Step[] Steps { get; set; }
+ [JsonPropertyName("headsign")] public string? Headsign { get; set; }
+ [JsonPropertyName("distance")] public double Distance { get; set; }
+ }
+
+ public class TransitRoute
+ {
+ [JsonPropertyName("shortName")] public string ShortName { get; set; }
+ [JsonPropertyName("longName")] public string LongName { get; set; }
+ [JsonPropertyName("agency")] public AgencyNameContainer Agency { get; set; }
+ [JsonPropertyName("color")] public string Color { get; set; }
+ [JsonPropertyName("textColor")] public string TextColor { get; set; }
+ }
+
+ public class LegPosition
+ {
+ [JsonPropertyName("name")] public string Name { get; set; }
+ [JsonPropertyName("lat")] public double Latitude { get; set; }
+ [JsonPropertyName("lon")] public double Longitude { get; set; }
+ [JsonPropertyName("stop")] public StopLocation Stop { get; set; }
+ }
+
+ public class ScheduledTimeContainer
+ {
+ [JsonPropertyName("scheduledTime")]
+ public string ScheduledTime8601 { get; set; }
+ }
+
+ public class AgencyNameContainer
+ {
+ [JsonPropertyName("name")] public string Name { get; set; }
+ }
+
+ public class StopCall
+ {
+ [JsonPropertyName("stopLocation")]
+ public StopLocation StopLocation { get; set; }
+ }
+
+ public class StopLocation
+ {
+ [JsonPropertyName("gtfsId")] public string GtfsId { get; set; }
+ [JsonPropertyName("code")] public string Code { get; set; }
+ [JsonPropertyName("name")] public string Name { get; set; }
+ [JsonPropertyName("lat")] public double Latitude { get; set; }
+ [JsonPropertyName("lon")] public double Longitude { get; set; }
+ }
+
+ public class Step
+ {
+ [JsonPropertyName("distance")] public double Distance { get; set; }
+ [JsonPropertyName("relativeDirection")] public string RelativeDirection { get; set; }
+ [JsonPropertyName("streetName")] public string StreetName { get; set; } // TODO: "sidewalk", "path" or actual street name
+ [JsonPropertyName("absoluteDirection")] public string AbsoluteDirection { get; set; }
+ [JsonPropertyName("lat")] public double Latitude { get; set; }
+ [JsonPropertyName("lon")] public double Longitude { get; set; }
+ }
+
+ public class LegGeometry
+ {
+ [JsonPropertyName("points")] public string? Points { get; set; }
+ }
+}