go/trains: split summarizeService into its own package
It might come in handy when sending push notifications to devices...
This commit is contained in:
parent
4f3356727a
commit
7af28f3ef5
5 changed files with 140 additions and 114 deletions
|
@ -16,118 +16,13 @@ import (
|
||||||
"github.com/jackc/pgx/v4/pgxpool"
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
"hg.lukegb.com/lukegb/depot/go/trains/webapi"
|
"hg.lukegb.com/lukegb/depot/go/trains/webapi/summarize"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
allowStress = flag.Bool("allow_stress", false, "Allow checking the validity of every record in the database")
|
allowStress = flag.Bool("allow_stress", false, "Allow checking the validity of every record in the database")
|
||||||
)
|
)
|
||||||
|
|
||||||
type querier interface {
|
|
||||||
Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error)
|
|
||||||
QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row
|
|
||||||
}
|
|
||||||
|
|
||||||
func summarizeService(ctx context.Context, pc querier, id int) (*webapi.ServiceData, error) {
|
|
||||||
row := pc.QueryRow(ctx, `
|
|
||||||
SELECT
|
|
||||||
ts.id, ts.rid, ts.uid, ts.rsid, ts.headcode, ts.scheduled_start_date::varchar,
|
|
||||||
ts.train_operator, COALESCE(rop.name, ''), COALESCE(rop.url, ''),
|
|
||||||
COALESCE(ts.delay_reason_code::int, 0), COALESCE(rlr.text, ''), COALESCE(ts.delay_reason_tiploc, ''), COALESCE(rlrloc.name, ''), COALESCE(rlrloc.crs, ''), COALESCE(rlrloc.toc, ''), COALESCE(rlrop.name, ''), COALESCE(rlrop.url, ''), COALESCE(ts.delay_reason_tiploc_near, false),
|
|
||||||
COALESCE(ts.cancellation_reason_code::int, 0), COALESCE(rlr.text, ''), COALESCE(ts.cancellation_reason_tiploc, ''), COALESCE(rlrloc.name, ''), COALESCE(rlrloc.crs, ''), COALESCE(rlrloc.toc, ''), COALESCE(rlrop.name, ''), COALESCE(rlrop.url, ''), COALESCE(ts.cancellation_reason_tiploc_near, false),
|
|
||||||
ts.active, ts.deleted, ts.cancelled
|
|
||||||
FROM
|
|
||||||
train_services ts
|
|
||||||
LEFT JOIN ref_tocs rop ON rop.toc=ts.train_operator
|
|
||||||
|
|
||||||
LEFT JOIN ref_late_running_reasons rlr ON rlr.code=ts.delay_reason_code::int
|
|
||||||
LEFT JOIN ref_locations rlrloc ON rlrloc.tiploc=ts.delay_reason_tiploc
|
|
||||||
LEFT JOIN ref_tocs rlrop ON rlrop.toc=rlrloc.toc
|
|
||||||
|
|
||||||
LEFT JOIN ref_cancel_reasons rc ON rc.code=ts.cancellation_reason_code::int
|
|
||||||
LEFT JOIN ref_locations rcloc ON rcloc.tiploc=ts.cancellation_reason_tiploc
|
|
||||||
LEFT JOIN ref_tocs rcop ON rcop.toc=rcloc.toc
|
|
||||||
WHERE
|
|
||||||
ts.id=$1
|
|
||||||
`, id)
|
|
||||||
|
|
||||||
sd := webapi.ServiceData{
|
|
||||||
DelayReason: &webapi.DisruptionReason{Location: &webapi.Location{Operator: &webapi.TrainOperator{}}},
|
|
||||||
CancelReason: &webapi.DisruptionReason{Location: &webapi.Location{Operator: &webapi.TrainOperator{}}},
|
|
||||||
Operator: &webapi.TrainOperator{},
|
|
||||||
}
|
|
||||||
if err := row.Scan(
|
|
||||||
&sd.Id, &sd.Rid, &sd.Uid, &sd.Rsid, &sd.Headcode, &sd.ScheduledStartDate,
|
|
||||||
&sd.Operator.Code, &sd.Operator.Name, &sd.Operator.Url,
|
|
||||||
&sd.DelayReason.Code, &sd.DelayReason.Text, &sd.DelayReason.Location.Tiploc, &sd.DelayReason.Location.Name, &sd.DelayReason.Location.Crs, &sd.DelayReason.Location.Operator.Code, &sd.DelayReason.Location.Operator.Name, &sd.DelayReason.Location.Operator.Url, &sd.DelayReason.NearLocation,
|
|
||||||
&sd.CancelReason.Code, &sd.CancelReason.Text, &sd.CancelReason.Location.Tiploc, &sd.CancelReason.Location.Name, &sd.CancelReason.Location.Crs, &sd.CancelReason.Location.Operator.Code, &sd.CancelReason.Location.Operator.Name, &sd.CancelReason.Location.Operator.Url, &sd.CancelReason.NearLocation,
|
|
||||||
&sd.IsActive, &sd.IsDeleted, &sd.IsCancelled,
|
|
||||||
); err != nil {
|
|
||||||
return nil, fmt.Errorf("reading from train_services for %d: %w", id, err)
|
|
||||||
}
|
|
||||||
sd.Canonicalize()
|
|
||||||
|
|
||||||
// Now for the locations.
|
|
||||||
rows, err := pc.Query(ctx, `
|
|
||||||
SELECT
|
|
||||||
tl.id,
|
|
||||||
tl.tiploc, COALESCE(rloc.name, ''), COALESCE(rloc.crs, ''), COALESCE(rloc.toc, ''), COALESCE(rloctoc.name, ''), COALESCE(rloctoc.url, ''),
|
|
||||||
tl.calling_point::varchar, COALESCE(tl.train_length, 0), tl.service_suppressed,
|
|
||||||
tl.schedule_cancelled,
|
|
||||||
COALESCE(tl.schedule_platform, ''), COALESCE(tl.platform, ''), COALESCE(tl.platform_confirmed, false), COALESCE(tl.platform_suppressed, false),
|
|
||||||
tl.schedule_false_destination_tiploc, COALESCE(rfdloc.name, ''), COALESCE(rfdloc.crs, ''), COALESCE(rfdloc.toc, ''), COALESCE(rfdloctoc.name, ''), COALESCE(rfdloctoc.url, ''),
|
|
||||||
|
|
||||||
tl.schedule_public_arrival, tl.schedule_working_arrival, tl.estimated_arrival, tl.working_estimated_arrival, tl.actual_arrival,
|
|
||||||
tl.schedule_public_departure, tl.schedule_working_departure, tl.estimated_departure, tl.working_estimated_departure, tl.actual_departure,
|
|
||||||
/* no public_pass */ tl.schedule_working_pass, tl.estimated_pass, tl.working_estimated_pass, tl.actual_pass
|
|
||||||
FROM
|
|
||||||
train_locations tl
|
|
||||||
LEFT JOIN ref_locations rloc ON rloc.tiploc=tl.tiploc
|
|
||||||
LEFT JOIN ref_tocs rloctoc ON rloctoc.toc=rloc.toc
|
|
||||||
|
|
||||||
LEFT JOIN ref_locations rfdloc ON rfdloc.tiploc=tl.schedule_false_destination_tiploc
|
|
||||||
LEFT JOIN ref_tocs rfdloctoc ON rfdloctoc.toc=rfdloc.toc
|
|
||||||
WHERE
|
|
||||||
tl.tsid=$1 AND tl.active_in_schedule
|
|
||||||
ORDER BY
|
|
||||||
COALESCE(tl.schedule_working_arrival, tl.schedule_working_pass, tl.schedule_working_departure)
|
|
||||||
`, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("querying locations for %d: %w", id, err)
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
for rows.Next() {
|
|
||||||
loc := webapi.ServiceLocation{
|
|
||||||
Location: &webapi.Location{Operator: &webapi.TrainOperator{}},
|
|
||||||
Platform: &webapi.PlatformData{},
|
|
||||||
FalseDestination: &webapi.Location{Operator: &webapi.TrainOperator{}},
|
|
||||||
ArrivalTiming: &webapi.TimingData{PublicScheduled: &webapi.DateTime{}, WorkingScheduled: &webapi.DateTime{}, PublicEstimated: &webapi.DateTime{}, WorkingEstimated: &webapi.DateTime{}, Actual: &webapi.DateTime{}},
|
|
||||||
DepartureTiming: &webapi.TimingData{PublicScheduled: &webapi.DateTime{}, WorkingScheduled: &webapi.DateTime{}, PublicEstimated: &webapi.DateTime{}, WorkingEstimated: &webapi.DateTime{}, Actual: &webapi.DateTime{}},
|
|
||||||
PassTiming: &webapi.TimingData{PublicScheduled: &webapi.DateTime{}, WorkingScheduled: &webapi.DateTime{}, PublicEstimated: &webapi.DateTime{}, WorkingEstimated: &webapi.DateTime{}, Actual: &webapi.DateTime{}},
|
|
||||||
}
|
|
||||||
if err := rows.Scan(
|
|
||||||
&loc.Id,
|
|
||||||
&loc.Location.Tiploc, &loc.Location.Name, &loc.Location.Crs, &loc.Location.Operator.Code, &loc.Location.Operator.Name, &loc.Location.Operator.Url,
|
|
||||||
&loc.CallingPointType, &loc.TrainLength, &loc.ServiceSuppressed,
|
|
||||||
&loc.Cancelled,
|
|
||||||
&loc.Platform.Scheduled, &loc.Platform.Live, &loc.Platform.Confirmed, &loc.Platform.Suppressed,
|
|
||||||
&loc.FalseDestination.Tiploc, &loc.FalseDestination.Name, &loc.FalseDestination.Crs, &loc.FalseDestination.Operator.Code, &loc.FalseDestination.Operator.Name, &loc.FalseDestination.Operator.Url,
|
|
||||||
loc.ArrivalTiming.PublicScheduled, loc.ArrivalTiming.WorkingScheduled, loc.ArrivalTiming.PublicEstimated, loc.ArrivalTiming.WorkingEstimated, loc.ArrivalTiming.Actual,
|
|
||||||
loc.DepartureTiming.PublicScheduled, loc.DepartureTiming.WorkingScheduled, loc.DepartureTiming.PublicEstimated, loc.DepartureTiming.WorkingEstimated, loc.DepartureTiming.Actual,
|
|
||||||
/*loc.PassTiming.PublicScheduled,*/ loc.PassTiming.WorkingScheduled, loc.PassTiming.PublicEstimated, loc.PassTiming.WorkingEstimated, loc.PassTiming.Actual,
|
|
||||||
); err != nil {
|
|
||||||
return nil, fmt.Errorf("scanning locations for %d: %w", id, err)
|
|
||||||
}
|
|
||||||
loc.Canonicalize()
|
|
||||||
sd.Locations = append(sd.Locations, &loc)
|
|
||||||
}
|
|
||||||
if rows.Err() != nil {
|
|
||||||
return nil, fmt.Errorf("iterating over locations for %d: %w", id, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &sd, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type watchingResponseWriter struct {
|
type watchingResponseWriter struct {
|
||||||
http.ResponseWriter
|
http.ResponseWriter
|
||||||
http.Flusher
|
http.Flusher
|
||||||
|
@ -205,9 +100,9 @@ func (s *server) stress(ctx context.Context, rw http.ResponseWriter, r *http.Req
|
||||||
if tsid == 0 {
|
if tsid == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
svc, err := summarizeService(ctx, conn, tsid)
|
svc, err := summarize.Service(ctx, conn, tsid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("summarizeService %v: %w", tsid, err)
|
return fmt.Errorf("summarize.Service %v: %w", tsid, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := protojson.Marshal(svc); err != nil {
|
if _, err := protojson.Marshal(svc); err != nil {
|
||||||
|
@ -276,7 +171,7 @@ func (s *server) handleJSON(ctx context.Context, rw http.ResponseWriter, r *http
|
||||||
}
|
}
|
||||||
defer conn.Release()
|
defer conn.Release()
|
||||||
|
|
||||||
svc, err := summarizeService(ctx, conn, id)
|
svc, err := summarize.Service(ctx, conn, id)
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
return httpError{
|
return httpError{
|
||||||
err: err,
|
err: err,
|
||||||
|
@ -355,14 +250,14 @@ func (s *server) handleEventStream(ctx context.Context, rw http.ResponseWriter,
|
||||||
rw.Header().Set("Content-Type", "text/event-stream")
|
rw.Header().Set("Content-Type", "text/event-stream")
|
||||||
rw.Header().Set("Cache-Control", "no-cache")
|
rw.Header().Set("Cache-Control", "no-cache")
|
||||||
|
|
||||||
encodeSvc := func(conn querier, id int) error {
|
encodeSvc := func(conn summarize.Querier, id int) error {
|
||||||
svc, err := summarizeService(ctx, conn, id)
|
svc, err := summarize.Service(ctx, conn, id)
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
if _, err := fmt.Fprintf(rw, "event: notyet\ndata: %d\n\n", id); err != nil {
|
if _, err := fmt.Fprintf(rw, "event: notyet\ndata: %d\n\n", id); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return fmt.Errorf("summarizeService(%d): %w", id, err)
|
return fmt.Errorf("summarize.Service(%d): %w", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := fmt.Fprint(rw, "data: "); err != nil {
|
if _, err := fmt.Fprint(rw, "data: "); err != nil {
|
||||||
|
|
|
@ -13,5 +13,6 @@ depot.third_party.buildGo.program {
|
||||||
gopkgs."google.golang.org".protobuf.encoding.protojson
|
gopkgs."google.golang.org".protobuf.encoding.protojson
|
||||||
gopkgs."golang.org".x.sync.errgroup
|
gopkgs."golang.org".x.sync.errgroup
|
||||||
depot.go.trains.webapi
|
depot.go.trains.webapi
|
||||||
|
depot.go.trains.webapi.summarize
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
{ depot, ... }:
|
{ depot, ... }@args:
|
||||||
(depot.third_party.buildGo.proto {
|
(depot.third_party.buildGo.proto {
|
||||||
name = "webapi";
|
name = "webapi";
|
||||||
path = "hg.lukegb.com/lukegb/depot/go/trains/webapi";
|
path = "hg.lukegb.com/lukegb/depot/go/trains/webapi";
|
||||||
|
@ -14,4 +14,6 @@
|
||||||
];
|
];
|
||||||
}).overrideGo (old: {
|
}).overrideGo (old: {
|
||||||
srcs = old.srcs ++ [ ./utils.go ];
|
srcs = old.srcs ++ [ ./utils.go ];
|
||||||
})
|
}) // {
|
||||||
|
summarize = import ./summarize args;
|
||||||
|
}
|
||||||
|
|
14
go/trains/webapi/summarize/default.nix
Normal file
14
go/trains/webapi/summarize/default.nix
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# SPDX-FileCopyrightText: 2020 Luke Granger-Brown <depot@lukegb.com>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
{ depot, ... }:
|
||||||
|
depot.third_party.buildGo.package {
|
||||||
|
name = "summarize";
|
||||||
|
path = "hg.lukegb.com/lukegb/depot/go/trains/webapi/summarize";
|
||||||
|
srcs = [ ./service.go ];
|
||||||
|
deps = with depot.third_party; [
|
||||||
|
gopkgs."github.com".jackc.pgx.v4
|
||||||
|
depot.go.trains.webapi
|
||||||
|
];
|
||||||
|
}
|
114
go/trains/webapi/summarize/service.go
Normal file
114
go/trains/webapi/summarize/service.go
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package summarize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v4"
|
||||||
|
"hg.lukegb.com/lukegb/depot/go/trains/webapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Querier interface {
|
||||||
|
Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error)
|
||||||
|
QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row
|
||||||
|
}
|
||||||
|
|
||||||
|
func Service(ctx context.Context, pc Querier, id int) (*webapi.ServiceData, error) {
|
||||||
|
row := pc.QueryRow(ctx, `
|
||||||
|
SELECT
|
||||||
|
ts.id, ts.rid, ts.uid, ts.rsid, ts.headcode, ts.scheduled_start_date::varchar,
|
||||||
|
ts.train_operator, COALESCE(rop.name, ''), COALESCE(rop.url, ''),
|
||||||
|
COALESCE(ts.delay_reason_code::int, 0), COALESCE(rlr.text, ''), COALESCE(ts.delay_reason_tiploc, ''), COALESCE(rlrloc.name, ''), COALESCE(rlrloc.crs, ''), COALESCE(rlrloc.toc, ''), COALESCE(rlrop.name, ''), COALESCE(rlrop.url, ''), COALESCE(ts.delay_reason_tiploc_near, false),
|
||||||
|
COALESCE(ts.cancellation_reason_code::int, 0), COALESCE(rlr.text, ''), COALESCE(ts.cancellation_reason_tiploc, ''), COALESCE(rlrloc.name, ''), COALESCE(rlrloc.crs, ''), COALESCE(rlrloc.toc, ''), COALESCE(rlrop.name, ''), COALESCE(rlrop.url, ''), COALESCE(ts.cancellation_reason_tiploc_near, false),
|
||||||
|
ts.active, ts.deleted, ts.cancelled
|
||||||
|
FROM
|
||||||
|
train_services ts
|
||||||
|
LEFT JOIN ref_tocs rop ON rop.toc=ts.train_operator
|
||||||
|
|
||||||
|
LEFT JOIN ref_late_running_reasons rlr ON rlr.code=ts.delay_reason_code::int
|
||||||
|
LEFT JOIN ref_locations rlrloc ON rlrloc.tiploc=ts.delay_reason_tiploc
|
||||||
|
LEFT JOIN ref_tocs rlrop ON rlrop.toc=rlrloc.toc
|
||||||
|
|
||||||
|
LEFT JOIN ref_cancel_reasons rc ON rc.code=ts.cancellation_reason_code::int
|
||||||
|
LEFT JOIN ref_locations rcloc ON rcloc.tiploc=ts.cancellation_reason_tiploc
|
||||||
|
LEFT JOIN ref_tocs rcop ON rcop.toc=rcloc.toc
|
||||||
|
WHERE
|
||||||
|
ts.id=$1
|
||||||
|
`, id)
|
||||||
|
|
||||||
|
sd := webapi.ServiceData{
|
||||||
|
DelayReason: &webapi.DisruptionReason{Location: &webapi.Location{Operator: &webapi.TrainOperator{}}},
|
||||||
|
CancelReason: &webapi.DisruptionReason{Location: &webapi.Location{Operator: &webapi.TrainOperator{}}},
|
||||||
|
Operator: &webapi.TrainOperator{},
|
||||||
|
}
|
||||||
|
if err := row.Scan(
|
||||||
|
&sd.Id, &sd.Rid, &sd.Uid, &sd.Rsid, &sd.Headcode, &sd.ScheduledStartDate,
|
||||||
|
&sd.Operator.Code, &sd.Operator.Name, &sd.Operator.Url,
|
||||||
|
&sd.DelayReason.Code, &sd.DelayReason.Text, &sd.DelayReason.Location.Tiploc, &sd.DelayReason.Location.Name, &sd.DelayReason.Location.Crs, &sd.DelayReason.Location.Operator.Code, &sd.DelayReason.Location.Operator.Name, &sd.DelayReason.Location.Operator.Url, &sd.DelayReason.NearLocation,
|
||||||
|
&sd.CancelReason.Code, &sd.CancelReason.Text, &sd.CancelReason.Location.Tiploc, &sd.CancelReason.Location.Name, &sd.CancelReason.Location.Crs, &sd.CancelReason.Location.Operator.Code, &sd.CancelReason.Location.Operator.Name, &sd.CancelReason.Location.Operator.Url, &sd.CancelReason.NearLocation,
|
||||||
|
&sd.IsActive, &sd.IsDeleted, &sd.IsCancelled,
|
||||||
|
); err != nil {
|
||||||
|
return nil, fmt.Errorf("reading from train_services for %d: %w", id, err)
|
||||||
|
}
|
||||||
|
sd.Canonicalize()
|
||||||
|
|
||||||
|
// Now for the locations.
|
||||||
|
rows, err := pc.Query(ctx, `
|
||||||
|
SELECT
|
||||||
|
tl.id,
|
||||||
|
tl.tiploc, COALESCE(rloc.name, ''), COALESCE(rloc.crs, ''), COALESCE(rloc.toc, ''), COALESCE(rloctoc.name, ''), COALESCE(rloctoc.url, ''),
|
||||||
|
tl.calling_point::varchar, COALESCE(tl.train_length, 0), tl.service_suppressed,
|
||||||
|
tl.schedule_cancelled,
|
||||||
|
COALESCE(tl.schedule_platform, ''), COALESCE(tl.platform, ''), COALESCE(tl.platform_confirmed, false), COALESCE(tl.platform_suppressed, false),
|
||||||
|
tl.schedule_false_destination_tiploc, COALESCE(rfdloc.name, ''), COALESCE(rfdloc.crs, ''), COALESCE(rfdloc.toc, ''), COALESCE(rfdloctoc.name, ''), COALESCE(rfdloctoc.url, ''),
|
||||||
|
|
||||||
|
tl.schedule_public_arrival, tl.schedule_working_arrival, tl.estimated_arrival, tl.working_estimated_arrival, tl.actual_arrival,
|
||||||
|
tl.schedule_public_departure, tl.schedule_working_departure, tl.estimated_departure, tl.working_estimated_departure, tl.actual_departure,
|
||||||
|
/* no public_pass */ tl.schedule_working_pass, tl.estimated_pass, tl.working_estimated_pass, tl.actual_pass
|
||||||
|
FROM
|
||||||
|
train_locations tl
|
||||||
|
LEFT JOIN ref_locations rloc ON rloc.tiploc=tl.tiploc
|
||||||
|
LEFT JOIN ref_tocs rloctoc ON rloctoc.toc=rloc.toc
|
||||||
|
|
||||||
|
LEFT JOIN ref_locations rfdloc ON rfdloc.tiploc=tl.schedule_false_destination_tiploc
|
||||||
|
LEFT JOIN ref_tocs rfdloctoc ON rfdloctoc.toc=rfdloc.toc
|
||||||
|
WHERE
|
||||||
|
tl.tsid=$1 AND tl.active_in_schedule
|
||||||
|
ORDER BY
|
||||||
|
COALESCE(tl.schedule_working_arrival, tl.schedule_working_pass, tl.schedule_working_departure)
|
||||||
|
`, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("querying locations for %d: %w", id, err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
loc := webapi.ServiceLocation{
|
||||||
|
Location: &webapi.Location{Operator: &webapi.TrainOperator{}},
|
||||||
|
Platform: &webapi.PlatformData{},
|
||||||
|
FalseDestination: &webapi.Location{Operator: &webapi.TrainOperator{}},
|
||||||
|
ArrivalTiming: &webapi.TimingData{PublicScheduled: &webapi.DateTime{}, WorkingScheduled: &webapi.DateTime{}, PublicEstimated: &webapi.DateTime{}, WorkingEstimated: &webapi.DateTime{}, Actual: &webapi.DateTime{}},
|
||||||
|
DepartureTiming: &webapi.TimingData{PublicScheduled: &webapi.DateTime{}, WorkingScheduled: &webapi.DateTime{}, PublicEstimated: &webapi.DateTime{}, WorkingEstimated: &webapi.DateTime{}, Actual: &webapi.DateTime{}},
|
||||||
|
PassTiming: &webapi.TimingData{PublicScheduled: &webapi.DateTime{}, WorkingScheduled: &webapi.DateTime{}, PublicEstimated: &webapi.DateTime{}, WorkingEstimated: &webapi.DateTime{}, Actual: &webapi.DateTime{}},
|
||||||
|
}
|
||||||
|
if err := rows.Scan(
|
||||||
|
&loc.Id,
|
||||||
|
&loc.Location.Tiploc, &loc.Location.Name, &loc.Location.Crs, &loc.Location.Operator.Code, &loc.Location.Operator.Name, &loc.Location.Operator.Url,
|
||||||
|
&loc.CallingPointType, &loc.TrainLength, &loc.ServiceSuppressed,
|
||||||
|
&loc.Cancelled,
|
||||||
|
&loc.Platform.Scheduled, &loc.Platform.Live, &loc.Platform.Confirmed, &loc.Platform.Suppressed,
|
||||||
|
&loc.FalseDestination.Tiploc, &loc.FalseDestination.Name, &loc.FalseDestination.Crs, &loc.FalseDestination.Operator.Code, &loc.FalseDestination.Operator.Name, &loc.FalseDestination.Operator.Url,
|
||||||
|
loc.ArrivalTiming.PublicScheduled, loc.ArrivalTiming.WorkingScheduled, loc.ArrivalTiming.PublicEstimated, loc.ArrivalTiming.WorkingEstimated, loc.ArrivalTiming.Actual,
|
||||||
|
loc.DepartureTiming.PublicScheduled, loc.DepartureTiming.WorkingScheduled, loc.DepartureTiming.PublicEstimated, loc.DepartureTiming.WorkingEstimated, loc.DepartureTiming.Actual,
|
||||||
|
/*loc.PassTiming.PublicScheduled,*/ loc.PassTiming.WorkingScheduled, loc.PassTiming.PublicEstimated, loc.PassTiming.WorkingEstimated, loc.PassTiming.Actual,
|
||||||
|
); err != nil {
|
||||||
|
return nil, fmt.Errorf("scanning locations for %d: %w", id, err)
|
||||||
|
}
|
||||||
|
loc.Canonicalize()
|
||||||
|
sd.Locations = append(sd.Locations, &loc)
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
return nil, fmt.Errorf("iterating over locations for %d: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &sd, nil
|
||||||
|
}
|
Loading…
Reference in a new issue