87 lines
3.5 KiB
Java
87 lines
3.5 KiB
Java
|
|
package me.belkacemi.iotalarm.infrastructure.persistence;
|
||
|
|
|
||
|
|
import me.belkacemi.iotalarm.application.query.port.AlarmReadModelPort;
|
||
|
|
import me.belkacemi.iotalarm.application.query.view.AlarmStatusView;
|
||
|
|
import me.belkacemi.iotalarm.application.query.view.AlertView;
|
||
|
|
import me.belkacemi.iotalarm.domain.model.AlarmPolicy;
|
||
|
|
import me.belkacemi.iotalarm.domain.model.AlarmState;
|
||
|
|
import me.belkacemi.iotalarm.infrastructure.persistence.jpa.AlarmStateJpaRepository;
|
||
|
|
import me.belkacemi.iotalarm.infrastructure.persistence.jpa.AlertJpaRepository;
|
||
|
|
import me.belkacemi.iotalarm.infrastructure.persistence.mapper.AlertMapper;
|
||
|
|
import org.springframework.data.domain.PageRequest;
|
||
|
|
import org.springframework.stereotype.Component;
|
||
|
|
|
||
|
|
import java.time.Clock;
|
||
|
|
import java.util.List;
|
||
|
|
import java.util.Optional;
|
||
|
|
import java.util.UUID;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ADAPTER SORTANT du cote LECTURE : implementation du {@link AlarmReadModelPort}.
|
||
|
|
*
|
||
|
|
* <p>Il ne charge jamais l'agregat. Il assemble une vue a partir de requetes
|
||
|
|
* ciblees - c'est la raison d'etre du CQRS : afficher un compteur d'alertes non
|
||
|
|
* acquittees via un {@code COUNT(*)} plutot qu'en rehydratant un objet metier
|
||
|
|
* complet dont on n'utiliserait aucune methode.</p>
|
||
|
|
*/
|
||
|
|
@Component
|
||
|
|
public class AlarmReadModelAdapter implements AlarmReadModelPort {
|
||
|
|
|
||
|
|
private final AlertJpaRepository alertRepository;
|
||
|
|
private final AlarmStateJpaRepository alarmStateRepository;
|
||
|
|
private final AlarmPolicy policy;
|
||
|
|
private final Clock clock;
|
||
|
|
|
||
|
|
public AlarmReadModelAdapter(AlertJpaRepository alertRepository,
|
||
|
|
AlarmStateJpaRepository alarmStateRepository,
|
||
|
|
AlarmPolicy policy,
|
||
|
|
Clock clock) {
|
||
|
|
this.alertRepository = alertRepository;
|
||
|
|
this.alarmStateRepository = alarmStateRepository;
|
||
|
|
this.policy = policy;
|
||
|
|
this.clock = clock;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public Optional<AlarmStatusView> alarmStatus(String zoneId) {
|
||
|
|
long unacknowledged = alertRepository.countByZoneIdAndAcknowledgedFalse(zoneId);
|
||
|
|
AlertView lastAlert = alertRepository.findFirstByZoneIdOrderByDetectedAtDesc(zoneId)
|
||
|
|
.map(AlertMapper::toView)
|
||
|
|
.orElse(null);
|
||
|
|
|
||
|
|
return Optional.of(alarmStateRepository.findById(zoneId)
|
||
|
|
.map(entity -> new AlarmStatusView(
|
||
|
|
entity.getZoneId(),
|
||
|
|
entity.getState().name(),
|
||
|
|
entity.getStateChangedAt(),
|
||
|
|
policy.exitDelay().toSeconds(),
|
||
|
|
entity.getLastAlertAt(),
|
||
|
|
unacknowledged,
|
||
|
|
lastAlert))
|
||
|
|
// Base neuve : l'alarme n'a simplement jamais ete armee. La
|
||
|
|
// console doit afficher DESARMEE, pas une erreur 404.
|
||
|
|
.orElseGet(() -> new AlarmStatusView(
|
||
|
|
zoneId,
|
||
|
|
AlarmState.DISARMED.name(),
|
||
|
|
clock.instant(),
|
||
|
|
policy.exitDelay().toSeconds(),
|
||
|
|
null,
|
||
|
|
unacknowledged,
|
||
|
|
lastAlert)));
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public List<AlertView> recentAlerts(String zoneId, int limit) {
|
||
|
|
return alertRepository
|
||
|
|
.findByZoneIdOrderByDetectedAtDesc(zoneId, PageRequest.of(0, limit))
|
||
|
|
.stream()
|
||
|
|
.map(AlertMapper::toView)
|
||
|
|
.toList();
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public Optional<AlertView> findAlert(UUID alertId) {
|
||
|
|
return alertRepository.findById(alertId).map(AlertMapper::toView);
|
||
|
|
}
|
||
|
|
}
|