Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package fr.insee.genesis.controller.rest;

import fr.insee.genesis.domain.model.surveyunit.rawdata.CombinedRawData;
import fr.insee.genesis.domain.service.rawdata.CombinedRawDataService;
import fr.insee.genesis.exceptions.GenesisException;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Slf4j
@Controller
@RequestMapping(path = "/combined-raw-data" )
public class CombinedRawDataController {

private static final String INTERROGATION_ID = "interrogationId";
private final CombinedRawDataService combinedRawDataService;

public CombinedRawDataController(CombinedRawDataService combinedRawDataService) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use annotation @requiredargsconstructor

this.combinedRawDataService = combinedRawDataService;
}

@Operation(summary = "Retrieve combined raw responses and Lunatic raw data for a given interrogationId")
@GetMapping
@PreAuthorize("hasAnyRole('ADMIN', 'USER_PLATINE')")
public ResponseEntity<CombinedRawData> getCombinetRawData(
@RequestParam(INTERROGATION_ID) String interrogationId
){CombinedRawData data = combinedRawDataService.getCombinedRawDataByInterrogationId(interrogationId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Use a DTO to be sure on what to return


if (data.rawResponses().isEmpty()) {
return ResponseEntity.notFound().build();
}

return ResponseEntity.ok(data);
}

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Rename it to combinedRawDataModel and create a similar DTO classed returned in the controller

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package fr.insee.genesis.domain.model.surveyunit.rawdata;

import java.util.List;

public record CombinedRawData(List<RawResponse> rawResponses,
List<LunaticJsonRawDataModel> lunaticRawData) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public interface LunaticJsonRawDataApiPort {
long countResponsesByQuestionnaireId(String campaignId);
Page<LunaticJsonRawDataModel> findRawDataByCampaignIdAndDate(String campaignId, Instant startDt, Instant endDt, Pageable pageable);

List<LunaticJsonRawDataModel> getRawDataByInterrogationId(String interrogationId);

@Deprecated(since = "1.13.0")
DataProcessResult processRawData(String campaignName, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
public interface RawResponseApiPort {

List<RawResponse> getRawResponses(String collectionInstrumentId, Mode mode, List<String> interrogationIdList);
List<RawResponse> getRawResponsesByInterrogationID(String interrogationId);
DataProcessResult processRawResponses(String collectionInstrumentId, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException;
DataProcessResult processRawResponses(String collectionInstrumentId) throws GenesisException;
List<SurveyUnitModel> convertRawResponse(List<RawResponse> rawResponses, VariablesMap variablesMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public interface LunaticJsonRawDataPersistencePort {

void save(LunaticJsonRawDataModel rawData);
List<LunaticJsonRawDataModel> findRawData(String campaignName, Mode mode, List<String> interrogationIdList);
List<LunaticJsonRawDataModel> findRawDataByInterrogationID(String interrogationId);
List<LunaticJsonRawDataModel> getAllUnprocessedData();
void updateProcessDates(String campaignId, Set<String> interrogationIds);
Set<String> findDistinctQuestionnaireIds();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
public interface RawResponsePersistencePort {

List<RawResponse> findRawResponses(String collectionInstrumentId, Mode mode, List<String> interrogationIdList);
List<RawResponse> findRawResponsesByInterrogationID(String interrogationId);
void updateProcessDates(String collectionInstrumentId, Set<String> interrogationIds);
List<String> getUnprocessedCollectionIds();
Set<String> findUnprocessedInterrogationIdsByCollectionInstrumentId(String collectionInstrumentId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public MetadataModel loadAndSaveIfNotExists(String campaignName, String collecti
saveMetadata(collectionInstrumentId.toUpperCase(), mode, metadataModel);
return metadataModel;
}


return questionnaireMetadataModels.getFirst().metadataModel();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package fr.insee.genesis.domain.service.rawdata;

import fr.insee.genesis.domain.model.surveyunit.rawdata.CombinedRawData;
import fr.insee.genesis.domain.model.surveyunit.rawdata.LunaticJsonRawDataModel;
import fr.insee.genesis.domain.model.surveyunit.rawdata.RawResponse;
import fr.insee.genesis.domain.ports.spi.LunaticJsonRawDataPersistencePort;
import fr.insee.genesis.domain.ports.spi.RawResponsePersistencePort;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
public class CombinedRawDataService {

@Qualifier("lunaticJsonMongoAdapterNew")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: qualifier is used in the case we have differents beans implementing the same interface, it's not the case here during normal functionning for now but we put it in case we add another implementation.
suggestion: No implem has this qualifier. Rename it to "lunaticJsonMongoAdapter" to correspond with the mongo adapter qualifier

private final LunaticJsonRawDataPersistencePort lunaticJsonRawDataPersistencePort;
@Qualifier("rawResponseMongoAdapter")
private final RawResponsePersistencePort rawResponsePersistencePort;

public CombinedRawDataService(LunaticJsonRawDataPersistencePort lunaticJsonRawDataPersistencePort, RawResponsePersistencePort rawResponsePersistencePort) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.lunaticJsonRawDataPersistencePort = lunaticJsonRawDataPersistencePort;
this.rawResponsePersistencePort = rawResponsePersistencePort;
}

public CombinedRawData getCombinedRawDataByInterrogationId(String interrogationId) {
List<RawResponse> rawResponses = rawResponsePersistencePort.findRawResponsesByInterrogationID(interrogationId);
List<LunaticJsonRawDataModel> lunaticRawData = lunaticJsonRawDataPersistencePort.findRawDataByInterrogationID(interrogationId);

return new CombinedRawData(rawResponses, lunaticRawData);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ public List<LunaticJsonRawDataModel> getRawData(String campaignName, Mode mode,
return lunaticJsonRawDataPersistencePort.findRawData(campaignName, mode, interrogationIdList);
}

@Override
public List<LunaticJsonRawDataModel> getRawDataByInterrogationId(String interrogationId) {
return lunaticJsonRawDataPersistencePort.findRawDataByInterrogationID(interrogationId);
}

@Override
@Deprecated(since = "1.13.0")
public DataProcessResult processRawData(String campaignName, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ public List<RawResponse> getRawResponses(String collectionInstrumentId, Mode mod
return rawResponsePersistencePort.findRawResponses(collectionInstrumentId,mode,interrogationIdList);
}

@Override
public List<RawResponse> getRawResponsesByInterrogationID(String interrogationId) {
return rawResponsePersistencePort.findRawResponsesByInterrogationID(interrogationId);
}

@Override
public DataProcessResult processRawResponses(String collectionInstrumentId, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException {
int dataCount=0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import fr.insee.genesis.domain.model.surveyunit.rawdata.LunaticJsonRawDataModel;
import fr.insee.genesis.domain.ports.spi.LunaticJsonRawDataPersistencePort;
import fr.insee.genesis.infrastructure.document.rawdata.LunaticJsonRawDataDocument;
import fr.insee.genesis.infrastructure.document.surveyunit.GroupedInterrogationDocument;
import fr.insee.genesis.infrastructure.mappers.GroupedInterrogationDocumentMapper;
import fr.insee.genesis.infrastructure.mappers.LunaticJsonRawDataDocumentMapper;
import fr.insee.genesis.infrastructure.repository.LunaticJsonMongoDBRepository;
Expand Down Expand Up @@ -55,6 +54,12 @@ public List<LunaticJsonRawDataModel> findRawData(String campaignName, Mode mode,
List<LunaticJsonRawDataDocument> rawDataDocs = repository.findModesByCampaignIdAndByModeAndinterrogationIdIninterrogationIdList(campaignName, mode, interrogationIdList);return LunaticJsonRawDataDocumentMapper.INSTANCE.listDocumentToListModel(rawDataDocs);
}

@Override
public List<LunaticJsonRawDataModel> findRawDataByInterrogationID(String interrogationId) {
List<LunaticJsonRawDataDocument> rawDataDocs = repository.findByInterrogationId(interrogationId);
return LunaticJsonRawDataDocumentMapper.INSTANCE.listDocumentToListModel(rawDataDocs);
}

@Override
public void updateProcessDates(String campaignId, Set<String> interrogationIds) {
mongoTemplate.updateMulti(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ public List<RawResponse> findRawResponses(String collectionInstrumentId, Mode mo
return RawResponseDocumentMapper.INSTANCE.listDocumentToListModel(rawDataDocs);
}

@Override
public List<RawResponse> findRawResponsesByInterrogationID(String interrogationId) {
List<RawResponseDocument> rawResponseDocumentList = repository.findByInterrogationId(interrogationId);
return RawResponseDocumentMapper.INSTANCE.listDocumentToListModel(rawResponseDocumentList);
}

@Override
public void updateProcessDates(String collectionInstrumentId, Set<String> interrogationIds) {
mongoTemplate.updateMulti(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public interface LunaticJsonMongoDBRepository extends MongoRepository<LunaticJso
@Query(value = "{ 'campaignId' : ?0, 'mode' : ?1, 'interrogationId': {$in: ?2} }")
List<LunaticJsonRawDataDocument> findModesByCampaignIdAndByModeAndinterrogationIdIninterrogationIdList(String campaignName, Mode mode, List<String> interrogationIdList);

@Query(value = "{ 'interrogationId': ?0}")
List<LunaticJsonRawDataDocument> findByInterrogationId(String interrogationId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: add @indexed to interrogationId in LunaticJsonRawDataDocument


Page<LunaticJsonRawDataDocument> findByCampaignIdAndRecordDateBetween(String campagneId, Instant start, Instant end, Pageable pageable);
long countByQuestionnaireId(String questionnaireId);
@Aggregation(pipeline = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@ public interface RawResponseRepository extends MongoRepository<RawResponseDocume
})
List<String> findInterrogationIdByCollectionInstrumentIdAndProcessDateIsNull(String collectionInstrumentId);

@Query(value = "{ 'interrogationId': ?0}")
List<RawResponseDocument> findByInterrogationId(String interrogationId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: add "@indexed" to interrogationId in rawResponseDocument

}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ public List<RawResponse> getRawResponses(String questionnaireModelId, Mode mode,
return List.of();
}

@Override
public List<RawResponse> getRawResponsesByInterrogationID(String interrogationId) {
return List.of();
}

@Override
public DataProcessResult processRawResponses(String questionnaireId, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ public List<RawResponse> getRawResponses(String questionnaireModelId, Mode mode,
return List.of();
}

@Override
public List<RawResponse> getRawResponsesByInterrogationID(String interrogationId) {
return List.of();
}

@Override
public DataProcessResult processRawResponses(String questionnaireId, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package fr.insee.genesis.domain.service.rawdata;

import fr.insee.genesis.domain.model.surveyunit.Mode;
import fr.insee.genesis.domain.model.surveyunit.rawdata.CombinedRawData;
import fr.insee.genesis.domain.model.surveyunit.rawdata.LunaticJsonRawDataModel;
import fr.insee.genesis.domain.model.surveyunit.rawdata.RawResponse;
import fr.insee.genesis.domain.ports.spi.LunaticJsonRawDataPersistencePort;
import fr.insee.genesis.domain.ports.spi.RawResponsePersistencePort;
import org.assertj.core.api.Assertions;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@ExtendWith(MockitoExtension.class)
class CombinedRawDataServiceTest {

@Mock
LunaticJsonRawDataPersistencePort lunaticJsonRawDataPersistencePort;

@Mock
RawResponsePersistencePort rawResponsePersistencePort;

@InjectMocks
CombinedRawDataService combinedRawDataService;

@Test
void getCombinedRawDataByInterrogationId_shouldReturnCombinedData() {
// GIVEN
String interrogationId = "INTERROGATION_1";

// Mock des RawResponses
RawResponse response1 = new RawResponse(
new ObjectId(),
interrogationId,
"COLLECTION_1",
Mode.WEB,
Map.of("question1", "answer1"),
LocalDateTime.now(),
null
);

RawResponse response2 = new RawResponse(
new ObjectId(),
interrogationId,
"COLLECTION_1",
Mode.WEB,
Map.of("question2", "answer2"),
LocalDateTime.now(),
null
);

List<RawResponse> rawResponses = List.of(response1, response2);

// Mock des LunaticJsonRawData
LunaticJsonRawDataModel lunatic1 = LunaticJsonRawDataModel.builder()
.campaignId("CAMPAIGN")
.questionnaireId("QUESTIONNAIRE")
.interrogationId(interrogationId)
.data(Map.of("key", "value"))
.mode(Mode.WEB)
.build();
List<LunaticJsonRawDataModel> lunaticRawData = List.of(lunatic1);

// WHEN
Mockito.when(rawResponsePersistencePort.findRawResponsesByInterrogationID(interrogationId))
.thenReturn(rawResponses);

Mockito.when(lunaticJsonRawDataPersistencePort.findRawDataByInterrogationID(interrogationId))
.thenReturn(lunaticRawData);

CombinedRawData result = combinedRawDataService.getCombinedRawDataByInterrogationId(interrogationId);

// THEN - assertions
Assertions.assertThat(result.rawResponses()).hasSize(2).containsExactlyInAnyOrderElementsOf(rawResponses);
Assertions.assertThat(result.lunaticRawData()).hasSize(1).containsExactlyInAnyOrderElementsOf(lunaticRawData);
}

@Test
void getCombinedRawData_shouldHandleEmptyLists() {
String interrogationId = "INTERROGATION_EMPTY";

Mockito.when(rawResponsePersistencePort.findRawResponsesByInterrogationID(interrogationId))
.thenReturn(List.of());
Mockito.when(lunaticJsonRawDataPersistencePort.findRawDataByInterrogationID(interrogationId))
.thenReturn(List.of());
CombinedRawData result = combinedRawDataService.getCombinedRawDataByInterrogationId(interrogationId);

Assertions.assertThat(result.rawResponses()).isEmpty();
Assertions.assertThat(result.lunaticRawData()).isEmpty();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,47 @@ void convertRawData_if_external_not_present_test() throws Exception {
Assertions.assertThat(suModels.getFirst().getExternalVariables()).isEmpty();
}


@Test
void getRawDataByInterrogationId_shouldReturnOnlyMatchingData() {
// GIVEN
lunaticJsonRawDataPersistanceStub.getMongoStub().clear();

String InterrogationId = "INTERROGATION_1";
String secondInterrogationId = "INTERROGATION_2";

LunaticJsonRawDataModel rawData1 = LunaticJsonRawDataModel.builder()
.campaignId("CAMPAIGN")
.questionnaireId("QUESTIONNAIRE")
.interrogationId(InterrogationId)
.data(Map.of("key", "value1"))
.mode(Mode.WEB)
.build();

LunaticJsonRawDataModel rawData2 = LunaticJsonRawDataModel.builder()
.campaignId("CAMPAIGN")
.questionnaireId("QUESTIONNAIRE")
.interrogationId(secondInterrogationId)
.data(Map.of("key", "value2"))
.mode(Mode.WEB)
.build();

lunaticJsonRawDataService.save(rawData1);
lunaticJsonRawDataService.save(rawData2);

// WHEN
List<LunaticJsonRawDataModel> result =
lunaticJsonRawDataService.getRawDataByInterrogationId(InterrogationId);

// THEN
Assertions.assertThat(result)
.hasSize(1)
.allMatch(data -> InterrogationId.equals(data.interrogationId()));

Assertions.assertThat(result.getFirst().data())
.containsEntry("key", "value1");
}

@Test
void convertRawData_should_not_throw_exception_if_collected_not_present() throws Exception {
//GIVEN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ public List<LunaticJsonRawDataDocument> findModesByCampaignIdAndByModeAndinterro
.toList();
}

@Override
public List<LunaticJsonRawDataDocument> findByInterrogationId(String interrogationId) {
return documents.stream()
.filter(doc -> Objects.equals(doc.interrogationId(), interrogationId))
.toList()
;
}

@Override
public Page<LunaticJsonRawDataDocument> findByCampaignIdAndRecordDateBetween(String campagneId, Instant start, Instant end, Pageable pageable){
return Page.empty(pageable);
Expand Down
Loading
Loading