Skip to content

Commit f59267c

Browse files
committed
combine duplicate flights DataElements
1 parent 13688a5 commit f59267c

File tree

3 files changed

+113
-69
lines changed

3 files changed

+113
-69
lines changed

go/common/flight.go

-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ type FlightId struct {
6565
}
6666

6767
type Flight struct {
68-
QueryDate LocalDate `json:"queryDate"`
6968
Airline AirlineIdentifier `json:"airline"`
7069
FlightNumber int `json:"flightNumber"`
7170
Suffix string `json:"suffix"`

go/cron/action/action.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
package action
22

3-
import "context"
3+
import (
4+
"context"
5+
"github.com/explore-flights/monorepo/go/common/adapt"
6+
)
47

58
type Action[IN any, OUT any] interface {
69
Handle(ctx context.Context, params IN) (OUT, error)
710
}
11+
12+
type MinimalS3Client interface {
13+
adapt.S3Getter
14+
adapt.S3Putter
15+
}

go/cron/action/convert_flight_schedules.go

+104-67
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
)
1515

1616
const (
17+
queryDateId int = -1
1718
codeShareChildId int = 10
1819
codeShareParentId int = 50
1920
)
@@ -30,43 +31,44 @@ type ConvertFlightSchedulesOutput struct {
3031
}
3132

3233
type cfsAction struct {
33-
s3c *s3.Client
34+
s3c MinimalS3Client
3435
}
3536

36-
func NewConvertFlightSchedulesAction(s3c *s3.Client) Action[ConvertFlightSchedulesParams, ConvertFlightSchedulesOutput] {
37+
func NewConvertFlightSchedulesAction(s3c MinimalS3Client) Action[ConvertFlightSchedulesParams, ConvertFlightSchedulesOutput] {
3738
return &cfsAction{s3c}
3839
}
3940

4041
func (a *cfsAction) Handle(ctx context.Context, params ConvertFlightSchedulesParams) (ConvertFlightSchedulesOutput, error) {
4142
ctx, cancel := context.WithCancel(ctx)
4243
defer cancel()
4344

44-
var grouped map[common.LocalDate][]*common.Flight
45-
{
46-
g, ctx := errgroup.WithContext(ctx)
47-
results := make([][]*common.Flight, len(params.DateRanges))
45+
ch := make(chan *common.Flight, 1024)
46+
g, ctx := errgroup.WithContext(ctx)
4847

49-
for i, r := range params.DateRanges {
50-
g.Go(func() error {
51-
flights, err := a.convertRange(ctx, params.InputBucket, params.InputPrefix, r[0], r[1])
52-
if err != nil {
53-
return err
54-
}
48+
for _, r := range params.DateRanges {
49+
g.Go(func() error {
50+
return a.convertRange(ctx, params.InputBucket, params.InputPrefix, r[0], r[1], ch)
51+
})
52+
}
5553

56-
results[i] = flights
57-
return nil
58-
})
59-
}
54+
done := make(chan map[common.LocalDate][]*common.Flight)
55+
go func() {
56+
defer close(done)
6057

61-
if err := g.Wait(); err != nil {
62-
return ConvertFlightSchedulesOutput{}, err
58+
result := make(map[common.LocalDate][]*common.Flight)
59+
for f := range ch {
60+
result[f.DepartureDate()] = append(result[f.DepartureDate()], f)
6361
}
6462

65-
grouped = groupByDepartureDateUTC(results)
63+
done <- result
64+
}()
65+
66+
if err := func() error { defer close(ch); return g.Wait() }(); err != nil {
67+
return ConvertFlightSchedulesOutput{}, err
6668
}
6769

68-
g, ctx := errgroup.WithContext(ctx)
69-
for d, flights := range grouped {
70+
g, ctx = errgroup.WithContext(ctx)
71+
for d, flights := range <-done {
7072
g.Go(func() error {
7173
return a.upsertFlights(
7274
ctx,
@@ -82,36 +84,24 @@ func (a *cfsAction) Handle(ctx context.Context, params ConvertFlightSchedulesPar
8284
return ConvertFlightSchedulesOutput{}, g.Wait()
8385
}
8486

85-
func (a *cfsAction) convertRange(ctx context.Context, inputBucket, inputPrefix string, start, end common.LocalDate) ([]*common.Flight, error) {
86-
var flights []*common.Flight
87-
87+
func (a *cfsAction) convertRange(ctx context.Context, inputBucket, inputPrefix string, start, end common.LocalDate, ch chan<- *common.Flight) error {
88+
g, ctx := errgroup.WithContext(ctx)
8889
for curr := range start.Until(end) {
89-
converted, err := a.convertSingle(ctx, inputBucket, inputPrefix, curr)
90-
if err != nil {
91-
return nil, err
92-
}
93-
94-
flights = append(flights, converted...)
90+
g.Go(func() error {
91+
return a.convertSingle(ctx, inputBucket, inputPrefix, curr, ch)
92+
})
9593
}
9694

97-
return flights, nil
95+
return g.Wait()
9896
}
9997

100-
func (a *cfsAction) convertSingle(ctx context.Context, inputBucket, inputPrefix string, d common.LocalDate) ([]*common.Flight, error) {
101-
var flights []*common.Flight
102-
{
103-
schedules, err := a.loadFlightSchedules(ctx, inputBucket, inputPrefix, d)
104-
if err != nil {
105-
return nil, err
106-
}
107-
108-
flights, err = convertFlightSchedulesToFlights(d, schedules)
109-
if err != nil {
110-
return nil, err
111-
}
98+
func (a *cfsAction) convertSingle(ctx context.Context, inputBucket, inputPrefix string, d common.LocalDate, ch chan<- *common.Flight) error {
99+
schedules, err := a.loadFlightSchedules(ctx, inputBucket, inputPrefix, d)
100+
if err != nil {
101+
return err
112102
}
113103

114-
return flights, nil
104+
return convertFlightSchedulesToFlights(ctx, d, schedules, ch)
115105
}
116106

117107
func (a *cfsAction) loadFlightSchedules(ctx context.Context, bucket, prefix string, d common.LocalDate) ([]lufthansa.FlightSchedule, error) {
@@ -137,20 +127,35 @@ func (a *cfsAction) upsertFlights(ctx context.Context, bucket, prefix string, d
137127
return err
138128
}
139129

140-
added := make(map[common.FlightId]struct{})
130+
added := make(map[common.FlightId]*common.Flight)
141131
result := make([]*common.Flight, 0, max(len(flights), len(existing)))
142132

143133
for _, f := range flights {
144-
if _, ok := added[f.Id()]; !ok {
134+
if addedFlight, ok := added[f.Id()]; ok {
135+
if err := combineFlights(addedFlight, f, queryDateRanges); err != nil {
136+
return err
137+
}
138+
} else {
145139
result = append(result, f)
146-
added[f.Id()] = struct{}{}
140+
added[f.Id()] = f
147141
}
148142
}
149143

150144
for _, f := range existing {
151-
if _, ok := added[f.Id()]; !ok && !queryDateRanges.Contains(f.QueryDate) {
152-
result = append(result, f)
153-
added[f.Id()] = struct{}{}
145+
if addedFlight, ok := added[f.Id()]; ok {
146+
if err := combineFlights(addedFlight, f, queryDateRanges); err != nil {
147+
return err
148+
}
149+
} else {
150+
flightQueryDate, err := common.ParseLocalDate(f.DataElements[queryDateId])
151+
if err != nil {
152+
return err
153+
}
154+
155+
if !queryDateRanges.Contains(flightQueryDate) {
156+
result = append(result, f)
157+
added[f.Id()] = f
158+
}
154159
}
155160
}
156161

@@ -189,15 +194,14 @@ func (a *cfsAction) loadFlights(ctx context.Context, bucket, s3Key string) ([]*c
189194
return flights, json.NewDecoder(resp.Body).Decode(&flights)
190195
}
191196

192-
func convertFlightSchedulesToFlights(queryDate common.LocalDate, schedules []lufthansa.FlightSchedule) ([]*common.Flight, error) {
197+
func convertFlightSchedulesToFlights(ctx context.Context, queryDate common.LocalDate, schedules []lufthansa.FlightSchedule, ch chan<- *common.Flight) error {
193198
lookup := make(map[common.FlightId]*common.Flight)
194199
codeShareIds := make(map[common.FlightId]struct{})
195200
addLater := make(map[common.FlightId][]*common.Flight)
196201

197202
for _, fs := range schedules {
198203
for _, leg := range fs.Legs {
199204
f := &common.Flight{
200-
QueryDate: queryDate,
201205
Airline: common.AirlineIdentifier(fs.Airline),
202206
FlightNumber: fs.FlightNumber,
203207
Suffix: fs.Suffix,
@@ -214,18 +218,22 @@ func convertFlightSchedulesToFlights(queryDate common.LocalDate, schedules []luf
214218
CodeShares: make(map[common.FlightNumber]map[int]string),
215219
}
216220

221+
f.DataElements[queryDateId] = queryDate.String()
222+
217223
lookup[f.Id()] = f
218224

219225
if codeSharesRaw := f.DataElements[codeShareChildId]; codeSharesRaw != "" {
220226
// this flight has codeshares
221227
for _, codeShare := range strings.Split(codeSharesRaw, "/") {
222228
codeShareFn, err := common.ParseFlightNumber(codeShare)
223229
if err != nil {
224-
return nil, err
230+
return err
225231
}
226232

227233
if _, ok := f.CodeShares[codeShareFn]; !ok {
228-
f.CodeShares[codeShareFn] = make(map[int]string)
234+
f.CodeShares[codeShareFn] = map[int]string{
235+
queryDateId: queryDate.String(),
236+
}
229237
}
230238

231239
// mark as codeshare
@@ -237,7 +245,7 @@ func convertFlightSchedulesToFlights(queryDate common.LocalDate, schedules []luf
237245
// this flight is a codeshare
238246
parentFn, err := common.ParseFlightNumber(codeShare)
239247
if err != nil {
240-
return nil, err
248+
return err
241249
}
242250

243251
parentFid := parentFn.Id(f.Departure())
@@ -265,7 +273,6 @@ func convertFlightSchedulesToFlights(queryDate common.LocalDate, schedules []luf
265273
// create a parent if the parent itself isn't present
266274
first := codeShares[0]
267275
f = &common.Flight{
268-
QueryDate: queryDate,
269276
Airline: fid.Number.Airline,
270277
FlightNumber: fid.Number.Number,
271278
Suffix: fid.Number.Suffix,
@@ -278,8 +285,10 @@ func convertFlightSchedulesToFlights(queryDate common.LocalDate, schedules []luf
278285
AircraftType: first.AircraftType,
279286
AircraftConfigurationVersion: first.AircraftConfigurationVersion,
280287
Registration: first.Registration,
281-
DataElements: make(map[int]string),
282-
CodeShares: make(map[common.FlightNumber]map[int]string),
288+
DataElements: map[int]string{
289+
queryDateId: queryDate.String(),
290+
},
291+
CodeShares: make(map[common.FlightNumber]map[int]string),
283292
}
284293

285294
lookup[fid] = f
@@ -290,23 +299,51 @@ func convertFlightSchedulesToFlights(queryDate common.LocalDate, schedules []luf
290299
}
291300
}
292301

293-
flights := make([]*common.Flight, 0, len(lookup)-len(codeShareIds))
294302
for fid, f := range lookup {
295303
if _, ok := codeShareIds[fid]; !ok {
296-
flights = append(flights, f)
304+
select {
305+
case ch <- f:
306+
case <-ctx.Done():
307+
return ctx.Err()
308+
}
297309
}
298310
}
299311

300-
return flights, nil
312+
return nil
301313
}
302314

303-
func groupByDepartureDateUTC(results [][]*common.Flight) map[common.LocalDate][]*common.Flight {
304-
grouped := make(map[common.LocalDate][]*common.Flight)
305-
for _, result := range results {
306-
for _, f := range result {
307-
grouped[f.DepartureDate()] = append(grouped[f.DepartureDate()], f)
315+
func combineFlights(f, other *common.Flight, queryDateRanges common.LocalDateRanges) error {
316+
otherQueryDate, err := common.ParseLocalDate(other.DataElements[queryDateId])
317+
if err != nil {
318+
return err
319+
}
320+
321+
if !queryDateRanges.Contains(otherQueryDate) {
322+
for k, v := range other.DataElements {
323+
if _, ok := f.DataElements[k]; !ok {
324+
f.DataElements[k] = v
325+
}
326+
}
327+
}
328+
329+
for codeShareFn, otherDataElements := range other.CodeShares {
330+
codeShareQueryDate, err := common.ParseLocalDate(otherDataElements[queryDateId])
331+
if err != nil {
332+
return err
333+
}
334+
335+
if !queryDateRanges.Contains(codeShareQueryDate) {
336+
if dataElements, ok := f.CodeShares[codeShareFn]; ok {
337+
for k, v := range otherDataElements {
338+
if _, ok := dataElements[k]; !ok {
339+
dataElements[k] = v
340+
}
341+
}
342+
} else {
343+
f.CodeShares[codeShareFn] = otherDataElements
344+
}
308345
}
309346
}
310347

311-
return grouped
348+
return nil
312349
}

0 commit comments

Comments
 (0)