diff --git a/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java b/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java index 31d3863..c5bd1ce 100644 --- a/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java +++ b/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java @@ -8,6 +8,7 @@ import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.tuple.Pair; import org.gridsuite.studyconfig.server.dto.*; import org.gridsuite.studyconfig.server.entities.ColumnEntity; import org.gridsuite.studyconfig.server.entities.GlobalFilterEntity; @@ -371,6 +372,38 @@ private static void reorderColumns(List columnOrder, List co columns.sort(Comparator.comparingInt(column -> columnOrder.indexOf(column.getUuid()))); } + private String newCandidate(String base, int n) { + return base + '_' + n; + } + + /** + * Generates a unique value by appending a numeric suffix if the original value already exists. + * + * @param originalValue the original value to make unique + * @param existingValues set of existing values to avoid conflicts with + * @return a unique value, either the original or with a numeric suffix + */ + private String getUniqueValue(String originalValue, Set existingValues) { + if (!existingValues.contains(originalValue)) { + return originalValue; + } + + int i = 1; + while (existingValues.contains(newCandidate(originalValue, i))) { + ++i; + } + return newCandidate(originalValue, i); + } + + private Pair getDuplicateIdAndNameCandidate(SpreadsheetConfigEntity entity, String columnId, String columnName) { + var existingColumnIds = entity.getColumns().stream().map(ColumnEntity::getId).collect(Collectors.toSet()); + var existingColumnNames = entity.getColumns().stream().map(ColumnEntity::getName).collect(Collectors.toSet()); + String newColumnId = getUniqueValue(columnId, existingColumnIds); + String newColumnName = getUniqueValue(columnName, existingColumnNames); + + return Pair.of(newColumnId, newColumnName); + } + @Transactional public void duplicateColumn(UUID id, UUID columnId) { SpreadsheetConfigEntity entity = findEntityById(id); @@ -378,9 +411,9 @@ public void duplicateColumn(UUID id, UUID columnId) { .findFirst().orElseThrow(() -> new EntityNotFoundException(COLUMN_NOT_FOUND + columnId)); ColumnEntity columnCopy = columnEntity.toBuilder().build(); columnCopy.setUuid(UUID.randomUUID()); - columnCopy.setId(columnCopy.getId() + "copy"); - columnCopy.setName(columnCopy.getName() + "-copy"); - + Pair idAndName = getDuplicateIdAndNameCandidate(entity, columnCopy.getId(), columnCopy.getName()); + columnCopy.setId(idAndName.getLeft()); + columnCopy.setName(idAndName.getRight()); List columns = entity.getColumns(); columns.add(columns.indexOf(columnEntity) + 1, columnCopy); entity.setColumns(columns); diff --git a/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java b/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java index b41b8d4..7d0019b 100644 --- a/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java +++ b/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java @@ -30,6 +30,7 @@ import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -328,12 +329,22 @@ void testDuplicateColumn() throws Exception { ColumnInfos duplicatedColumnInfos = configAfterDuplicate.columns().get(1); assertThat(columnInfos.uuid()).isNotEqualTo(duplicatedColumnInfos.uuid()); - assertThat(columnInfos.id()).isNotEqualTo(duplicatedColumnInfos.id()); + assertEquals(columnInfos.id() + "_1", duplicatedColumnInfos.id()); + assertEquals(columnInfos.name() + "_1", duplicatedColumnInfos.name()); assertThat(columnInfos.visible()).isEqualTo(duplicatedColumnInfos.visible()); assertThat(columnInfos.formula()).isEqualTo(duplicatedColumnInfos.formula()); assertThat(columnInfos.dependencies()).isEqualTo(duplicatedColumnInfos.dependencies()); assertThat(columnInfos.precision()).isEqualTo(duplicatedColumnInfos.precision()); + mockMvc.perform(post(URI_SPREADSHEET_CONFIG_GET_PUT + configId + URI_COLUMN_BASE + "/" + columnId + "/duplicate")) + .andExpect(status().isNoContent()); + configAfterDuplicate = getSpreadsheetConfig(configId); + assertThat(configAfterDuplicate.columns()).hasSize(6); + duplicatedColumnInfos = configAfterDuplicate.columns().get(1); + assertThat(columnInfos.uuid()).isNotEqualTo(duplicatedColumnInfos.uuid()); + assertEquals(columnInfos.id() + "_2", duplicatedColumnInfos.id()); + assertEquals(columnInfos.name() + "_2", duplicatedColumnInfos.name()); + mockMvc.perform(post(URI_SPREADSHEET_CONFIG_GET_PUT + configId + URI_COLUMN_BASE + "/" + UUID.randomUUID() + "/duplicate")) .andExpect(status().isNotFound()); }