From b62a9b9ae6e1f863feb9b09824e4fac7615f4dbb Mon Sep 17 00:00:00 2001 From: Maverick Studer Date: Thu, 21 Nov 2024 16:06:38 +0100 Subject: [PATCH] RED-8811: Merge in recreated type does not work properly --- .../service/DictionaryManagementService.java | 20 ++-- .../persistence/EntryPersistenceService.java | 7 ++ .../repository/TypeRepository.java | 2 +- .../dictionaryentry/EntryRepository.java | 5 + .../integration/tests/DictionaryTest.java | 95 ++++++++++++++++++- 5 files changed, 118 insertions(+), 11 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryManagementService.java index 552e84aa5..824e4caca 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryManagementService.java @@ -239,10 +239,11 @@ public class DictionaryManagementService { @Transactional public void addEntries(String typeId, List entries, boolean removeCurrent, boolean ignoreInvalidEntries, DictionaryEntryType dictionaryEntryType) { + addEntries(typeId, entries, removeCurrent, ignoreInvalidEntries, dictionaryEntryType, false); } - - + + @Transactional public void addEntries(String typeId, List entries, boolean removeCurrent, boolean ignoreInvalidEntries, DictionaryEntryType dictionaryEntryType, boolean isImport) { @@ -293,7 +294,10 @@ public class DictionaryManagementService { // check for the existence of dossier type and create in case it does not exist if (isDossierTypeId(typeId)) { try { - dictionaryPersistenceService.getType(typeId); + TypeEntity type = dictionaryPersistenceService.getType(typeId, true); + if (type.isDeleted()) { + dictionaryPersistenceService.undeleteType(typeId); + } } catch (NotFoundException e) { // type not found check first dossier is matching the specified dossier template var dossierId = getDossierIdFromTypeId(typeId); @@ -397,9 +401,13 @@ public class DictionaryManagementService { dictionaryPersistenceService.deleteType(typeId); - entryPersistenceService.deleteAllEntriesForTypeId(typeId, currentVersion + 1, DictionaryEntryType.ENTRY); - entryPersistenceService.deleteAllEntriesForTypeId(typeId, currentVersion + 1, DictionaryEntryType.FALSE_POSITIVE); - entryPersistenceService.deleteAllEntriesForTypeId(typeId, currentVersion + 1, DictionaryEntryType.FALSE_RECOMMENDATION); + if (isDossierTypeId(typeId)) { + entryPersistenceService.hardDeleteAllEntriesForTypeId(typeId); + } else { + entryPersistenceService.deleteAllEntriesForTypeId(typeId, currentVersion + 1, DictionaryEntryType.ENTRY); + entryPersistenceService.deleteAllEntriesForTypeId(typeId, currentVersion + 1, DictionaryEntryType.FALSE_POSITIVE); + entryPersistenceService.deleteAllEntriesForTypeId(typeId, currentVersion + 1, DictionaryEntryType.FALSE_RECOMMENDATION); + } dictionaryPersistenceService.incrementVersion(typeId); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/EntryPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/EntryPersistenceService.java index e3952250c..987694a43 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/EntryPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/EntryPersistenceService.java @@ -184,6 +184,13 @@ public class EntryPersistenceService { } + @Transactional + public void hardDeleteAllEntriesForTypeId(String typeId) { + + entryRepository.hardDeleteAllEntriesForTypeId(typeId); + } + + public void cloneEntries(String originalTypeId, String newTypeId) { entryRepository.cloneEntries(originalTypeId, newTypeId); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/TypeRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/TypeRepository.java index 6ecb0ae37..00d5e5089 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/TypeRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/TypeRepository.java @@ -86,7 +86,7 @@ public interface TypeRepository extends JpaRepository { void softDeleteTypeById(@Param("typeId") String typeId); - @Modifying + @Modifying(clearAutomatically = true, flushAutomatically = true) @Query("Update TypeEntity t set t.softDeletedTime = null where t.id = :typeId and t.softDeletedTime is not null") int unSoftDeleteTypeById(@Param("typeId") String typeId); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/dictionaryentry/EntryRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/dictionaryentry/EntryRepository.java index d1892996f..69170a652 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/dictionaryentry/EntryRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/dictionaryentry/EntryRepository.java @@ -29,6 +29,11 @@ public interface EntryRepository extends EntryRepositoryCustom, JpaRepository testList1 = List.of("William c. Spare", "Charalampos", "Carina Wilson", "PATRICIA A. SHEEHY", "William C. Spare", "carlsen", "Patricia A. Sheehy"); private final List testList2 = List.of("William C. Spare", "Charalampos", "Carina Wilson", "Patricia A. Sheehy", "William c. Spare", "carlsen", "PATRICIA A. SHEEHY"); @@ -1176,7 +1183,7 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { var type = dictionaryClient.addType(createTypeValue); - List customTypes = dictionaryClient.getAllTypes(dossierTemplate.getId(), dossier.getId(), false).getTypes() + List customTypes = dictionaryClient.getAllTypes(dossierTemplate.getId(), dossier.getId(), false).getTypes() .stream() .filter(t -> !t.isSystemManaged()) .toList(); @@ -1205,6 +1212,86 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { } + @Test + void testRecreateTypeAndCheckMergedDictionary() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "TestDossier"); + + var type = typeProvider.testAndProvideType(dossierTemplate, null, "type1", false); + + List templateEntries = List.of("aaa", "bbb"); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), templateEntries, false, null, DictionaryEntryType.ENTRY); + var templateDictionary = dictionaryClient.getDictionaryForType(type.getType(), dossierTemplate.getId(), null); + assertThat(templateDictionary.getEntries()).containsExactlyInAnyOrderElementsOf(templateEntries); + + List dossierEntries = List.of("ccc"); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), dossierEntries, false, dossier.getId(), DictionaryEntryType.ENTRY); + var dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), dossierTemplate.getId(), dossier.getId()); + assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrderElementsOf(dossierEntries); + + Dictionary mergedDictionary = dictionaryClient.getMergedDictionaries(type.getType(), type.getDossierTemplateId(), dossier.getId()); + assertThat(mergedDictionary).isNotNull(); + List allEntries = new ArrayList<>(templateEntries); + allEntries.addAll(dossierEntries); + assertThat(mergedDictionary.getEntries()).containsExactlyInAnyOrderElementsOf(allEntries); + + List newDossierEntries = List.of("entry d"); + UpdateEntries updateEntries = new UpdateEntries(newDossierEntries, allEntries); + dictionaryClient.updateEntries(type.getType(), type.getDossierTemplateId(), updateEntries, dossier.getId(), DictionaryEntryType.ENTRY); + + List deleted = entryRepository.findAll().stream().filter(DictionaryEntryEntity::isDeleted).toList(); + assertEquals(3, deleted.size()); + + var updatedDossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), dossierTemplate.getId(), dossier.getId()); + assertThat(updatedDossierDictionary.getEntries()).containsExactlyInAnyOrderElementsOf(newDossierEntries); + + // deletion + dictionaryClient.deleteType(type.getType(), type.getDossierTemplateId()); + Assertions.assertThrows(FeignException.NotFound.class, () -> dictionaryClient.getDictionaryForType(type.getType(), dossierTemplate.getId(), null)); + + List deletedType1Entities = typeRepository.findAllTypesByDossierTemplateIdOrDossierId(dossierTemplate.getId(), dossier.getId()) + .stream() + .filter(typeEntity -> typeEntity.getType().equals("type1") && typeEntity.isDeleted()) + .toList(); + + assertEquals(2, deletedType1Entities.size()); + + deleted = entryRepository.findAll().stream().filter(DictionaryEntryEntity::isDeleted).toList(); + assertEquals(2, deleted.size()); + + // recreation + var type2 = typeProvider.testAndProvideType(dossierTemplate, null, "type1", false); + + dictionaryClient.addEntry(type2.getType(), type2.getDossierTemplateId(), templateEntries, false, null, DictionaryEntryType.ENTRY); + + deleted = entryRepository.findAll().stream().filter(DictionaryEntryEntity::isDeleted).toList(); + assertEquals(0, deleted.size()); + + deletedType1Entities = typeRepository.findAllTypesByDossierTemplateIdOrDossierId(dossierTemplate.getId(), dossier.getId()) + .stream() + .filter(typeEntity -> typeEntity.getType().equals("type1") && typeEntity.isDeleted()) + .toList(); + + assertEquals(1, deletedType1Entities.size()); + + // problematic call because it creates/update entities on a get + dictionaryClient.getAllTypes(dossierTemplate.getId(), dossier.getId(), false); + + deletedType1Entities = typeRepository.findAllTypesByDossierTemplateIdOrDossierId(dossierTemplate.getId(), dossier.getId()) + .stream() + .filter(typeEntity -> typeEntity.getType().equals("type1") && typeEntity.isDeleted()) + .toList(); + + assertEquals(0, deletedType1Entities.size()); + + Dictionary mergedDictionary2 = dictionaryClient.getMergedDictionaries(type2.getType(), type2.getDossierTemplateId(), dossier.getId()); + assertThat(mergedDictionary2).isNotNull(); + assertThat(mergedDictionary2.getEntries()).containsExactlyInAnyOrderElementsOf(templateEntries); + assertThat(mergedDictionary2.getEntries()).doesNotContain("entry d"); + } + + private static final class ListContentWithoutOrderAndWithoutDuplicatesComparator implements Comparator> { @SuppressWarnings("SuspiciousMethodCalls")