Skip to content

Commit cf092a6

Browse files
committed
feat: new raw data process endpoint
1 parent 3b54bed commit cf092a6

File tree

15 files changed

+197
-2
lines changed

15 files changed

+197
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# Changelog
2+
## 1.13.0 [TODO]
3+
### Changed
4+
- New raw data process endpoint
5+
26
## 1.12.2 [2025-11-06]
37
### Fixed
48
- Scientific notation for Doubles during raw data processing

src/main/java/fr/insee/genesis/controller/rest/responses/RawResponseController.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ public ResponseEntity<LunaticJsonRawDataModel> getJsonRawData(
161161
@Operation(summary = "Process raw data of a campaign")
162162
@PostMapping(path = "/lunatic-json/process")
163163
@PreAuthorize("hasRole('SCHEDULER')")
164+
@Deprecated(since = "1.13.0")
164165
public ResponseEntity<String> processJsonRawData(
165166
@RequestParam("campaignName") String campaignName,
166167
@RequestParam("questionnaireId") String questionnaireId,
@@ -180,6 +181,24 @@ public ResponseEntity<String> processJsonRawData(
180181
}
181182
}
182183

184+
@Operation(summary = "Process raw data of a questionnaire")
185+
@PostMapping(path = "/lunatic-json/{questionnaireId}/process")
186+
@PreAuthorize("hasRole('SCHEDULER')")
187+
public ResponseEntity<String> processJsonRawData(
188+
@PathVariable String questionnaireId
189+
) {
190+
log.info("Try to process raw JSON datas for questionnaire {}",questionnaireId);
191+
try {
192+
DataProcessResult result = lunaticJsonRawDataApiPort.processRawData(questionnaireId);
193+
return result.formattedDataCount() == 0 ?
194+
ResponseEntity.ok("%d document(s) processed".formatted(result.dataCount()))
195+
: ResponseEntity.ok("%d document(s) processed, including %d FORMATTED after data verification"
196+
.formatted(result.dataCount(), result.formattedDataCount()));
197+
} catch (GenesisException e) {
198+
return ResponseEntity.status(e.getStatus()).body(e.getMessage());
199+
}
200+
}
201+
183202
@Operation(summary = "Get processed data ids from last n hours (default 24h)")
184203
@GetMapping(path = "/lunatic-json/processed/ids")
185204
@PreAuthorize("hasRole('ADMIN')")
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
package fr.insee.genesis.domain.model.surveyunit.rawdata;
22

3-
public record DataProcessResult(int dataCount, int formattedDataCount) {
3+
import fr.insee.genesis.exceptions.GenesisError;
4+
5+
import java.util.List;
6+
7+
public record DataProcessResult(int dataCount, int formattedDataCount, List<GenesisError> errors) {
48
}

src/main/java/fr/insee/genesis/domain/ports/api/LunaticJsonRawDataApiPort.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ public interface LunaticJsonRawDataApiPort {
2828
long countResponsesByQuestionnaireId(String campaignId);
2929
Page<LunaticJsonRawDataModel> findRawDataByCampaignIdAndDate(String campaignId, Instant startDt, Instant endDt, Pageable pageable);
3030

31+
@Deprecated(since = "1.13.0")
3132
DataProcessResult processRawData(String campaignName, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException;
33+
34+
DataProcessResult processRawData(String questionnaireId) throws GenesisException;
35+
3236
Map<String, List<String>> findProcessedIdsgroupedByQuestionnaireSince(LocalDateTime since);
3337
}

src/main/java/fr/insee/genesis/domain/ports/spi/LunaticJsonRawDataPersistencePort.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ public interface LunaticJsonRawDataPersistencePort {
2222
long countResponsesByQuestionnaireId(String questionnaireId);
2323
List<GroupedInterrogation> findProcessedIdsGroupedByQuestionnaireSince(LocalDateTime since);
2424
List<GroupedInterrogation> findUnprocessedIds();
25+
Set<String> findUnprocessedInterrogationIdsByQuestionnaire(String questionnaireId);
2526
}

src/main/java/fr/insee/genesis/domain/service/rawdata/LunaticJsonRawDataService.java

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public List<LunaticJsonRawDataModel> getRawData(String campaignName, Mode mode,
100100
}
101101

102102
@Override
103+
@Deprecated(since = "1.13.0")
103104
public DataProcessResult processRawData(String campaignName, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException {
104105
int dataCount=0;
105106
int formattedDataCount=0;
@@ -156,7 +157,73 @@ public DataProcessResult processRawData(String campaignName, List<String> interr
156157
batchNumber++;
157158
}
158159
}
159-
return new DataProcessResult(dataCount, formattedDataCount);
160+
return new DataProcessResult(dataCount, formattedDataCount, errors);
161+
}
162+
163+
@Override
164+
public DataProcessResult processRawData(String questionnaireId) throws GenesisException {
165+
int dataCount=0;
166+
int formattedDataCount=0;
167+
DataProcessingContextModel dataProcessingContext =
168+
dataProcessingContextService.getContextByPartitionId(questionnaireId);
169+
List<GenesisError> errors = new ArrayList<>();
170+
171+
List<Mode> modesList = controllerUtils.getModesList(questionnaireId, null);
172+
for (Mode mode : modesList) {
173+
//Load and save metadata into database, throw exception if none
174+
VariablesMap variablesMap = metadataService.loadAndSaveIfNotExists(questionnaireId, questionnaireId, mode, fileUtils,
175+
errors).getVariables();
176+
if (variablesMap == null) {
177+
throw new GenesisException(400,
178+
"Error during metadata parsing for mode %s :%n%s"
179+
.formatted(mode, errors.getLast().getMessage())
180+
);
181+
}
182+
Set<String> interrogationIds =
183+
lunaticJsonRawDataPersistencePort.findUnprocessedInterrogationIdsByQuestionnaire(questionnaireId);
184+
185+
186+
int totalBatchs = Math.ceilDiv(interrogationIds.size() , config.getRawDataProcessingBatchSize());
187+
int batchNumber = 1;
188+
List<String> interrogationIdListForMode = new ArrayList<>(interrogationIds);
189+
while(!interrogationIdListForMode.isEmpty()){
190+
log.info("Processing raw data batch {}/{}", batchNumber, totalBatchs);
191+
int maxIndex = Math.min(interrogationIdListForMode.size(), config.getRawDataProcessingBatchSize());
192+
List<String> interrogationIdToProcess = interrogationIdListForMode.subList(0, maxIndex);
193+
194+
List<LunaticJsonRawDataModel> rawData = getRawData(questionnaireId, mode, interrogationIdToProcess);
195+
196+
List<SurveyUnitModel> surveyUnitModels = convertRawData(
197+
rawData,
198+
variablesMap
199+
);
200+
201+
//Save converted data
202+
surveyUnitQualityService.verifySurveyUnits(surveyUnitModels, variablesMap);
203+
surveyUnitService.saveSurveyUnits(surveyUnitModels);
204+
205+
//Update process dates
206+
updateProcessDates(surveyUnitModels);
207+
208+
//Increment data count
209+
dataCount += surveyUnitModels.size();
210+
formattedDataCount += surveyUnitModels.stream()
211+
.filter(surveyUnitModel -> surveyUnitModel.getState().equals(DataState.FORMATTED))
212+
.toList()
213+
.size();
214+
215+
//Send processed ids grouped by questionnaire (if review activated)
216+
if(dataProcessingContext != null && dataProcessingContext.isWithReview()) {
217+
sendProcessedIdsToQualityTool(surveyUnitModels);
218+
}
219+
220+
//Remove processed ids from list
221+
interrogationIdListForMode = interrogationIdListForMode.subList(maxIndex, interrogationIdListForMode.size());
222+
223+
batchNumber++;
224+
}
225+
}
226+
return new DataProcessResult(dataCount, formattedDataCount, errors);
160227
}
161228

162229
private void sendProcessedIdsToQualityTool(List<SurveyUnitModel> surveyUnitModels) {

src/main/java/fr/insee/genesis/infrastructure/adapter/LunaticJsonRawDataMongoAdapter.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import fr.insee.genesis.domain.model.surveyunit.rawdata.LunaticJsonRawDataModel;
77
import fr.insee.genesis.domain.ports.spi.LunaticJsonRawDataPersistencePort;
88
import fr.insee.genesis.infrastructure.document.rawdata.LunaticJsonRawDataDocument;
9+
import fr.insee.genesis.infrastructure.document.surveyunit.GroupedInterrogationDocument;
910
import fr.insee.genesis.infrastructure.mappers.GroupedInterrogationDocumentMapper;
1011
import fr.insee.genesis.infrastructure.mappers.LunaticJsonRawDataDocumentMapper;
1112
import fr.insee.genesis.infrastructure.repository.LunaticJsonMongoDBRepository;
@@ -96,4 +97,8 @@ public List<GroupedInterrogation> findUnprocessedIds() {
9697
return GroupedInterrogationDocumentMapper.INSTANCE.listDocumentToListModel(repository.aggregateRawGroupedWithNullProcessDate());
9798
}
9899

100+
@Override
101+
public Set<String> findUnprocessedInterrogationIdsByQuestionnaire(String questionnaireId) {
102+
return new HashSet<>(repository.getUnprocessedInterrogationIds(questionnaireId));
103+
}
99104
}

src/main/java/fr/insee/genesis/infrastructure/document/context/DataProcessingContextDocument.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import lombok.Data;
66
import org.bson.types.ObjectId;
77
import org.springframework.data.annotation.Id;
8+
import org.springframework.data.mongodb.core.index.Indexed;
89
import org.springframework.data.mongodb.core.mapping.Document;
910

1011
import java.time.LocalDateTime;
@@ -23,6 +24,7 @@ public DataProcessingContextDocument(String partitionId,
2324

2425
@Id
2526
private ObjectId id;
27+
@Indexed
2628
private String partitionId; //ex Survey Name, campaignId
2729
private LocalDateTime lastExecution;
2830
private List<KraftwerkExecutionSchedule> kraftwerkExecutionScheduleList;

src/main/java/fr/insee/genesis/infrastructure/document/lunaticmodel/LunaticModelDocument.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fr.insee.genesis.infrastructure.document.lunaticmodel;
22

33
import lombok.Builder;
4+
import org.springframework.data.mongodb.core.index.Indexed;
45
import org.springframework.data.mongodb.core.mapping.Document;
56

67
import java.time.LocalDateTime;
@@ -9,6 +10,7 @@
910
@Builder
1011
@Document(collection = "lunaticmodels")
1112
public record LunaticModelDocument (
13+
@Indexed
1214
String questionnaireId,
1315
Map<String,Object> lunaticModel,
1416
LocalDateTime recordDate

src/main/java/fr/insee/genesis/infrastructure/document/metadata/QuestionnaireMetadataDocument.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
import fr.insee.bpm.metadata.model.MetadataModel;
44
import fr.insee.genesis.domain.model.surveyunit.Mode;
55
import org.springframework.data.mongodb.core.index.CompoundIndex;
6+
import org.springframework.data.mongodb.core.index.Indexed;
67
import org.springframework.data.mongodb.core.mapping.Document;
78

89
@CompoundIndex(name = "questionnaireId_1_mode_1", def = "{'questionnaireId': 1, 'mode': 1}")
910
@Document(collection = "questionnaireMetadatas")
1011
public record QuestionnaireMetadataDocument(
12+
@Indexed
1113
String questionnaireId,
1214
Mode mode,
1315
MetadataModel metadataModel

0 commit comments

Comments
 (0)