package webapi import ( "fmt" "time" "github.com/jackc/pgtype" "google.golang.org/protobuf/types/known/timestamppb" ) func (toc *TrainOperator) IsEmpty() bool { return toc == nil || toc.Code == "" } func (toc *TrainOperator) Canonicalize() { if toc == nil { return } } func (loc *Location) IsEmpty() bool { return loc == nil || loc.Tiploc == "" } func (loc *Location) Canonicalize() { if loc == nil { return } if loc.Operator.IsEmpty() { loc.Operator = nil } loc.Operator.Canonicalize() } func (dr *DisruptionReason) IsEmpty() bool { return dr == nil || dr.Code == 0 } func (dr *DisruptionReason) Canonicalize() { if dr == nil { return } if dr.Location.IsEmpty() { dr.Location = nil } dr.Location.Canonicalize() } func (sd *ServiceData) Canonicalize() { if sd.DelayReason.IsEmpty() { sd.DelayReason = nil } sd.DelayReason.Canonicalize() if sd.CancelReason.IsEmpty() { sd.CancelReason = nil } sd.CancelReason.Canonicalize() } func (tz *TimeZone) ToLocation() (*time.Location, error) { return time.LoadLocation(tz.GetName()) } func (dt *DateTime) ToTime() (time.Time, error) { tz := dt.GetTimezone() if tz == nil { return time.Time{}, fmt.Errorf("no timezone specified") } loc, err := tz.ToLocation() if err != nil { return time.Time{}, fmt.Errorf("loading timezone (%s / offset %v): %w", tz.GetName(), tz.GetUtcOffset(), err) } return dt.GetTimestamp().AsTime().In(loc), nil } func (dt *DateTime) decodeWith(ci *pgtype.ConnInfo, src []byte, dec func(*pgtype.Timestamptz, *pgtype.ConnInfo, []byte) error) error { dt.Timestamp = nil dt.Timezone = nil if src == nil { return nil } ttz := &pgtype.Timestamptz{} if err := dec(ttz, ci, src); err != nil { return err } if ttz.Status != pgtype.Present { return nil } *dt = *(FromTime(ttz.Time)) return nil } func (dt *DateTime) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error { return dt.decodeWith(ci, src, (*pgtype.Timestamptz).DecodeBinary) } func (dt *DateTime) DecodeText(ci *pgtype.ConnInfo, src []byte) error { return dt.decodeWith(ci, src, (*pgtype.Timestamptz).DecodeText) } func (dt *DateTime) AssignTo(dst interface{}) error { if dt == nil { return pgtype.NullAssignTo(dst) } switch dst := dst.(type) { case (*DateTime): *dst = *dt return nil default: if nextDst, retry := pgtype.GetAssignToDstType(dst); retry { return dt.AssignTo(nextDst) } return fmt.Errorf("unable to assign to %T, sad trombone", dst) } return fmt.Errorf("cannot decode %#v into %T, sad trombone", dt, dst) } func FromTime(t time.Time) *DateTime { zName, zOffset := t.Zone() tz := &TimeZone{ Name: zName, UtcOffset: int32(zOffset), } return &DateTime{ Timestamp: timestamppb.New(t), Timezone: tz, } } func (dt *DateTime) IsZero() bool { if dt.GetTimestamp() == nil { return true } t, err := dt.ToTime() if err != nil { return true } return t.IsZero() } func (td *TimingData) IsEmpty() bool { if td == nil { return true } return td.PublicScheduled.IsZero() && td.WorkingScheduled.IsZero() && td.PublicEstimated.IsZero() && td.WorkingEstimated.IsZero() && td.Actual.IsZero() } func (td *TimingData) Canonicalize() { if td == nil { return } ts := []**DateTime{&td.PublicScheduled, &td.WorkingScheduled, &td.PublicEstimated, &td.WorkingEstimated, &td.Actual} for _, t := range ts { if *t == nil || (*t).IsZero() { *t = nil } } } func (pd *PlatformData) IsEmpty() bool { return pd.Scheduled == "" && pd.Live == "" } func (pd *PlatformData) Canonicalize() {} func (sl *ServiceLocation) Canonicalize() { if sl == nil { return } sl.Location.Canonicalize() if sl.Platform.IsEmpty() { sl.Platform = nil } sl.Platform.Canonicalize() if sl.FalseDestination.IsEmpty() { sl.FalseDestination = nil } sl.FalseDestination.Canonicalize() if sl.ArrivalTiming.IsEmpty() { sl.ArrivalTiming = nil } sl.ArrivalTiming.Canonicalize() if sl.DepartureTiming.IsEmpty() { sl.DepartureTiming = nil } sl.DepartureTiming.Canonicalize() if sl.PassTiming.IsEmpty() { sl.PassTiming = nil } sl.PassTiming.Canonicalize() }