Aggregation
This commit is contained in:
parent
c998d79c16
commit
3782c10693
23
src/main/java/de/ph87/data/series/AggregationWrapperDto.java
Normal file
23
src/main/java/de/ph87/data/series/AggregationWrapperDto.java
Normal file
@ -0,0 +1,23 @@
|
||||
package de.ph87.data.series;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
|
||||
@Data
|
||||
public class AggregationWrapperDto {
|
||||
|
||||
public final Alignment alignment;
|
||||
|
||||
public final ZonedDateTime date;
|
||||
|
||||
public final List<IAggregationDto> aggregations;
|
||||
|
||||
public AggregationWrapperDto(final Alignment alignment, final ZonedDateTime date, final List<IAggregationDto> aggregations) {
|
||||
this.alignment = alignment;
|
||||
this.date = date;
|
||||
this.aggregations = aggregations;
|
||||
}
|
||||
|
||||
}
|
||||
@ -19,8 +19,13 @@ public class Aligned {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Aligned minus(final long offset) {
|
||||
return new Aligned(alignment, alignment.plus.apply(date, -offset));
|
||||
public Aligned plus(final long amount) {
|
||||
return new Aligned(alignment, alignment.plus(date, amount));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Aligned minus(final long amount) {
|
||||
return plus(-amount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,27 +7,27 @@ import java.time.temporal.*;
|
||||
import java.util.function.*;
|
||||
|
||||
public enum Alignment {
|
||||
FIVE(Duration.ofMinutes(5), t -> t.truncatedTo(ChronoUnit.MINUTES).minusMinutes(t.getMinute() % 5), (t, a) -> t.plusMinutes(5 * a)),
|
||||
HOUR(Duration.ofHours(1), t -> t.truncatedTo(ChronoUnit.HOURS), ZonedDateTime::plusHours),
|
||||
DAY(Duration.ofDays(1), t -> t.truncatedTo(ChronoUnit.DAYS), ZonedDateTime::plusDays),
|
||||
WEEK(Duration.ofDays(7), t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfWeek().getValue() - 1), ZonedDateTime::plusWeeks),
|
||||
MONTH(Duration.ofDays(31), t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfMonth() - 1), ZonedDateTime::plusMonths),
|
||||
YEAR(Duration.ofDays(366), t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfYear() - 1), ZonedDateTime::plusYears),
|
||||
FIVE(t -> t.truncatedTo(ChronoUnit.MINUTES).minusMinutes(t.getMinute() % 5), Duration.ofMinutes(5), Duration.ofMinutes(5)),
|
||||
HOUR(t -> t.truncatedTo(ChronoUnit.HOURS), Duration.ofHours(1), Duration.ofHours(1)),
|
||||
DAY(t -> t.truncatedTo(ChronoUnit.DAYS), Duration.ofDays(1), Duration.ofDays(1)),
|
||||
WEEK(t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfWeek().getValue() - 1), Period.ofWeeks(1), Duration.ofDays(7)),
|
||||
MONTH(t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfMonth() - 1), Period.ofMonths(1), Duration.ofDays(31)),
|
||||
YEAR(t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfYear() - 1), Period.ofYears(1), Duration.ofDays(366)),
|
||||
;
|
||||
|
||||
@NonNull
|
||||
public final Duration maxDuration;
|
||||
|
||||
@NonNull
|
||||
public final Function<ZonedDateTime, ZonedDateTime> align;
|
||||
|
||||
@NonNull
|
||||
public final BiFunction<ZonedDateTime, Long, ZonedDateTime> plus;
|
||||
public final TemporalAmount amount;
|
||||
|
||||
Alignment(@NonNull final Duration maxDuration, @NonNull final Function<@NonNull ZonedDateTime, @NonNull ZonedDateTime> align, @NonNull final BiFunction<@NonNull ZonedDateTime, @NonNull Long, @NonNull ZonedDateTime> plus) {
|
||||
@NonNull
|
||||
public final Duration maxDuration;
|
||||
|
||||
Alignment(@NonNull final Function<@NonNull ZonedDateTime, @NonNull ZonedDateTime> align, @NonNull final TemporalAmount amount, @NonNull final Duration maxDuration) {
|
||||
this.maxDuration = maxDuration;
|
||||
this.align = align;
|
||||
this.plus = plus;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -35,4 +35,25 @@ public enum Alignment {
|
||||
return new Aligned(this, date);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ZonedDateTime plus(@NonNull final ZonedDateTime date, final long amount) {
|
||||
return date.plus(multiplyAmount(amount));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@SuppressWarnings("unused")
|
||||
public ZonedDateTime minus(@NonNull final ZonedDateTime date, final long amount) {
|
||||
return plus(date, -amount);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public TemporalAmount multiplyAmount(final long amount) {
|
||||
if (this.amount instanceof final Duration duration) {
|
||||
return duration.multipliedBy(amount);
|
||||
} else if (this.amount instanceof final Period period) {
|
||||
return period.multipliedBy((int) amount);
|
||||
}
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
10
src/main/java/de/ph87/data/series/IAggregationDto.java
Normal file
10
src/main/java/de/ph87/data/series/IAggregationDto.java
Normal file
@ -0,0 +1,10 @@
|
||||
package de.ph87.data.series;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
public interface IAggregationDto {
|
||||
|
||||
@NonNull
|
||||
SeriesDto getSeries();
|
||||
|
||||
}
|
||||
31
src/main/java/de/ph87/data/series/SeriesController.java
Normal file
31
src/main/java/de/ph87/data/series/SeriesController.java
Normal file
@ -0,0 +1,31 @@
|
||||
package de.ph87.data.series;
|
||||
|
||||
import de.ph87.data.series.meter.*;
|
||||
import de.ph87.data.series.varying.*;
|
||||
import lombok.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("Series")
|
||||
public class SeriesController {
|
||||
|
||||
private final MeterService meterService;
|
||||
|
||||
private final VaryingService varyingService;
|
||||
|
||||
@NonNull
|
||||
@GetMapping("agg/all/{alignmentName}/{offsetAmount}")
|
||||
public AggregationWrapperDto agg(@PathVariable final String alignmentName, @PathVariable final long offsetAmount) {
|
||||
final Alignment alignment = Alignment.valueOf(alignmentName);
|
||||
final ZonedDateTime date = alignment.align(ZonedDateTime.now()).minus(offsetAmount).date;
|
||||
final List<IAggregationDto> aggregations = new ArrayList<>();
|
||||
aggregations.addAll(meterService.findAllAggregations(alignment, date));
|
||||
aggregations.addAll(varyingService.findAllAggregations(alignment, date));
|
||||
return new AggregationWrapperDto(alignment, date, aggregations);
|
||||
}
|
||||
|
||||
}
|
||||
@ -48,7 +48,7 @@ public class SeriesService {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private SeriesDto toDto(@NonNull final Series series) {
|
||||
public SeriesDto toDto(@NonNull final Series series) {
|
||||
return new SeriesDto(series);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
package de.ph87.data.series.meter;
|
||||
|
||||
import de.ph87.data.series.*;
|
||||
import lombok.*;
|
||||
|
||||
@Data
|
||||
public class MeterAggregation {
|
||||
|
||||
@NonNull
|
||||
public final Series series;
|
||||
|
||||
public final double delta;
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package de.ph87.data.series.meter;
|
||||
|
||||
import de.ph87.data.series.*;
|
||||
import lombok.*;
|
||||
|
||||
@Data
|
||||
public class MeterAggregationDto implements IAggregationDto {
|
||||
|
||||
@NonNull
|
||||
public final SeriesDto series;
|
||||
|
||||
public final double delta;
|
||||
|
||||
public MeterAggregationDto(@NonNull final MeterAggregation meterAggregation, @NonNull final SeriesDto series) {
|
||||
this.series = series;
|
||||
this.delta = meterAggregation.delta;
|
||||
}
|
||||
|
||||
}
|
||||
@ -14,6 +14,7 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.*;
|
||||
import org.springframework.transaction.annotation.*;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
@ -75,14 +76,7 @@ public class MeterService {
|
||||
|
||||
@NonNull
|
||||
public List<GraphPoint> getPoints(@NonNull final SeriesDto series, @NonNull final Aligned begin, @NonNull final Aligned end) {
|
||||
final List<? extends MeterValue> graphPoints = switch (begin.alignment) {
|
||||
case FIVE -> meterFiveRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
||||
case HOUR -> meterHourRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
||||
case DAY -> meterDayRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
||||
case WEEK -> meterWeekRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
||||
case MONTH -> meterMonthRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
||||
case YEAR -> meterYearRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
||||
};
|
||||
final List<? extends MeterValue> graphPoints = findRepository(begin.alignment).findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
||||
final List<GraphPoint> points = graphPoints.stream().map(meterValue -> new GraphPoint(meterValue.getId().getDate(), meterValue.getMax() - meterValue.getMin())).collect(Collectors.toCollection(LinkedList::new));
|
||||
for (int i = 0; i < points.size() - 1; i++) {
|
||||
if (points.get(i).date.compareTo(points.get(i + 1).date) == 0) {
|
||||
@ -94,4 +88,26 @@ public class MeterService {
|
||||
return points;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<MeterAggregationDto> findAllAggregations(@NonNull final Alignment alignment, @NonNull final ZonedDateTime date) {
|
||||
return findRepository(alignment).findAllDeltaSum(date).stream().map(this::toDto).toList();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private MeterAggregationDto toDto(@NonNull final MeterAggregation meterAggregation) {
|
||||
return new MeterAggregationDto(meterAggregation, seriesService.toDto(meterAggregation.series));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private MeterValueRepository<?> findRepository(@NonNull final Alignment alignment) {
|
||||
return switch (alignment) {
|
||||
case FIVE -> meterFiveRepository;
|
||||
case HOUR -> meterHourRepository;
|
||||
case DAY -> meterDayRepository;
|
||||
case WEEK -> meterWeekRepository;
|
||||
case MONTH -> meterMonthRepository;
|
||||
case YEAR -> meterYearRepository;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package de.ph87.data.series.meter;
|
||||
|
||||
import lombok.*;
|
||||
import org.springframework.data.jpa.repository.*;
|
||||
import org.springframework.data.repository.*;
|
||||
|
||||
import java.time.*;
|
||||
@ -11,4 +12,7 @@ public interface MeterValueRepository<T extends MeterValue> extends ListCrudRepo
|
||||
|
||||
List<T> findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(long id, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
||||
|
||||
@Query("select new de.ph87.data.series.meter.MeterAggregation(m.id.meter.series, sum(m.max - m.min)) from #{#entityName} m where m.id.date = :date group by m.id.meter.series")
|
||||
List<MeterAggregation> findAllDeltaSum(@NonNull ZonedDateTime date);
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
package de.ph87.data.series.varying;
|
||||
|
||||
import de.ph87.data.series.*;
|
||||
import lombok.*;
|
||||
|
||||
@Data
|
||||
public class VaryingAggregation {
|
||||
|
||||
@NonNull
|
||||
public final Series series;
|
||||
|
||||
public final double min;
|
||||
|
||||
public final double avg;
|
||||
|
||||
public final double max;
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package de.ph87.data.series.varying;
|
||||
|
||||
import de.ph87.data.series.*;
|
||||
import lombok.*;
|
||||
|
||||
@Data
|
||||
public class VaryingAggregationDto implements IAggregationDto {
|
||||
|
||||
@NonNull
|
||||
public final SeriesDto series;
|
||||
|
||||
public final double min;
|
||||
|
||||
public final double avg;
|
||||
|
||||
public final double max;
|
||||
|
||||
public VaryingAggregationDto(@NonNull final VaryingAggregation varyingAggregation, @NonNull final SeriesDto series) {
|
||||
this.series = series;
|
||||
this.min = varyingAggregation.min;
|
||||
this.avg = varyingAggregation.avg;
|
||||
this.max = varyingAggregation.max;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package de.ph87.data.series.varying;
|
||||
|
||||
import lombok.*;
|
||||
import org.springframework.data.jpa.repository.*;
|
||||
import org.springframework.data.repository.*;
|
||||
|
||||
import java.time.*;
|
||||
@ -11,4 +12,7 @@ public interface VaryingRepository<T extends Varying> extends ListCrudRepository
|
||||
|
||||
List<T> findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(long id, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
||||
|
||||
@Query("select new de.ph87.data.series.varying.VaryingAggregation(m.id.series, m.min, m.avg, m.max) from #{#entityName} m where m.id.date = :date")
|
||||
List<VaryingAggregation> findAllDeltaSum(@NonNull ZonedDateTime date);
|
||||
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.*;
|
||||
import org.springframework.transaction.annotation.*;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@ -61,15 +62,33 @@ public class VaryingService {
|
||||
|
||||
@NonNull
|
||||
public List<GraphPoint> getPoints(@NonNull final SeriesDto series, @NonNull final Aligned begin, @NonNull final Aligned end) {
|
||||
final List<? extends Varying> graphPoints = switch (begin.alignment) {
|
||||
case FIVE -> varyingFiveRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
||||
case HOUR -> varyingHourRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
||||
case DAY -> varyingDayRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
||||
case WEEK -> varyingWeekRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
||||
case MONTH -> varyingMonthRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
||||
case YEAR -> varyingYearRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
||||
return findRepository(begin.alignment)
|
||||
.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date)
|
||||
.stream()
|
||||
.map(v -> new GraphPoint(v.getId().getDate(), v.getAvg()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<VaryingAggregationDto> findAllAggregations(@NonNull final Alignment alignment, @NonNull final ZonedDateTime date) {
|
||||
return findRepository(alignment).findAllDeltaSum(date).stream().map(this::toDto).toList();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private VaryingAggregationDto toDto(@NonNull final VaryingAggregation varyingAggregation) {
|
||||
return new VaryingAggregationDto(varyingAggregation, seriesService.toDto(varyingAggregation.series));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private VaryingRepository<?> findRepository(@NonNull final Alignment alignment) {
|
||||
return switch (alignment) {
|
||||
case FIVE -> varyingFiveRepository;
|
||||
case HOUR -> varyingHourRepository;
|
||||
case DAY -> varyingDayRepository;
|
||||
case WEEK -> varyingWeekRepository;
|
||||
case MONTH -> varyingMonthRepository;
|
||||
case YEAR -> varyingYearRepository;
|
||||
};
|
||||
return graphPoints.stream().map(v -> new GraphPoint(v.getId().getDate(), v.getAvg())).toList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user