Mercurial > gemma
changeset 3541:d26a0ce526cb import_review
merge with default
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Fri, 31 May 2019 09:35:09 +0200 |
parents | c71f1b15c5d9 (current diff) b268cae2df39 (diff) |
children | 603055f52834 |
files | |
diffstat | 17 files changed, 208 insertions(+), 149 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/fairway/Fairwayprofile.vue Wed May 29 15:42:32 2019 +0200 +++ b/client/src/components/fairway/Fairwayprofile.vue Fri May 31 09:35:09 2019 +0200 @@ -17,9 +17,15 @@ </div> <div class="legend"> <span - style="background-color: #4a2f06; width: 20px; height: 20px;" + style="width: 14px; height: 14px; background-color: #4a2f06; border: solid 3px black; background-clip: padding-box; box-sizing: content-box;" ></span> - Ground + Sediment + </div> + <div class="legend"> + <span + style="width: 14px; height: 14px; background-color: rgba(74, 47, 6, 0.6); border: solid 3px #943007; background-clip: padding-box; box-sizing: content-box;" + ></span> + Sediment (Compare) </div> <div> <select @@ -96,9 +102,9 @@ height: null, margin: { top: 20, - right: 40, - bottom: 30, - left: 40 + right: 80, + bottom: 60, + left: 80 }, form: { template: null @@ -141,6 +147,7 @@ }; }, computed: { + ...mapGetters("map", ["openLayersMap"]), ...mapGetters("fairwayprofile", ["totalLength"]), ...mapState("fairwayprofile", [ "additionalSurvey", @@ -149,32 +156,21 @@ "endPoint", "fairwayData", "maxAlt", - "referenceWaterLevel", - "selectedWaterLevel", - "waterLevels" + "selectedWaterLevel" ]), + ...mapState("bottlenecks", ["selectedSurvey", "selectedBottleneck"]), ...mapState("application", ["paneSetup"]), title() { let dates = [this.selectedSurvey.date_info]; + let waterlevelLabel = + this.selectedWaterLevel === "ref" + ? this.selectedSurvey.depth_reference + : "Current"; if (this.additionalSurvey) dates.push(this.additionalSurvey.date_info); dates.map(d => this.$options.filters.dateTime(d, true)); return `${this.$gettext("Fairwayprofile")}: ${ this.selectedBottleneck - } (${dates.join(", ")})`; - }, - selectedSurvey: { - get() { - return this.$store.state.bottlenecks.selectedSurvey; - } - }, - selectedBottleneck: { - get() { - return this.$store.state.bottlenecks.selectedBottleneck; - } - }, - ...mapState("bottlenecks", ["selectedSurvey"]), - relativeWaterLevelDelta() { - return this.selectedWaterLevel.value - this.referenceWaterLevel; + } (${dates.join(", ")}) WL: ${waterlevelLabel} (${this.waterlevel} cm)`; }, currentData() { if ( @@ -192,15 +188,20 @@ return []; return this.currentProfile[this.additionalSurvey.date_info].points; }, - xScale() { - return [0, this.totalLength]; + bottleneck() { + return this.openLayersMap() + .getLayer("BOTTLENECKS") + .getSource() + .getFeatures() + .find(f => f.get("objnam") === this.selectedBottleneck); }, - yScaleRight() { - //ToDO calcReleativeDepth(this.maxAlt) to get the - // maximum depth according to the actual waterlevel - // additionally: take the one which is higher reference or current waterlevel - const DELTA = this.maxAlt * 1.1 - this.maxAlt; - return [this.maxAlt * 1 + DELTA, -DELTA]; + waterlevel() { + return this.selectedWaterLevel === "ref" + ? this.refWaterlevel + : this.bottleneck.get("gm_waterlevel"); + }, + refWaterlevel() { + return this.selectedSurvey.waterlevel_value; } }, watch: { @@ -371,7 +372,7 @@ } }); } - this.pdf.doc.save("Fairwayprofile diagram"); + this.pdf.doc.save(this.title.replace(/\s/g, "_").replace(/[():,]/g, "")); }, addDiagram(position, offset, width, height) { let x = offset.x, @@ -429,36 +430,17 @@ this.pdf.doc.circle(x, y + 10, 2, "FD"); this.pdf.doc.text(x + 3, y + 11, "Ground"); }, - calcRelativeDepth(depth) { - /* takes a depth value and substracts the delta of the relative waterlevel - * say the reference level is above the current level, the ground is nearer, - * thus, the depth is lower. - * - * E.g.: - * - * Reference waterlevel 5m, current 4m => delta = -1m - * If the distance to the ground was 3m from the 5m mark - * it is now only 2m from the current waterlevel. - * - * Vice versa: - * - * If the reference level is 5m and the current 6m => delta = +1m - * The ground is one meter farer away from the current waterlevel - * - */ - return depth - this.relativeWaterLevelDelta; - }, drawDiagram() { d3.select(".diagram-container svg").remove(); this.scaleFairwayProfile(); let svg = d3.select(".diagram-container").append("svg"); svg.attr("width", "100%"); svg.attr("height", "100%"); - const width = this.width - this.margin.right - 1.5 * this.margin.left; - const height = this.height - this.margin.top - 2 * this.margin.bottom; + const width = this.width - this.margin.right - this.margin.left; + const height = this.height - this.margin.top - this.margin.bottom; const currentData = this.currentData; const additionalData = this.additionalData; - const { xScale, yScaleRight, graph } = this.generateCoordinates( + const { xScale, yScaleRight, graph } = this.generateScalesAndGraph( svg, height, width @@ -498,7 +480,6 @@ } for (let data of this.fairwayData) { const [startPoint, endPoint, depth] = data.coordinates[0]; - const style = data.style(); let fairwayArea = d3 .area() .x(function(d) { @@ -513,7 +494,7 @@ .datum([{ x: startPoint, y: depth }, { x: endPoint, y: depth }]) .attr("fill", "#002AFF") .attr("fill-opacity", 0.65) - .attr("stroke", style[0].getStroke().getColor()) + .attr("stroke", "transparent") .attr("d", fairwayArea); } }, @@ -521,14 +502,21 @@ graph .append("text") .attr("transform", ["rotate(-90)"]) - .attr("y", this.width - 70) + .attr("y", this.width - 100) .attr("x", -(this.height - this.margin.top - this.margin.bottom) / 2) - .attr("dy", "1em") .attr("fill", "black") .style("text-anchor", "middle") .text("Depth [m]"); graph .append("text") + .attr("transform", ["rotate(-90)"]) + .attr("y", -50) + .attr("x", -(this.height - this.margin.top - this.margin.bottom) / 2) + .attr("fill", "black") + .style("text-anchor", "middle") + .text("Waterlevel [cm]"); + graph + .append("text") .attr("y", -50) .attr("x", -(height / 4)) .attr("dy", "1em") @@ -540,21 +528,35 @@ ]) .text("Width [m]"); }, - generateCoordinates(svg, height, width) { + generateScalesAndGraph(svg, height, width) { let xScale = d3 .scaleLinear() - .domain(this.xScale) + .domain([0, this.totalLength]) .rangeRound([0, width]); - xScale.ticks(5); - let yScaleRight = d3 .scaleLinear() - .domain(this.yScaleRight) + .domain([ + this.maxAlt * 1.1 + + Math.abs(this.waterlevel - this.refWaterlevel) / 100, + -(this.maxAlt * 0.1) + ]) .rangeRound([height, 0]); - let xAxis = d3.axisBottom(xScale); - let yAxis2 = d3.axisRight(yScaleRight); + let yScaleLeft = d3 + .scaleLinear() + .domain([ + this.waterlevel - + (this.maxAlt * 100 + + Math.abs(this.waterlevel - this.refWaterlevel)), + this.waterlevel + this.maxAlt * 0.1 * 100 + ]) + .rangeRound([height, 0]); + + let xAxis = d3.axisBottom(xScale).ticks(5); + let yAxisRight = d3.axisRight(yScaleRight); + let yAxisLeft = d3.axisLeft(yScaleLeft); + let graph = svg .append("g") .attr( @@ -564,7 +566,7 @@ graph .append("g") .attr("transform", "translate(0," + height + ")") - .call(xAxis.ticks(5)) + .call(xAxis) .selectAll(".tick text") .attr("fill", "black") .select(function() { @@ -575,7 +577,7 @@ graph .append("g") .attr("transform", "translate(" + width + ",0)") - .call(yAxis2) + .call(yAxisRight) .selectAll(".tick text") .attr("fill", "black") .select(function() { @@ -583,6 +585,18 @@ }) .selectAll(".tick line") .attr("stroke", "black"); + graph + .append("g") + .attr("transform", "translate(0 0)") + .call(yAxisLeft) + .selectAll(".tick text") + .attr("fill", "black") + .select(function() { + return this.parentNode; + }) + .selectAll(".tick line") + .attr("stroke", "black"); + graph.selectAll(".domain").attr("stroke", "black"); return { xScale, yScaleRight, graph }; }, @@ -601,7 +615,7 @@ .datum([{ x: 0, y: 0 }, { x: this.totalLength, y: 0 }]) .attr("fill-opacity", 0.65) .attr("fill", WATER_COLOR) - .attr("stroke", WATER_COLOR) + .attr("stroke", "transparent") .attr("d", waterArea); }, drawProfile({ @@ -620,25 +634,27 @@ .x(d => { return xScale(d.x); }) - .y(d => { - return yScaleRight(d.y); - }); + .y(d => + yScaleRight( + d.y + Math.abs(this.waterlevel - this.refWaterlevel) / 100 + ) + ); let profileArea = d3 .area() .x(function(d) { return xScale(d.x); }) .y0(height) - .y1(function(d) { - return yScaleRight(d.y); - }); + .y1(d => + yScaleRight( + d.y + Math.abs(this.waterlevel - this.refWaterlevel) / 100 + ) + ); graph .append("path") .datum(part) .attr("fill", color) - .attr("stroke", color) - .attr("stroke-width", 3) - .attr("stroke-opacity", opacity) + .attr("stroke", "transparent") .attr("fill-opacity", opacity) .attr("d", profileArea); graph
--- a/client/src/components/fairway/Profiles.vue Wed May 29 15:42:32 2019 +0200 +++ b/client/src/components/fairway/Profiles.vue Fri May 31 09:35:09 2019 +0200 @@ -37,7 +37,7 @@ </select> <div v-if="selectedBottleneck"> <div class="d-flex mt-2"> - <div class="flex-fill"> + <div class="flex-fill" style="max-width: 75px;"> <small class="text-muted"> <translate>Waterlevel</translate>: </small> @@ -45,15 +45,11 @@ v-model="selectedWaterLevel" class="form-control form-control-sm small" > - <option value="" v-if="Object.keys(waterLevels).length === 0"> - <translate>Current</translate> + <option value="ref"> + <translate>Depth Reference</translate> </option> - <option - v-for="wl in Object.keys(waterLevels)" - :key="wl" - :value="wl" - > - {{ wl | surveyDate }} + <option value="current"> + <translate>Current Waterlevel</translate> </option> </select> </div> @@ -327,7 +323,7 @@ }, selectedWaterLevel: { get() { - return this.$store.state.fairwayprofile.selectedWaterLevel.date || ""; + return this.$store.state.fairwayprofile.selectedWaterLevel; }, set(value) { this.$store.commit("fairwayprofile/setSelectedWaterLevel", value);
--- a/client/src/components/importconfiguration/ScheduledImports.vue Wed May 29 15:42:32 2019 +0200 +++ b/client/src/components/importconfiguration/ScheduledImports.vue Fri May 31 09:35:09 2019 +0200 @@ -393,6 +393,7 @@ </button> <div> <button + v-if="!currentSchedule.id" @click="triggerManualImport" type="button" class="btn btn-sm btn-outline-info" @@ -568,6 +569,22 @@ return false; } }, + usernamePasswordFilled() { + if ( + this.isCredentialsRequired && + this.currentSchedule.id && + this.username + ) + return true; + if ( + this.isCredentialsRequired && + !this.currentSchedule.id && + this.username && + this.password + ) + return true; + return false; + }, isValid() { if (!this.import_) return false; if (this.isToleranceRequired && !this.tolerance) return false; @@ -576,8 +593,7 @@ if (this.isURLRequired && !this.url) return false; if (this.isSortbyRequired && !this.sortBy) return false; if (this.isFeatureTypeRequired && !this.featureType) return false; - if (this.isCredentialsRequired && (!this.username || !this.password)) - return false; + if (!this.usernamePasswordFilled) return false; if (this.import_ == this.$options.IMPORTTYPES.FAIRWAYDIMENSION) { if ( !this.LOS || @@ -856,12 +872,12 @@ config["tolerance"] = parseFloat(this.tolerance); } if (this.isCredentialsRequired) { - if (!this.username || !this.password) return; + if (!this.usernamePasswordFilled) return; config = { ...config, - user: this.username, - password: this.password + user: this.username }; + if (!this.currentSchedule.id) config["password"] = this.password; } if (this.import_ == this.$options.IMPORTTYPES.FAIRWAYDIMENSION) { if (
--- a/client/src/components/importconfiguration/types/Distancemarksvirtual.vue Wed May 29 15:42:32 2019 +0200 +++ b/client/src/components/importconfiguration/types/Distancemarksvirtual.vue Fri May 31 09:35:09 2019 +0200 @@ -59,7 +59,10 @@ <font-awesome-icon :icon="passwordVisible ? 'eye-slash' : 'eye'" /> </span> </div> - <div v-if="!password" class="d-flex flex-row"> + <div + v-if="!password && !this.currentSchedule.id" + class="d-flex flex-row" + > <small ><translate class="text-danger" >Please enter a Password</translate @@ -85,6 +88,8 @@ * Author(s): * Thomas Junk <thomas.junk@intevation.de> */ + +import { mapState } from "vuex"; export default { name: "distancemarksvirtual", props: ["url", "username", "password"], @@ -94,6 +99,10 @@ }; }, computed: { + ...mapState("importschedule", [ + "importScheduleDetailVisible", + "currentSchedule" + ]), showPassword() { if (this.passwordVisible) return "text"; return "password";
--- a/client/src/components/importconfiguration/types/Waterwaygauges.vue Wed May 29 15:42:32 2019 +0200 +++ b/client/src/components/importconfiguration/types/Waterwaygauges.vue Fri May 31 09:35:09 2019 +0200 @@ -59,7 +59,10 @@ <font-awesome-icon :icon="passwordVisible ? 'eye-slash' : 'eye'" /> </span> </div> - <div v-if="!password" class="d-flex flex-row"> + <div + v-if="!password && !this.currentSchedule.id" + class="d-flex flex-row" + > <small ><translate class="text-danger" >Please enter a Password</translate @@ -85,6 +88,9 @@ * Author(s): * Thomas Junk <thomas.junk@intevation.de> */ + +import { mapState } from "vuex"; + export default { name: "waterwaygauges", props: ["username", "password", "url"], @@ -94,6 +100,10 @@ }; }, computed: { + ...mapState("importschedule", [ + "importScheduleDetailVisible", + "currentSchedule" + ]), showPassword() { if (this.passwordVisible) return "text"; return "password";
--- a/client/src/store/fairwayprofile.js Wed May 29 15:42:32 2019 +0200 +++ b/client/src/store/fairwayprofile.js Fri May 31 09:35:09 2019 +0200 @@ -28,9 +28,7 @@ minAlt: 0, maxAlt: 0, currentProfile: {}, - referenceWaterLevel: null, - waterLevels: {}, - selectedWaterLevel: "", + selectedWaterLevel: "ref", fairwayData: [], startPoint: null, endPoint: null, @@ -61,7 +59,7 @@ state.additionalSurvey = additionalSurvey; }, setSelectedWaterLevel: (state, level) => { - state.selectedWaterLevel = state.waterLevels[level]; + state.selectedWaterLevel = level; }, setDifferencesLoading: (state, value) => { state.differencesLoading = value; @@ -69,8 +67,6 @@ profileLoaded: (state, answer) => { const { response, surveyDate } = answer; const { data } = response; - const { waterlevel } = response.data.properties; - const { value, when } = waterlevel; const coordinates = data.geometry.coordinates; if (!coordinates) return; const startPoint = state.startPoint; @@ -79,12 +75,6 @@ const result = prepareProfile({ geoJSON, startPoint, endPoint }); // Use Vue.set() to make new object properties rective // https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats - const entry = { - date: when, - value: value - }; - state.waterLevels = { [when]: entry }; - state.selectedWaterLevel = entry; Vue.set(state.currentProfile, surveyDate, { points: result.points, length: result.lengthPolyLine @@ -116,9 +106,7 @@ state.fairwayData = []; state.startPoint = null; state.endPoint = null; - state.referenceWaterLevel = null; - state.waterLevels = {}; - state.selectedWaterLevel = ""; + state.selectedWaterLevel = "ref"; }, previousCuts: (state, previousCuts) => { state.previousCuts = previousCuts;
--- a/pkg/controllers/cross.go Wed May 29 15:42:32 2019 +0200 +++ b/pkg/controllers/cross.go Fri May 31 09:35:09 2019 +0200 @@ -21,7 +21,6 @@ "net/http" "time" - "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/models" "gemma.intevation.de/gemma/pkg/octree" ) @@ -167,13 +166,6 @@ Type: "MultiLineString", Coordinates: joined, }, - Properties: map[string]interface{}{ - "waterlevel": map[string]interface{}{ - // TODO: Fetch values from database. - "value": float64(50), - "when": start.Format(common.TimeFormat), - }, - }, }, }
--- a/pkg/controllers/importconfig.go Wed May 29 15:42:32 2019 +0200 +++ b/pkg/controllers/importconfig.go Fri May 31 09:35:09 2019 +0200 @@ -177,9 +177,19 @@ return } - what := ctor() + // Remove `password` from the attributes to be delivered to the client. + // Even a priviledged user shall not be able to see the password. + // (See config.ListAllPersistentConfigurationsContext() for the other + // place where this is done.) + filteredAttributes := make(common.Attributes) + for key, value := range cfg.Attributes { + if key != "password" { + filteredAttributes[key] = value + } + } - if err = cfg.Attributes.Unmarshal(what); err != nil { + what := ctor() + if err = filteredAttributes.Unmarshal(what); err != nil { return }
--- a/pkg/controllers/stretches.go Wed May 29 15:42:32 2019 +0200 +++ b/pkg/controllers/stretches.go Fri May 31 09:35:09 2019 +0200 @@ -418,7 +418,7 @@ return } - from, ok := parseFormTime(rw, req, "form", time.Now().AddDate(-1, 0, 0)) + from, ok := parseFormTime(rw, req, "from", time.Now().AddDate(-1, 0, 0)) if !ok { return }
--- a/pkg/imports/agm.go Wed May 29 15:42:32 2019 +0200 +++ b/pkg/imports/agm.go Fri May 31 09:35:09 2019 +0200 @@ -182,10 +182,12 @@ staging_done ) VALUES ( ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int), - (SELECT validity FROM waterway.gauges - WHERE location - = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) - AND validity @> CAST($6 AS timestamp with time zone)), + COALESCE( + (SELECT validity FROM waterway.gauges + WHERE location + = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) + AND validity @> CAST($6 AS timestamp with time zone)), + tstzrange(NULL, NULL)), $6, $7, $8,
--- a/pkg/imports/bn.go Wed May 29 15:42:32 2019 +0200 +++ b/pkg/imports/bn.go Fri May 31 09:35:09 2019 +0200 @@ -20,6 +20,7 @@ "errors" "regexp" "strconv" + "strings" "time" "gemma.intevation.de/gemma/pkg/soap/ifbn" @@ -63,8 +64,10 @@ ) VALUES ( $1, isrs_fromText($2), - (SELECT validity FROM waterway.gauges - WHERE location = isrs_fromText($2) AND NOT erased), + COALESCE( + (SELECT validity FROM waterway.gauges + WHERE location = isrs_fromText($2) AND NOT erased), + tstzrange(NULL, NULL)), $3, $4, isrsrange(least(isrs_fromText($5), isrs_fromText($6)), @@ -268,10 +271,12 @@ rb, lb := splitRBLB(bn.Rb_lb) var revisitingTime *int - if bn.Revisiting_time != nil { + if bn.Revisiting_time != nil && + len(strings.TrimSpace(*bn.Revisiting_time)) > 0 { i, err := strconv.Atoi(*bn.Revisiting_time) if err != nil { - feedback.Warn("Cannot convert '%s' to number of months", + feedback.Warn( + "Cannot convert given revisiting time '%s' to number of months", *bn.Revisiting_time) } else { revisitingTime = &i
--- a/pkg/imports/config.go Wed May 29 15:42:32 2019 +0200 +++ b/pkg/imports/config.go Fri May 31 09:35:09 2019 +0200 @@ -269,7 +269,12 @@ if pc.Attributes == nil { pc.Attributes = common.Attributes{} } - pc.Attributes.Set(k.String, v.String) + // Prevent sending the `password` back to the client. + // (See importconfig.infoImportConfig() for the other place + // where this is done.) + if k.String != "password" { + pc.Attributes.Set(k.String, v.String) + } } }
--- a/pkg/imports/errors.go Wed May 29 15:42:32 2019 +0200 +++ b/pkg/imports/errors.go Fri May 31 09:35:09 2019 +0200 @@ -57,10 +57,10 @@ switch err.SchemaName { case "waterway": switch err.TableName { - case "gauge_measurements": + case "gauge_measurements", "gauge_predictions", "bottlenecks": switch err.ConstraintName { case "gauge_key": - return "Referenced gauge is not in database" + return "Referenced gauge with matching temporal validity not available" } } }
--- a/pkg/imports/gm.go Wed May 29 15:42:32 2019 +0200 +++ b/pkg/imports/gm.go Fri May 31 09:35:09 2019 +0200 @@ -73,10 +73,12 @@ staging_done ) VALUES ( ($1, $2, $3, $4, $5), - (SELECT validity FROM waterway.gauges - WHERE location - = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) - AND validity @> CAST($6 AS timestamp with time zone)), + COALESCE( + (SELECT validity FROM waterway.gauges + WHERE location + = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) + AND validity @> CAST($6 AS timestamp with time zone)), + tstzrange(NULL, NULL)), $6, $7, $8, @@ -108,10 +110,12 @@ source_organization ) VALUES( ($1, $2, $3, $4, $5), - (SELECT validity FROM waterway.gauges - WHERE location - = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) - AND validity @> CAST($6 AS timestamp with time zone)), + COALESCE( + (SELECT validity FROM waterway.gauges + WHERE location + = ($1::char(2), $2::char(3), $3::char(5), $4::char(5), $5::int) + AND validity @> CAST($6 AS timestamp with time zone)), + tstzrange(NULL, NULL)), $6, $7, $8,
--- a/pkg/imports/sr.go Wed May 29 15:42:32 2019 +0200 +++ b/pkg/imports/sr.go Fri May 31 09:35:09 2019 +0200 @@ -164,7 +164,8 @@ selectGaugeLDCSQL = ` SELECT - grwl.value + grwl.value, + grwl.depth_reference FROM waterway.gauges_reference_water_levels grwl JOIN waterway.bottlenecks bns ON grwl.location = bns.gauge_location @@ -208,7 +209,11 @@ if m.DepthReference == "ZPG" { feedback.Info("Found ZPG as reference system -> translating Z values to LDC") var ldc float64 - err := conn.QueryRowContext(ctx, selectGaugeLDCSQL, m.Bottleneck).Scan(&ldc) + var depthReference string + err := conn.QueryRowContext(ctx, selectGaugeLDCSQL, m.Bottleneck).Scan( + &ldc, + &depthReference, + ) switch { case err == sql.ErrNoRows: return nil, errors.New("Cannot load LDC value") @@ -218,7 +223,7 @@ xform = func(v octree.Vertex) octree.Vertex { return octree.Vertex{X: v.X, Y: v.Y, Z: ldc - v.Z} } - m.DepthReference = "LDC" + m.DepthReference = depthReference } if err := m.Validate(ctx, conn); err != nil {
--- a/pkg/imports/wg.go Wed May 29 15:42:32 2019 +0200 +++ b/pkg/imports/wg.go Fri May 31 09:35:09 2019 +0200 @@ -235,10 +235,10 @@ gauges = append(gauges, isrs) feedback.Info("Processing %s", code) - // We need a valid time range to identify gauge versions in DB + // We need a valid, non-empty time range to identify gauge versions if dr.Enddate != nil && dr.Startdate != nil && - time.Time(*dr.Enddate).Before(time.Time(*dr.Startdate)) { - feedback.Warn("End date before start date") + !time.Time(*dr.Enddate).After(time.Time(*dr.Startdate)) { + feedback.Warn("End date not after start date") unchanged++ continue }
--- a/schema/gemma.sql Wed May 29 15:42:32 2019 +0200 +++ b/schema/gemma.sql Fri May 31 09:35:09 2019 +0200 @@ -280,7 +280,7 @@ geom geography(POINT, 4326) NOT NULL, applicability_from_km int8, applicability_to_km int8, - validity tstzrange, + validity tstzrange NOT NULL, zero_point double precision NOT NULL, geodref varchar, date_info timestamp with time zone NOT NULL, @@ -288,6 +288,7 @@ lastupdate timestamp with time zone NOT NULL, -- entry removed from external data source (RIS-Index)/historicised: erased boolean NOT NULL DEFAULT false, + CHECK (erased OR NOT isempty(validity)), PRIMARY KEY (location, validity), EXCLUDE USING GiST (isrs_astext(location) WITH =, validity WITH &&) DEFERRABLE INITIALLY DEFERRED @@ -490,9 +491,9 @@ bottleneck_id varchar UNIQUE NOT NULL, gauge_location isrs NOT NULL, gauge_validity tstzrange NOT NULL, - FOREIGN KEY (gauge_location, gauge_validity) REFERENCES gauges - ON UPDATE CASCADE, - -- XXX: DRC references "ch. 3.1.1", which does not exist in document. + CONSTRAINT gauge_key + FOREIGN KEY (gauge_location, gauge_validity) REFERENCES gauges + ON UPDATE CASCADE, objnam varchar, nobjnm varchar, stretch isrsrange NOT NULL,