From 3428cda9d18529089b384482cfdfbe09e1ec4836 Mon Sep 17 00:00:00 2001 From: Olivier Maury <Olivier.Maury@inrae.fr> Date: Wed, 13 Mar 2024 10:50:44 +0100 Subject: [PATCH] =?UTF-8?q?Limiter=20la=20p=C3=A9riode=20affich=C3=A9e=20s?= =?UTF-8?q?ur=20le=20graphique.=20fixes=20#20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/init_data.h2.sql | 18 +-- sql/init_data.postgresql.sql | 10 +- sql/migration.sql | 123 ++++++++++-------- sql/periods.csv | 8 +- sql/schema.tables.sql | 4 + sql/test_sql_on_postgresql.sh | 10 ++ .../agrometinfo/www/server/model/Period.java | 10 ++ .../www/server/rs/IndicatorResource.java | 25 +++- 8 files changed, 133 insertions(+), 75 deletions(-) create mode 100755 sql/test_sql_on_postgresql.sh diff --git a/sql/init_data.h2.sql b/sql/init_data.h2.sql index 61324b1..af14566 100644 --- a/sql/init_data.h2.sql +++ b/sql/init_data.h2.sql @@ -55,11 +55,13 @@ INSERT INTO cellpra (cell, pra, ratio) -- period CREATE TEMPORARY TABLE IF NOT EXISTS tmp_period ( code VARCHAR, - phase VARCHAR + phase VARCHAR, + firstday VARCHAR, + lastday VARCHAR ); -INSERT INTO tmp_period (code, phase) SELECT * FROM CSVREAD('../sql/periods.csv'); -INSERT INTO period (code, name, phase) - SELECT t.code, k.id, t.phase +INSERT INTO tmp_period (code, phase, firstday, lastday) SELECT * FROM CSVREAD('../sql/periods.csv'); +INSERT INTO period (code, name, phase, firstday, lastday) + SELECT t.code, k.id, t.phase, t.firstday, t.lastday FROM tmp_period AS t JOIN i18nkey AS k ON k.string=t.code; @@ -90,7 +92,7 @@ CREATE TEMPORARY TABLE IF NOT EXISTS tmp_dailyvalue ( comparedvalue DOUBLE PRECISION ); INSERT INTO tmp_dailyvalue (indicator, period, cell, date, computedvalue, comparedvalue) - SELECT * FROM CSVREAD('../sql/dailyvalues.csv'); + SELECT * FROM CSVREAD('../sql/dailyvalues.csv'); INSERT INTO dailyvalue (indicator, cell, date, computedvalue, comparedvalue) SELECT i.id, t.cell, t.date, t.computedvalue, t.comparedvalue FROM tmp_dailyvalue AS t @@ -107,7 +109,7 @@ CREATE TEMPORARY TABLE IF NOT EXISTS tmp_normalvalue ( computedvalue DOUBLE PRECISION ); INSERT INTO tmp_normalvalue (indicator, period, cell, doy, computedvalue) - SELECT * FROM CSVREAD('../sql/normalvalues.csv'); + SELECT * FROM CSVREAD('../sql/normalvalues.csv'); INSERT INTO normalvalue (indicator, cell, doy, computedvalue) SELECT i.id, t.cell, t.doy, t.computedvalue FROM tmp_normalvalue AS t @@ -117,5 +119,5 @@ INSERT INTO normalvalue (indicator, cell, doy, computedvalue) -- simulation INSERT INTO simulation (date, simulationid, started, ended) VALUES - ('2024-02-19', 1, '2024-02-20 12:00:00', '2024-02-20 12:30:00'), - ('2024-02-20', 2, '2024-02-21 13:00:00', NULL); \ No newline at end of file + ('2024-02-19', 1, '2024-02-20 12:00:00', '2024-02-20 12:30:00'), + ('2024-02-20', 2, '2024-02-21 13:00:00', NULL); diff --git a/sql/init_data.postgresql.sql b/sql/init_data.postgresql.sql index e5cd199..84c10d4 100644 --- a/sql/init_data.postgresql.sql +++ b/sql/init_data.postgresql.sql @@ -63,11 +63,13 @@ INSERT INTO cell (id, lat, lon, lat1, lon1, lat2, lon2, lat3, lon3, lat4, lon4, -- period CREATE TEMPORARY TABLE IF NOT EXISTS tmp_period ( code VARCHAR, - phase VARCHAR + phase VARCHAR, + firstday VARCHAR, + lastday VARCHAR ); -\COPY tmp_period (code, phase) FROM periods.csv WITH DELIMITER ',' HEADER CSV; -INSERT INTO period (code, name, phase) - SELECT t.code, k.id, t.phase +\COPY tmp_period (code, phase, firstday, lastday) FROM periods.csv WITH DELIMITER ',' HEADER CSV; +INSERT INTO period (code, name, phase, firstday, lastday) + SELECT t.code, k.id, t.phase, t.firstday, t.lastday FROM tmp_period AS t JOIN i18nkey AS k ON k.string=t.code; diff --git a/sql/migration.sql b/sql/migration.sql index 83d6144..e4094c6 100644 --- a/sql/migration.sql +++ b/sql/migration.sql @@ -36,21 +36,21 @@ BEGIN SELECT schemaversion() INTO schemaversion; RAISE INFO '% Apply migrations after %...', TIMEOFDAY(), schemaversion; FOR routine IN - SELECT - routine_name, - substring(routine_name, 8) AS migration_version - FROM information_schema.routines - WHERE routine_type = 'FUNCTION' AND - routine_name LIKE 'upgrade20%' AND - substring(routine_name, 8) NOT IN (SELECT version FROM dbmigration) AND - substring(routine_name, 8) > schemaversion - ORDER BY routine_name + SELECT + routine_name, + substring(routine_name, 8) AS migration_version + FROM information_schema.routines + WHERE routine_type = 'FUNCTION' AND + routine_name LIKE 'upgrade20%' AND + substring(routine_name, 8) NOT IN (SELECT version FROM dbmigration) AND + substring(routine_name, 8) > schemaversion + ORDER BY routine_name LOOP - RAISE INFO '% %() start', TIMEOFDAY(), routine.routine_name; - EXECUTE format('SELECT %I()', routine.routine_name); - INSERT INTO dbmigration (version) values(routine.migration_version); - RAISE INFO '% %() end', TIMEOFDAY(), routine.routine_name; - applied := applied + 1; + RAISE INFO '% %() start', TIMEOFDAY(), routine.routine_name; + EXECUTE format('SELECT %I()', routine.routine_name); + INSERT INTO dbmigration (version) values(routine.migration_version); + RAISE INFO '% %() end', TIMEOFDAY(), routine.routine_name; + applied := applied + 1; END LOOP; RAISE INFO '% % migrations were applied', TIMEOFDAY(), applied; RETURN applied; @@ -90,19 +90,19 @@ COMMENT ON FUNCTION drop_applied_migration_functions() IS 'Purge database from a --- CREATE OR REPLACE FUNCTION upgrade20231023() RETURNS boolean AS $BODY$ BEGIN - ALTER TABLE indicator DROP COLUMN colorsequence; - DROP TABLE colorsequence; - ALTER TABLE indicator ADD COLUMN colorsequencename VARCHAR; - ALTER TABLE indicator ADD COLUMN nbofclasses INTEGER; - CREATE TYPE QUANTILETYPE AS ENUM('CENTILES_05', 'QUANTILES', 'DECILES', 'QUINTILES', 'QUARTILES'); - ALTER TABLE indicator ADD COLUMN quantiletype QUANTILETYPE; - UPDATE indicator SET quantiletype='QUINTILES'; - UPDATE indicator SET colorsequencename='Precipitation' WHERE code='rainsum'; - UPDATE indicator SET colorsequencename='Blues' WHERE code='frostdaystmin'; - UPDATE indicator SET colorsequencename='Temperature' WHERE code IN ('mint', 'meant', 'maxt'); - UPDATE indicator SET colorsequencename='YlOrRd' WHERE code IN ('hdaystmax', 'hdaystmax1'); - ALTER TABLE indicator ADD CONSTRAINT "CK_indicator_colorsequence" CHECK (nbofclasses IS NOT NULL OR quantiletype IS NOT NULL); - RETURN true; + ALTER TABLE indicator DROP COLUMN colorsequence; + DROP TABLE colorsequence; + ALTER TABLE indicator ADD COLUMN colorsequencename VARCHAR; + ALTER TABLE indicator ADD COLUMN nbofclasses INTEGER; + CREATE TYPE QUANTILETYPE AS ENUM('CENTILES_05', 'QUANTILES', 'DECILES', 'QUINTILES', 'QUARTILES'); + ALTER TABLE indicator ADD COLUMN quantiletype QUANTILETYPE; + UPDATE indicator SET quantiletype='QUINTILES'; + UPDATE indicator SET colorsequencename='Precipitation' WHERE code='rainsum'; + UPDATE indicator SET colorsequencename='Blues' WHERE code='frostdaystmin'; + UPDATE indicator SET colorsequencename='Temperature' WHERE code IN ('mint', 'meant', 'maxt'); + UPDATE indicator SET colorsequencename='YlOrRd' WHERE code IN ('hdaystmax', 'hdaystmax1'); + ALTER TABLE indicator ADD CONSTRAINT "CK_indicator_colorsequence" CHECK (nbofclasses IS NOT NULL OR quantiletype IS NOT NULL); + RETURN true; END $BODY$ language plpgsql; @@ -112,23 +112,23 @@ language plpgsql; --- CREATE OR REPLACE FUNCTION upgrade20231030() RETURNS boolean AS $BODY$ BEGIN - ALTER TABLE "indicator" ALTER COLUMN quantiletype TYPE VARCHAR USING QUANTILETYPE::VARCHAR; - DROP TYPE QUANTILETYPE; - CREATE TYPE QUANTILETYPE AS ENUM('CENTILES_05', 'QUANTILES', 'DECILES', 'QUINTILES', 'QUARTILES', 'SEXTILES'); - ALTER TABLE "indicator" ALTER COLUMN quantiletype TYPE QUANTILETYPE USING quantiletype::quantiletype; - UPDATE indicator SET quantiletype='SEXTILES'; - --- #12 - CREATE TYPE AGGREGATIONTYPE AS ENUM('AVG', 'MAX'); - ALTER TABLE "indicator" ADD COLUMN aggregationtype AGGREGATIONTYPE; - UPDATE indicator SET unit='mm' WHERE code IN ('rainsum'); - UPDATE indicator SET unit='j' WHERE code IN ('frostdaystmin', 'hdaystmax', 'hdaystmax1'); - UPDATE indicator SET unit='°C' WHERE code IN ('maxt', 'meant', 'mint'); - UPDATE indicator SET aggregationtype='MAX' WHERE code IN ('frostdaystmin', 'hdaystmax', 'hdaystmax1', 'rainsum'); - UPDATE indicator SET aggregationtype='AVG' WHERE code IN ('maxt', 'meant', 'mint'); - ALTER TABLE "indicator" ALTER COLUMN aggregationtype SET NOT NULL; - --- #8 - UPDATE indicator SET colorsequencename='TemperatureReversed' WHERE code IN ('mint', 'meant', 'maxt'); - RETURN true; + ALTER TABLE "indicator" ALTER COLUMN quantiletype TYPE VARCHAR USING QUANTILETYPE::VARCHAR; + DROP TYPE QUANTILETYPE; + CREATE TYPE QUANTILETYPE AS ENUM('CENTILES_05', 'QUANTILES', 'DECILES', 'QUINTILES', 'QUARTILES', 'SEXTILES'); + ALTER TABLE "indicator" ALTER COLUMN quantiletype TYPE QUANTILETYPE USING quantiletype::quantiletype; + UPDATE indicator SET quantiletype='SEXTILES'; + --- #12 + CREATE TYPE AGGREGATIONTYPE AS ENUM('AVG', 'MAX'); + ALTER TABLE "indicator" ADD COLUMN aggregationtype AGGREGATIONTYPE; + UPDATE indicator SET unit='mm' WHERE code IN ('rainsum'); + UPDATE indicator SET unit='j' WHERE code IN ('frostdaystmin', 'hdaystmax', 'hdaystmax1'); + UPDATE indicator SET unit='°C' WHERE code IN ('maxt', 'meant', 'mint'); + UPDATE indicator SET aggregationtype='MAX' WHERE code IN ('frostdaystmin', 'hdaystmax', 'hdaystmax1', 'rainsum'); + UPDATE indicator SET aggregationtype='AVG' WHERE code IN ('maxt', 'meant', 'mint'); + ALTER TABLE "indicator" ALTER COLUMN aggregationtype SET NOT NULL; + --- #8 + UPDATE indicator SET colorsequencename='TemperatureReversed' WHERE code IN ('mint', 'meant', 'maxt'); + RETURN true; END $BODY$ language plpgsql; @@ -138,8 +138,8 @@ language plpgsql; -- CREATE OR REPLACE FUNCTION upgrade20231215() RETURNS boolean AS $BODY$ BEGIN - INSERT INTO department (id, "name", region) VALUES(75, '75 - Paris', 75); - RETURN true; + INSERT INTO department (id, "name", region) VALUES(75, '75 - Paris', 75); + RETURN true; END $BODY$ language plpgsql; @@ -149,9 +149,9 @@ language plpgsql; -- CREATE OR REPLACE FUNCTION upgrade20240220() RETURNS boolean AS $BODY$ BEGIN - INSERT INTO simulation (date, simulationid, started, ended) VALUES - ('2024-02-19', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); - RETURN true; + INSERT INTO simulation (date, simulationid, started, ended) VALUES + ('2024-02-19', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); + RETURN true; END $BODY$ language plpgsql; @@ -161,10 +161,27 @@ language plpgsql; -- CREATE OR REPLACE FUNCTION upgrade20240306() RETURNS boolean AS $BODY$ BEGIN - CREATE INDEX IF NOT EXISTS "IX_dailyvalue" ON dailyvalue (date, indicator); - ALTER TABLE indicator DROP COLUMN aggregationtype; - DROP TYPE AGGREGATIONTYPE; - RETURN true; + CREATE INDEX IF NOT EXISTS "IX_dailyvalue" ON dailyvalue USING btree (date, indicator); + ALTER TABLE indicator DROP COLUMN aggregationtype; + DROP TYPE AGGREGATIONTYPE; + RETURN true; +END +$BODY$ +language plpgsql; + +-- +-- #20 +-- +CREATE OR REPLACE FUNCTION upgrade20240313() RETURNS boolean AS $BODY$ +BEGIN + ALTER TABLE period ADD COLUMN firstday VARCHAR(10); + ALTER TABLE period ADD COLUMN lastday VARCHAR(10); + UPDATE period SET firstday='YYYY-01-01', lastday='YYYY-12-31' WHERE code='year'; + UPDATE period SET firstday='YYYY-04-01', lastday='YYYY-10-15' WHERE code='summer'; + UPDATE period SET firstday='XXXX-10-31', lastday='YYYY-08-31' WHERE code='winter'; + ALTER TABLE period ALTER COLUMN firstday SET NOT NULL; + ALTER TABLE period ALTER COLUMN lastday SET NOT NULL; + RETURN true; END $BODY$ language plpgsql; diff --git a/sql/periods.csv b/sql/periods.csv index 97291a0..099bccc 100644 --- a/sql/periods.csv +++ b/sql/periods.csv @@ -1,4 +1,4 @@ -code,phase -year,s2s8 -summer,s4s7 -winter,s1s6 \ No newline at end of file +code,phase,firstday,lastday +year,s2s8,YYYY-01-01,YYYY-12-31 +summer,s4s7,YYYY-04-01,YYYY-10-15 +winter,s1s6,XXXX-10-31,YYYY-08-31 \ No newline at end of file diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql index 7d7074a..169877d 100644 --- a/sql/schema.tables.sql +++ b/sql/schema.tables.sql @@ -132,6 +132,8 @@ CREATE TABLE IF NOT EXISTS period ( code VARCHAR NOT NULL, name INTEGER NOT NULL, phase VARCHAR NOT NULL, + firstday VARCHAR(10) NOT NULL, + lastday VARCHAR(10) NOT NULL, created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "PK_period" PRIMARY KEY (id), CONSTRAINT "FK_period_i18n" FOREIGN KEY (name) REFERENCES i18n (id), @@ -139,6 +141,8 @@ CREATE TABLE IF NOT EXISTS period ( ); COMMENT ON TABLE period IS 'Period when the indicator is computed.'; COMMENT ON COLUMN period.phase IS 'Related phase name from GETARI file.'; +COMMENT ON COLUMN period.firstday IS 'The first day of the agroclimatic phase.'; +COMMENT ON COLUMN period.lastday IS 'The last day of the agroclimatic phase.'; CREATE TABLE IF NOT EXISTS indicator ( id SERIAL, diff --git a/sql/test_sql_on_postgresql.sh b/sql/test_sql_on_postgresql.sh new file mode 100755 index 0000000..a1a3802 --- /dev/null +++ b/sql/test_sql_on_postgresql.sh @@ -0,0 +1,10 @@ +#!/bin/bash +cd $(dirname $0) +dropdb agrometinfotmp +createdb agrometinfotmp +psql agrometinfotmp -1 -f schema.types.postgresql.sql +psql agrometinfotmp -1 -f schema.tables.sql +psql agrometinfotmp -1 -f init_data.postgresql.sql +sleep 1 +dropdb agrometinfotmp +echo "done" diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Period.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Period.java index 2f4a63e..0292122 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Period.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Period.java @@ -36,6 +36,16 @@ public class Period { */ @Column(name = "code") private String code; + /** + * First day of agroclimatic phase. + */ + @Column(name = "firstday") + private String firstDay; + /** + * Last day of agroclimatic phase. + */ + @Column(name = "lastday") + private String lastDay; /** * Defined to use in @JoinTable. */ diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java index 465e6d6..907b1d2 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/IndicatorResource.java @@ -3,7 +3,6 @@ package fr.agrometinfo.www.server.rs; import static fr.agrometinfo.www.server.util.GeometryUtils.toFeature; import java.time.LocalDate; -import java.time.ZoneId; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -62,6 +61,19 @@ import lombok.extern.log4j.Log4j2; @RequestScoped public class IndicatorResource implements IndicatorService { + /** + * Get the date related to the year. + * + * @param year year + * @param dateTemplate date template with YYYY for year and XXXX for previous year + * @return date from template. + */ + private static LocalDate getDate(final Integer year, final String dateTemplate) { + return LocalDate.parse(dateTemplate// + .replace("YYYY", String.valueOf(year))// + .replace("XXXX", String.valueOf(year - 1))); + } + private static String getTranslation(final Map<String, String> names, final Locale locale) { final var locales = List.of(locale, Locale.FRENCH, Locale.ENGLISH); for (final Locale l : locales) { @@ -304,6 +316,8 @@ public class IndicatorResource implements IndicatorService { .build()); } + final var firstDay = getDate(year, indicator.getPeriod().getFirstDay()); + final var lastDay = getDate(year, indicator.getPeriod().getLastDay()); final var date = praDailyValueDao.findLastDate(indicator, year); final Double averageValue; final Double comparedValue; @@ -311,7 +325,6 @@ public class IndicatorResource implements IndicatorService { // By default, all key-value pairs in TreeMap are sorted in their natural // ordering. final Map<Date, Float> dailyValues = new TreeMap<>(); - final LocalDate yearAgo = date.minusYears(1); final SimpleFeature parentFeature; final String featureName; if (level == FeatureLevel.REGION) { @@ -332,12 +345,12 @@ public class IndicatorResource implements IndicatorService { featureName = null; averageValue = praDailyValueDao.findAverageComputedValue(indicator, date); comparedValue = praDailyValueDao.findAverageComparedValue(indicator, date); - tmpDailyValues = praDailyValueDao.findDailyValues(indicator, yearAgo, date); + tmpDailyValues = praDailyValueDao.findDailyValues(indicator, firstDay, lastDay); parentFeature = null; } else { averageValue = praDailyValueDao.findAverageComputedValue(indicator, date, regionId); comparedValue = praDailyValueDao.findAverageComparedValue(indicator, date, regionId); - tmpDailyValues = praDailyValueDao.findDailyValues(indicator, yearAgo, date, region); + tmpDailyValues = praDailyValueDao.findDailyValues(indicator, firstDay, lastDay, region); featureName = region.getName(); parentFeature = null; } @@ -346,7 +359,7 @@ public class IndicatorResource implements IndicatorService { final PraDailyValue value = praDailyValueDao.find(indicator, date, pra); averageValue = value.getComputedValue().doubleValue(); comparedValue = value.getComparedValue().doubleValue(); - tmpDailyValues = praDailyValueDao.findDailyValues(indicator, yearAgo, date, pra); + tmpDailyValues = praDailyValueDao.findDailyValues(indicator, firstDay, lastDay, pra); featureName = pra.getName(); parentFeature = new SimpleFeature(); parentFeature.setId(String.valueOf(pra.getDepartment().getRegion().getId())); @@ -371,7 +384,7 @@ public class IndicatorResource implements IndicatorService { if (comparedValue != null) { dto.setComparedValue(comparedValue.floatValue()); } - dto.setDate(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant())); + dto.setDate(DateUtils.toDate(date)); dto.setDailyValues(dailyValues); if (featureName != null) { dto.setFeatureName(featureName); -- GitLab