Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ ON CONFLICT (study_id,observation_id,participant_id,start) DO UPDATE SET "end" =
""";

private static final String DELETE_ALL = "DELETE FROM occurred_observation";
private static final String CLEANUP_BY_STUDY_ID ="DELETE FROM occurred_observation WHERE study_id = :study_id" ;
private final JdbcTemplate template;
private final NamedParameterJdbcTemplate namedTemplate;

Expand Down Expand Up @@ -202,4 +203,13 @@ private static RowMapper<Instant> getInstantRowMapper(String field, boolean with
return (rs, rowNum) -> withTimezone ? RepositoryUtils.readInstantUTC(rs, field) :
RepositoryUtils.readInstant(rs, field);
}

/**
* Cleans all OccurredOccurrencies for the parsed StudyId
* @param studyId
*/
public void cleanup(Long studyId) {
final var params = toParams(studyId);
namedTemplate.update(CLEANUP_BY_STUDY_ID, params);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
package io.redlink.more.studymanager.service;

import io.redlink.more.studymanager.model.OccurredObservation;
import io.redlink.more.studymanager.model.Study;
import io.redlink.more.studymanager.model.generator.RandomTokenGenerator;
import io.redlink.more.studymanager.repository.OccurredObservationRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.*;
Expand Down Expand Up @@ -89,4 +92,18 @@ public Stream<OccurredObservation> streamActiveOccurredObservationsForParticipan
ACTIVE_DATA_STATES);
}

/**
* Aligns OccurredObservations with the study status
* @param study
*/
@Transactional
public void alignParticipantsWithStudyState(Study study) {
//NOTE: for CLOSE this should be a NO-OP, as participants and observations are also deleted and
// OccurredObservations use delete cascade on those FK
if (EnumSet.of(Study.Status.DRAFT, Study.Status.CLOSED).contains(study.getStudyState())) {
repository.cleanup(study.getStudyId());
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,24 @@ public class StudyService {
private final StudyStateService studyStateService;
private final IntegrationService integrationService;
private final ElasticService elasticService;
private final OccurredObservationService occurredObservationService;

private final PushNotificationService pushNotificationService;
private final StudyGroupRepository studyGroupRepository;


public StudyService(StudyRepository studyRepository, StudyAclRepository aclRepository, UserRepository userRepo,
StudyStateService studyStateService, InterventionService interventionService, ObservationService observationService,
ParticipantService participantService, IntegrationService integrationService, ElasticService elasticService, PushNotificationService pushNotificationService, StudyGroupRepository studyGroupRepository) {
public StudyService(StudyRepository studyRepository,
StudyAclRepository aclRepository,
UserRepository userRepo,
StudyStateService studyStateService,
InterventionService interventionService,
ObservationService observationService,
ParticipantService participantService,
IntegrationService integrationService,
ElasticService elasticService,
OccurredObservationService occurredObservationService,
PushNotificationService pushNotificationService,
StudyGroupRepository studyGroupRepository) {
this.studyRepository = studyRepository;
this.aclRepository = aclRepository;
this.userRepo = userRepo;
Expand All @@ -76,6 +86,7 @@ public StudyService(StudyRepository studyRepository, StudyAclRepository aclRepos
this.participantService = participantService;
this.integrationService = integrationService;
this.elasticService = elasticService;
this.occurredObservationService = occurredObservationService;
this.pushNotificationService = pushNotificationService;
this.studyGroupRepository = studyGroupRepository;
}
Expand Down Expand Up @@ -135,6 +146,7 @@ public Optional<Study> setStatus(Long studyId, Study.Status newState, User user)
pushNotificationService.sendStudyStateUpdate(participant, oldState, s.getStudyState())
);
participantService.alignParticipantsWithStudyState(s);
occurredObservationService.alignParticipantsWithStudyState(s);
if (s.getStudyState() == Study.Status.DRAFT) {
log.info("Study {} transitioned back to {}, dropping collected observation data", study.getStudyId(), s.getStudyState());
elasticService.deleteIndex(s.getStudyId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,56 @@ public void testInsertListUpdateDelete() {
//validate that searching for a combination with no entry returns null
var lastStartTimeNotFound = occurredObservationRepository.getLatestStartTime(studyId, -1, null, null, null);
assertThat(lastStartTimeNotFound).isNull();

//Test cleanup by StudyId

Long study2Id = studyRepository.insert(new Study().setContact(new Contact().setPerson("test2").setEmail("test2"))).getStudyId();
Integer study2GroupId = studyGroupRepository.insert(new StudyGroup().setStudyId(study2Id)).getStudyGroupId();
Instant study2StartTime = Instant.now().truncatedTo(ChronoUnit.MINUTES).minus(1, ChronoUnit.DAYS);
Instant study2EndTime = study2StartTime.plus(2, ChronoUnit.HOURS);

Observation study2Observation = observationRepository.insert(new Observation()
.setStudyId(study2Id)
.setType(type)
.setTitle("Accelerometer Observation")
.setStudyGroupId(study2GroupId)
.setProperties(new ObservationProperties(Map.of("testProperty", "testValue")))
.setSchedule(new Event()
.setDateStart(startTime)
.setDateEnd(endTime)
.setRRule(new RecurrenceRule().setFreq("DAILY").setCount(7)))
.setHidden(false)
.setNoSchedule(false));

Participant study2Participant = participantRepository.insert(new Participant()
.setAlias("participant x")
.setStudyGroupId(study2GroupId)
.setStudyId(study2Id)
.setRegistrationToken("TEST456"));

var study2OccurredObservation = occurredObservationRepository.upsert(new OccurredObservation(
study2Id,
study2Observation.getObservationId(),
study2Participant.getParticipantId(),
study2StartTime,
study2EndTime));

//validate that their exists now an occurred observation for the 2nd study
assertThat(occurredObservationRepository.listOccurredObservations(
study2Id, null, null, null, null).count()).isEqualTo(1);

//not clean all occurred observations for the first study
occurredObservationRepository.cleanup(studyId);

//assert that all accurred observations are deleted
assertThat(occurredObservationRepository.listOccurredObservations(
studyId, null, null, null, null).count()).isEqualTo(0);

//assert that the occurred observations for study2 are still present
assertThat(occurredObservationRepository.listOccurredObservations(
study2Id, null, null, null, null).count()).isEqualTo(1);


}

}
Loading