# HG changeset patch # User Thomas Junk # Date 1564068151 -7200 # Node ID d9c3eb32190f3172288ef7105af8c59d7f08293c # Parent 2db1124c32f73d2c62b175318d57ff288914f311# Parent 1562a5fb36dc44f7d2deb0e47b31081be02294f3 merge with default diff -r 2db1124c32f7 -r d9c3eb32190f pkg/common/time.go --- a/pkg/common/time.go Thu Jul 25 17:22:10 2019 +0200 +++ b/pkg/common/time.go Thu Jul 25 17:22:31 2019 +0200 @@ -27,8 +27,26 @@ DateFormat = "2006-01-02" ) +// TimeParser is a list of time formats. +type TimeParser []string + var utc0 = time.Unix(0, 0) +// Parse tries to parse a given string by the entries of the layout +// list one after another. The first matching time is returned. +// If no layout matches the last error is returned or time zero +// if the layout list is empty. +func (tg TimeParser) Parse(s string) (time.Time, error) { + var err error + var t time.Time + for _, layout := range tg { + if t, err = time.Parse(layout, s); err == nil { + break + } + } + return t, err +} + func InterpolateTime(t1 time.Time, m1 float64, t2 time.Time, m2 float64) func(float64) time.Time { // f(m1) = t1 diff -r 2db1124c32f7 -r d9c3eb32190f pkg/controllers/gauges.go --- a/pkg/controllers/gauges.go Thu Jul 25 17:22:10 2019 +0200 +++ b/pkg/controllers/gauges.go Thu Jul 25 17:22:31 2019 +0200 @@ -636,7 +636,7 @@ } } - cs[i].Value = common.NashSutcliffe(predicted, observed) + cs[i].Value = sanitizeFloat64(common.NashSutcliffe(predicted, observed)) cs[i].Samples = len(predicted) predicted = predicted[:0] @@ -652,6 +652,18 @@ return } +func sanitizeFloat64(x float64) float64 { + switch { + case math.IsNaN(x): + return 0 + case math.IsInf(x, +1): + return math.MaxFloat64 + case math.IsInf(x, -1): + return -math.MaxFloat64 + } + return x +} + func waterlevels(rw http.ResponseWriter, req *http.Request) { gauge := mux.Vars(req)["gauge"] diff -r 2db1124c32f7 -r d9c3eb32190f pkg/imports/agm.go --- a/pkg/imports/agm.go Thu Jul 25 17:22:10 2019 +0200 +++ b/pkg/imports/agm.go Thu Jul 25 17:22:31 2019 +0200 @@ -31,6 +31,7 @@ "strings" "time" + "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/misc" "gemma.intevation.de/gemma/pkg/models" ) @@ -103,10 +104,10 @@ return os.RemoveAll(agm.Dir) } -var guessDate = misc.TimeGuesser([]string{ +var guessDate = common.TimeParser([]string{ "02.01.2006 15:04", "2006-01-02T15:04:05-07:00", -}).Guess +}).Parse type timetz struct{ time.Time } diff -r 2db1124c32f7 -r d9c3eb32190f pkg/imports/fa.go --- a/pkg/imports/fa.go Thu Jul 25 17:22:10 2019 +0200 +++ b/pkg/imports/fa.go Thu Jul 25 17:22:31 2019 +0200 @@ -37,11 +37,6 @@ Insecure bool `json:"insecure"` } -type uniqueFairwayAvailability struct { - BottleneckId string - Surdat time.Time -} - // FAJobKind is import queue type identifier. const FAJobKind JobKind = "fa" @@ -61,14 +56,7 @@ FROM waterway.effective_fairway_availability ORDER BY measure_date DESC LIMIT 1 ` - listFairwayAvailabilitySQL = ` -SELECT - fa.id, - bn.bottleneck_id, - fa.surdat -FROM waterway.fairway_availability fa -JOIN waterway.bottlenecks bn ON bn.id = fa.bottleneck_id -` + insertFASQL = ` INSERT INTO waterway.fairway_availability ( position_code, @@ -87,7 +75,11 @@ $4, $5, $6 -) +) ON CONFLICT (bottleneck_id, surdat) DO UPDATE SET + position_code = EXCLUDED.position_code, + critical = EXCLUDED.critical, + date_info = EXCLUDED.date_info, + source_organization = EXCLUDED.source_organization RETURNING id` insertBnPdfsSQL = ` @@ -104,6 +96,7 @@ $4, $5 ) ON CONFLICT ON CONSTRAINT bottleneck_pdfs_pkey DO NOTHING` + insertEFASQL = ` INSERT INTO waterway.effective_fairway_availability ( fairway_availability_id, @@ -131,6 +124,7 @@ $9, $10 ) ON CONFLICT ON CONSTRAINT effective_fairway_availability_pkey DO NOTHING` + insertFAVSQL = ` INSERT INTO waterway.fa_reference_values ( fairway_availability_id, @@ -215,36 +209,6 @@ return bns, nil } -func loadFairwayAvailabilities(ctx context.Context, tx *sql.Tx) (map[uniqueFairwayAvailability]int64, error) { - rows, err := tx.QueryContext(ctx, listFairwayAvailabilitySQL) - if err != nil { - return nil, err - } - defer rows.Close() - fairwayAvailabilities := map[uniqueFairwayAvailability]int64{} - for rows.Next() { - var id int64 - var bnId string - var sd time.Time - if err = rows.Scan( - &id, - &bnId, - &sd, - ); err != nil { - return nil, err - } - key := uniqueFairwayAvailability{ - BottleneckId: bnId, - Surdat: sd, - } - fairwayAvailabilities[key] = id - } - if err = rows.Err(); err != nil { - return nil, err - } - return fairwayAvailabilities, nil -} - func latestDate(ctx context.Context, tx *sql.Tx) (pgtype.Timestamp, error) { var date pgtype.Timestamp err := tx.QueryRowContext(ctx, latestMeasureDateSQL).Scan(&date) @@ -285,12 +249,7 @@ return nil, err } - fairwayAvailabilities, err := loadFairwayAvailabilities(ctx, tx) - if err != nil { - return nil, err - } - - faids, err := doForFAs(ctx, bns, fairwayAvailabilities, fas, tx, feedback) + faids, err := doForFAs(ctx, bns, fas, tx, feedback) if err != nil { return nil, fmt.Errorf("Error processing data: %v", err) } @@ -320,7 +279,6 @@ func doForFAs( ctx context.Context, bnIds bottlenecks, - fairwayAvailabilities map[uniqueFairwayAvailability]int64, fas []*ifaf.FairwayAvailability, tx *sql.Tx, feedback Feedback, @@ -355,25 +313,17 @@ feedback.Warn("Bottleneck %s not found in database.", faRes.Bottleneck_id) continue } - uniqueFa := uniqueFairwayAvailability{ - BottleneckId: faRes.Bottleneck_id, - Surdat: faRes.SURDAT, - } - var found bool - if faID, found = fairwayAvailabilities[uniqueFa]; !found { - err = insertFAStmt.QueryRowContext( - ctx, - faRes.POSITION, - faRes.Bottleneck_id, - faRes.SURDAT, - faRes.Critical, - faRes.Date_Info, - faRes.Source, - ).Scan(&faID) - if err != nil { - return nil, err - } - fairwayAvailabilities[uniqueFa] = faID + err = insertFAStmt.QueryRowContext( + ctx, + faRes.POSITION, + faRes.Bottleneck_id, + faRes.SURDAT, + faRes.Critical, + faRes.Date_Info, + faRes.Source, + ).Scan(&faID) + if err != nil { + return nil, err } feedback.Info("Processing for Bottleneck %s", faRes.Bottleneck_id) faIDs = append(faIDs, faRes.Bottleneck_id) diff -r 2db1124c32f7 -r d9c3eb32190f pkg/imports/fd.go --- a/pkg/imports/fd.go Thu Jul 25 17:22:10 2019 +0200 +++ b/pkg/imports/fd.go Thu Jul 25 17:22:31 2019 +0200 @@ -21,7 +21,7 @@ "io" "time" - "gemma.intevation.de/gemma/pkg/misc" + "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/pgxutils" "gemma.intevation.de/gemma/pkg/wfs" ) @@ -48,11 +48,11 @@ type fdTime struct{ time.Time } -var guessFDTime = misc.TimeGuesser([]string{ +var guessFDTime = common.TimeParser([]string{ "20060102", "2006", "", -}).Guess +}).Parse func (fdt *fdTime) UnmarshalJSON(data []byte) error { var s string diff -r 2db1124c32f7 -r d9c3eb32190f pkg/imports/wp.go --- a/pkg/imports/wp.go Thu Jul 25 17:22:10 2019 +0200 +++ b/pkg/imports/wp.go Thu Jul 25 17:22:31 2019 +0200 @@ -30,7 +30,7 @@ "github.com/jackc/pgx/pgtype" - "gemma.intevation.de/gemma/pkg/misc" + "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/models" "gemma.intevation.de/gemma/pkg/wfs" ) @@ -418,7 +418,7 @@ feedback.Info( "Matching points to lines with a precision of %.4fm.", precision) - parseDate := misc.TimeGuesser([]string{"02.01.2006"}).Guess + parseDate := common.TimeParser([]string{"02.01.2006"}).Parse insertStmt, err := tx.PrepareContext(ctx, insertWaterwayProfileSQL) if err != nil { diff -r 2db1124c32f7 -r d9c3eb32190f pkg/misc/time.go --- a/pkg/misc/time.go Thu Jul 25 17:22:10 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -// This is Free Software under GNU Affero General Public License v >= 3.0.Reader. -// without warranty, see README.md and license for details. -// -// SPDX-License-Identifier: AGPL-3.0-or-later -// License-Filename: LICENSES/AGPL-3.0.txt -// -// Copyright (C) 2018 by via donau -// – Österreichische Wasserstraßen-Gesellschaft mbH -// Software engineering by Intevation GmbH -// -// Author(s): -// * Sascha L. Teichmann - -package misc - -import "time" - -// TimeGuesser is a list of time formats. -type TimeGuesser []string - -// Guess tries to parse a given string by the entries of the layout -// list one after another. The first matching time is returned. -// If no layout matches the last error is returned or time zero -// if the layout list is empty. -func (tg TimeGuesser) Guess(s string) (time.Time, error) { - var err error - var t time.Time - for _, layout := range tg { - if t, err = time.Parse(layout, s); err == nil { - break - } - } - return t, err -} diff -r 2db1124c32f7 -r d9c3eb32190f pkg/soap/nts/service.go --- a/pkg/soap/nts/service.go Thu Jul 25 17:22:10 2019 +0200 +++ b/pkg/soap/nts/service.go Thu Jul 25 17:22:31 2019 +0200 @@ -18,14 +18,14 @@ "encoding/xml" "time" - "gemma.intevation.de/gemma/pkg/misc" + "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/soap" ) -var guessDateTime = misc.TimeGuesser([]string{ +var guessDateTime = common.TimeParser([]string{ "2006-01-02T15:04:05", "2006-01-02T15:04:05-07:00", -}).Guess +}).Parse type DateTime struct{ time.Time } diff -r 2db1124c32f7 -r d9c3eb32190f schema/gemma.sql --- a/schema/gemma.sql Thu Jul 25 17:22:10 2019 +0200 +++ b/schema/gemma.sql Thu Jul 25 17:22:31 2019 +0200 @@ -826,8 +826,8 @@ id int PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, state import_state NOT NULL DEFAULT 'queued', kind varchar NOT NULL, - enqueued timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - due timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + enqueued timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, + due timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, retry_wait interval CHECK(retry_wait IS NULL OR retry_wait >= interval '0 microseconds'), @@ -850,7 +850,7 @@ CREATE TABLE import_logs ( import_id int NOT NULL REFERENCES imports(id) ON DELETE CASCADE, - time timestamp NOT NULL DEFAULT now(), + time timestamp with time zone NOT NULL DEFAULT now(), kind log_type NOT NULL DEFAULT 'info', msg TEXT NOT NULL ) diff -r 2db1124c32f7 -r d9c3eb32190f schema/updates/1010/01.timezones-imports.sql --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/schema/updates/1010/01.timezones-imports.sql Thu Jul 25 17:22:31 2019 +0200 @@ -0,0 +1,3 @@ +ALTER TABLE import.imports ALTER COLUMN enqueued TYPE timestamp with time zone; +ALTER TABLE import.imports ALTER COLUMN due TYPE timestamp with time zone; +ALTER TABLE import.import_logs ALTER COLUMN time TYPE timestamp with time zone; diff -r 2db1124c32f7 -r d9c3eb32190f schema/version.sql --- a/schema/version.sql Thu Jul 25 17:22:10 2019 +0200 +++ b/schema/version.sql Thu Jul 25 17:22:31 2019 +0200 @@ -1,1 +1,1 @@ -INSERT INTO gemma_schema_version(version) VALUES (1009); +INSERT INTO gemma_schema_version(version) VALUES (1010);