diff --git a/src/main/java/de/numcodex/feasibility_gui_backend/terminology/TerminologyService.java b/src/main/java/de/numcodex/feasibility_gui_backend/terminology/TerminologyService.java index be29883d..60be57d5 100644 --- a/src/main/java/de/numcodex/feasibility_gui_backend/terminology/TerminologyService.java +++ b/src/main/java/de/numcodex/feasibility_gui_backend/terminology/TerminologyService.java @@ -29,8 +29,9 @@ public class TerminologyService { private final MappingRepository mappingRepository; private String uiProfilePath; - private static final List SORTED_CATEGORIES = List.of("Einwilligung", "MII_PR_Consent_Einwilligung", "Bioprobe", - "Diagnose", "Laboruntersuchung", "Medikamentenverabreichung", "Person", "ProfileSpecimenBioprobe", "Prozedur"); + + @Value("${app.ontologyOrder}") + private List sortedCategories; private Map terminologyEntries = new HashMap<>(); private List categoryEntries = new ArrayList<>(); private Map terminologyEntriesWithOnlyDirectChildren = new HashMap<>(); @@ -128,9 +129,18 @@ public TerminologyEntry getEntry(UUID nodeId) throws NodeNotFoundException { } public List getCategories() { - categoryEntries.sort( - Comparator.comparing(value -> SORTED_CATEGORIES.indexOf(value.getDisplay()))); - return categoryEntries; + var sortedCategoryEntries = new ArrayList(); + + List found = categoryEntries.stream().filter(value -> sortedCategories.contains(value.getDisplay())).collect(Collectors.toList()); + List notFound = categoryEntries.stream().filter(value -> !sortedCategories.contains(value.getDisplay())).collect(Collectors.toList()); + + found.sort(Comparator.comparing(value -> sortedCategories.indexOf(value.getDisplay()))); + notFound.sort(Comparator.comparing(CategoryEntry::getDisplay)); + + sortedCategoryEntries.addAll(found); + sortedCategoryEntries.addAll(notFound); + + return sortedCategoryEntries; } public List getSelectableEntries(String query, UUID categoryId) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e4266de8..626c186d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -40,6 +40,7 @@ management: app: # AKTIN or DSF or MOCK or DIRECT ontologyFolder: ${ONTOLOGY_FILES_FOLDER_UI:ontology/ui_trees} + ontologyOrder: ${ONTOLOGY_ORDER:Diagnose, Prozedur, Person, Laboruntersuchung, Medikamente, Bioprobe, Einwilligung} mappingsFile: ${MAPPINGS_FILE:ontology/mapping_cql.json} conceptTreeFile: ${CONCEPT_TREE_FILE:ontology/mapping_tree.json} fhirTranslationEnabled: ${FHIR_TRANSLATE_ENABLED:false} diff --git a/src/test/java/de/numcodex/feasibility_gui_backend/terminology/TerminologyServiceTest.java b/src/test/java/de/numcodex/feasibility_gui_backend/terminology/TerminologyServiceTest.java index b388eae4..28c737ae 100644 --- a/src/test/java/de/numcodex/feasibility_gui_backend/terminology/TerminologyServiceTest.java +++ b/src/test/java/de/numcodex/feasibility_gui_backend/terminology/TerminologyServiceTest.java @@ -11,6 +11,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; import java.io.IOException; import java.util.List; @@ -30,6 +31,8 @@ class TerminologyServiceTest { private static UUID CATEGORY_1_ID = UUID.fromString("2ec77ac6-2547-2aff-031b-337d9ff80cff"); private static UUID CATEGORY_2_ID = UUID.fromString("457b3f3b-bf4e-45da-b676-dc63d31942dd"); + private static UUID CATEGORY_A_ID = UUID.fromString("30a20f30-77db-11ee-b962-0242ac120002"); + private static UUID CATEGORY_B_ID = UUID.fromString("385d2db8-77db-11ee-b962-0242ac120002"); private static UUID VALID_NODE_ID_CAT1 = UUID.fromString("72ceaea9-c1ff-2e94-5fc0-7ba34feca654"); private static UUID VALID_NODE_ID_CAT2 = UUID.fromString("33ca0320-81e5-406f-bdfd-c649e443ddd6"); @@ -81,17 +84,40 @@ void testGetEntry_throwsOnUnknown() throws IOException { } @Test - void testGetCategories() throws IOException { + void testGetCategories_order1() throws IOException { var terminologyService = createTerminologyService("src/test/resources/ontology/ui_profiles"); - var categoriesResult = assertDoesNotThrow(() -> terminologyService.getCategories()); + ReflectionTestUtils.setField(terminologyService, "sortedCategories", List.of("Category2", "Category3", "Category1")); + + var categoriesResult = assertDoesNotThrow(terminologyService::getCategories); + assertNotNull(categoriesResult); + assertFalse(categoriesResult.isEmpty()); + assertThat(categoriesResult) + .hasSize(4) + .extracting(CategoryEntry::getDisplay, CategoryEntry::getCatId) + .containsExactly( + tuple("Category2", CATEGORY_2_ID), + tuple("Category1", CATEGORY_1_ID), + tuple("CategoryA", CATEGORY_A_ID), + tuple("CategoryB", CATEGORY_B_ID) + ); + } + + @Test + void testGetCategories_order2() throws IOException { + var terminologyService = createTerminologyService("src/test/resources/ontology/ui_profiles"); + ReflectionTestUtils.setField(terminologyService, "sortedCategories", List.of("CategoryB", "CategoryX", "CategoryY")); + + var categoriesResult = assertDoesNotThrow(terminologyService::getCategories); assertNotNull(categoriesResult); assertFalse(categoriesResult.isEmpty()); assertThat(categoriesResult) - .hasSize(2) + .hasSize(4) .extracting(CategoryEntry::getDisplay, CategoryEntry::getCatId) - .containsExactlyInAnyOrder( + .containsExactly( + tuple("CategoryB", CATEGORY_B_ID), tuple("Category1", CATEGORY_1_ID), - tuple("Category2", CATEGORY_2_ID) + tuple("Category2", CATEGORY_2_ID), + tuple("CategoryA", CATEGORY_A_ID) ); } diff --git a/src/test/resources/ontology/ui_profiles/CategoryA.json b/src/test/resources/ontology/ui_profiles/CategoryA.json new file mode 100644 index 00000000..6936a049 --- /dev/null +++ b/src/test/resources/ontology/ui_profiles/CategoryA.json @@ -0,0 +1,60 @@ +{ + "children": [ + { + "context": { + "code": "CategoryA", + "display": "CategoryA", + "system": "fdpg.mii.cds", + "version": "1.0.0" + }, + "display": "Termcode A_1", + "id": "33ca0320-81e5-406f-bdfd-c649e443ddd6", + "leaf": true, + "selectable": true, + "termCodes": [ + { + "code": "tcA_1", + "display": "Termcode A_1", + "system": "http://some.system/", + "version": "http://some.system/123/version/456" + } + ] + }, + { + "context": { + "code": "CategoryA", + "display": "CategoryA", + "system": "fdpg.mii.cds", + "version": "1.0.0" + }, + "display": "Termcode A_2", + "id": "0da2a746-d23f-4668-9160-51d83edbd02c", + "leaf": true, + "selectable": true, + "termCodes": [ + { + "code": "tcA_2", + "display": "Termcode A_2", + "system": "http://some.system/", + "version": "http://some.system/123/version/456" + } + ] + } + ], + "context": { + "code": "CategoryA", + "display": "CategoryA", + "system": "fdpg.mii.cds" + }, + "display": "CategoryA", + "id": "30a20f30-77db-11ee-b962-0242ac120002", + "leaf": false, + "selectable": false, + "termCodes": [ + { + "code": "CategoryA", + "display": "CategoryA", + "system": "fdpg.mii.cds" + } + ] +} diff --git a/src/test/resources/ontology/ui_profiles/CategoryB.json b/src/test/resources/ontology/ui_profiles/CategoryB.json new file mode 100644 index 00000000..394b8ee0 --- /dev/null +++ b/src/test/resources/ontology/ui_profiles/CategoryB.json @@ -0,0 +1,60 @@ +{ + "children": [ + { + "context": { + "code": "CategoryB", + "display": "CategoryB", + "system": "fdpg.mii.cds", + "version": "1.0.0" + }, + "display": "Termcode B_1", + "id": "33ca0320-81e5-406f-bdfd-c649e443ddd6", + "leaf": true, + "selectable": true, + "termCodes": [ + { + "code": "tcB_1", + "display": "Termcode B_1", + "system": "http://some.system/", + "version": "http://some.system/123/version/456" + } + ] + }, + { + "context": { + "code": "CategoryB", + "display": "CategoryB", + "system": "fdpg.mii.cds", + "version": "1.0.0" + }, + "display": "Termcode B_2", + "id": "0da2a746-d23f-4668-9160-51d83edbd02c", + "leaf": true, + "selectable": true, + "termCodes": [ + { + "code": "tcB_2", + "display": "Termcode B_2", + "system": "http://some.system/", + "version": "http://some.system/123/version/456" + } + ] + } + ], + "context": { + "code": "CategoryB", + "display": "CategoryB", + "system": "fdpg.mii.cds" + }, + "display": "CategoryB", + "id": "385d2db8-77db-11ee-b962-0242ac120002", + "leaf": false, + "selectable": false, + "termCodes": [ + { + "code": "CategoryB", + "display": "CategoryB", + "system": "fdpg.mii.cds" + } + ] +}