Mercurial > gemma
changeset 5199:5001582f2ee1 new-fwa
Prepare to treat stretches and sections, too.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Fri, 08 May 2020 11:43:06 +0200 |
parents | 0e91d200299d |
children | 5572da077c89 |
files | pkg/controllers/fwa.go |
diffstat | 1 files changed, 173 insertions(+), 60 deletions(-) [+] |
line wrap: on
line diff
--- a/pkg/controllers/fwa.go Fri May 08 09:24:19 2020 +0200 +++ b/pkg/controllers/fwa.go Fri May 08 11:43:06 2020 +0200 @@ -16,6 +16,7 @@ import ( "context" "database/sql" + "fmt" "log" "net/http" "time" @@ -37,6 +38,16 @@ WHERE bottleneck_id = $1 AND validity && tstzrange($2, $3)` + + selectSymbolBottlenecksSQL = ` +SELECT + distinct(b.bottleneck_id) +FROM + users.%s s, waterway.bottlenecks b +WHERE + ST_Intersects(b.area, s.area) + AND s.name = $1 + AND b.validity && tstzrange($2, $3)` ) type ( @@ -47,8 +58,101 @@ } limitingValidities []limitingValidity + + bottleneck struct { + id string + validities limitingValidities + } ) +func fairwayAvailability(rw http.ResponseWriter, req *http.Request) { + + from, to, ok := parseFromTo(rw, req) + if !ok { + return + } + + vars := mux.Vars(req) + name := vars["name"] + if name == "" { + http.Error(rw, "missing 'name' parameter.", http.StatusBadRequest) + return + } + + ctx := req.Context() + conn := middleware.GetDBConn(req) + + // Function to extract the bottleneck_id's from the query. + var extract func(context.Context, *sql.Conn, string, time.Time, time.Time) ([]bottleneck, error) + + switch vars["kind"] { + case "bottleneck": + extract = extractBottleneck + case "stretch": + extract = extractStretch + case "section": + extract = extractSection + default: + http.Error(rw, "Invalid kind type.", http.StatusBadRequest) + return + } + + bottlenecks, err := extract(ctx, conn, name, from, to) + if err != nil { + log.Println("error: %v\n", err) + http.Error(rw, "cannot extract bottlenecks", http.StatusBadRequest) + return + } + + // load validities and limiting factors + for i := range bottlenecks { + if err := bottlenecks[i].loadLimitingValidities(ctx, conn, from, to); err != nil { + log.Printf("error: %v\n", err) + http.Error(rw, "cannot load validities", http.StatusInternalServerError) + return + } + } + + // TODO: Implement me! +} + +func dusk(t time.Time) time.Time { + return time.Date( + t.Year(), + t.Month(), + t.Day(), + 0, 0, 0, 0, + t.Location()) +} + +func dawn(t time.Time) time.Time { + return time.Date( + t.Year(), + t.Month(), + t.Day(), + 23, 59, 59, 999999999, + t.Location()) +} + +func parseFromTo( + rw http.ResponseWriter, + req *http.Request, +) (time.Time, time.Time, bool) { + from, ok := parseFormTime(rw, req, "from", time.Now().AddDate(-1, 0, 0)) + if !ok { + return time.Time{}, time.Time{}, false + } + + to, ok := parseFormTime(rw, req, "to", from.AddDate(1, 0, 0)) + if !ok { + return time.Time{}, time.Time{}, false + } + + from, to = common.OrderTime(from, to) + // Operate on daily basis so go to full days. + return dusk(from), dawn(to), true +} + func (lv *limitingValidity) intersects(from, to time.Time) bool { return !(to.Before(lv.lower) || from.After(lv.upper)) } @@ -107,74 +211,83 @@ return lvs, rows.Err() } -func fairwayAvailability(rw http.ResponseWriter, req *http.Request) { - - vars := mux.Vars(req) +func loadSymbolBottlenecksFromTo( + ctx context.Context, + conn *sql.Conn, + what, name string, + from, to time.Time, +) ([]bottleneck, error) { - switch vars["kind"] { - case "bottleneck": - fairwayAvailabilityBottleneck(rw, req) - case "stretch": // TODO: Implement me! - case "section": // TODO: Implement me! - default: - http.Error(rw, "Invalid kind type.", http.StatusBadRequest) - return + rows, err := conn.QueryContext( + ctx, + fmt.Sprintf(selectSymbolBottlenecksSQL, what), + name, + from, to) + if err != nil { + return nil, err } + defer rows.Close() + + var bottlenecks []bottleneck + + for rows.Next() { + var b bottleneck + if err := rows.Scan(&b.id); err != nil { + return nil, err + } + bottlenecks = append(bottlenecks, b) + } + + return bottlenecks, rows.Err() } -func parseFromTo( - rw http.ResponseWriter, - req *http.Request, -) (time.Time, time.Time, bool) { - from, ok := parseFormTime(rw, req, "from", time.Now().AddDate(-1, 0, 0)) - if !ok { - return time.Time{}, time.Time{}, false - } - - to, ok := parseFormTime(rw, req, "to", from.AddDate(1, 0, 0)) - if !ok { - return time.Time{}, time.Time{}, false - } - from, to = common.OrderTime(from, to) - return from, to, true +func extractBottleneck( + _ context.Context, + _ *sql.Conn, + name string, + _, _ time.Time, +) ([]bottleneck, error) { + return []bottleneck{{id: name}}, nil } -func fairwayAvailabilityBottleneck(rw http.ResponseWriter, req *http.Request) { - - vars := mux.Vars(req) - - bottleneckID := vars["name"] - if bottleneckID == "" { - http.Error(rw, "missing bottleneck_id", http.StatusBadRequest) - return - } - log.Printf("info: fairway availability for bottleneck_id '%s'\n", bottleneckID) - - from, to, ok := parseFromTo(rw, req) - if !ok { - return - } - - los, ok := parseFormInt(rw, req, "los", 1) - if !ok { - return - } - - ctx := req.Context() - conn := middleware.GetDBConn(req) - - lvs, err := loadLimitingValidities( +func extractStretch( + ctx context.Context, + conn *sql.Conn, + name string, + from, to time.Time, +) ([]bottleneck, error) { + return loadSymbolBottlenecksFromTo( ctx, conn, - bottleneckID, + "stretches", name, + from, to) +} + +func extractSection( + ctx context.Context, + conn *sql.Conn, + name string, + from, to time.Time, +) ([]bottleneck, error) { + return loadSymbolBottlenecksFromTo( + ctx, + conn, + "sections", name, from, to) - if err != nil { - log.Printf("error: %v\n", err) - http.Error(rw, "Loading validities failed", http.StatusInternalServerError) - return +} + +func (bn *bottleneck) loadLimitingValidities( + ctx context.Context, + conn *sql.Conn, + from, to time.Time, +) error { + vs, err := loadLimitingValidities( + ctx, + conn, + bn.id, + from, to) + if err == nil { + bn.validities = vs } - - // TODO: Implement me! - _ = los - _ = lvs + return err }