mirror of https://github.com/bvn13/covid19-ru.git
added previous stats data to api responses - per each stats data provided
parent
c70993ebff
commit
3006a00ebb
|
@ -24,7 +24,7 @@ import java.time.LocalDateTime;
|
|||
@Data
|
||||
@Entity
|
||||
@Table(schema = "covid", name = "cvd_stats")
|
||||
public class CovidStat {
|
||||
public class CovidStat implements StatsProvider {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "cvd_stats_seq")
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
Copyright [2020] [bvn13]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bvn13.covid19.model.entities;
|
||||
|
||||
public interface StatsProvider {
|
||||
long getSick();
|
||||
long getHealed();
|
||||
long getDied();
|
||||
}
|
|
@ -1,11 +1,30 @@
|
|||
/*
|
||||
Copyright [2020] [bvn13]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bvn13.covid19.site.controllers;
|
||||
|
||||
import com.bvn13.covid19.model.entities.CovidStat;
|
||||
import com.bvn13.covid19.model.entities.CovidUpdate;
|
||||
import com.bvn13.covid19.model.entities.Region;
|
||||
import com.bvn13.covid19.model.entities.StatsProvider;
|
||||
import com.bvn13.covid19.site.model.CovidAllStats;
|
||||
import com.bvn13.covid19.site.model.CovidData;
|
||||
import com.bvn13.covid19.site.model.CovidDayStats;
|
||||
import com.bvn13.covid19.site.service.CovidStatsMaker;
|
||||
import com.bvn13.covid19.site.service.CovidStatsResponseMaker;
|
||||
import com.bvn13.covid19.site.repositories.RegionsRepository;
|
||||
import com.bvn13.covid19.site.service.StatisticsPreparator;
|
||||
import com.bvn13.covid19.site.service.StatisticsAggregator;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
@ -16,10 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
|
@ -27,8 +43,9 @@ import java.util.stream.Collectors;
|
|||
@RequestMapping("/stats")
|
||||
public class AllStatsController {
|
||||
|
||||
private final CovidStatsMaker covidStatsMaker;
|
||||
private final CovidStatsResponseMaker covidStatsResponseMaker;
|
||||
private final StatisticsPreparator statisticsPreparator;
|
||||
private final StatisticsAggregator statisticsAggregator;
|
||||
private final RegionsRepository regionsRepository;
|
||||
|
||||
@Value("${app.zone-id}")
|
||||
private String zoneIdStr;
|
||||
|
@ -51,45 +68,53 @@ public class AllStatsController {
|
|||
}
|
||||
|
||||
private CovidAllStats constructResponseForRegion(String regionName) {
|
||||
return CovidAllStats.builder()
|
||||
.regions(Collections.singletonList(regionName))
|
||||
.progress(covidStatsMaker.findAllLastUpdatesPerDay().stream()
|
||||
.map(covidUpdate -> CovidDayStats.builder()
|
||||
.datetime(covidUpdate.getDatetime())
|
||||
.updatedOn(covidUpdate.getCreatedOn().atZone(zoneId))
|
||||
.stats(convertStatsToData(findCovidStatsByUpdateIdAndRegion(covidUpdate.getId(), regionName)))
|
||||
.build())
|
||||
.sorted(CovidDayStats::compareTo)
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
return regionsRepository.findFirstByName(regionName)
|
||||
.map(region -> CovidAllStats.builder()
|
||||
.regions(Collections.singletonList(region.getName()))
|
||||
.progress(compoundProgressForRegions(Collections.singletonList(region)))
|
||||
.build()
|
||||
)
|
||||
.orElse(CovidAllStats.builder()
|
||||
.regions(Collections.singletonList(regionName))
|
||||
.progress(Collections.emptyList())
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
private CovidAllStats constructResponseForAllRegions() {
|
||||
return CovidAllStats.builder()
|
||||
.regions(covidStatsMaker.findAllRegionsNames())
|
||||
.progress(covidStatsMaker.findAllLastUpdatesPerDay().stream()
|
||||
.map(covidUpdate -> CovidDayStats.builder()
|
||||
.datetime(covidUpdate.getDatetime())
|
||||
.updatedOn(covidUpdate.getCreatedOn().atZone(zoneId))
|
||||
.stats(convertStatsToData(findCovidStatsByUpdateId(covidUpdate.getId())))
|
||||
.build())
|
||||
.sorted(CovidDayStats::compareTo)
|
||||
.collect(Collectors.toList()))
|
||||
.regions(statisticsPreparator.findAllRegionsNames())
|
||||
.progress(compoundProgressForRegions(regionsRepository.findAll()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<CovidData> convertStatsToData(Collection<CovidStat> stats) {
|
||||
return covidStatsResponseMaker.convertStats(stats);
|
||||
}
|
||||
|
||||
private List<CovidStat> findCovidStatsByUpdateIdAndRegion(long updateId, String region) {
|
||||
return covidStatsMaker.findCovidStatsByUpdateInfoId(updateId).stream()
|
||||
.filter(covidStat -> region.equals(covidStat.getRegion().getName()))
|
||||
private List<CovidDayStats> compoundProgressForRegions(List<Region> regions) {
|
||||
return statisticsPreparator.findAllLastUpdatesPerDay().stream()
|
||||
.map(covidUpdate -> prepareDayStats(covidUpdate, regions))
|
||||
.sorted(CovidDayStats::compareTo)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<CovidStat> findCovidStatsByUpdateId(long updateId) {
|
||||
return new ArrayList<>(covidStatsMaker.findCovidStatsByUpdateInfoId(updateId));
|
||||
private CovidDayStats prepareDayStats(CovidUpdate currentUpdate, List<Region> regions) {
|
||||
List<CovidStat> currentStats = findCovidStatsByUpdateIdAndRegion(currentUpdate.getId(), regions);
|
||||
Optional<CovidUpdate> prevUpdate = statisticsPreparator.findPrevUpdateByDate(currentUpdate.getDatetime());
|
||||
Map<Region, StatsProvider> prevStats = prevUpdate
|
||||
.map(covidUpdate -> statisticsPreparator.findCovidStatsByUpdateInfoId(covidUpdate.getId()).stream()
|
||||
.collect(Collectors.toMap(CovidStat::getRegion, (cs) -> (StatsProvider) cs))
|
||||
)
|
||||
.orElseGet(() -> new HashMap<>(0));
|
||||
|
||||
return CovidDayStats.builder()
|
||||
.datetime(currentUpdate.getDatetime())
|
||||
.updatedOn(currentUpdate.getCreatedOn().atZone(zoneId))
|
||||
.stats(statisticsAggregator.prepareStats(currentStats, prevStats))
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<CovidStat> findCovidStatsByUpdateIdAndRegion(long updateId, List<Region> regions) {
|
||||
return statisticsPreparator.findCovidStatsByUpdateInfoId(updateId).stream()
|
||||
.filter(covidStat -> regions.contains(covidStat.getRegion()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,9 +16,13 @@ limitations under the License.
|
|||
|
||||
package com.bvn13.covid19.site.controllers;
|
||||
|
||||
import com.bvn13.covid19.model.entities.CovidStat;
|
||||
import com.bvn13.covid19.model.entities.CovidUpdate;
|
||||
import com.bvn13.covid19.model.entities.Region;
|
||||
import com.bvn13.covid19.model.entities.StatsProvider;
|
||||
import com.bvn13.covid19.site.model.CovidDayStats;
|
||||
import com.bvn13.covid19.site.service.CovidStatsMaker;
|
||||
import com.bvn13.covid19.site.service.CovidStatsResponseMaker;
|
||||
import com.bvn13.covid19.site.service.StatisticsPreparator;
|
||||
import com.bvn13.covid19.site.service.StatisticsAggregator;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
@ -27,14 +31,19 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/stats")
|
||||
public class LastStatsController {
|
||||
|
||||
private final CovidStatsMaker covidStatsMaker;
|
||||
private final CovidStatsResponseMaker covidStatsResponseMaker;
|
||||
private final StatisticsPreparator statisticsPreparator;
|
||||
private final StatisticsAggregator statisticsAggregator;
|
||||
|
||||
@Value("${app.zone-id}")
|
||||
private String zoneIdStr;
|
||||
|
@ -47,13 +56,24 @@ public class LastStatsController {
|
|||
|
||||
@GetMapping("/last")
|
||||
public CovidDayStats getStatistics() {
|
||||
return covidStatsMaker.findLastUpdate()
|
||||
.map(covidUpdate -> CovidDayStats.builder()
|
||||
.datetime(covidUpdate.getDatetime())
|
||||
.updatedOn(covidUpdate.getCreatedOn().atZone(zoneId))
|
||||
.stats(covidStatsResponseMaker.convertStats(covidStatsMaker.findCovidStatsByUpdateInfoId(covidUpdate.getId())))
|
||||
.build())
|
||||
.orElse(CovidDayStats.builder().build());
|
||||
Optional<CovidUpdate> lastUpdate = statisticsPreparator.findLastUpdate();
|
||||
if (lastUpdate.isPresent()) {
|
||||
Collection<CovidStat> currentStats = statisticsPreparator.findCovidStatsByUpdateInfoId(lastUpdate.get().getId());
|
||||
Optional<CovidUpdate> prevUpdate = statisticsPreparator.findPrevUpdateByDate(lastUpdate.get().getDatetime());
|
||||
Map<Region, StatsProvider> prevStats = prevUpdate
|
||||
.map(covidUpdate -> statisticsPreparator.findCovidStatsByUpdateInfoId(covidUpdate.getId()).stream()
|
||||
.collect(Collectors.toMap(CovidStat::getRegion, (cs) -> (StatsProvider) cs))
|
||||
)
|
||||
.orElseGet(() -> new HashMap<>(0));
|
||||
|
||||
return CovidDayStats.builder()
|
||||
.datetime(lastUpdate.get().getDatetime())
|
||||
.updatedOn(lastUpdate.get().getCreatedOn().atZone(zoneId))
|
||||
.stats(statisticsAggregator.prepareStats(currentStats, prevStats))
|
||||
.build();
|
||||
} else {
|
||||
return CovidDayStats.builder().build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
/*
|
||||
Copyright [2020] [bvn13]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bvn13.covid19.site.controllers;
|
||||
|
||||
import com.bvn13.covid19.site.service.CovidStatsMaker;
|
||||
import com.bvn13.covid19.site.service.StatisticsPreparator;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -13,11 +29,11 @@ import java.util.List;
|
|||
@RequestMapping("/regions")
|
||||
public class RegionsController {
|
||||
|
||||
private final CovidStatsMaker covidStatsMaker;
|
||||
private final StatisticsPreparator statisticsPreparator;
|
||||
|
||||
@GetMapping
|
||||
public List<String> getAllRegions() {
|
||||
return covidStatsMaker.findAllRegionsNames();
|
||||
return statisticsPreparator.findAllRegionsNames();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,16 +16,27 @@ limitations under the License.
|
|||
|
||||
package com.bvn13.covid19.site.model;
|
||||
|
||||
import com.bvn13.covid19.model.entities.StatsProvider;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
|
||||
@Builder
|
||||
@Builder(toBuilder = true)
|
||||
@Value
|
||||
public class CovidData {
|
||||
public class CovidData implements StatsProvider {
|
||||
|
||||
String region;
|
||||
long sick;
|
||||
long healed;
|
||||
long died;
|
||||
|
||||
Delta previous;
|
||||
|
||||
@Builder
|
||||
@Value
|
||||
public static class Delta implements StatsProvider {
|
||||
long sick;
|
||||
long healed;
|
||||
long died;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,9 +20,12 @@ import com.bvn13.covid19.site.dtos.CovidUpdateInfoDto;
|
|||
import com.bvn13.covid19.model.entities.CovidUpdate;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -32,6 +35,9 @@ public interface CovidUpdatesRepository extends JpaRepository<CovidUpdate, Long>
|
|||
@Query("select new com.bvn13.covid19.site.dtos.CovidUpdateInfoDto(max(U.createdOn)) from CovidUpdate U")
|
||||
Optional<CovidUpdateInfoDto> findLastUpdate();
|
||||
|
||||
@Query("select U from CovidUpdate U where U.datetime >= :date1 and U.datetime < :date2")
|
||||
Optional<CovidUpdate> findByDateOfUpdate(@Param("date1") ZonedDateTime date1, @Param("date2") ZonedDateTime date2);
|
||||
|
||||
@Query("select U from CovidUpdate U where U.id in (select max(U1.id) from CovidUpdate U1 group by U1.datetime)")
|
||||
Collection<CovidUpdate> findAllLastUpdatesPerDay();
|
||||
|
||||
|
|
|
@ -4,6 +4,9 @@ import com.bvn13.covid19.model.entities.Region;
|
|||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface RegionsRepository extends JpaRepository<Region, Long> {
|
||||
Optional<Region> findFirstByName(String name);
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package com.bvn13.covid19.site.service;
|
||||
|
||||
import com.bvn13.covid19.model.entities.CovidStat;
|
||||
import com.bvn13.covid19.site.model.CovidData;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class CovidStatsResponseMaker {
|
||||
|
||||
public List<CovidData> convertStats(Collection<CovidStat> stats) {
|
||||
return stats.stream()
|
||||
.map(stat -> CovidData.builder()
|
||||
.region(stat.getRegion().getName())
|
||||
.sick(stat.getSick())
|
||||
.healed(stat.getHealed())
|
||||
.died(stat.getDied())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright [2020] [bvn13]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bvn13.covid19.site.service;
|
||||
|
||||
import com.bvn13.covid19.model.entities.CovidStat;
|
||||
import com.bvn13.covid19.model.entities.Region;
|
||||
import com.bvn13.covid19.model.entities.StatsProvider;
|
||||
import com.bvn13.covid19.site.model.CovidData;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class StatisticsAggregator {
|
||||
|
||||
private static final StatsProvider zero = CovidData.Delta.builder()
|
||||
.sick(0L)
|
||||
.healed(0L)
|
||||
.died(0L)
|
||||
.build();
|
||||
|
||||
|
||||
public List<CovidData> prepareStats(Collection<CovidStat> current, Map<Region, StatsProvider> previous) {
|
||||
return current.stream()
|
||||
.map(stat -> Pair.of(stat, Optional.ofNullable(previous.get(stat.getRegion()))))
|
||||
.map(statPair -> CovidData.builder()
|
||||
.region(statPair.getFirst().getRegion().getName())
|
||||
.sick(statPair.getFirst().getSick())
|
||||
.healed(statPair.getFirst().getHealed())
|
||||
.died(statPair.getFirst().getDied())
|
||||
.previous(CovidData.Delta.builder()
|
||||
.sick(statPair.getSecond().orElse(zero).getSick())
|
||||
.healed(statPair.getSecond().orElse(zero).getHealed())
|
||||
.died(statPair.getSecond().orElse(zero).getDied())
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
|
@ -23,10 +23,17 @@ import com.bvn13.covid19.site.repositories.CovidStatsRepository;
|
|||
import com.bvn13.covid19.site.repositories.CovidUpdatesRepository;
|
||||
import com.bvn13.covid19.site.repositories.RegionsRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.transaction.Transactional;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -35,12 +42,30 @@ import java.util.stream.Collectors;
|
|||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class CovidStatsMaker {
|
||||
public class StatisticsPreparator {
|
||||
|
||||
private final CovidStatsRepository statsRepository;
|
||||
private final CovidUpdatesRepository updatesRepository;
|
||||
private final RegionsRepository regionsRepository;
|
||||
|
||||
private LocalDate projectStartDate;
|
||||
private ZonedDateTime projectStartZonedDate;
|
||||
@Value("${app.zone-id}")
|
||||
private String zoneIdStr;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
ZoneId zoneId = ZoneId.of(zoneIdStr);
|
||||
projectStartZonedDate = projectStartDate.atTime(0, 0, 0).atZone(zoneId);
|
||||
}
|
||||
|
||||
@Value("${app.project-start-date}")
|
||||
private void setProjectStartDate(String ld) {
|
||||
if (ld != null && !ld.isEmpty()) {
|
||||
projectStartDate = LocalDate.parse(ld);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Collection<CovidStat> getLastCovidStats() {
|
||||
return updatesRepository.findLastUpdate()
|
||||
|
@ -59,6 +84,26 @@ public class CovidStatsMaker {
|
|||
.flatMap(updateInfo -> updatesRepository.findFirstByCreatedOn(updateInfo.getCreatedOn()));
|
||||
}
|
||||
|
||||
@Cacheable(
|
||||
cacheNames = "covid-prev-update-by-date",
|
||||
unless = "#result == null"
|
||||
)
|
||||
public Optional<CovidUpdate> findPrevUpdateByDate(ZonedDateTime date) {
|
||||
if (date.isBefore(projectStartZonedDate)) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
Optional<CovidUpdate> update = updatesRepository.findByDateOfUpdate(
|
||||
dateWithTime(prevDate(date), 0, 0, 0),
|
||||
dateWithTime(date, 0, 0, 0)
|
||||
);
|
||||
if (update.isPresent()) {
|
||||
return update;
|
||||
} else {
|
||||
return findPrevUpdateByDate(prevDate(date));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Cacheable(
|
||||
cacheNames = "covid-stats-by-update-info-id",
|
||||
condition = "#updateInfoId > 0",
|
||||
|
@ -84,4 +129,15 @@ public class CovidStatsMaker {
|
|||
return regionsRepository.findAll().stream().map(Region::getName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ZonedDateTime prevDate(ZonedDateTime date) {
|
||||
return date.minus(1, ChronoUnit.DAYS);
|
||||
}
|
||||
|
||||
private ZonedDateTime dateWithTime(ZonedDateTime date, int hour, int minute, int second) {
|
||||
return date
|
||||
.withHour(hour)
|
||||
.withMinute(minute)
|
||||
.withSecond(second);
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,7 @@ server:
|
|||
app:
|
||||
zone-id: Europe/Moscow
|
||||
main-url: http://localhost:8080
|
||||
project-start-date: 2020-03-01
|
||||
|
||||
spring:
|
||||
application:
|
||||
|
@ -13,7 +14,7 @@ spring:
|
|||
type: caffeine
|
||||
caffeine:
|
||||
spec: expireAfterWrite=15m
|
||||
cache-names: covid-last-update, covid-all-days-updates, covid-stats-by-update-info-id, covid-regions
|
||||
cache-names: covid-last-update, covid-all-days-updates, covid-stats-by-update-info-id, covid-regions, covid-prev-update-by-date
|
||||
|
||||
flyway:
|
||||
enabled: false
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<title>Home page</title>
|
||||
<title>Статистика COVID19 в России</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
|
||||
|
@ -28,6 +28,13 @@
|
|||
<canvas id="chart"></canvas>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<a href="https://github.com/bvn13/covid19-ru">Исходный код</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://twitter.com/bvn13">@bvn13 - Автор проекта</a>
|
||||
</p>
|
||||
|
||||
<script th:inline="javascript">
|
||||
var mainUrl = [[${@mainConfig.getMainUrl()}]];
|
||||
|
||||
|
@ -68,34 +75,73 @@
|
|||
function showData(json) {
|
||||
var labels = _.map(json.progress, (progress) => progress.datetime.substr(0, 10));
|
||||
var sick = _.map(json.progress, (progress) => progress.stats.length > 0 ? progress.stats[0].sick : 0);
|
||||
var sickDeltas = _.map(json.progress, (progress) =>
|
||||
progress.stats.length > 0
|
||||
? progress.stats[0].sick - progress.stats[0].previous.sick
|
||||
: 0
|
||||
);
|
||||
var healed = _.map(json.progress, (progress) => progress.stats.length > 0 ? progress.stats[0].healed : 0);
|
||||
var healedDeltas = _.map(json.progress, (progress) =>
|
||||
progress.stats.length > 0
|
||||
? progress.stats[0].healed - progress.stats[0].previous.healed
|
||||
: 0
|
||||
);
|
||||
var died = _.map(json.progress, (progress) => progress.stats.length > 0 ? progress.stats[0].died : 0);
|
||||
var diedDeltas = _.map(json.progress, (progress) =>
|
||||
progress.stats.length > 0
|
||||
? progress.stats[0].died - progress.stats[0].previous.died
|
||||
: 0
|
||||
);
|
||||
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Всего',
|
||||
label: 'Всего (чел.)',
|
||||
data: sick,
|
||||
backgroundColor: 'red',
|
||||
borderColor: 'red',
|
||||
borderWidth: 1,
|
||||
fill: false
|
||||
}, {
|
||||
label: 'Выздоровело',
|
||||
label: 'Выздоровело (чел.)',
|
||||
data: healed,
|
||||
backgroundColor: 'green',
|
||||
borderColor: 'green',
|
||||
borderWidth: 1,
|
||||
fill: false
|
||||
}, {
|
||||
label: 'Умерло',
|
||||
label: 'Умерло (чел.)',
|
||||
data: died,
|
||||
backgroundColor: 'black',
|
||||
borderColor: 'black',
|
||||
borderWidth: 1,
|
||||
fill: false
|
||||
}, {
|
||||
label: 'Всего (дельта чел.)',
|
||||
data: sickDeltas,
|
||||
backgroundColor: 'red',
|
||||
borderColor: 'red',
|
||||
borderWidth: 1,
|
||||
borderDash: [5, 15],
|
||||
fill: false
|
||||
}, {
|
||||
label: 'Выздоровело (дельта чел.)',
|
||||
data: healedDeltas,
|
||||
backgroundColor: 'green',
|
||||
borderColor: 'green',
|
||||
borderWidth: 1,
|
||||
borderDash: [5, 15],
|
||||
fill: false
|
||||
}, {
|
||||
label: 'Умерло (дельта чел.)',
|
||||
data: diedDeltas,
|
||||
backgroundColor: 'black',
|
||||
borderColor: 'black',
|
||||
borderWidth: 1,
|
||||
borderDash: [5, 15],
|
||||
fill: false
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
|
|
Loading…
Reference in New Issue