From 109b9c274486b03fad3a11b77c38852ad960e516 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Fri, 4 Nov 2016 16:15:12 +0100 Subject: [PATCH] SONAR-8089 Load all measures at once --- .../sonar/server/component/ws/TreeAction.java | 93 ++++++++----- .../measure/ws/ComponentTreeAction.java | 44 ++++--- .../measure/ws/ComponentTreeDataLoader.java | 123 ++++-------------- .../server/measure/ws/ComponentTreeSort.java | 36 +---- .../measure/ws/ComponentTreeActionTest.java | 3 + 5 files changed, 125 insertions(+), 174 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/TreeAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/TreeAction.java index 93db78f2ab7..cf14648c5e9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/TreeAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/TreeAction.java @@ -19,8 +19,11 @@ */ package org.sonar.server.component.ws; +import com.google.common.base.Function; import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Ordering; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.List; @@ -40,6 +43,7 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTreeQuery; +import org.sonar.db.component.ComponentTreeQuery.Strategy; import org.sonar.server.component.ComponentFinder; import org.sonar.server.user.UserSession; import org.sonarqube.ws.WsComponents.TreeWsResponse; @@ -48,9 +52,13 @@ import org.sonarqube.ws.client.component.TreeWsRequest; import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.collect.FluentIterable.from; import static com.google.common.collect.Sets.newHashSet; +import static java.lang.String.CASE_INSENSITIVE_ORDER; import static java.lang.String.format; import static java.util.Collections.emptyMap; +import static org.sonar.api.utils.Paging.offset; import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02; +import static org.sonar.db.component.ComponentTreeQuery.Strategy.CHILDREN; +import static org.sonar.db.component.ComponentTreeQuery.Strategy.LEAVES; import static org.sonar.server.component.ComponentFinder.ParamNames.BASE_COMPONENT_ID_AND_KEY; import static org.sonar.server.component.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException; @@ -66,12 +74,17 @@ import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUA import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_STRATEGY; public class TreeAction implements ComponentsWsAction { + private static final int MAX_SIZE = 500; private static final int QUERY_MINIMUM_LENGTH = 3; private static final String ALL_STRATEGY = "all"; private static final String CHILDREN_STRATEGY = "children"; private static final String LEAVES_STRATEGY = "leaves"; - private static final Set STRATEGIES = ImmutableSortedSet.of(ALL_STRATEGY, CHILDREN_STRATEGY, LEAVES_STRATEGY); + private static final Map STRATEGIES = ImmutableMap.of( + ALL_STRATEGY, LEAVES, + CHILDREN_STRATEGY, CHILDREN, + LEAVES_STRATEGY, LEAVES); + private static final String NAME_SORT = "name"; private static final String PATH_SORT = "path"; private static final String QUALIFIER_SORT = "qualifier"; @@ -137,7 +150,7 @@ public class TreeAction implements ComponentsWsAction { "
  • all: return all the descendants components of the base component. Grandchildren are returned.
  • " + "
  • leaves: return all the descendant components (files, in general) which don't have other children. They are the leaves of the component tree.
  • " + "") - .setPossibleValues(STRATEGIES) + .setPossibleValues(STRATEGIES.keySet()) .setDefaultValue(ALL_STRATEGY); } @@ -148,33 +161,20 @@ public class TreeAction implements ComponentsWsAction { } private TreeWsResponse doHandle(TreeWsRequest treeWsRequest) { - DbSession dbSession = dbClient.openSession(false); - try { + try (DbSession dbSession = dbClient.openSession(false)) { ComponentDto baseComponent = componentFinder.getByUuidOrKey(dbSession, treeWsRequest.getBaseComponentId(), treeWsRequest.getBaseComponentKey(), BASE_COMPONENT_ID_AND_KEY); checkPermissions(baseComponent); ComponentTreeQuery query = toComponentTreeQuery(treeWsRequest, baseComponent); - List components; - int total; - switch (treeWsRequest.getStrategy()) { - case CHILDREN_STRATEGY: - components = dbClient.componentDao().selectDescendants(dbSession, query); - total = components.size(); - break; - case LEAVES_STRATEGY: - case ALL_STRATEGY: - components = dbClient.componentDao().selectDescendants(dbSession, query); - total = components.size(); - break; - default: - throw new IllegalStateException("Unknown component tree strategy"); - } + List components = dbClient.componentDao().selectDescendants(dbSession, query); + int total = components.size(); + components = sortComponents(components, treeWsRequest); + components = paginateComponents(components, treeWsRequest); + Map referenceComponentsByUuid = searchReferenceComponentsByUuid(dbSession, components); return buildResponse(baseComponent, components, referenceComponentsByUuid, - Paging.forPageIndex(query.getPage()).withPageSize(query.getPageSize()).andTotal(total)); - } finally { - dbClient.closeSession(dbSession); + Paging.forPageIndex(treeWsRequest.getPage()).withPageSize(treeWsRequest.getPageSize()).andTotal(total)); } } @@ -200,8 +200,7 @@ public class TreeAction implements ComponentsWsAction { } } - private static TreeWsResponse buildResponse(ComponentDto baseComponent, List components, - Map referenceComponentsByUuid, Paging paging) { + private static TreeWsResponse buildResponse(ComponentDto baseComponent, List components, Map referenceComponentsByUuid, Paging paging) { TreeWsResponse.Builder response = TreeWsResponse.newBuilder(); response.getPagingBuilder() .setPageIndex(paging.pageIndex()) @@ -222,10 +221,7 @@ public class TreeAction implements ComponentsWsAction { ComponentTreeQuery.Builder query = ComponentTreeQuery.builder() .setBaseUuid(baseComponent.uuid()) - .setPage(request.getPage()) - .setPageSize(request.getPageSize()) - .setSortFields(request.getSort()) - .setAsc(request.getAsc()); + .setStrategy(STRATEGIES.get(request.getStrategy())); if (request.getQuery() != null) { query.setNameOrKeyQuery(request.getQuery()); } @@ -261,7 +257,7 @@ public class TreeAction implements ComponentsWsAction { TreeWsRequest treeWsRequest = new TreeWsRequest() .setBaseComponentId(request.param(PARAM_BASE_COMPONENT_ID)) .setBaseComponentKey(request.param(PARAM_BASE_COMPONENT_KEY)) - .setStrategy(request.param(PARAM_STRATEGY)) + .setStrategy(request.mandatoryParam(PARAM_STRATEGY)) .setQuery(request.param(Param.TEXT_QUERY)) .setQualifiers(request.paramAsStrings(PARAM_QUALIFIERS)) .setSort(request.mandatoryParamAsStrings(Param.SORT)) @@ -276,4 +272,43 @@ public class TreeAction implements ComponentsWsAction { return treeWsRequest; } + private static List paginateComponents(List components, TreeWsRequest wsRequest) { + return from(components) + .skip(offset(wsRequest.getPage(), wsRequest.getPageSize())) + .limit(wsRequest.getPageSize()) + .toList(); + } + + public static List sortComponents(List components, TreeWsRequest wsRequest) { + List sortParameters = wsRequest.getSort(); + if (sortParameters == null || sortParameters.isEmpty()) { + return components; + } + boolean isAscending = wsRequest.getAsc(); + Map> orderingsBySortField = ImmutableMap.>builder() + .put(NAME_SORT, stringOrdering(isAscending, ComponentDto::name)) + .put(QUALIFIER_SORT, stringOrdering(isAscending, ComponentDto::qualifier)) + .put(PATH_SORT, stringOrdering(isAscending, ComponentDto::path)) + .build(); + + String firstSortParameter = sortParameters.get(0); + Ordering primaryOrdering = orderingsBySortField.get(firstSortParameter); + if (sortParameters.size() > 1) { + for (int i = 1; i < sortParameters.size(); i++) { + String secondarySortParameter = sortParameters.get(i); + Ordering secondaryOrdering = orderingsBySortField.get(secondarySortParameter); + primaryOrdering = primaryOrdering.compound(secondaryOrdering); + } + } + return primaryOrdering.immutableSortedCopy(components); + } + + private static Ordering stringOrdering(boolean isAscending, Function function) { + Ordering ordering = Ordering.from(CASE_INSENSITIVE_ORDER); + if (!isAscending) { + ordering = ordering.reverse(); + } + return ordering.nullsLast().onResultOf(function); + } + } diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java index d0fafede87c..dbe62325ffa 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java @@ -19,16 +19,36 @@ */ package org.sonar.server.measure.ws; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedSet; +import java.util.Map; +import java.util.Set; +import org.sonar.api.i18n.I18n; +import org.sonar.api.resources.ResourceTypes; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.server.ws.WebService.Param; +import org.sonar.api.utils.Paging; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ComponentTreeQuery.Strategy; +import org.sonar.db.metric.MetricDto; +import org.sonarqube.ws.WsMeasures; +import org.sonarqube.ws.WsMeasures.ComponentTreeWsResponse; +import org.sonarqube.ws.client.measure.ComponentTreeWsRequest; + import static java.lang.String.format; import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02; +import static org.sonar.db.component.ComponentTreeQuery.Strategy.CHILDREN; +import static org.sonar.db.component.ComponentTreeQuery.Strategy.LEAVES; import static org.sonar.server.measure.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createAdditionalFieldsParameter; import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createDeveloperParameters; import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createMetricKeysParameter; import static org.sonar.server.measure.ws.MetricDtoToWsMetric.metricDtoToWsMetric; import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; -import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter; +import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; import static org.sonar.server.ws.WsUtils.checkRequest; import static org.sonar.server.ws.WsUtils.writeProtobuf; import static org.sonarqube.ws.client.measure.MeasuresWsParameters.ACTION_COMPONENT_TREE; @@ -46,21 +66,6 @@ import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_METRIC_ import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_QUALIFIERS; import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_STRATEGY; -import com.google.common.collect.ImmutableSortedSet; -import java.util.Set; -import org.sonar.api.i18n.I18n; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.server.ws.WebService.Param; -import org.sonar.api.utils.Paging; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.metric.MetricDto; -import org.sonarqube.ws.WsMeasures; -import org.sonarqube.ws.WsMeasures.ComponentTreeWsResponse; -import org.sonarqube.ws.client.measure.ComponentTreeWsRequest; - /** *

    Navigate through components based on different strategy with specified measures. * To limit the number of rows in database, a best value algorithm exists in database.

    @@ -84,7 +89,10 @@ public class ComponentTreeAction implements MeasuresWsAction { static final String ALL_STRATEGY = "all"; static final String CHILDREN_STRATEGY = "children"; static final String LEAVES_STRATEGY = "leaves"; - static final Set STRATEGIES = ImmutableSortedSet.of(ALL_STRATEGY, CHILDREN_STRATEGY, LEAVES_STRATEGY); + static final Map STRATEGIES = ImmutableMap.of( + ALL_STRATEGY, LEAVES, + CHILDREN_STRATEGY, CHILDREN, + LEAVES_STRATEGY, LEAVES); // sort static final String NAME_SORT = "name"; static final String PATH_SORT = "path"; @@ -176,7 +184,7 @@ public class ComponentTreeAction implements MeasuresWsAction { "
  • all: return all the descendants components of the base component. Grandchildren are returned.
  • " + "
  • leaves: return all the descendant components (files, in general) which don't have other children. They are the leaves of the component tree.
  • " + "") - .setPossibleValues(STRATEGIES) + .setPossibleValues(STRATEGIES.keySet()) .setDefaultValue(ALL_STRATEGY); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeDataLoader.java b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeDataLoader.java index 04f5c44c397..201b1f2a6a9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeDataLoader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeDataLoader.java @@ -26,12 +26,12 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; import com.google.common.collect.HashBasedTable; -import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.collect.Table; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; @@ -51,7 +51,7 @@ import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTreeQuery; import org.sonar.db.component.SnapshotDto; import org.sonar.db.measure.MeasureDto; -import org.sonar.db.measure.MeasureQuery; +import org.sonar.db.measure.MeasureTreeQuery; import org.sonar.db.metric.MetricDto; import org.sonar.db.metric.MetricDtoFunctions; import org.sonar.server.component.ComponentFinder; @@ -63,21 +63,15 @@ import org.sonarqube.ws.client.measure.ComponentTreeWsRequest; import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.FluentIterable.from; -import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; import static java.lang.String.format; import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNull; import static org.sonar.api.utils.Paging.offset; import static org.sonar.server.component.ComponentFinder.ParamNames.BASE_COMPONENT_ID_AND_KEY; import static org.sonar.server.component.ComponentFinder.ParamNames.DEVELOPER_ID_AND_KEY; -import static org.sonar.server.measure.ws.ComponentTreeAction.ALL_STRATEGY; -import static org.sonar.server.measure.ws.ComponentTreeAction.CHILDREN_STRATEGY; import static org.sonar.server.measure.ws.ComponentTreeAction.LEAVES_STRATEGY; -import static org.sonar.server.measure.ws.ComponentTreeAction.METRIC_PERIOD_SORT; -import static org.sonar.server.measure.ws.ComponentTreeAction.METRIC_SORT; -import static org.sonar.server.measure.ws.ComponentTreeAction.NAME_SORT; +import static org.sonar.server.measure.ws.ComponentTreeAction.STRATEGIES; import static org.sonar.server.measure.ws.ComponentTreeAction.WITH_MEASURES_ONLY_METRIC_SORT_FILTER; import static org.sonar.server.measure.ws.SnapshotDtoToWsPeriods.snapshotToWsPeriods; import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException; @@ -110,19 +104,18 @@ public class ComponentTreeDataLoader { } Long developerId = searchDeveloperId(dbSession, wsRequest); - ComponentTreeQuery dbQuery = toComponentTreeQuery(wsRequest, baseComponent); - ComponentDtosAndTotal componentDtosAndTotal = searchComponents(dbSession, dbQuery, wsRequest); - List components = componentDtosAndTotal.componentDtos; + ComponentTreeQuery componentTreeQuery = toComponentTreeQuery(wsRequest, baseComponent); + List components = searchComponents(dbSession, componentTreeQuery); List metrics = searchMetrics(dbSession, wsRequest); List periods = snapshotToWsPeriods(baseSnapshot.get()); - Table measuresByComponentUuidAndMetric = searchMeasuresByComponentUuidAndMetric(dbSession, baseComponent, components, metrics, - periods, developerId); + Table measuresByComponentUuidAndMetric = searchMeasuresByComponentUuidAndMetric(dbSession, baseComponent, componentTreeQuery, components, + metrics, periods, developerId); components = filterComponents(components, measuresByComponentUuidAndMetric, metrics, wsRequest); components = sortComponents(components, wsRequest, metrics, measuresByComponentUuidAndMetric); - int componentCount = computeComponentCount(componentDtosAndTotal.total, components, componentWithMeasuresOnly(wsRequest)); + + int componentCount = components.size(); components = paginateComponents(components, wsRequest); - Map referenceComponentsById = searchReferenceComponentsById(dbSession, components); return ComponentTreeData.builder() .setBaseComponent(baseComponent) @@ -131,17 +124,13 @@ public class ComponentTreeDataLoader { .setMeasuresByComponentUuidAndMetric(measuresByComponentUuidAndMetric) .setMetrics(metrics) .setPeriods(periods) - .setReferenceComponentsByUuid(referenceComponentsById) + .setReferenceComponentsByUuid(searchReferenceComponentsById(dbSession, components)) .build(); } finally { dbClient.closeSession(dbSession); } } - private static int computeComponentCount(int dbComponentCount, List components, boolean returnOnlyComponentsWithMeasures) { - return returnOnlyComponentsWithMeasures ? components.size() : dbComponentCount; - } - @CheckForNull private Long searchDeveloperId(DbSession dbSession, ComponentTreeWsRequest wsRequest) { if (wsRequest.getDeveloperId() == null && wsRequest.getDeveloperKey() == null) { @@ -164,24 +153,12 @@ public class ComponentTreeDataLoader { .uniqueIndex(ComponentDto::uuid); } - private ComponentDtosAndTotal searchComponents(DbSession dbSession, ComponentTreeQuery dbQuery, ComponentTreeWsRequest wsRequest) { - if (dbQuery.getQualifiers() != null && dbQuery.getQualifiers().isEmpty()) { - return new ComponentDtosAndTotal(Collections.emptyList(), 0); - } - String strategy = requireNonNull(wsRequest.getStrategy()); - switch (strategy) { - case CHILDREN_STRATEGY: - return new ComponentDtosAndTotal( - dbClient.componentDao().selectDescendants(dbSession, dbQuery), - 0); - case LEAVES_STRATEGY: - case ALL_STRATEGY: - return new ComponentDtosAndTotal( - dbClient.componentDao().selectDescendants(dbSession, dbQuery), - 0); - default: - throw new IllegalStateException("Unknown component tree strategy"); + private List searchComponents(DbSession dbSession, ComponentTreeQuery componentTreeQuery) { + Collection qualifiers = componentTreeQuery.getQualifiers(); + if (qualifiers != null && qualifiers.isEmpty()) { + return Collections.emptyList(); } + return dbClient.componentDao().selectDescendants(dbSession, componentTreeQuery); } private List searchMetrics(DbSession dbSession, ComponentTreeWsRequest request) { @@ -199,20 +176,18 @@ public class ComponentTreeDataLoader { return metrics; } - private Table searchMeasuresByComponentUuidAndMetric(DbSession dbSession, ComponentDto baseComponent, - List components, List metrics, - List periods, @Nullable Long developerId) { - List componentUuids = new ArrayList<>(); - componentUuids.add(baseComponent.uuid()); - components.stream().forEach(c -> componentUuids.add(c.uuid())); + private Table searchMeasuresByComponentUuidAndMetric(DbSession dbSession, ComponentDto baseComponent, ComponentTreeQuery componentTreeQuery, + List components, List metrics, List periods, @Nullable Long developerId) { Map metricsById = Maps.uniqueIndex(metrics, MetricDtoFunctions.toId()); - MeasureQuery measureQuery = MeasureQuery.builder() + MeasureTreeQuery measureQuery = MeasureTreeQuery.builder() + .setStrategy(MeasureTreeQuery.Strategy.valueOf(componentTreeQuery.getStrategy().name())) + .setNameOrKeyQuery(componentTreeQuery.getNameOrKeyQuery()) + .setQualifiers(componentTreeQuery.getQualifiers()) .setPersonId(developerId) - .setComponentUuids(baseComponent.projectUuid(), componentUuids) .setMetricIds(new ArrayList<>(metricsById.keySet())) .build(); - List measureDtos = dbClient.measureDao().selectByQuery(dbSession, measureQuery); + List measureDtos = dbClient.measureDao().selectTreeByQuery(dbSession, baseComponent, measureQuery); Table measuresByComponentUuidAndMetric = HashBasedTable.create(components.size(), metrics.size()); for (MeasureDto measureDto : measureDtos) { @@ -276,29 +251,16 @@ public class ComponentTreeDataLoader { private static List sortComponents(List components, ComponentTreeWsRequest wsRequest, List metrics, Table measuresByComponentUuidAndMetric) { - if (!isSortByMetric(wsRequest)) { - return components; - } - return ComponentTreeSort.sortComponents(components, wsRequest, metrics, measuresByComponentUuidAndMetric); } private static List paginateComponents(List components, ComponentTreeWsRequest wsRequest) { - if (!isSortByMetric(wsRequest)) { - return components; - } - return from(components) .skip(offset(wsRequest.getPage(), wsRequest.getPageSize())) .limit(wsRequest.getPageSize()) .toList(); } - private static boolean isSortByMetric(ComponentTreeWsRequest wsRequest) { - requireNonNull(wsRequest.getSort()); - return wsRequest.getSort().contains(METRIC_SORT) || wsRequest.getSort().contains(METRIC_PERIOD_SORT); - } - @CheckForNull private List childrenQualifiers(ComponentTreeWsRequest request, String baseQualifier) { List requestQualifiers = request.getQualifiers(); @@ -323,29 +285,17 @@ public class ComponentTreeDataLoader { private ComponentTreeQuery toComponentTreeQuery(ComponentTreeWsRequest wsRequest, ComponentDto baseComponent) { List childrenQualifiers = childrenQualifiers(wsRequest, baseComponent.qualifier()); - List sortsWithoutMetricSort = newArrayList(Iterables.filter(wsRequest.getSort(), IsNotMetricSort.INSTANCE)); - sortsWithoutMetricSort = sortsWithoutMetricSort.isEmpty() ? singletonList(NAME_SORT) : sortsWithoutMetricSort; - - ComponentTreeQuery.Builder dbQuery = ComponentTreeQuery.builder() + ComponentTreeQuery.Builder componentTreeQueryBuilder = ComponentTreeQuery.builder() .setBaseUuid(baseComponent.uuid()) - .setPage(wsRequest.getPage()) - .setPageSize(wsRequest.getPageSize()) - .setSortFields(sortsWithoutMetricSort) - .setAsc(wsRequest.getAsc()); + .setStrategy(STRATEGIES.get(wsRequest.getStrategy())); if (wsRequest.getQuery() != null) { - dbQuery.setNameOrKeyQuery(wsRequest.getQuery()); + componentTreeQueryBuilder.setNameOrKeyQuery(wsRequest.getQuery()); } if (childrenQualifiers != null) { - dbQuery.setQualifiers(childrenQualifiers); + componentTreeQueryBuilder.setQualifiers(childrenQualifiers); } - // load all components if we must sort by metric value - if (isSortByMetric(wsRequest)) { - dbQuery.setPage(1); - dbQuery.setPageSize(Integer.MAX_VALUE); - } - - return dbQuery.build(); + return componentTreeQueryBuilder.build(); } private void checkPermissions(ComponentDto baseComponent) { @@ -356,16 +306,6 @@ public class ComponentTreeDataLoader { } } - private static class ComponentDtosAndTotal { - private final List componentDtos; - private final int total; - - private ComponentDtosAndTotal(List componentDtos, int total) { - this.componentDtos = componentDtos; - this.total = total; - } - } - private enum IsFileComponent implements Predicate { INSTANCE; @@ -397,15 +337,6 @@ public class ComponentTreeDataLoader { } } - private enum IsNotMetricSort implements Predicate { - INSTANCE; - - @Override - public boolean apply(@Nonnull String input) { - return !input.equals(METRIC_SORT) && !input.equals(METRIC_PERIOD_SORT); - } - } - private static class MatchMetricKey implements Predicate { private final String metricKeyToSort; diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeSort.java b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeSort.java index a833af62fed..be1d15aaf97 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeSort.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeSort.java @@ -57,7 +57,7 @@ import static org.sonar.server.measure.ws.ComponentTreeAction.NAME_SORT; import static org.sonar.server.measure.ws.ComponentTreeAction.PATH_SORT; import static org.sonar.server.measure.ws.ComponentTreeAction.QUALIFIER_SORT; -class ComponentTreeSort { +public class ComponentTreeSort { private static final Set NUMERIC_VALUE_TYPES = EnumSet.of(BOOL, FLOAT, INT, MILLISEC, WORK_DUR, PERCENT, RATING); private static final Set TEXTUAL_VALUE_TYPES = EnumSet.of(DATA, DISTRIB, STRING); @@ -66,7 +66,7 @@ class ComponentTreeSort { // static method only } - static List sortComponents(List components, ComponentTreeWsRequest wsRequest, List metrics, + public static List sortComponents(List components, ComponentTreeWsRequest wsRequest, List metrics, Table measuresByComponentUuidAndMetric) { List sortParameters = wsRequest.getSort(); if (sortParameters == null || sortParameters.isEmpty()) { @@ -95,15 +95,15 @@ class ComponentTreeSort { } private static Ordering componentNameOrdering(boolean isAscending) { - return stringOrdering(isAscending, ComponentDtoToName.INSTANCE); + return stringOrdering(isAscending, ComponentDto::name); } private static Ordering componentQualifierOrdering(boolean isAscending) { - return stringOrdering(isAscending, ComponentDtoToQualifier.INSTANCE); + return stringOrdering(isAscending, ComponentDto::qualifier); } private static Ordering componentPathOrdering(boolean isAscending) { - return stringOrdering(isAscending, ComponentDtoToPath.INSTANCE); + return stringOrdering(isAscending, ComponentDto::path); } private static Ordering stringOrdering(boolean isAscending, Function function) { @@ -272,30 +272,4 @@ class ComponentTreeSort { } } - private enum ComponentDtoToName implements Function { - INSTANCE; - - @Override - public String apply(@Nonnull ComponentDto input) { - return input.name(); - } - } - - private enum ComponentDtoToQualifier implements Function { - INSTANCE; - - @Override - public String apply(@Nonnull ComponentDto input) { - return input.qualifier(); - } - } - - private enum ComponentDtoToPath implements Function { - INSTANCE; - - @Override - public String apply(@Nonnull ComponentDto input) { - return input.path(); - } - } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/ws/ComponentTreeActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/ws/ComponentTreeActionTest.java index 8b469742061..098f917316b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/ws/ComponentTreeActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/measure/ws/ComponentTreeActionTest.java @@ -287,6 +287,9 @@ public class ComponentTreeActionTest { .setParam(Param.PAGE_SIZE, "3")); assertThat(response.getComponentsList()).extracting("id").containsExactly("file-uuid-4", "file-uuid-5", "file-uuid-6"); + assertThat(response.getPaging().getPageIndex()).isEqualTo(2); + assertThat(response.getPaging().getPageSize()).isEqualTo(3); + assertThat(response.getPaging().getTotal()).isEqualTo(9); } @Test -- 2.39.5