Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: codelists endpoints #343

Open
wants to merge 41 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
8186af5
chore(model): create codeList model
laurentC35 Feb 20, 2025
67b09b8
chore(model): create utils function to convert model
laurentC35 Feb 20, 2025
44712ff
feat: create new Service to manage codeLists
laurentC35 Feb 20, 2025
caa406b
feat: create CodesList controller
laurentC35 Feb 20, 2025
1db67d3
ref: update controller numbering
laurentC35 Feb 20, 2025
b398abf
test: handle new feature (codesList)
laurentC35 Feb 20, 2025
a2c161f
bump: 4.12.0-SNAPSHOT
laurentC35 Feb 20, 2025
cab9cbc
fix: add empty parent to code
laurentC35 Feb 20, 2025
822d04e
bump: 4.12.0-SNAPSHOT.1
laurentC35 Feb 20, 2025
da58832
ref: rename to CodesListService
laurentC35 Feb 20, 2025
5ea6e27
ref: improve method with stream
laurentC35 Feb 20, 2025
049423d
ref: simplify impl
laurentC35 Feb 20, 2025
2848a2f
wip: create VariableService
laurentC35 Feb 20, 2025
4135c28
ref: remove cast to QuestionType
laurentC35 Feb 21, 2025
855524f
ref: move PoguesModelUtils
laurentC35 Feb 21, 2025
ced4e84
ref: move utils function to CodeList class
laurentC35 Feb 21, 2025
ee74e87
ref: create utils class according to Poges-Model
laurentC35 Feb 21, 2025
ce4faa8
ref: simplify variableService
laurentC35 Feb 21, 2025
b5f8fdc
ref: remove VariableService
laurentC35 Feb 21, 2025
678e3a7
fix: variableName generation
laurentC35 Feb 21, 2025
0ea1ace
test: perform new tests
laurentC35 Feb 21, 2025
158bfed
bump; 4.12.0-SNAPSHOT.2
laurentC35 Feb 21, 2025
7f15bc8
ref: split codes
laurentC35 Feb 25, 2025
c163028
test: add test for heart method
laurentC35 Feb 25, 2025
9f66a54
bump: 4.12.0-SNAPSHOT.3
laurentC35 Feb 25, 2025
eb3ab7a
ref: simplify variables generation
laurentC35 Feb 25, 2025
a14574e
fix: mapping with response collected variables Id
laurentC35 Feb 25, 2025
4d673d4
test: check variable factory
laurentC35 Feb 25, 2025
e7acd31
fix: update table condition
laurentC35 Feb 25, 2025
a62e57b
feat: remove clarification Question for question with updatedCodeList
laurentC35 Feb 25, 2025
704fda2
bump: 4.12.0-SNAPSHOT.4
laurentC35 Feb 25, 2025
2ee1efa
fix: naming convention (keep only allow char for variable name)
laurentC35 Feb 26, 2025
7d691bf
fix: getNeededCollectedVariablesInQuestionnaire method (add arbitrary…
laurentC35 Feb 26, 2025
5f8b1a7
bump: 4.12.0-SNAPSHOT.5
laurentC35 Feb 26, 2025
5ce4ed9
fix: name of MultipleChoice variables
laurentC35 Feb 27, 2025
cef2818
ref: Exception to handle CodeList custom message
laurentC35 Feb 27, 2025
540e2f3
test: fix test with exception
laurentC35 Feb 27, 2025
132ac5f
chore: add content type
laurentC35 Feb 27, 2025
2e70108
bump: 4.12.0-SNAPSHOT.6
laurentC35 Feb 27, 2025
461da5e
feat: return list of updatedQuestion
laurentC35 Feb 27, 2025
4c36dcd
Merge branch 'main' into feat/codelists-endpoints
laurentC35 Mar 12, 2025
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
37 changes: 5 additions & 32 deletions src/main/java/fr/insee/pogues/service/CodesListService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,24 @@

import static fr.insee.pogues.utils.CodesListConverter.*;
import static fr.insee.pogues.utils.json.JSONFunctions.jsonStringtoJsonNode;
import static fr.insee.pogues.utils.model.CodesList.getListOfQuestionIdWhereCodesListIsUsed;

@Service
@Slf4j
public class CodesListService {
private QuestionnairesService questionnairesService;
private VariableService variableService;

@Autowired

Choose a reason for hiding this comment

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

Plus besoin du @Autowired comme tu utilises déjà l'injection par constructeur. tu eux remove

Suggested change
@Autowired

public CodesListService(QuestionnairesService questionnairesService){
public CodesListService(QuestionnairesService questionnairesService, VariableService variableService){
this.questionnairesService = questionnairesService;
this.variableService = variableService;
}

public boolean updateOrAddCodeListToQuestionnaire(String questionnaireId, String idCodesList, CodesList codesList) throws Exception {
Questionnaire questionnaire = retrieveQuestionnaireWithId(questionnaireId);
boolean created = updateOrAddCodeListToQuestionnaire(questionnaire, idCodesList, codesList);
if(!created) variableService.updateQuestionAndVariablesAccordingToCodesList(questionnaire, idCodesList);
updateQuestionnaireInDataBase(questionnaire);
return created;
}
Expand Down Expand Up @@ -91,38 +95,7 @@ boolean updateOrAddCodeListDTD(List<CodeList> existingCodeLists, String idCodesL
return false;
}

List<String> getListOfQuestionIdWhereCodesListIsUsed(Questionnaire questionnaire, String codesListId){
return getListOfQuestionWhereCodesListIsUsed(questionnaire, codesListId).stream()
.map(componentType -> componentType.getId())
.toList();
}

List<ComponentType> getListOfQuestionWhereCodesListIsUsed(Questionnaire questionnaire, String codesListId){
return questionnaire.getChild().stream()
.map(componentType -> getListOfQuestionWhereCodesListIsUsed(componentType, codesListId))
.flatMap(Collection::stream).toList();
}

List<ComponentType> getListOfQuestionWhereCodesListIsUsed(ComponentType poguesComponent, String codesListId){
List<ComponentType> questions = new ArrayList<>();
if(poguesComponent.getClass().equals(SequenceType.class)){
((SequenceType) poguesComponent).getChild().stream().forEach(childComponent -> {
questions.addAll(getListOfQuestionWhereCodesListIsUsed(childComponent, codesListId));
});
}
if(poguesComponent.getClass().equals(QuestionType.class)){
QuestionTypeEnum questionType = ((QuestionType) poguesComponent).getQuestionType();
((QuestionType) poguesComponent).getResponse().forEach(responseType -> {
if(codesListId.equals(responseType.getCodeListReference())) questions.add(poguesComponent);
});
if(questionType.equals(QuestionTypeEnum.TABLE) || questionType.equals(QuestionTypeEnum.MULTIPLE_CHOICE)){
((QuestionType) poguesComponent).getResponseStructure().getDimension().forEach(dimensionType -> {
if(codesListId.equals(dimensionType.getCodeListReference())) questions.add(poguesComponent);
});
}
}
return questions;
}


void addCodeListDTD(List<CodeList> existingCodeLists, CodesList codesListDtdToAdd){
Expand Down
99 changes: 24 additions & 75 deletions src/main/java/fr/insee/pogues/service/VariableService.java
Original file line number Diff line number Diff line change
@@ -1,94 +1,43 @@
package fr.insee.pogues.service;

import fr.insee.pogues.model.*;
import fr.insee.pogues.persistence.service.QuestionnairesService;
import fr.insee.pogues.utils.PoguesDeserializer;
import fr.insee.pogues.utils.PoguesSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.*;
import java.util.stream.IntStream;

import static fr.insee.pogues.utils.json.JSONFunctions.jsonStringtoJsonNode;
import static fr.insee.pogues.utils.model.CodesList.getListOfQuestionWhereCodesListIsUsed;
import static fr.insee.pogues.utils.model.question.MultipleChoice.updateMultipleChoiceQuestionAccordingToCodeList;
import static fr.insee.pogues.utils.model.question.Table.updateTableQuestionAccordingToCodeList;
import static fr.insee.pogues.utils.model.Variables.*;

@Service
public class VariableService {

private QuestionnairesService questionnairesService;

private CodesListService codesListService;

@Autowired
public VariableService(QuestionnairesService questionnairesService, CodesListService codesListService){
this.questionnairesService = questionnairesService;
this.codesListService = codesListService;
}

public void updateQuestionAndVariablesAccordingToCodesList(Questionnaire questionnaire, String updatedCodeListId){
// Retrieve updatedCodeList in questionnaire
CodeList codeList = questionnaire.getCodeLists().getCodeList().stream().filter(cL -> updatedCodeListId.equals(cL.getId())).findFirst().get();
// handleOnly MULTIPLE_CHOICE question for now
List<ComponentType> questionsToModify = codesListService
.getListOfQuestionWhereCodesListIsUsed(questionnaire, updatedCodeListId).stream()
.filter(componentType -> ((QuestionType) componentType).getQuestionType().equals(QuestionTypeEnum.MULTIPLE_CHOICE)).toList();
// retrieve collected variables of multipleQuestion
List<String> oldVariables = questionsToModify.stream()
.map(componentType -> getVariableOfMultipleQuestion((QuestionType) componentType))
.flatMap(Collection::stream)
// Just retrieve MULTIPLE_CHOICE and TABLE questions
List<QuestionType> questionsToModify = getListOfQuestionWhereCodesListIsUsed(questionnaire, updatedCodeListId).stream()
.filter(questionType -> {
QuestionTypeEnum questionTypeEnum = questionType.getQuestionType();
return QuestionTypeEnum.MULTIPLE_CHOICE.equals(questionTypeEnum) || QuestionTypeEnum.TABLE.equals(questionTypeEnum);
})
.toList();
// remove old variables
questionnaire.getVariables().getVariable().removeIf(variable -> oldVariables.contains(variable.getId()));

// generate response first with CollectedVariableReference id generated
List<ResponseType> responses;


// generate new variable according to codeList
List<VariableType> newVariables = questionsToModify.stream()
.map(componentType -> computeNewVariableAccordingToCodeListMultipleChoice(codeList, componentType.getName()))
// modify Multiple and Table question and get there new Variables
List<VariableType> variables = questionsToModify.stream()
.map(questionType -> {
QuestionTypeEnum questionTypeEnum = questionType.getQuestionType();
if(QuestionTypeEnum.MULTIPLE_CHOICE.equals(questionTypeEnum)) return updateMultipleChoiceQuestionAccordingToCodeList(questionType, codeList);
return updateTableQuestionAccordingToCodeList(questionType, codeList, questionnaire.getCodeLists().getCodeList());
})
.flatMap(Collection::stream)
.toList();

// add new variables
questionnaire.getVariables().getVariable().addAll(newVariables);

}

private List<String> getVariableOfMultipleQuestion(QuestionType multipleQuestion){
if(!multipleQuestion.getQuestionType().equals(QuestionTypeEnum.MULTIPLE_CHOICE)) return List.of();
return multipleQuestion.getResponse().stream()
.map(responseType -> responseType.getCollectedVariableReference())
.toList();
}

private VariableType buildBooleanVariableFromCode(CodeType codeType, String name){
CollectedVariableType collectedVariableType = new CollectedVariableType();
collectedVariableType.setId(UUID.randomUUID().toString());
collectedVariableType.setName(name);
collectedVariableType.setLabel(String.format("%s - %s",codeType.getValue(), codeType.getLabel()));
DatatypeType booleanType = new BooleanDatatypeType();
booleanType.setTypeName(DatatypeTypeEnum.BOOLEAN);
collectedVariableType.setDatatype(booleanType);
return collectedVariableType;
}

public List<VariableType> computeNewVariableAccordingToCodeListMultipleChoice(CodeList codeList, String questionName){
return IntStream.range(0, codeList.getCode().size())
.mapToObj(index -> buildBooleanVariableFromCode(codeList.getCode().get(index), String.format("%s%d",questionName,index+1)))
.toList();
}


private Questionnaire retrieveQuestionnaireWithId(String id) throws Exception {
return PoguesDeserializer.questionnaireToJavaObject(questionnairesService.getQuestionnaireByID(id));
}

private void updateQuestionnaireInDataBase(Questionnaire questionnaire) throws Exception {
questionnairesService.updateQuestionnaire(
questionnaire.getId(),
jsonStringtoJsonNode(PoguesSerializer.questionnaireJavaToString(questionnaire)));
// add new variables to questionnaire
questionnaire.getVariables().getVariable().addAll(variables);
// Delete variables that are not referenced in response
List<String> neededCollectedVariables = getNeededCollectedVariablesInQuestionnaire(questionnaire);
questionnaire.getVariables().getVariable().removeIf(variableType -> !neededCollectedVariables.contains(variableType.getId()));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import java.util.List;

import static fr.insee.pogues.utils.PoguesModelUtils.getSequences;
import static fr.insee.pogues.utils.model.PoguesModelUtils.getSequences;

/**
* Implementation of CompositionStep to replace questionnaire reference by its sequences.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

import java.util.List;

import static fr.insee.pogues.utils.PoguesModelUtils.getFlowControlBounds;
import static fr.insee.pogues.utils.PoguesModelUtils.getSequences;
import static fr.insee.pogues.utils.model.PoguesModelUtils.getFlowControlBounds;
import static fr.insee.pogues.utils.model.PoguesModelUtils.getSequences;

/**
* Implementation of CompositionStep to update FlowControl (filters) objects when de-referencing a questionnaire.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

import java.util.List;

import static fr.insee.pogues.utils.PoguesModelUtils.getIterationBounds;
import static fr.insee.pogues.utils.PoguesModelUtils.getSequences;
import static fr.insee.pogues.utils.model.PoguesModelUtils.getIterationBounds;
import static fr.insee.pogues.utils.model.PoguesModelUtils.getSequences;

/**
* Implementation of CompositionStep to update Iteration (loops) objects when de-referencing a questionnaire.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import fr.insee.pogues.model.IterationType;
import fr.insee.pogues.model.Questionnaire;
import fr.insee.pogues.model.VariableType;
import fr.insee.pogues.utils.PoguesModelUtils;
import fr.insee.pogues.utils.model.PoguesModelUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

import static fr.insee.pogues.utils.PoguesModelUtils.getIterationBounds;
import static fr.insee.pogues.utils.model.PoguesModelUtils.getIterationBounds;

/**
* Implementation of CompositionStep to update variable scopes when de-referencing a questionnaire.
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/fr/insee/pogues/utils/model/CodesList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package fr.insee.pogues.utils.model;

import fr.insee.pogues.model.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class CodesList {

public static List<QuestionType> getListOfQuestionWhereCodesListIsUsed(Questionnaire questionnaire, String codesListId){
return questionnaire.getChild().stream()
.map(componentType -> getListOfQuestionWhereCodesListIsUsed(componentType, codesListId))
.flatMap(Collection::stream).toList();
}

public static List<String> getListOfQuestionIdWhereCodesListIsUsed(Questionnaire questionnaire, String codesListId){
return getListOfQuestionWhereCodesListIsUsed(questionnaire, codesListId).stream()
.map(componentType -> componentType.getId())
.toList();
}

public static List<QuestionType> getListOfQuestionWhereCodesListIsUsed(ComponentType poguesComponent, String codesListId){
List<QuestionType> questions = new ArrayList<>();
if(poguesComponent.getClass().equals(SequenceType.class)){
((SequenceType) poguesComponent).getChild().stream().forEach(childComponent -> {
questions.addAll(getListOfQuestionWhereCodesListIsUsed(childComponent, codesListId));
});
}
if(poguesComponent.getClass().equals(QuestionType.class)){
QuestionTypeEnum questionType = ((QuestionType) poguesComponent).getQuestionType();
((QuestionType) poguesComponent).getResponse().forEach(responseType -> {
if(codesListId.equals(responseType.getCodeListReference())) questions.add((QuestionType) poguesComponent);
});
if(questionType.equals(QuestionTypeEnum.TABLE) || questionType.equals(QuestionTypeEnum.MULTIPLE_CHOICE)){
((QuestionType) poguesComponent).getResponseStructure().getDimension().forEach(dimensionType -> {
if(codesListId.equals(dimensionType.getCodeListReference())) questions.add((QuestionType) poguesComponent);
});
}
}
return questions;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package fr.insee.pogues.utils;
package fr.insee.pogues.utils.model;

import fr.insee.pogues.exception.IllegalFlowControlException;
import fr.insee.pogues.exception.IllegalIterationException;
Expand Down
52 changes: 52 additions & 0 deletions src/main/java/fr/insee/pogues/utils/model/Variables.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package fr.insee.pogues.utils.model;

import fr.insee.pogues.model.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Variables {

public static VariableType buildBooleanVariableFromCode(CodeType codeType, String variableId, String name){
CollectedVariableType collectedVariableType = new CollectedVariableType();
collectedVariableType.setId(variableId);
collectedVariableType.setName(name);
collectedVariableType.setLabel(String.format("%s - %s",codeType.getValue(), codeType.getLabel()));
DatatypeType booleanType = new BooleanDatatypeType();
booleanType.setTypeName(DatatypeTypeEnum.BOOLEAN);
collectedVariableType.setDatatype(booleanType);
return collectedVariableType;
}

public static VariableType buildCollectedVariableFromDataType(DatatypeType datatype, String variableId, String name, String label){
CollectedVariableType collectedVariableType = new CollectedVariableType();
collectedVariableType.setDatatype(datatype);
collectedVariableType.setId(variableId);
collectedVariableType.setName(name);
collectedVariableType.setLabel(label);
return collectedVariableType;
}

public static List<String> getNeededCollectedVariablesInQuestionnaire(Questionnaire questionnaire){
return questionnaire.getChild().stream()
.map(componentType -> getNeededCollectedVariablesInQuestionnaire(componentType))
.flatMap(Collection::stream).toList();
}

public static List<String> getNeededCollectedVariablesInQuestionnaire(ComponentType poguesComponent){
List<String> variablesIds = new ArrayList<>();
if(poguesComponent.getClass().equals(SequenceType.class)){
((SequenceType) poguesComponent).getChild().stream().forEach(childComponent -> {
variablesIds.addAll(getNeededCollectedVariablesInQuestionnaire(childComponent));
});
}
if(poguesComponent.getClass().equals(QuestionType.class)){
((QuestionType) poguesComponent).getResponse().forEach(responseType -> {
String collectedVariable = responseType.getCollectedVariableReference();
if(collectedVariable != null) variablesIds.add(collectedVariable);
});
}
return variablesIds;
}
}
19 changes: 19 additions & 0 deletions src/main/java/fr/insee/pogues/utils/model/question/Common.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package fr.insee.pogues.utils.model.question;

import fr.insee.pogues.model.MappingType;

import java.util.UUID;

public class Common {

public static String getNewUniqueId(){
return UUID.randomUUID().toString();
}

public static MappingType createNewMapping(String mappingSource, String mappingTarget){
MappingType mapping = new MappingType();
mapping.setMappingSource(mappingSource);
mapping.setMappingTarget(mappingTarget);
return mapping;
}
}
Loading