aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2016-11-04 11:28:44 +0100
committerJulien Lancelot <julien.lancelot@sonarsource.com>2016-11-08 11:12:51 +0100
commitb67b21e7324e78bab3876f460cfe426455b2d367 (patch)
tree940698429a5416afbe404757d1c68712892b5e53
parent617497c27c42a9ce4d782d1bfa8249c3a0d94083 (diff)
downloadsonarqube-b67b21e7324e78bab3876f460cfe426455b2d367.tar.gz
sonarqube-b67b21e7324e78bab3876f460cfe426455b2d367.zip
SONAR-8089 Merge ComponentDao#selectChildren and selectDescendants
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/ws/TreeAction.java46
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStep.java15
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeDataLoader.java6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest.java7
-rw-r--r--sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java64
-rw-r--r--sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java8
-rw-r--r--sonar-db/src/main/java/org/sonar/db/component/ComponentTreeQuery.java42
-rw-r--r--sonar-db/src/main/java/org/sonar/db/purge/PurgeDao.java15
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml53
-rw-r--r--sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java253
10 files changed, 170 insertions, 339 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 3ddb250ea0b..93db78f2ab7 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,26 +19,6 @@
*/
package org.sonar.server.component.ws;
-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.format;
-import static java.util.Collections.emptyMap;
-import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
-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;
-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.WsUtils.checkRequest;
-import static org.sonar.server.ws.WsUtils.writeProtobuf;
-import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_TREE;
-import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BASE_COMPONENT_ID;
-import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BASE_COMPONENT_KEY;
-import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS;
-import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_STRATEGY;
-
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
@@ -65,6 +45,26 @@ import org.sonar.server.user.UserSession;
import org.sonarqube.ws.WsComponents.TreeWsResponse;
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.format;
+import static java.util.Collections.emptyMap;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
+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;
+import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+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.component.ComponentsWsParameters.ACTION_TREE;
+import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BASE_COMPONENT_ID;
+import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BASE_COMPONENT_KEY;
+import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS;
+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;
@@ -158,13 +158,13 @@ public class TreeAction implements ComponentsWsAction {
int total;
switch (treeWsRequest.getStrategy()) {
case CHILDREN_STRATEGY:
- components = dbClient.componentDao().selectChildren(dbSession, query);
- total = dbClient.componentDao().countChildren(dbSession, query);
+ components = dbClient.componentDao().selectDescendants(dbSession, query);
+ total = components.size();
break;
case LEAVES_STRATEGY:
case ALL_STRATEGY:
components = dbClient.componentDao().selectDescendants(dbSession, query);
- total = dbClient.componentDao().countDescendants(dbSession, query);
+ total = components.size();
break;
default:
throw new IllegalStateException("Unknown component tree strategy");
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStep.java
index 5ffd9591cd5..38e1f2ab914 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStep.java
@@ -41,8 +41,11 @@ import org.sonar.core.hash.SourceLinesHashesComputer;
import org.sonar.core.util.CloseableIterator;
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.db.source.FileSourceDto;
+import org.sonar.server.computation.task.projectanalysis.analysis.Analysis;
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.server.computation.task.projectanalysis.component.Component;
import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit;
@@ -50,21 +53,18 @@ import org.sonar.server.computation.task.projectanalysis.component.DepthTraversa
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder;
import org.sonar.server.computation.task.projectanalysis.component.TypeAwareVisitorAdapter;
import org.sonar.server.computation.task.projectanalysis.filemove.FileSimilarity.File;
-import org.sonar.server.computation.task.projectanalysis.analysis.Analysis;
import org.sonar.server.computation.task.projectanalysis.source.SourceLinesRepository;
import org.sonar.server.computation.task.step.ComputationStep;
import static com.google.common.base.Splitter.on;
import static com.google.common.collect.FluentIterable.from;
import static java.util.Arrays.asList;
-import static java.util.Collections.singletonList;
import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
public class FileMoveDetectionStep implements ComputationStep {
protected static final int MIN_REQUIRED_SCORE = 85;
private static final Logger LOG = Loggers.get(FileMoveDetectionStep.class);
private static final List<String> FILE_QUALIFIERS = asList(Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE);
- private static final List<String> SORT_FIELDS = singletonList("name");
private static final Splitter LINES_HASHES_SPLITTER = on('\n');
private final AnalysisMetadataHolder analysisMetadataHolder;
@@ -152,15 +152,14 @@ public class FileMoveDetectionStep implements ComputationStep {
try (DbSession dbSession = dbClient.openSession(false)) {
// FIXME no need to use such a complex query, joining on SNAPSHOTS and retrieving all column of table PROJECTS, replace with dedicated
// mapper method
- return from(dbClient.componentDao().selectDescendants(
+ List<ComponentDto> componentDtos = dbClient.componentDao().selectDescendants(
dbSession,
ComponentTreeQuery.builder()
.setBaseUuid(rootHolder.getRoot().getUuid())
.setQualifiers(FILE_QUALIFIERS)
- .setSortFields(SORT_FIELDS)
- .setPageSize(Integer.MAX_VALUE)
- .setPage(1)
- .build()))
+ .setStrategy(Strategy.LEAVES)
+ .build());
+ return from(componentDtos)
.transform(componentDto -> new DbComponent(componentDto.getId(), componentDto.key(), componentDto.uuid(), componentDto.path()))
.uniqueIndex(DbComponent::getKey);
}
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 8a2d059c215..04f5c44c397 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
@@ -172,13 +172,13 @@ public class ComponentTreeDataLoader {
switch (strategy) {
case CHILDREN_STRATEGY:
return new ComponentDtosAndTotal(
- dbClient.componentDao().selectChildren(dbSession, dbQuery),
- dbClient.componentDao().countChildren(dbSession, dbQuery));
+ dbClient.componentDao().selectDescendants(dbSession, dbQuery),
+ 0);
case LEAVES_STRATEGY:
case ALL_STRATEGY:
return new ComponentDtosAndTotal(
dbClient.componentDao().selectDescendants(dbSession, dbQuery),
- dbClient.componentDao().countDescendants(dbSession, dbQuery));
+ 0);
default:
throw new IllegalStateException("Unknown component tree strategy");
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest.java
index f19049bcabc..15bb327294c 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest.java
@@ -44,11 +44,11 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTreeQuery;
import org.sonar.db.source.FileSourceDao;
import org.sonar.db.source.FileSourceDto;
+import org.sonar.server.computation.task.projectanalysis.analysis.Analysis;
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
-import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
import org.sonar.server.computation.task.projectanalysis.component.Component;
import org.sonar.server.computation.task.projectanalysis.component.ReportComponent;
-import org.sonar.server.computation.task.projectanalysis.analysis.Analysis;
+import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
import org.sonar.server.computation.task.projectanalysis.source.SourceLinesRepositoryRule;
import static com.google.common.base.Joiner.on;
@@ -287,9 +287,6 @@ public class FileMoveDetectionStepTest {
ComponentTreeQuery query = captor.getValue();
assertThat(query.getBaseUuid()).isEqualTo(PROJECT.getUuid());
- assertThat(query.getPage()).isEqualTo(1);
- assertThat(query.getPageSize()).isEqualTo(Integer.MAX_VALUE);
- assertThat(query.getSqlSort()).isEqualTo("LOWER(p.name) ASC, p.name ASC");
assertThat(query.getQualifiers()).containsOnly(FILE, UNIT_TEST_FILE);
}
diff --git a/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java b/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java
index fd5fe9dc652..62c4652b05d 100644
--- a/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java
+++ b/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java
@@ -34,15 +34,12 @@ import org.apache.ibatis.session.RowBounds;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.db.Dao;
-import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbSession;
import org.sonar.db.RowNotFoundException;
-import org.sonar.db.WildcardPosition;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Maps.newHashMapWithExpectedSize;
import static java.util.Collections.emptyList;
-import static org.sonar.api.utils.Paging.offset;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
import static org.sonar.db.DatabaseUtils.executeLargeUpdates;
@@ -167,42 +164,7 @@ public class ComponentDao implements Dao {
}
/**
- * Select the children of a base component, given by its UUID. The components that are not present in last
- * analysis are ignored.
- *
- * An empty list is returned if the base component does not exist or if the base component is a leaf.
- */
- public List<ComponentDto> selectChildren(DbSession dbSession, ComponentTreeQuery query) {
- Optional<ComponentDto> componentOpt = selectByUuid(dbSession, query.getBaseUuid());
- if (!componentOpt.isPresent()) {
- return emptyList();
- }
- ComponentDto component = componentOpt.get();
- RowBounds rowBounds = new RowBounds(offset(query.getPage(), query.getPageSize()), query.getPageSize());
- return mapper(dbSession).selectChildren(query, uuidPathForChildrenQuery(component), rowBounds);
- }
-
- /**
- * Count the children of a base component, given by its UUID. The components that are not present in last
- * analysis are ignored.
- *
- * Zero is returned if the base component does not exist or if the base component is a leaf.
- */
- public int countChildren(DbSession dbSession, ComponentTreeQuery query) {
- Optional<ComponentDto> componentOpt = selectByUuid(dbSession, query.getBaseUuid());
- if (!componentOpt.isPresent()) {
- return 0;
- }
- ComponentDto component = componentOpt.get();
- return mapper(dbSession).countChildren(query, uuidPathForChildrenQuery(component));
- }
-
- private static String uuidPathForChildrenQuery(ComponentDto component) {
- return component.getUuidPath() + component.uuid() + ".";
- }
-
- /**
- * Select the descendants of a base component, given by its UUID. The components that are not present in last
+ * Select the children or the leaves of a base component, given by its UUID. The components that are not present in last
* analysis are ignored.
*
* An empty list is returned if the base component does not exist or if the base component is a leaf.
@@ -210,30 +172,10 @@ public class ComponentDao implements Dao {
public List<ComponentDto> selectDescendants(DbSession dbSession, ComponentTreeQuery query) {
Optional<ComponentDto> componentOpt = selectByUuid(dbSession, query.getBaseUuid());
if (!componentOpt.isPresent()) {
- return Collections.emptyList();
- }
- ComponentDto component = componentOpt.get();
- RowBounds rowBounds = new RowBounds(offset(query.getPage(), query.getPageSize()), query.getPageSize());
- return mapper(dbSession).selectDescendants(query, uuidPathForDescendantsQuery(component), rowBounds);
- }
-
- /**
- * Count the descendants of a base component, given by its UUID. The components that are not present in last
- * analysis are ignored.
- *
- * Zero is returned if the base component does not exist or if the base component is a leaf.
- */
- public int countDescendants(DbSession dbSession, ComponentTreeQuery query) {
- Optional<ComponentDto> componentOpt = selectByUuid(dbSession, query.getBaseUuid());
- if (!componentOpt.isPresent()) {
- return 0;
+ return emptyList();
}
ComponentDto component = componentOpt.get();
- return mapper(dbSession).countDescendants(query, uuidPathForDescendantsQuery(component));
- }
-
- private static String uuidPathForDescendantsQuery(ComponentDto component) {
- return DatabaseUtils.buildLikeValue(component.getUuidPath() + component.uuid() + ".", WildcardPosition.AFTER);
+ return mapper(dbSession).selectDescendants(query, query.getUuidPath(component));
}
public ComponentDto selectOrFailByKey(DbSession session, String key) {
diff --git a/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java b/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java
index 027a67fe5a1..7e41d5c97b4 100644
--- a/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java
+++ b/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java
@@ -64,13 +64,7 @@ public interface ComponentMapper {
List<ComponentDto> selectAncestors(@Param("query") ComponentTreeQuery query, @Param("baseUuidPathLike") String baseUuidPathLike);
- List<ComponentDto> selectChildren(@Param("query") ComponentTreeQuery query, @Param("baseUuidPath") String baseUuidPath, RowBounds rowBounds);
-
- int countChildren(@Param("query") ComponentTreeQuery query, @Param("baseUuidPath") String baseUuidPath);
-
- List<ComponentDto> selectDescendants(@Param("query") ComponentTreeQuery query, @Param("baseUuidPathLike") String baseUuidPathLike, RowBounds rowBounds);
-
- int countDescendants(@Param("query") ComponentTreeQuery query, @Param("baseUuidPathLike") String baseUuidPathLike);
+ List<ComponentDto> selectDescendants(@Param("query") ComponentTreeQuery query, @Param("baseUuidPath") String baseUuidPath);
/**
* Return all project (PRJ/TRK) uuids
diff --git a/sonar-db/src/main/java/org/sonar/db/component/ComponentTreeQuery.java b/sonar-db/src/main/java/org/sonar/db/component/ComponentTreeQuery.java
index b987ff47928..c8f47f6cd75 100644
--- a/sonar-db/src/main/java/org/sonar/db/component/ComponentTreeQuery.java
+++ b/sonar-db/src/main/java/org/sonar/db/component/ComponentTreeQuery.java
@@ -28,6 +28,7 @@ import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.sonar.db.WildcardPosition;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Lists.newArrayList;
@@ -37,6 +38,11 @@ import static org.sonar.db.DatabaseUtils.buildLikeValue;
import static org.sonar.db.WildcardPosition.AFTER;
public class ComponentTreeQuery {
+
+ public enum Strategy {
+ CHILDREN, LEAVES
+ }
+
@CheckForNull
private final String nameOrKeyQuery;
// SONAR-7681 a public implementation of List must be used in MyBatis - potential concurrency exceptions otherwise
@@ -49,6 +55,7 @@ public class ComponentTreeQuery {
private final String baseUuid;
private final String sqlSort;
private final String direction;
+ private final Strategy strategy;
private ComponentTreeQuery(Builder builder) {
this.nameOrKeyQuery = builder.nameOrKeyQuery;
@@ -56,8 +63,9 @@ public class ComponentTreeQuery {
this.page = builder.page;
this.pageSize = builder.pageSize;
this.baseUuid = builder.baseUuid;
+ this.strategy = requireNonNull(builder.strategy);
this.direction = builder.asc ? "ASC" : "DESC";
- this.sqlSort = sortFieldsToSqlSort(builder.sortFields, direction);
+ this.sqlSort = builder.sortFields != null ? sortFieldsToSqlSort(builder.sortFields, direction) : null;
}
public Collection<String> getQualifiers() {
@@ -74,10 +82,12 @@ public class ComponentTreeQuery {
return nameOrKeyQuery == null ? null : buildLikeValue(nameOrKeyQuery, AFTER).toLowerCase(Locale.ENGLISH);
}
+ @Deprecated
public Integer getPage() {
return page;
}
+ @Deprecated
public Integer getPageSize() {
return pageSize;
}
@@ -86,18 +96,36 @@ public class ComponentTreeQuery {
return baseUuid;
}
+ public Strategy getStrategy() {
+ return strategy;
+ }
+
+ @Deprecated
public String getSqlSort() {
return sqlSort;
}
+ @Deprecated
public String getDirection() {
return direction;
}
+ public String getUuidPath(ComponentDto component) {
+ switch (strategy) {
+ case CHILDREN:
+ return component.getUuidPath() + component.uuid() + ".";
+ case LEAVES:
+ return buildLikeValue(component.getUuidPath() + component.uuid() + ".", WildcardPosition.AFTER);
+ default:
+ throw new IllegalArgumentException("Unknown strategy : " + strategy);
+ }
+ }
+
public static Builder builder() {
return new Builder();
}
+ @Deprecated
private static String sortFieldsToSqlSort(List<String> sortFields, String direction) {
return sortFields
.stream()
@@ -117,6 +145,7 @@ public class ComponentTreeQuery {
private String baseUuid;
private List<String> sortFields;
private boolean asc = true;
+ private Strategy strategy;
private Builder() {
// private constructor
@@ -124,7 +153,6 @@ public class ComponentTreeQuery {
public ComponentTreeQuery build() {
requireNonNull(baseUuid);
- requireNonNull(sortFields);
return new ComponentTreeQuery(this);
}
@@ -138,11 +166,13 @@ public class ComponentTreeQuery {
return this;
}
+ @Deprecated
public Builder setPage(int page) {
this.page = page;
return this;
}
+ @Deprecated
public Builder setPageSize(int pageSize) {
this.pageSize = pageSize;
return this;
@@ -153,18 +183,26 @@ public class ComponentTreeQuery {
return this;
}
+ public Builder setStrategy(Strategy strategy) {
+ this.strategy = requireNonNull(strategy);
+ return this;
+ }
+
+ @Deprecated
public Builder setSortFields(List<String> sorts) {
checkArgument(sorts != null && !sorts.isEmpty());
this.sortFields = sorts;
return this;
}
+ @Deprecated
public Builder setAsc(boolean asc) {
this.asc = asc;
return this;
}
}
+ @Deprecated
private static class SortFieldToSqlSortFieldFunction implements Function<String, String> {
private static final String PATTERN = "LOWER(p.%1$s) %2$s, p.%1$s %2$s";
diff --git a/sonar-db/src/main/java/org/sonar/db/purge/PurgeDao.java b/sonar-db/src/main/java/org/sonar/db/purge/PurgeDao.java
index 0b5a2f48700..aba3ff7e704 100644
--- a/sonar-db/src/main/java/org/sonar/db/purge/PurgeDao.java
+++ b/sonar-db/src/main/java/org/sonar/db/purge/PurgeDao.java
@@ -34,6 +34,7 @@ import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDao;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTreeQuery;
+import org.sonar.db.component.ComponentTreeQuery.Strategy;
import static java.util.Collections.emptyList;
import static org.sonar.api.utils.DateUtils.dateToLong;
@@ -45,7 +46,6 @@ import static org.sonar.db.DatabaseUtils.executeLargeInputs;
public class PurgeDao implements Dao {
private static final Logger LOG = Loggers.get(PurgeDao.class);
private static final String[] UNPROCESSED_STATUS = new String[] {"U"};
- private static final List<String> UUID_FIELD_SORT = Collections.singletonList("uuid");
private final ComponentDao componentDao;
private final System2 system2;
@@ -112,9 +112,10 @@ public class PurgeDao implements Dao {
List<String> componentWithoutHistoricalDataUuids = componentDao
.selectDescendants(
dbSession,
- newComponentTreeQuery()
+ ComponentTreeQuery.builder()
.setBaseUuid(rootUuid)
.setQualifiers(Arrays.asList(scopesWithoutHistoricalData))
+ .setStrategy(Strategy.LEAVES)
.build())
.stream().map(ComponentDto::uuid)
.collect(Collectors.toList());
@@ -122,16 +123,6 @@ public class PurgeDao implements Dao {
purgeCommands.deleteComponentMeasures(analysisUuids, componentWithoutHistoricalDataUuids);
}
- /**
- * Creates a new ComponentTreeQuery.Builder with properties that don't matter here but are mandatory populated.
- */
- private static ComponentTreeQuery.Builder newComponentTreeQuery() {
- return ComponentTreeQuery.builder()
- .setPage(1)
- .setPageSize(Integer.MAX_VALUE)
- .setSortFields(UUID_FIELD_SORT);
- }
-
private void purgeDisabledComponents(DbSession session, Collection<String> uuids, PurgeListener listener) {
PurgeMapper mapper = mapper(session);
executeLargeInputs(uuids,
diff --git a/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml
index 52dd7c88206..8a3aa4973a9 100644
--- a/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml
+++ b/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml
@@ -331,29 +331,30 @@
order by ${query.sqlSort}
</select>
- <!-- "p" is children -->
- <select id="selectChildren" resultType="Component">
+ <select id="selectDescendants" resultType="Component">
select
<include refid="componentColumns"/>
- <include refid="sqlChildren"/>
- order by ${query.sqlSort}
+ <include refid="selectDescendantsQuery"/>
</select>
- <select id="countChildren" resultType="int">
- select count(p.id)
- <include refid="sqlChildren"/>
- </select>
-
- <sql id="sqlChildren">
+ <sql id="selectDescendantsQuery">
from projects p
inner join projects base on base.project_uuid = p.project_uuid and base.uuid = #{query.baseUuid}
- where
- p.enabled = ${_true}
- and p.uuid_path = #{baseUuidPath}
- <include refid="sqlTreeFilters"/>
+ <where>
+ <choose>
+ <when test="query.getStrategy().name() == 'CHILDREN'">
+ and p.uuid_path = #{baseUuidPath}
+ </when>
+ <otherwise>
+ and p.uuid_path like #{baseUuidPath} ESCAPE '/'
+ </otherwise>
+ </choose>
+ <include refid="selectDescendantsFilters"/>
+ </where>
</sql>
- <sql id="sqlTreeFilters">
+ <sql id="selectDescendantsFilters">
+ and p.enabled = ${_true}
<if test="query.qualifiers != null">
and p.qualifier in
<foreach collection="query.qualifiers" item="qualifier" open="(" close=")" separator=",">
@@ -379,28 +380,6 @@
</if>
</sql>
- <!-- "p" is descendants -->
- <select id="selectDescendants" resultType="Component">
- select
- <include refid="componentColumns"/>
- <include refid="sqlDescendants"/>
- order by ${query.sqlSort}
- </select>
-
- <select id="countDescendants" resultType="int">
- select count(p.id)
- <include refid="sqlDescendants"/>
- </select>
-
- <sql id="sqlDescendants">
- from projects p
- inner join projects base on base.project_uuid=p.project_uuid and base.uuid = #{query.baseUuid}
- where
- p.enabled = ${_true}
- and p.uuid_path like #{baseUuidPathLike} ESCAPE '/'
- <include refid="sqlTreeFilters"/>
- </sql>
-
<select id="countRootComponents" resultType="int">
select count(p.id)
from projects p
diff --git a/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java b/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java
index 394d2a241e9..70f3e206e23 100644
--- a/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java
@@ -47,6 +47,8 @@ import static org.sonar.db.component.ComponentTesting.newProjectCopy;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.db.component.ComponentTesting.newSubView;
import static org.sonar.db.component.ComponentTesting.newView;
+import static org.sonar.db.component.ComponentTreeQuery.Strategy.CHILDREN;
+import static org.sonar.db.component.ComponentTreeQuery.Strategy.LEAVES;
public class ComponentDaoTest {
@@ -677,8 +679,7 @@ public class ComponentDaoTest {
.setBModuleUuidPath("moduleUuidPath")
.setBName("name")
.setBPath("path")
- .setBQualifier("qualifier")
- );
+ .setBQualifier("qualifier"));
dbSession.commit();
Map<String, Object> row = selectBColumnsForUuid("U1");
@@ -840,7 +841,47 @@ public class ComponentDaoTest {
}
@Test
- public void selectChildren() {
+ public void selectParent() {
+ // project -> module -> file
+ ComponentDto project = newProjectDto(PROJECT_UUID);
+ componentDb.insertProjectAndSnapshot(project);
+ ComponentDto module = newModuleDto(MODULE_UUID, project);
+ componentDb.insertComponent(module);
+ ComponentDto file = newFileDto(module, null, FILE_1_UUID);
+ componentDb.insertComponent(file);
+ db.commit();
+
+ assertThat(underTest.selectParent(dbSession, project)).isAbsent();
+ assertThat(underTest.selectParent(dbSession, module).get().uuid()).isEqualTo(PROJECT_UUID);
+ assertThat(underTest.selectParent(dbSession, file).get().uuid()).isEqualTo(MODULE_UUID);
+ }
+
+ @Test
+ public void selectAncestors() {
+ // project -> module -> file
+ ComponentDto project = newProjectDto(PROJECT_UUID);
+ componentDb.insertProjectAndSnapshot(project);
+ ComponentDto module = newModuleDto(MODULE_UUID, project);
+ componentDb.insertComponent(module);
+ ComponentDto file = newFileDto(module, null, FILE_1_UUID);
+ componentDb.insertComponent(file);
+ db.commit();
+
+ // ancestors of root
+ List<ComponentDto> ancestors = underTest.selectAncestors(dbSession, project);
+ assertThat(ancestors).isEmpty();
+
+ // ancestors of module
+ ancestors = underTest.selectAncestors(dbSession, module);
+ assertThat(ancestors).extracting("uuid").containsExactly(PROJECT_UUID);
+
+ // ancestors of file
+ ancestors = underTest.selectAncestors(dbSession, file);
+ assertThat(ancestors).extracting("uuid").containsExactly(PROJECT_UUID, MODULE_UUID);
+ }
+
+ @Test
+ public void select_descendants_with_children_stragegy() {
// project has 2 children: module and file 1. Other files are part of module.
ComponentDto project = newProjectDto(PROJECT_UUID);
componentDb.insertProjectAndSnapshot(project);
@@ -857,133 +898,81 @@ public class ComponentDaoTest {
// test children of root
ComponentTreeQuery query = newTreeQuery(PROJECT_UUID).build();
- List<ComponentDto> children = underTest.selectChildren(dbSession, query);
- assertThat(children).extracting("uuid").containsExactly(FILE_1_UUID, MODULE_UUID);
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(2);
+ List<ComponentDto> children = underTest.selectDescendants(dbSession, query);
+ assertThat(children).extracting("uuid").containsOnly(FILE_1_UUID, MODULE_UUID);
// test children of root, filtered by qualifier
query = newTreeQuery(PROJECT_UUID).setQualifiers(asList(Qualifiers.MODULE)).build();
- children = underTest.selectChildren(dbSession, query);
- assertThat(children).extracting("uuid").containsExactly(MODULE_UUID);
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(1);
+ children = underTest.selectDescendants(dbSession, query);
+ assertThat(children).extracting("uuid").containsOnly(MODULE_UUID);
// test children of intermediate component (module here), default ordering by
query = newTreeQuery(MODULE_UUID).build();
- assertThat(underTest.selectChildren(dbSession, query)).extracting("uuid").containsOnly(FILE_2_UUID, FILE_3_UUID);
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(2);
+ assertThat(underTest.selectDescendants(dbSession, query)).extracting("uuid").containsOnly(FILE_2_UUID, FILE_3_UUID);
// test children of leaf component (file here)
query = newTreeQuery(FILE_1_UUID).build();
- assertThat(underTest.selectChildren(dbSession, query)).isEmpty();
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(0);
+ assertThat(underTest.selectDescendants(dbSession, query)).isEmpty();
// test children of root, matching name
query = newTreeQuery(PROJECT_UUID).setNameOrKeyQuery("One").build();
- assertThat(underTest.selectChildren(dbSession, query)).extracting("uuid").containsOnly(FILE_1_UUID);
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(1);
+ assertThat(underTest.selectDescendants(dbSession, query)).extracting("uuid").containsOnly(FILE_1_UUID);
// test children of root, matching case-insensitive name
query = newTreeQuery(PROJECT_UUID).setNameOrKeyQuery("OnE").build();
- assertThat(underTest.selectChildren(dbSession, query)).extracting("uuid").containsOnly(FILE_1_UUID);
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(1);
+ assertThat(underTest.selectDescendants(dbSession, query)).extracting("uuid").containsOnly(FILE_1_UUID);
// test children of root, matching key
query = newTreeQuery(PROJECT_UUID).setNameOrKeyQuery("file-key-1").build();
- assertThat(underTest.selectChildren(dbSession, query)).extracting("uuid").containsOnly(FILE_1_UUID);
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(1);
+ assertThat(underTest.selectDescendants(dbSession, query)).extracting("uuid").containsOnly(FILE_1_UUID);
// test children of root, without matching name nor key
query = newTreeQuery(PROJECT_UUID).setNameOrKeyQuery("does-not-exist").build();
- assertThat(underTest.selectChildren(dbSession, query)).isEmpty();
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(0);
+ assertThat(underTest.selectDescendants(dbSession, query)).isEmpty();
// test children of intermediate component (module here), matching name
query = newTreeQuery(MODULE_UUID).setNameOrKeyQuery("Two").build();
- assertThat(underTest.selectChildren(dbSession, query)).extracting("uuid").containsOnly(FILE_2_UUID);
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(1);
+ assertThat(underTest.selectDescendants(dbSession, query)).extracting("uuid").containsOnly(FILE_2_UUID);
// test children of intermediate component (module here), without matching name
query = newTreeQuery(MODULE_UUID).setNameOrKeyQuery("does-not-exist").build();
- assertThat(underTest.selectChildren(dbSession, query)).isEmpty();
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(0);
+ assertThat(underTest.selectDescendants(dbSession, query)).isEmpty();
// test children of leaf component (file here)
query = newTreeQuery(FILE_1_UUID).build();
- assertThat(underTest.selectChildren(dbSession, query)).isEmpty();
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(0);
+ assertThat(underTest.selectDescendants(dbSession, query)).isEmpty();
// test children of leaf component (file here), matching name
query = newTreeQuery(FILE_1_UUID).setNameOrKeyQuery("Foo").build();
- assertThat(underTest.selectChildren(dbSession, query)).isEmpty();
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(0);
- }
-
- @Test
- public void selectChildren_with_pagination() {
- ComponentDto project = newProjectDto(PROJECT_UUID);
- componentDb.insertProjectAndSnapshot(project);
- for (int i = 1; i <= 9; i++) {
- componentDb.insertComponent(newFileDto(project, null, "file-uuid-" + i));
- }
- db.commit();
-
- ComponentTreeQuery query = newTreeQuery(PROJECT_UUID)
- .setPage(2)
- .setPageSize(3)
- .setAsc(false)
- .build();
-
- assertThat(underTest.selectChildren(dbSession, query)).extracting("uuid").containsExactly("file-uuid-6", "file-uuid-5", "file-uuid-4");
- assertThat(underTest.countChildren(dbSession, query)).isEqualTo(9);
+ assertThat(underTest.selectDescendants(dbSession, query)).isEmpty();
}
@Test
- public void selectChildren_ordered_by_file_path() {
+ public void select_descendants_with_leaves_stragegy() {
ComponentDto project = newProjectDto(PROJECT_UUID);
componentDb.insertProjectAndSnapshot(project);
- componentDb.insertComponent(newFileDto(project, null, "file-uuid-1").setName("file-name-1").setPath("3"));
- componentDb.insertComponent(newFileDto(project, null, "file-uuid-2").setName("file-name-2").setPath("2"));
- componentDb.insertComponent(newFileDto(project, null, "file-uuid-3").setName("file-name-3").setPath("1"));
+ componentDb.insertComponent(newModuleDto("module-1-uuid", project));
+ componentDb.insertComponent(newFileDto(project, null, "file-1-uuid"));
+ componentDb.insertComponent(newFileDto(project, null, "file-2-uuid"));
db.commit();
componentDb.indexAllComponents();
- ComponentTreeQuery query = newTreeQuery(PROJECT_UUID)
- .setSortFields(singletonList("path"))
- .setAsc(true)
- .build();
+ ComponentTreeQuery query = newTreeQuery(PROJECT_UUID).setStrategy(LEAVES).build();
- List<ComponentDto> result = underTest.selectChildren(dbSession, query);
- assertThat(result).extracting("uuid").containsExactly("file-uuid-3", "file-uuid-2", "file-uuid-1");
+ List<ComponentDto> result = underTest.selectDescendants(dbSession, query);
+ assertThat(result).extracting("uuid").containsOnly("file-1-uuid", "file-2-uuid", "module-1-uuid");
}
@Test
- public void selectChildren_returns_empty_list_if_base_component_does_not_exist() {
- ComponentTreeQuery query = newTreeQuery(PROJECT_UUID).build();
+ public void select_descendants_returns_empty_list_if_base_component_does_not_exist() {
+ ComponentTreeQuery query = newTreeQuery(PROJECT_UUID).setStrategy(CHILDREN).build();
- List<ComponentDto> result = underTest.selectChildren(dbSession, query);
+ List<ComponentDto> result = underTest.selectDescendants(dbSession, query);
assertThat(result).isEmpty();
}
@Test
- public void selectChildren_of_a_view() {
- ComponentDto view = newView(A_VIEW_UUID);
- componentDb.insertViewAndSnapshot(view);
- // one subview
- ComponentDto subView = newSubView(view, "subview-uuid", "subview-key").setName("subview-name");
- componentDb.insertComponent(subView);
- // one project and its copy linked to the view
- ComponentDto project = newProjectDto(PROJECT_UUID).setName("project-name");
- componentDb.insertProjectAndSnapshot(project);
- componentDb.insertComponent(newProjectCopy("project-copy-uuid", project, view));
- componentDb.indexAllComponents();
- ComponentTreeQuery query = newTreeQuery(A_VIEW_UUID).build();
-
- List<ComponentDto> components = underTest.selectChildren(dbSession, query);
- assertThat(components).extracting("uuid").containsOnly("project-copy-uuid", "subview-uuid");
- }
-
- @Test
- public void selectChildren_of_a_view_and_filter_by_name() {
+ public void select_descendants_of_a_view_and_filter_by_name() {
ComponentDto view = newView(A_VIEW_UUID);
componentDb.insertViewAndSnapshot(view);
// one subview
@@ -994,113 +983,15 @@ public class ComponentDaoTest {
componentDb.insertProjectAndSnapshot(project);
componentDb.insertComponent(newProjectCopy("project-copy-uuid", project, view));
componentDb.indexAllComponents();
- ComponentTreeQuery dbQuery = newTreeQuery(A_VIEW_UUID).setNameOrKeyQuery("name").build();
+ ComponentTreeQuery dbQuery = newTreeQuery(A_VIEW_UUID).setNameOrKeyQuery("name").setStrategy(CHILDREN).build();
- List<ComponentDto> components = underTest.selectChildren(dbSession, dbQuery);
+ List<ComponentDto> components = underTest.selectDescendants(dbSession, dbQuery);
assertThat(components).extracting("uuid").containsOnly("project-copy-uuid", "subview-uuid");
}
- @Test
- public void selectParent() {
- // project -> module -> file
- ComponentDto project = newProjectDto(PROJECT_UUID);
- componentDb.insertProjectAndSnapshot(project);
- ComponentDto module = newModuleDto(MODULE_UUID, project);
- componentDb.insertComponent(module);
- ComponentDto file = newFileDto(module, null, FILE_1_UUID);
- componentDb.insertComponent(file);
- db.commit();
-
- assertThat(underTest.selectParent(dbSession, project)).isAbsent();
- assertThat(underTest.selectParent(dbSession, module).get().uuid()).isEqualTo(PROJECT_UUID);
- assertThat(underTest.selectParent(dbSession, file).get().uuid()).isEqualTo(MODULE_UUID);
- }
-
- @Test
- public void selectAncestors() {
- // project -> module -> file
- ComponentDto project = newProjectDto(PROJECT_UUID);
- componentDb.insertProjectAndSnapshot(project);
- ComponentDto module = newModuleDto(MODULE_UUID, project);
- componentDb.insertComponent(module);
- ComponentDto file = newFileDto(module, null, FILE_1_UUID);
- componentDb.insertComponent(file);
- db.commit();
-
- // ancestors of root
- List<ComponentDto> ancestors = underTest.selectAncestors(dbSession, project);
- assertThat(ancestors).isEmpty();
-
- // ancestors of module
- ancestors = underTest.selectAncestors(dbSession, module);
- assertThat(ancestors).extracting("uuid").containsExactly(PROJECT_UUID);
-
- // ancestors of file
- ancestors = underTest.selectAncestors(dbSession, file);
- assertThat(ancestors).extracting("uuid").containsExactly(PROJECT_UUID, MODULE_UUID);
- }
-
- @Test
- public void selectDescendants() {
- ComponentDto project = newProjectDto(PROJECT_UUID);
- componentDb.insertProjectAndSnapshot(project);
- componentDb.insertComponent(newModuleDto("module-1-uuid", project));
- componentDb.insertComponent(newFileDto(project, null, "file-1-uuid"));
- componentDb.insertComponent(newFileDto(project, null, "file-2-uuid"));
- db.commit();
- componentDb.indexAllComponents();
-
- ComponentTreeQuery query = newTreeQuery(PROJECT_UUID).build();
-
- List<ComponentDto> result = underTest.selectDescendants(dbSession, query);
- assertThat(result).extracting("uuid").containsExactly("file-1-uuid", "file-2-uuid", "module-1-uuid");
- int count = underTest.countDescendants(dbSession, query);
- assertThat(count).isEqualTo(3);
- }
-
- @Test
- public void selectDescendants_returns_empty_list_if_base_component_does_not_exist() {
- ComponentTreeQuery query = newTreeQuery(PROJECT_UUID).build();
-
- List<ComponentDto> result = underTest.selectDescendants(dbSession, query);
- assertThat(result).isEmpty();
- }
-
- @Test
- public void selectDescendants_of_a_project_paginated_and_ordered() {
- ComponentDto project = newProjectDto(PROJECT_UUID).setKey("project-key");
- componentDb.insertProjectAndSnapshot(project);
- componentDb.insertComponent(newModuleDto("module-1-uuid", project));
- componentDb.insertComponent(newFileDto(project, null, "file-uuid-1").setName("file-name-1"));
- componentDb.insertComponent(newFileDto(project, null, "another-uuid"));
- for (int i = 2; i <= 9; i++) {
- componentDb.insertComponent(newFileDto(project, null, "file-uuid-" + i).setName("file-name-" + i));
- }
- db.commit();
- componentDb.indexAllComponents();
-
- ComponentTreeQuery query = newTreeQuery(PROJECT_UUID)
- .setQualifiers(newArrayList(Qualifiers.FILE))
- .setPage(2)
- .setPageSize(3)
- .setNameOrKeyQuery("file-name")
- .setSortFields(singletonList("name"))
- .setAsc(false)
- .build();
-
- List<ComponentDto> result = underTest.selectDescendants(dbSession, query);
- int count = underTest.countDescendants(dbSession, query);
-
- assertThat(count).isEqualTo(9);
- assertThat(result).extracting("uuid").containsExactly("file-uuid-6", "file-uuid-5", "file-uuid-4");
- }
-
private static ComponentTreeQuery.Builder newTreeQuery(String baseUuid) {
return ComponentTreeQuery.builder()
- .setPage(1)
- .setPageSize(500)
.setBaseUuid(baseUuid)
- .setSortFields(singletonList("name"))
- .setAsc(true);
+ .setStrategy(CHILDREN);
}
}