Skip to content

Commit

Permalink
Parse schedule relationships for trip descriptors and stop time updates
Browse files Browse the repository at this point in the history
  • Loading branch information
cedarbaum committed Sep 23, 2024
1 parent 65dace7 commit 2c26282
Show file tree
Hide file tree
Showing 7 changed files with 2,990 additions and 542 deletions.
2 changes: 2 additions & 0 deletions hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ func (h *hasher) trip(t *Trip) {
h.number(t.ID.HasStartTime)
h.number(t.ID.StartTime)
h.number(int64(len(t.StopTimeUpdates)))
h.number(t.ID.ScheduleRelationship)
for i := range t.StopTimeUpdates {
stu := &t.StopTimeUpdates[i]
hashNumberPtr(h, stu.StopSequence)
h.stringPtr(stu.StopID)
h.stringPtr(stu.NyctTrack)
h.number(stu.ScheduleRelationship)
for _, event := range []*StopTimeEvent{stu.Arrival, stu.Departure} {
h.number(event == nil)
if event == nil {
Expand Down
2,843 changes: 2,349 additions & 494 deletions proto/gtfs-realtime.pb.go

Large diffs are not rendered by default.

527 changes: 497 additions & 30 deletions proto/gtfs-realtime.proto

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions proto/us-ny-mta-alerts-extension.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions proto/us-ny-mta-trips-extension.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 54 additions & 13 deletions realtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package gtfs
import (
"fmt"
"regexp"
"sort"
"strconv"
"time"

Expand Down Expand Up @@ -38,6 +39,8 @@ func (trip *Trip) GetVehicle() Vehicle {
return Vehicle{}
}

type TripScheduleRelationship = gtfsrt.TripDescriptor_ScheduleRelationship

type TripID struct {
ID string
RouteID string
Expand All @@ -48,15 +51,46 @@ type TripID struct {

HasStartDate bool
StartDate time.Time

ScheduleRelationship TripScheduleRelationship
}

// Define ordering on trip ids for test consistency
func (t1 TripID) Less(t2 TripID) bool {
if t1.ID != t2.ID {
return t1.ID < t2.ID
}
if t1.RouteID != t2.RouteID {
return t1.RouteID < t2.RouteID
}
if t1.DirectionID != t2.DirectionID {
return t1.DirectionID < t2.DirectionID
}
if t1.HasStartTime != t2.HasStartTime {
return !t1.HasStartTime && t2.HasStartTime
}
if t1.HasStartTime && t1.StartTime != t2.StartTime {
return t1.StartTime < t2.StartTime
}
if t1.HasStartDate != t2.HasStartDate {
return !t1.HasStartDate && t2.HasStartDate
}
if t1.HasStartDate && !t1.StartDate.Equal(t2.StartDate) {
return t1.StartDate.Before(t2.StartDate)
}
return t1.ScheduleRelationship < t2.ScheduleRelationship
}

type StopTimeUpdateScheduleRelationship = gtfsrt.TripUpdate_StopTimeUpdate_ScheduleRelationship

// TODO: shouldn't this just be StopTime?
type StopTimeUpdate struct {
StopSequence *uint32
StopID *string
Arrival *StopTimeEvent
Departure *StopTimeEvent
NyctTrack *string
StopSequence *uint32
StopID *string
Arrival *StopTimeEvent
Departure *StopTimeEvent
NyctTrack *string
ScheduleRelationship StopTimeUpdateScheduleRelationship
}

func (stopTimeUpdate *StopTimeUpdate) GetArrival() StopTimeEvent {
Expand Down Expand Up @@ -326,6 +360,11 @@ func ParseRealtime(content []byte, opts *ParseRealtimeOptions) (*Realtime, error
}
result.Trips = append(result.Trips, *trip)
}

sort.Slice(result.Trips, func(i, j int) bool {
return result.Trips[i].ID.Less(result.Trips[j].ID)
})

for vehicleID, vehicle := range vehiclesByID {
if tripID, ok := vehicleIDToTripID[vehicleID]; ok {
vehicle.Trip = tripsById[tripID]
Expand Down Expand Up @@ -363,11 +402,12 @@ func parseTripUpdate(tripUpdate *gtfsrt.TripUpdate, opts *ParseRealtimeOptions)
}
for _, stopTimeUpdate := range tripUpdate.StopTimeUpdate {
trip.StopTimeUpdates = append(trip.StopTimeUpdates, StopTimeUpdate{
StopSequence: stopTimeUpdate.StopSequence,
StopID: stopTimeUpdate.StopId,
Arrival: convertStopTimeEvent(stopTimeUpdate.Arrival),
Departure: convertStopTimeEvent(stopTimeUpdate.Departure),
NyctTrack: opts.Extension.GetTrack(stopTimeUpdate),
StopSequence: stopTimeUpdate.StopSequence,
StopID: stopTimeUpdate.StopId,
Arrival: convertStopTimeEvent(stopTimeUpdate.Arrival),
Departure: convertStopTimeEvent(stopTimeUpdate.Departure),
NyctTrack: opts.Extension.GetTrack(stopTimeUpdate),
ScheduleRelationship: stopTimeUpdate.GetScheduleRelationship(),
})
}
if tripUpdate.Vehicle == nil {
Expand Down Expand Up @@ -453,9 +493,10 @@ func parseOptionalTripDescriptor(tripDesc *gtfsrt.TripDescriptor, opts *ParseRea

func parseTripDescriptor(tripDesc *gtfsrt.TripDescriptor, opts *ParseRealtimeOptions) TripID {
id := TripID{
ID: tripDesc.GetTripId(),
RouteID: tripDesc.GetRouteId(),
DirectionID: parseDirectionID_GTFSRealtime(tripDesc.DirectionId),
ID: tripDesc.GetTripId(),
RouteID: tripDesc.GetRouteId(),
DirectionID: parseDirectionID_GTFSRealtime(tripDesc.DirectionId),
ScheduleRelationship: tripDesc.GetScheduleRelationship(),
}
id.HasStartTime, id.StartTime = parseStartTime(tripDesc.StartTime)
id.HasStartDate, id.StartDate = parseStartDate(tripDesc.StartDate, opts.timezoneOrUTC())
Expand Down
85 changes: 84 additions & 1 deletion realtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ import (

const (
tripID1 = "tripID1"
tripID2 = "tripID2"
tripID3 = "tripID3"
vehicleID1 = "vehicleID1"
stopID1 = "stopID1"
stopID2 = "stopID2"
stopID3 = "stopID3"
)

var createTime time.Time = time.Unix(2<<28, 0).UTC()
Expand Down Expand Up @@ -41,6 +45,46 @@ func TestRealtime(t *testing.T) {
// TODO: other fields
},
},
{
Id: ptr("2"),
TripUpdate: &gtfsrt.TripUpdate{
Trip: &gtfsrt.TripDescriptor{
TripId: ptr(tripID2),
ScheduleRelationship: ptr(gtfsrt.TripDescriptor_ADDED),
},
StopTimeUpdate: []*gtfsrt.TripUpdate_StopTimeUpdate{
{
StopId: ptr(stopID1),
StopSequence: ptr(uint32(1)),
Arrival: &gtfsrt.TripUpdate_StopTimeEvent{
Time: ptr(int64(time1.Unix())),
},
},
{
StopId: ptr(stopID2),
StopSequence: ptr(uint32(2)),
ScheduleRelationship: ptr(gtfsrt.TripUpdate_StopTimeUpdate_SKIPPED),
Arrival: &gtfsrt.TripUpdate_StopTimeEvent{
Time: ptr(int64(time2.Unix())),
},
},
{
StopId: ptr(stopID3),
StopSequence: ptr(uint32(3)),
ScheduleRelationship: ptr(gtfsrt.TripUpdate_StopTimeUpdate_NO_DATA),
},
},
},
},
{
Id: ptr("3"),
TripUpdate: &gtfsrt.TripUpdate{
Trip: &gtfsrt.TripDescriptor{
TripId: ptr(tripID3),
ScheduleRelationship: ptr(gtfsrt.TripDescriptor_CANCELED),
},
},
},
},
want: func() *gtfs.Realtime {
trip := gtfs.Trip{
Expand All @@ -58,9 +102,48 @@ func TestRealtime(t *testing.T) {
}
trip.Vehicle = &vehicle
vehicle.Trip = &trip

trip2 := gtfs.Trip{
ID: gtfs.TripID{
ID: tripID2,
ScheduleRelationship: gtfsrt.TripDescriptor_ADDED,
},
StopTimeUpdates: []gtfs.StopTimeUpdate{
{
StopID: ptr(stopID1),
StopSequence: ptr(uint32(1)),
Arrival: &gtfs.StopTimeEvent{
Time: &time1,
},
},
{
StopID: ptr(stopID2),
StopSequence: ptr(uint32(2)),
Arrival: &gtfs.StopTimeEvent{
Time: &time2,
},
ScheduleRelationship: gtfsrt.TripUpdate_StopTimeUpdate_SKIPPED,
},
{
StopID: ptr(stopID3),
StopSequence: ptr(uint32(3)),
ScheduleRelationship: gtfsrt.TripUpdate_StopTimeUpdate_NO_DATA,
},
},
IsEntityInMessage: true,
}

trip3 := gtfs.Trip{
ID: gtfs.TripID{
ID: tripID3,
ScheduleRelationship: gtfsrt.TripDescriptor_CANCELED,
},
IsEntityInMessage: true,
}

return &gtfs.Realtime{
CreatedAt: createTime,
Trips: []gtfs.Trip{trip},
Trips: []gtfs.Trip{trip, trip2, trip3},
Vehicles: []gtfs.Vehicle{vehicle},
}
}(),
Expand Down

0 comments on commit 2c26282

Please sign in to comment.