From 6d275addb536a27cb459063079918fe59519d08f Mon Sep 17 00:00:00 2001 From: Yannan <73408381+YannanGao-gs@users.noreply.github.com> Date: Fri, 9 Aug 2024 09:14:57 -0400 Subject: [PATCH] support sortby in Query store manager (#3009) --- .../query/api/QueryStoreManager.java | 43 +++++++++++++--- .../query/model/QuerySearchSortBy.java | 22 +++++++++ .../query/model/QuerySearchSpecification.java | 1 + .../query/api/TestQueryStoreManager.java | 49 ++++++++++++++----- 4 files changed, 96 insertions(+), 19 deletions(-) create mode 100644 legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/model/QuerySearchSortBy.java diff --git a/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/api/QueryStoreManager.java b/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/api/QueryStoreManager.java index 97eb293712b..f5aa2396cbf 100644 --- a/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/api/QueryStoreManager.java +++ b/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/api/QueryStoreManager.java @@ -34,6 +34,8 @@ import org.eclipse.collections.impl.utility.LazyIterate; import org.eclipse.collections.impl.utility.ListIterate; import org.finos.legend.engine.application.query.model.*; +import org.finos.legend.engine.protocol.pure.v1.model.context.EngineErrorType; +import org.finos.legend.engine.shared.core.operational.errorManagement.EngineException; import org.finos.legend.engine.shared.core.vault.Vault; import javax.lang.model.SourceVersion; @@ -252,13 +254,19 @@ public List searchQueries(QuerySearchSpecification searchSpecification, S } List queries = new ArrayList<>(); + List aggregateLists = new ArrayList<>(); + aggregateLists.add(Aggregates.addFields(new Field<>("isCurrentUser", new Document("$eq", Arrays.asList("$owner", currentUser))))); + aggregateLists.add(Aggregates.match(filters.isEmpty() ? EMPTY_FILTER : Filters.and(filters))); + aggregateLists.add(Aggregates.sort(Sorts.descending("isCurrentUser"))); + if (searchSpecification.sortByOption != null) + { + aggregateLists.add(Aggregates.sort(Sorts.descending(getSortByField(searchSpecification.sortByOption)))); + } + aggregateLists.add(Aggregates.project(Projections.include(LIGHT_QUERY_PROJECTION))); + aggregateLists.add(Aggregates.limit(Math.min(MAX_NUMBER_OF_QUERIES, searchSpecification.limit == null ? Integer.MAX_VALUE : searchSpecification.limit))); AggregateIterable documents = this.getQueryCollection() - .aggregate(Arrays.asList( - Aggregates.addFields(new Field("isCurrentUser", new Document("$eq", Arrays.asList("$owner", currentUser)))), - Aggregates.match(filters.isEmpty() ? EMPTY_FILTER : Filters.and(filters)), - Aggregates.sort(Sorts.descending("isCurrentUser")), - Aggregates.project(Projections.include(LIGHT_QUERY_PROJECTION)), - Aggregates.limit(Math.min(MAX_NUMBER_OF_QUERIES, searchSpecification.limit == null ? Integer.MAX_VALUE : searchSpecification.limit)))); + .aggregate(aggregateLists); + for (Document doc : documents) { queries.add(documentToQuery(doc)); @@ -266,6 +274,29 @@ public List searchQueries(QuerySearchSpecification searchSpecification, S return queries; } + public String getSortByField(QuerySearchSortBy sortBy) + { + switch (sortBy) + { + case SORT_BY_CREATE: + { + return "createdAt"; + } + case SORT_BY_VIEW: + { + return "lastOpenAt"; + } + case SORT_BY_UPDATE: + { + return "lastUpdatedAt"; + } + default: + { + throw new EngineException("Fail to understand sort-by value", EngineErrorType.COMPILATION); + } + } + } + public List getQueries(List queryIds) { if (queryIds.size() > GET_QUERIES_LIMIT) diff --git a/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/model/QuerySearchSortBy.java b/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/model/QuerySearchSortBy.java new file mode 100644 index 00000000000..9a273d8c5d2 --- /dev/null +++ b/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/model/QuerySearchSortBy.java @@ -0,0 +1,22 @@ +// Copyright 2020 Goldman Sachs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.finos.legend.engine.application.query.model; + +public enum QuerySearchSortBy +{ + SORT_BY_CREATE, + SORT_BY_VIEW, + SORT_BY_UPDATE, +} diff --git a/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/model/QuerySearchSpecification.java b/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/model/QuerySearchSpecification.java index 291c9a75126..a25adb86df5 100644 --- a/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/model/QuerySearchSpecification.java +++ b/legend-engine-application-query/src/main/java/org/finos/legend/engine/application/query/model/QuerySearchSpecification.java @@ -31,4 +31,5 @@ public class QuerySearchSpecification // so that we can search if a query contains all the taggedValues specified in the // search specification public Boolean combineTaggedValuesCondition; + public QuerySearchSortBy sortByOption; } diff --git a/legend-engine-application-query/src/test/java/org/finos/legend/engine/application/query/api/TestQueryStoreManager.java b/legend-engine-application-query/src/test/java/org/finos/legend/engine/application/query/api/TestQueryStoreManager.java index 205bfebf51a..19cbe7fb63a 100644 --- a/legend-engine-application-query/src/test/java/org/finos/legend/engine/application/query/api/TestQueryStoreManager.java +++ b/legend-engine-application-query/src/test/java/org/finos/legend/engine/application/query/api/TestQueryStoreManager.java @@ -19,15 +19,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import org.eclipse.collections.api.block.function.Function0; import org.eclipse.collections.api.factory.Lists; -import org.finos.legend.engine.application.query.model.Query; -import org.finos.legend.engine.application.query.model.QueryEvent; -import org.finos.legend.engine.application.query.model.QueryParameterValue; -import org.finos.legend.engine.application.query.model.QueryProjectCoordinates; -import org.finos.legend.engine.application.query.model.QuerySearchSpecification; -import org.finos.legend.engine.application.query.model.QuerySearchTermSpecification; -import org.finos.legend.engine.application.query.model.QueryExplicitExecutionContext; -import org.finos.legend.engine.application.query.model.QueryDataSpaceExecutionContext; -import org.finos.legend.engine.application.query.model.QueryExecutionContext; +import org.finos.legend.engine.application.query.model.*; import org.finos.legend.engine.application.query.utils.TestMongoClientProvider; import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.domain.StereotypePtr; import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.domain.TagPtr; @@ -42,10 +34,8 @@ import org.junit.Test; import java.time.Instant; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; public class TestQueryStoreManager { @@ -58,6 +48,7 @@ static class TestQuerySearchSpecificationBuilder public Integer limit; public Boolean showCurrentUserQueriesOnly; public Boolean combineTaggedValuesCondition; + public QuerySearchSortBy sortByOption; TestQuerySearchSpecificationBuilder withSearchTerm(String searchTerm) { @@ -125,6 +116,12 @@ TestQuerySearchSpecificationBuilder withCombineTaggedValuesCondition(Boolean com return this; } + TestQuerySearchSpecificationBuilder withSortByOption(QuerySearchSortBy sortByOption) + { + this.sortByOption = sortByOption; + return this; + } + QuerySearchSpecification build() { QuerySearchSpecification searchSpecification = new QuerySearchSpecification(); @@ -135,6 +132,7 @@ QuerySearchSpecification build() searchSpecification.limit = this.limit; searchSpecification.showCurrentUserQueriesOnly = this.showCurrentUserQueriesOnly; searchSpecification.combineTaggedValuesCondition = this.combineTaggedValuesCondition; + searchSpecification.sortByOption = this.sortByOption; return searchSpecification; } } @@ -533,6 +531,31 @@ public void testGetQueriesWithProjectCoordinates() throws Exception Assert.assertEquals(4, queryStoreManager.searchQueries(new TestQuerySearchSpecificationBuilder().withProjectCoordinates(Lists.fixedSize.of(coordinate1, coordinate2, coordinate3, coordinate4)).build(), currentUser).size()); } + @Test + public void testGetQueriesWithSortBy() throws Exception + { + String currentUser = "testUser"; + Query testQuery1 = TestQueryBuilder.create("1", "query1", currentUser).withGroupId("test").withArtifactId("test").withLegacyExecutionContext().build(); + Query testQuery2 = TestQueryBuilder.create("2", "query2", currentUser).withGroupId("test").withArtifactId("test").withLegacyExecutionContext().build(); + Query testQuery3 = TestQueryBuilder.create("3", "query3", currentUser).withGroupId("something").withArtifactId("something").withLegacyExecutionContext().build(); + Query testQuery4 = TestQueryBuilder.create("4", "query4", currentUser).withGroupId("something.another").withArtifactId("something-another").withVersionId("1.0.0").withLegacyExecutionContext().build(); + + // create in order 1 -> 4 -> 2 -> 3 + queryStoreManager.createQuery(testQuery1, currentUser); + queryStoreManager.createQuery(testQuery4, currentUser); + queryStoreManager.createQuery(testQuery2, currentUser); + queryStoreManager.createQuery(testQuery3, currentUser); + + Assert.assertEquals(4, queryStoreManager.searchQueries(new TestQuerySearchSpecificationBuilder().withSortByOption(QuerySearchSortBy.SORT_BY_CREATE).build(), currentUser).size()); + Assert.assertEquals(Arrays.asList("3", "2", "4", "1"), queryStoreManager.searchQueries(new TestQuerySearchSpecificationBuilder().withSortByOption(QuerySearchSortBy.SORT_BY_CREATE).build(), currentUser).stream().map(q -> q.id).collect(Collectors.toList())); + + queryStoreManager.updateQuery("2", TestQueryBuilder.create("2", "query2NewlyUpdated", currentUser).withLegacyExecutionContext().build(), currentUser); + Assert.assertEquals(Arrays.asList("2", "3", "4", "1"), queryStoreManager.searchQueries(new TestQuerySearchSpecificationBuilder().withSortByOption(QuerySearchSortBy.SORT_BY_UPDATE).build(), currentUser).stream().map(q -> q.id).collect(Collectors.toList())); + + queryStoreManager.getQuery("1"); + Assert.assertEquals(Arrays.asList("1", "2", "3", "4"), queryStoreManager.searchQueries(new TestQuerySearchSpecificationBuilder().withSortByOption(QuerySearchSortBy.SORT_BY_VIEW).build(), currentUser).stream().map(q -> q.id).collect(Collectors.toList())); + } + @Test public void testGetQueriesWithStereotypes() throws Exception {