diff --git a/modules/platform/nuxeo-platform-query-api/src/main/java/org/nuxeo/ecm/platform/query/nxql/CoreQueryAndFetchPageProvider.java b/modules/platform/nuxeo-platform-query-api/src/main/java/org/nuxeo/ecm/platform/query/nxql/CoreQueryAndFetchPageProvider.java index 85aaac5c137f..bf722d39367a 100644 --- a/modules/platform/nuxeo-platform-query-api/src/main/java/org/nuxeo/ecm/platform/query/nxql/CoreQueryAndFetchPageProvider.java +++ b/modules/platform/nuxeo-platform-query-api/src/main/java/org/nuxeo/ecm/platform/query/nxql/CoreQueryAndFetchPageProvider.java @@ -175,12 +175,11 @@ public List> getCurrentPage() { } protected void buildQuery() { - List sort = null; + List sort = new ArrayList<>(); List quickFilters = getQuickFilters(); String quickFiltersClause = ""; if (quickFilters != null && !quickFilters.isEmpty()) { - sort = new ArrayList<>(); for (QuickFilter quickFilter : quickFilters) { String clause = quickFilter.getClause(); if (!quickFiltersClause.isEmpty() && clause != null) { @@ -190,15 +189,14 @@ protected void buildQuery() { } sort.addAll(quickFilter.getSortInfos()); } - } else if (sortInfos != null) { - sort = sortInfos; } - SortInfo[] sortArray = null; - if (sort != null) { - sortArray = sort.toArray(new SortInfo[] {}); + if (sortInfos != null) { + sort.addAll(sortInfos); } + SortInfo[] sortArray = sort.toArray(SortInfo[]::new); + String newQuery; PageProviderDefinition def = getDefinition(); WhereClauseDefinition whereClause = def.getWhereClause(); diff --git a/modules/platform/nuxeo-platform-query-api/src/main/java/org/nuxeo/ecm/platform/query/nxql/CoreQueryDocumentPageProvider.java b/modules/platform/nuxeo-platform-query-api/src/main/java/org/nuxeo/ecm/platform/query/nxql/CoreQueryDocumentPageProvider.java index cd885aef1de3..c55979dccceb 100644 --- a/modules/platform/nuxeo-platform-query-api/src/main/java/org/nuxeo/ecm/platform/query/nxql/CoreQueryDocumentPageProvider.java +++ b/modules/platform/nuxeo-platform-query-api/src/main/java/org/nuxeo/ecm/platform/query/nxql/CoreQueryDocumentPageProvider.java @@ -199,12 +199,11 @@ public List getCurrentPage() { } protected void buildQuery(CoreSession coreSession) { - List sort = null; + List sort = new ArrayList<>(); List quickFilters = getQuickFilters(); String quickFiltersClause = ""; if (quickFilters != null && !quickFilters.isEmpty()) { - sort = new ArrayList<>(); for (QuickFilter quickFilter : quickFilters) { String clause = quickFilter.getClause(); if (clause != null) { @@ -216,15 +215,14 @@ protected void buildQuery(CoreSession coreSession) { } sort.addAll(quickFilter.getSortInfos()); } - } else if (sortInfos != null) { - sort = sortInfos; } - SortInfo[] sortArray = null; - if (sort != null) { - sortArray = sort.toArray(new SortInfo[] {}); + if (sortInfos != null) { + sort.addAll(sortInfos); } + SortInfo[] sortArray = sort.toArray(SortInfo[]::new); + String newQuery; PageProviderDefinition def = getDefinition(); WhereClauseDefinition whereClause = def.getWhereClause(); diff --git a/modules/platform/nuxeo-platform-query-api/src/test/java/org/nuxeo/ecm/platform/query/core/TestPageProviderCurrentPage.java b/modules/platform/nuxeo-platform-query-api/src/test/java/org/nuxeo/ecm/platform/query/core/TestPageProviderCurrentPage.java index 056d395540dd..a194e3de50f8 100644 --- a/modules/platform/nuxeo-platform-query-api/src/test/java/org/nuxeo/ecm/platform/query/core/TestPageProviderCurrentPage.java +++ b/modules/platform/nuxeo-platform-query-api/src/test/java/org/nuxeo/ecm/platform/query/core/TestPageProviderCurrentPage.java @@ -20,10 +20,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import java.io.Serializable; import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.inject.Inject; @@ -32,6 +34,7 @@ import org.junit.runner.RunWith; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; +import org.nuxeo.ecm.core.api.SortInfo; import org.nuxeo.ecm.core.test.CoreFeature; import org.nuxeo.ecm.core.test.annotations.Granularity; import org.nuxeo.ecm.core.test.annotations.RepositoryConfig; @@ -43,6 +46,7 @@ import org.nuxeo.runtime.test.runner.Deploy; import org.nuxeo.runtime.test.runner.Features; import org.nuxeo.runtime.test.runner.FeaturesRunner; +import org.nuxeo.runtime.test.runner.TransactionalFeature; /** * @since 9.3 see NXP-23092 @@ -59,6 +63,9 @@ public class TestPageProviderCurrentPage { protected static final int SECOND_PAGE_NUM_DOCS = 25; + @Inject + protected TransactionalFeature transactionalFeature; + @Inject protected PageProviderService pps; @@ -129,4 +136,102 @@ public void testPageProviderCurrentPageWithoutPageSize() { assertEquals(prevId, ((DocumentModel) page.get(0)).getId()); } + // NXP-30360 + @Deploy("org.nuxeo.ecm.platform.query.api.test:test-pageprovider-quick-filter-contrib.xml") + @Test + @SuppressWarnings("unchecked") + public void testPageProviderSortAndQuickFilter() { + DocumentModel rootFolder = session.createDocumentModel("/", "rootFolder", "Folder"); + rootFolder = session.createDocument(rootFolder); + DocumentModel folder = session.createDocumentModel("/rootFolder", "folder", "Folder"); + folder.setPropertyValue("dc:title", "Folder"); + session.createDocument(folder); + DocumentModel file1 = session.createDocumentModel("/rootFolder", "file1", "File"); + file1.setPropertyValue("dc:title", "File 1"); + session.createDocument(file1); + DocumentModel file2 = session.createDocumentModel("/rootFolder", "file2", "File"); + file2.setPropertyValue("dc:title", "File 2"); + session.createDocument(file2); + transactionalFeature.nextTransaction(); + + var props = Map.of(CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY, (Serializable) session); + // default sort infos, no quick filter + PageProvider pp = pps.getPageProvider("test_quick_filter", null, 0L, 0L, props, rootFolder.getId()); + assertNotNull(pp); + List docs = (List) pp.getCurrentPage(); + assertEquals(3, docs.size()); + assertEquals("File 1", docs.get(0).getTitle()); + assertEquals("File 2", docs.get(1).getTitle()); + assertEquals("Folder", docs.get(2).getTitle()); + + // custom sort infos, no quick filter + var sortInfos = List.of(new SortInfo("dc:title", false)); + pp = pps.getPageProvider("test_quick_filter", sortInfos, 0L, 0L, props, rootFolder.getId()); + assertNotNull(pp); + docs = (List) pp.getCurrentPage(); + assertEquals(3, docs.size()); + assertEquals("Folder", docs.get(0).getTitle()); + assertEquals("File 2", docs.get(1).getTitle()); + assertEquals("File 1", docs.get(2).getTitle()); + + // custom sort infos, quick filter + var ppd = pps.getPageProviderDefinition("test_quick_filter"); + pp = pps.getPageProvider("test_quick_filter", sortInfos, 0L, 0L, props, null, ppd.getQuickFilters(), + rootFolder.getId()); + assertNotNull(pp); + docs = (List) pp.getCurrentPage(); + assertEquals(2, docs.size()); + assertEquals("File 2", docs.get(0).getTitle()); + assertEquals("File 1", docs.get(1).getTitle()); + } + + // NXP-30360 + @Deploy("org.nuxeo.ecm.platform.query.api.test:test-pageprovider-quick-filter-contrib.xml") + @Test + @SuppressWarnings("unchecked") + public void testPageProviderSortAndQuickFilterWithQueryAndFetch() { + DocumentModel rootFolder = session.createDocumentModel("/", "rootFolder", "Folder"); + rootFolder = session.createDocument(rootFolder); + DocumentModel folder = session.createDocumentModel("/rootFolder", "folder", "Folder"); + folder.setPropertyValue("dc:title", "Folder"); + session.createDocument(folder); + DocumentModel file1 = session.createDocumentModel("/rootFolder", "file1", "File"); + file1.setPropertyValue("dc:title", "File 1"); + session.createDocument(file1); + DocumentModel file2 = session.createDocumentModel("/rootFolder", "file2", "File"); + file2.setPropertyValue("dc:title", "File 2"); + session.createDocument(file2); + transactionalFeature.nextTransaction(); + + var props = Map.of(CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY, (Serializable) session); + // default sort infos, no quick filter + PageProvider pp = pps.getPageProvider("test_quick_filter_fetch", null, 0L, 0L, props, rootFolder.getId()); + assertNotNull(pp); + List> res = (List>) pp.getCurrentPage(); + assertEquals(3, res.size()); + assertEquals("File 1", res.get(0).get("dc:title")); + assertEquals("File 2", res.get(1).get("dc:title")); + assertEquals("Folder", res.get(2).get("dc:title")); + + // custom sort infos, no quick filter + var sortInfos = List.of(new SortInfo("dc:title", false)); + pp = pps.getPageProvider("test_quick_filter_fetch", sortInfos, 0L, 0L, props, rootFolder.getId()); + assertNotNull(pp); + res = (List>) pp.getCurrentPage(); + assertEquals(3, res.size()); + assertEquals("Folder", res.get(0).get("dc:title")); + assertEquals("File 2", res.get(1).get("dc:title")); + assertEquals("File 1", res.get(2).get("dc:title")); + + // custom sort infos, quick filter + var ppd = pps.getPageProviderDefinition("test_quick_filter_fetch"); + pp = pps.getPageProvider("test_quick_filter_fetch", sortInfos, 0L, 0L, props, null, ppd.getQuickFilters(), + rootFolder.getId()); + assertNotNull(pp); + res = (List>) pp.getCurrentPage(); + assertEquals(2, res.size()); + assertEquals("File 2", res.get(0).get("dc:title")); + assertEquals("File 1", res.get(1).get("dc:title")); + } + } diff --git a/modules/platform/nuxeo-platform-query-api/src/test/resources/test-pageprovider-quick-filter-contrib.xml b/modules/platform/nuxeo-platform-query-api/src/test/resources/test-pageprovider-quick-filter-contrib.xml new file mode 100644 index 000000000000..223a00485490 --- /dev/null +++ b/modules/platform/nuxeo-platform-query-api/src/test/resources/test-pageprovider-quick-filter-contrib.xml @@ -0,0 +1,37 @@ + + + + + + + + + SELECT * FROM Document WHERE ecm:parentId = ? + + + + + ecm:mixinType != 'Folderish' + + + 20 + + + + + SELECT dc:title FROM Document WHERE ecm:parentId = ? + + + + + ecm:mixinType != 'Folderish' + + + 20 + + + + + diff --git a/modules/platform/nuxeo-search/nuxeo-search-rest-api/src/test/java/org/nuxeo/ecm/restapi/server/jaxrs/search/test/SearchTest.java b/modules/platform/nuxeo-search/nuxeo-search-rest-api/src/test/java/org/nuxeo/ecm/restapi/server/jaxrs/search/test/SearchTest.java index d424edb58a84..e14d15a94f51 100644 --- a/modules/platform/nuxeo-search/nuxeo-search-rest-api/src/test/java/org/nuxeo/ecm/restapi/server/jaxrs/search/test/SearchTest.java +++ b/modules/platform/nuxeo-search/nuxeo-search-rest-api/src/test/java/org/nuxeo/ecm/restapi/server/jaxrs/search/test/SearchTest.java @@ -48,6 +48,7 @@ import org.nuxeo.runtime.api.Framework; import org.nuxeo.runtime.test.runner.Features; import org.nuxeo.runtime.test.runner.FeaturesRunner; +import org.nuxeo.runtime.test.runner.TransactionalFeature; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; @@ -68,6 +69,9 @@ public class SearchTest extends BaseTest { @Inject protected CoreFeature coreFeature; + @Inject + protected TransactionalFeature transactionalFeature; + protected static final String QUERY_EXECUTE_PATH = "search/lang/NXQL/execute"; protected static final String SAVED_SEARCH_PATH = "search/saved"; @@ -349,6 +353,47 @@ public void iCanUseAssociativeQuickFilter() throws IOException { } } + @Test + public void iCanPerformPageProviderWithQuickFilterAndSortInfo() throws IOException { + DocumentModel rootFolder = RestServerInit.getFolder(1, session); + DocumentModel folder = session.createDocumentModel(rootFolder.getPathAsString(), "folder", "Folder"); + folder.setPropertyValue("dc:title", "Folder"); + session.createDocument(folder); + transactionalFeature.nextTransaction(); + + MultivaluedMap queryParams = new MultivaluedMapImpl(); + queryParams.add("ecm_path", "[\"" + rootFolder.getPathAsString() + "\"]"); + queryParams.add("sortBy", "dc:title"); + queryParams.add("sortOrder", "desc"); + try (CloseableClientResponse response = getResponse(RequestType.GET, + getSearchPageProviderExecutePath("default_search"), queryParams)) { + assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + JsonNode node = mapper.readTree(response.getEntityInputStream()); + List entries = getLogEntries(node); + assertEquals(6, entries.size()); + assertEquals("Note 4", entries.get(0).get("title").textValue()); + assertEquals("Note 3", entries.get(1).get("title").textValue()); + assertEquals("Note 2", entries.get(2).get("title").textValue()); + assertEquals("Note 1", entries.get(3).get("title").textValue()); + assertEquals("Note 0", entries.get(4).get("title").textValue()); + assertEquals("Folder", entries.get(5).get("title").textValue()); + } + + queryParams.add("quickFilters", "noFolder"); + try (CloseableClientResponse response = getResponse(RequestType.GET, + getSearchPageProviderExecutePath("default_search"), queryParams)) { + assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + JsonNode node = mapper.readTree(response.getEntityInputStream()); + List entries = getLogEntries(node); + assertEquals(5, entries.size()); + assertEquals("Note 4", entries.get(0).get("title").textValue()); + assertEquals("Note 3", entries.get(1).get("title").textValue()); + assertEquals("Note 2", entries.get(2).get("title").textValue()); + assertEquals("Note 1", entries.get(3).get("title").textValue()); + assertEquals("Note 0", entries.get(4).get("title").textValue()); + } + } + @Test public void iCanPerformPageProviderWithNamedParametersInvalid() throws Exception { try (CloseableClientResponse response = getResponse(RequestType.GET,