-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refetch transit leg with node query of GTFS GraphQL API #6045
base: dev-2.x
Are you sure you want to change the base?
Refetch transit leg with node query of GTFS GraphQL API #6045
Conversation
@binh-dam-ibigroup This might be interesting for you. @vesameskanen I almost cannot believe that it is so easy! |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev-2.x #6045 +/- ##
=============================================
+ Coverage 69.74% 69.79% +0.04%
- Complexity 17316 17364 +48
=============================================
Files 1960 1962 +2
Lines 74267 74380 +113
Branches 7603 7627 +24
=============================================
+ Hits 51796 51910 +114
+ Misses 19829 19827 -2
- Partials 2642 2643 +1 ☔ View full report in Codecov by Sentry. |
@@ -445,6 +447,15 @@ public DataFetcher<Object> node() { | |||
// TODO: Add geometry | |||
return new NearbyStop(stop, Integer.parseInt(parts[0]), null, null); | |||
} | |||
case "Leg": | |||
if (id.equals("null") || id.isBlank()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really want to treat the string "null" specially? In what case can this happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that Leg base class retuns null in getLegReference() method, and that value gets encoded into relay id. Decoding the relay id produces a string value 'null'.
I added the check to prevent unhandled exception when somebody tries to refetch non-transit legs. Maybe there is a more elegant way to handle such situations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now the response for non-transit legs is
"data": { "node": null }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about checking if the reference returns null
in LegImpl
and never return the string "null" but the null
value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a better solution. We should make the id field nullable in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried making id of Node type nullable and everything seems to work fine.
Another option would be to encode null as an empty string in LegReferenceSerializer, in which case id.isBlank() test would work. This might also fix problems in transmodel api.
@@ -611,7 +611,7 @@ type Itinerary { | |||
walkTime: Long | |||
} | |||
|
|||
type Leg { | |||
type Leg implements Node { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure this is backwards-compatible but lets discuss in the dev meeting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm almost 100% sure it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to do some research on this, but could not find anything. So, lets change it and see what happens - maybe wait with merging this PR after the next release?
This is easy because this was already done in the transmodel API. However, the transmodel API has own legs query for this because it lacks the node query/interface. |
@vesameskanen will still add some integration tests for this. |
GTFS integration tests currently cannot test leg refetching, because mocked itineraries lack essential data used in encoding the leg information. Integration test now tests only that legs contain the id. |
public DataFetcher<Relay.ResolvedGlobalId> id() { | ||
return environment -> { | ||
var ref = getSource(environment).getLegReference(); | ||
var id = (ref == null) ? "" : LegReferenceSerializer.encode(ref); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yesterday in the developer meeting we thought it might make sense to use some special string like "NotAvailable" instead of "null" or empty string.
@@ -669,6 +669,8 @@ type Leg { | |||
For non-transit legs, null. | |||
""" | |||
headsign: String | |||
"An identifier for the leg, which can be used to re-fetch transit leg information." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should also mention that an invalid reference id is returned for other legs. Also, mention that the id might not be usable forever since the data and ids within data can change over time.
Also, move all encoding/decoding logig to LegReferenceSerializer class.
@@ -26,7 +28,7 @@ private LegReferenceSerializer() {} | |||
@Nullable | |||
public static String encode(LegReference legReference) { | |||
if (legReference == null) { | |||
return null; | |||
return notAvailable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since u change this, do you also need to update the transmodel API handling of missing value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Transmodel API works as expected. null is encoded as 'NotAvailable' and 'NotAvailable' is decoded as null.
The only change I can think of is maybe removing isBlank() check from TransmodelGraphQLSchema.java.
I tested new legs with relay and got lots of problems. Relay does not accept nodes with same node id but different content. Either all leg types must be serialized to unique id ('NotAvailable' is not OK), or we have to revert node interface for legs and add a dedicated leg query. Any opinions? |
Maybe I don't get it but don't all legs have the same type in GraphQL? |
@vesameskanen explained to me that the issue is that the non-transit legs all have the same id. We discussed this today and thought maybe the solution would be to generate unique ids based on actual leg data (such as departure/arrival time) even if we don't support refetching based on those ids. I tried adding tests for refetching the legs through the node query in the graphql integration tests on Tuesday but creating/maintaining such test would be slightly difficult. |
String.join( | ||
"", | ||
leg.start().time().toString(), | ||
leg.end().time().toString(), | ||
leg.getFrom().toStringShort(), | ||
leg.getTo().toStringShort() | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlike the transit leg references, this is now not "double base64 encoded" (for transit the original reference is already base64 encoded and then encoded again with the leg:
prefix). I wonder if we should encode this as well or not.
I like that this is only on the GTFS API so it doesn't potentially break transmodel clients who might rely on the fact that non-null ids are refetchable-
@@ -244,6 +245,10 @@ default boolean getRealTime() { | |||
return false; | |||
} | |||
|
|||
default RealTimeState getRealTimeState() { | |||
return RealTimeState.SCHEDULED; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if it's better to return SCHEDULED or null? SCHEDULED for street legs feels a bit wrong, on the other hand that's how it worked in otp1 seemingly.
@@ -427,6 +433,7 @@ public String toString() { | |||
.addEnum("alightRule", getAlightRule()) | |||
.addObj("transferFromPrevLeg", transferFromPrevLeg) | |||
.addObj("transferToNextLeg", transferToNextLeg) | |||
.addEnum("realtimeState", getRealTimeState()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if we should add this to the toString as this is not Leg's own field.
We discussed this pr again in the dev meeting today and came to the conclusion that it's better to create own |
Summary
GTFS leg object now includes a graphql node id . Transit leg can be refetched using the Node query:
query legQuery { node(id: "foo") { ... on Leg { mode start { estimated { time } } } } }
Such query can be used to update an itinerary and to detect if the itinerary is no longer possible because of delays or canceled trips.
Non-transit legs cannot be refetched - the response is always null.
This PR also adds missing implementation for querying leg's realtimeState via GTFS graphql API.
Documentation
In the graphql schema.