2021-11-18 22:24:20 +00:00
|
|
|
package darwindb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
|
|
|
|
pgx "github.com/jackc/pgx/v4"
|
2024-11-16 15:30:41 +00:00
|
|
|
"git.lukegb.com/lukegb/depot/go/trains/darwin"
|
2021-11-18 22:24:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type scheduleMode int
|
|
|
|
|
|
|
|
const (
|
|
|
|
scheduleModeOverwrite scheduleMode = iota
|
|
|
|
scheduleModeIgnoreExisting
|
|
|
|
)
|
|
|
|
|
|
|
|
// handleSchedule processes a Darwin Schedule.
|
|
|
|
func handleSchedule(ctx context.Context, tx pgx.Tx, s *darwin.Schedule, a *Affected, sm scheduleMode) error {
|
|
|
|
startTS, err := startTime(s)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("finding start time for RID %v: %w", s.RID, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var cancelCode, cancelTIPLOC *string
|
|
|
|
var cancelTIPLOCNear *bool
|
|
|
|
if s.CancellationReason != nil {
|
|
|
|
cancelCode = &s.CancellationReason.Code
|
|
|
|
cancelTIPLOC = &s.CancellationReason.TIPLOC
|
|
|
|
cancelTIPLOCNear = &s.CancellationReason.Near
|
|
|
|
}
|
|
|
|
sql := `
|
|
|
|
INSERT INTO train_services
|
|
|
|
(rid, uid, rsid, headcode, scheduled_start_date, effective_start_time,
|
|
|
|
train_operator, status, train_category, is_passenger_svc, is_charter, is_q_train,
|
|
|
|
cancellation_reason_code, cancellation_reason_tiploc, cancellation_reason_tiploc_near,
|
|
|
|
active, deleted, cancelled)
|
|
|
|
VALUES
|
|
|
|
($1, $2, $3, $4, $5, $6,
|
|
|
|
$7, COALESCE($8, 'P'), COALESCE($9, 'OO'), COALESCE($10, true), COALESCE($11, false), COALESCE($12, false),
|
|
|
|
$13, $14, $15,
|
|
|
|
COALESCE($16, true), $17, COALESCE($18, false))
|
|
|
|
ON CONFLICT (rid)`
|
|
|
|
switch sm {
|
|
|
|
case scheduleModeOverwrite:
|
|
|
|
sql += ` DO UPDATE SET
|
|
|
|
uid=$2, rsid=$3, headcode=$4, scheduled_start_date=$5, effective_start_time=$6,
|
|
|
|
train_operator=$7, status=COALESCE($8, 'P'), train_category=COALESCE($9, 'OO'), is_passenger_svc=COALESCE($10, true), is_charter=COALESCE($11, false), is_q_train=COALESCE($12, train_services.is_q_train),
|
|
|
|
cancellation_reason_code=$13, cancellation_reason_tiploc=$14, cancellation_reason_tiploc_near=$15,
|
|
|
|
active=COALESCE($16, 'true'), deleted=$17, cancelled=COALESCE($18, 'false')
|
|
|
|
`
|
|
|
|
case scheduleModeIgnoreExisting:
|
|
|
|
sql += ` DO NOTHING
|
|
|
|
`
|
|
|
|
}
|
|
|
|
sql += `RETURNING id`
|
|
|
|
row := tx.QueryRow(ctx, sql,
|
|
|
|
s.RID, s.UID, s.RSID, s.TrainID, s.SSD, startTS,
|
|
|
|
s.TOC, s.Status, s.TrainCat, s.IsPassengerSvc, s.IsCharter, s.IsQTrain,
|
|
|
|
cancelCode, cancelTIPLOC, cancelTIPLOCNear,
|
|
|
|
s.IsActive, s.Deleted, s.Cancelled)
|
|
|
|
var serviceID int
|
|
|
|
if err := row.Scan(&serviceID); err == pgx.ErrNoRows && sm == scheduleModeIgnoreExisting {
|
|
|
|
// The row existed already.
|
|
|
|
return nil
|
|
|
|
} else if err != nil {
|
|
|
|
log.Printf("inserting schedule for RID %v: %v", s.RID, err)
|
|
|
|
return fmt.Errorf("inserting schedule for RID %v: %w", s.RID, err)
|
|
|
|
}
|
|
|
|
a.RID(s.RID)
|
|
|
|
a.TSID(serviceID)
|
|
|
|
|
|
|
|
// Insert/update all the locations.
|
|
|
|
var activeLocations []int
|
|
|
|
for _, cp := range s.CallingPoints {
|
|
|
|
var locid int
|
|
|
|
row := tx.QueryRow(ctx, `
|
|
|
|
SELECT train_locations_upsert_from_schedule(
|
|
|
|
p_tsid => $1, p_rid => $2, p_tiploc => $3, p_calling_point => $4,
|
|
|
|
p_schedule_public_arrival => $5, p_schedule_working_arrival => $6,
|
|
|
|
p_schedule_public_departure => $7, p_schedule_working_departure => $8,
|
|
|
|
p_schedule_working_pass => $9,
|
|
|
|
p_schedule_route_delay => $10, p_schedule_activity => $11, p_schedule_planned_activity => $12, p_schedule_cancelled => $13,
|
|
|
|
p_schedule_false_destination_tiploc => $14, p_schedule_platform => $15)
|
|
|
|
`,
|
|
|
|
serviceID, s.RID, cp.TIPLOC, cp.XMLName.Local,
|
|
|
|
timeToTimestamp(cp.PTA, startTS), timeToTimestamp(cp.WTA, startTS),
|
|
|
|
timeToTimestamp(cp.PTD, startTS), timeToTimestamp(cp.WTD, startTS),
|
|
|
|
timeToTimestamp(cp.WTP, startTS),
|
|
|
|
cp.RDelay, cp.Act, cp.PlanAct, cp.Cancelled,
|
|
|
|
cp.FD, cp.Platform,
|
|
|
|
)
|
|
|
|
if err := row.Scan(&locid); err != nil {
|
|
|
|
log.Printf("updating location %v from RID %v/my ID %v: %v", cp.TIPLOC, s.RID, serviceID, err)
|
|
|
|
zz, _ := json.MarshalIndent(s, "", " ")
|
|
|
|
log.Println(string(zz))
|
|
|
|
zz, _ = json.MarshalIndent(cp, "", " ")
|
|
|
|
log.Println(string(zz))
|
|
|
|
return fmt.Errorf("updating location %v from RID %v/my ID %v: %w", cp.TIPLOC, s.RID, serviceID, err)
|
|
|
|
} else {
|
|
|
|
activeLocations = append(activeLocations, locid)
|
|
|
|
}
|
|
|
|
a.TIPLOC(cp.TIPLOC)
|
|
|
|
}
|
|
|
|
if _, err := tx.Exec(ctx, "UPDATE train_locations SET active_in_schedule=false WHERE tsid=$1 AND NOT (id = ANY ($2))", serviceID, activeLocations); err != nil {
|
|
|
|
return fmt.Errorf("marking old locations as removed from schedule for RID %v/my ID %v (active locations: %v): %w", s.RID, serviceID, activeLocations, err)
|
|
|
|
}
|
|
|
|
fmt.Printf("s")
|
|
|
|
return nil
|
|
|
|
}
|