diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java index 1791f34c2..1d94f7353 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java @@ -428,6 +428,37 @@ public List findAll(String searchString, Vocabulary vocabulary) { } } + /** + * Finds terms whose label contains the specified search string. + * + * @param searchString String the search term labels by + * @return List of matching terms + */ + public List findAll(String searchString) { + Objects.requireNonNull(searchString); + final TypedQuery query = em.createNativeQuery("SELECT DISTINCT ?term WHERE {" + + "GRAPH ?vocabulary { " + + "?term a ?type ; " + + " ?hasLabel ?label ; " + + "FILTER CONTAINS(LCASE(?label), LCASE(?searchString)) ." + + "}" + + "?term ?inVocabulary ?vocabulary ." + + "} ORDER BY LCASE(?label)", TermDto.class) + .setParameter("type", typeUri) + .setParameter("hasLabel", LABEL_PROP) + .setParameter("inVocabulary", URI.create( + cz.cvut.kbss.termit.util.Vocabulary.s_p_je_pojmem_ze_slovniku)) + .setParameter("searchString", searchString, + config.get(ConfigParam.LANGUAGE)); + try { + final List terms = executeQueryAndLoadSubTerms(query); + terms.forEach(this::loadParentSubTerms); + return terms; + } catch (RuntimeException e) { + throw new PersistenceException(e); + } + } + private void loadParentSubTerms(TermDto parent) { parent.setSubTerms(loadSubTerms(parent)); if (parent.getParentTerms() != null) { diff --git a/src/main/java/cz/cvut/kbss/termit/rest/TermController.java b/src/main/java/cz/cvut/kbss/termit/rest/TermController.java index c8bfc30cc..4331d6145 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/TermController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/TermController.java @@ -536,4 +536,16 @@ public List getAllRoots(@RequestParam(name = Constants.QueryParams.PAGE @RequestParam(name = "includeTerms", required = false, defaultValue = "") List includeTerms) { return termService.findAllRoots(createPageRequest(pageSize, pageNo), includeTerms); } + + /** + * Get all terms preferred labels of which match the given searchString. + * + * @param searchString String to filter term labels by. + * @return List of terms of the specific vocabulary. + */ + @GetMapping(value = "/terms", + produces = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) + public List getAll(@RequestParam String searchString) { + return termService.findAll(searchString); + } } diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java b/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java index 7f7911da5..a4d6b1b94 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java @@ -170,6 +170,17 @@ public List findAll(String searchString, Vocabulary vocabulary) { return repositoryService.findAll(searchString, vocabulary); } + /** + * Finds all terms label of which is matching the searchString. + * + * @param searchString string to search the label by + * @return Matching terms + */ + public List findAll(String searchString) { + Objects.requireNonNull(searchString); + return repositoryService.findAll(searchString); + } + /** * Finds all terms which match the specified search string in the specified vocabulary and any vocabularies it * (transitively) imports. diff --git a/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java b/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java index e825f0d84..15bc8fb97 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java @@ -252,6 +252,16 @@ public List findAll(String searchString, Vocabulary vocabulary) { return termDao.findAll(searchString, vocabulary); } + /** + * Gets all terms from a vocabulary, with label matching the searchString + * + * @param searchString String to search by + * @return List of terms ordered by label + */ + public List findAll(String searchString) { + return termDao.findAll(searchString); + } + /** * Finds all terms which match the specified search string in the specified vocabulary and any vocabularies it * (transitively) imports. diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java index ff9c2852b..0d882990d 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java @@ -190,6 +190,16 @@ void findAllBySearchStringReturnsTermsWithMatchingLabel() { assertTrue(toDtos(terms).contains(result.get(0))); } + @Test + void findAllBySearchStringWithoutVocabularyReturnsTermsWithMatchingLabel() { + final List terms = generateTerms(10); + addTermsAndSave(new HashSet<>(terms), vocabulary); + + final List result = sut.findAll(terms.get(0).getLabel().get(Constants.DEFAULT_LANGUAGE)); + assertEquals(1, result.size()); + assertTrue(toDtos(terms).contains(result.get(0))); + } + @Test void findAllBySearchStringReturnsTermsWithMatchingLabelWhichAreNotRoots() { final List terms = generateTerms(10); diff --git a/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java b/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java index 052c92c6c..79c1c2ac3 100644 --- a/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java @@ -1,12 +1,37 @@ package cz.cvut.kbss.termit.rest; +import static cz.cvut.kbss.termit.environment.Environment.termsToDtos; +import static cz.cvut.kbss.termit.util.Constants.DEFAULT_PAGE_SPEC; +import static cz.cvut.kbss.termit.util.Constants.DEFAULT_TERM_NAMESPACE_SEPARATOR; +import static cz.cvut.kbss.termit.util.Constants.QueryParams.PAGE; +import static cz.cvut.kbss.termit.util.Constants.QueryParams.PAGE_SIZE; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyCollection; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.head; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + import com.fasterxml.jackson.core.type.TypeReference; import com.github.jsonldjava.utils.JsonUtils; import cz.cvut.kbss.jopa.model.MultilingualString; import cz.cvut.kbss.jopa.vocabulary.SKOS; import cz.cvut.kbss.jsonld.JsonLd; -import cz.cvut.kbss.termit.dto.listing.TermDto; import cz.cvut.kbss.termit.dto.assignment.TermAssignments; +import cz.cvut.kbss.termit.dto.listing.TermDto; import cz.cvut.kbss.termit.environment.Environment; import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.exception.NotFoundException; @@ -22,10 +47,25 @@ import cz.cvut.kbss.termit.service.IdentifierResolver; import cz.cvut.kbss.termit.service.business.TermService; import cz.cvut.kbss.termit.service.export.util.TypeAwareByteArrayResource; -import cz.cvut.kbss.termit.util.*; +import cz.cvut.kbss.termit.util.ConfigParam; +import cz.cvut.kbss.termit.util.Configuration; +import cz.cvut.kbss.termit.util.Constants; import cz.cvut.kbss.termit.util.Constants.Excel; import cz.cvut.kbss.termit.util.Constants.QueryParams; import cz.cvut.kbss.termit.util.Constants.Turtle; +import cz.cvut.kbss.termit.util.CsvUtils; +import cz.cvut.kbss.termit.util.Vocabulary; +import java.io.ByteArrayOutputStream; +import java.net.URI; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.junit.jupiter.api.BeforeEach; @@ -41,25 +81,6 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MvcResult; -import java.io.ByteArrayOutputStream; -import java.net.URI; -import java.time.Instant; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import static cz.cvut.kbss.termit.environment.Environment.termsToDtos; -import static cz.cvut.kbss.termit.util.Constants.DEFAULT_PAGE_SPEC; -import static cz.cvut.kbss.termit.util.Constants.DEFAULT_TERM_NAMESPACE_SEPARATOR; -import static cz.cvut.kbss.termit.util.Constants.QueryParams.PAGE; -import static cz.cvut.kbss.termit.util.Constants.QueryParams.PAGE_SIZE; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @ExtendWith(MockitoExtension.class) class TermControllerTest extends BaseControllerTestRunner { @@ -991,4 +1012,12 @@ void addCommentStandaloneReturnsLocationHeaderWithGeneratedIdentifier() throws E .andExpect(status().isCreated()).andReturn(); verifyLocationEquals("/comments/" + name, mvcResult); } + + @Test + void getAllTermsCallsServiceWithSearchString() throws Exception { + final String searchString = "test"; + mockMvc.perform(get("/terms").param("searchString", searchString)) + .andExpect(status().isOk()); + verify(termServiceMock).findAll(searchString); + } } diff --git a/src/test/java/cz/cvut/kbss/termit/service/business/TermServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/business/TermServiceTest.java index af8003572..dab820bba 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/business/TermServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/business/TermServiceTest.java @@ -198,6 +198,16 @@ void findAllRetrievesAllTermsFromVocabularyUsingRepositoryService() { verify(termRepositoryService).findAll(vocabulary); } + @Test + void findAllCallsFindAllInRepositoryService() { + final List terms = Collections.singletonList(new TermDto(Generator.generateTermWithId())); + final String searchString = "test"; + when(termRepositoryService.findAll(searchString)).thenReturn(terms); + final List result = sut.findAll(searchString); + assertEquals(terms, result); + verify(termRepositoryService).findAll(searchString); + } + @Test void getReferenceRetrievesTermReferenceFromRepositoryService() { final Term t = Generator.generateTermWithId(); diff --git a/src/test/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermServiceTest.java index 5bc00cd54..436cb6f04 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermServiceTest.java @@ -50,7 +50,7 @@ void getRequiredVocabularyReferenceRetrievesReferenceToVocabularyFromService() { void findAllRetrievesAllTermsFromServiceAndTransformsThemToReadOnlyVersion() { final Vocabulary vocabulary = Generator.generateVocabularyWithId(); final List terms = Generator.generateTermsWithIds(5); - when(termService.findAll(any())).thenReturn(terms); + when(termService.findAll(any(Vocabulary.class))).thenReturn(terms); final List result = sut.findAll(vocabulary); assertEquals(termsToDtos(terms), result); diff --git a/src/test/java/cz/cvut/kbss/termit/service/repository/TermRepositoryServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/repository/TermRepositoryServiceTest.java index fdf3b472a..3710db196 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/repository/TermRepositoryServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/repository/TermRepositoryServiceTest.java @@ -501,6 +501,27 @@ void findAllIncludingImportedBySearchStringReturnsMatchingTerms() { assertTrue(termsToDtos(matching).containsAll(result)); } + @Test + void findAllWithSearchStringReturnsMatchingTerms() { + final List terms = Generator + .generateTermsWithIds(10) + .stream().map(TermDto::new).collect(Collectors.toList()); + final String searchString = "Result"; + final List matching = terms.subList(0, 5); + matching.forEach(t -> t.getLabel().set(Constants.DEFAULT_LANGUAGE, searchString + " " + t.getLabel())); + + vocabulary.getGlossary().setRootTerms(terms.stream().map(Asset::getUri).collect(Collectors.toSet())); + terms.forEach(t -> t.setVocabulary(vocabulary.getUri())); + final Descriptor termDescriptor = descriptorFactory.termDescriptor(vocabulary); + transactional(() -> { + terms.forEach(t -> em.persist(t, termDescriptor)); + }); + + List result = sut.findAll(searchString); + assertEquals(matching.size(), result.size()); + assertTrue(matching.containsAll(result)); + } + @Test void addChildTermAllowsAddingChildTermToDifferentVocabularyThanParent() { final Term parentTerm = generateParentTermFromDifferentVocabulary();