]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5718 Add possibility to select wanted facets in result
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Mon, 27 Oct 2014 16:04:18 +0000 (17:04 +0100)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Mon, 27 Oct 2014 16:38:34 +0000 (17:38 +0100)
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java
server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/search/QueryContext.java
server/sonar-server/src/main/java/org/sonar/server/search/ws/SearchRequestHandler.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/search/QueryContextTest.java

index 6628c3a3a28f1a52127dba925540df5f59dbfd75..825ad80f0a2397e3ca093c97ffaee2e204436110 100644 (file)
@@ -303,19 +303,37 @@ public class IssueIndex extends BaseIndex<Issue, IssueDto, String> {
   private void setFacets(IssueQuery query, QueryContext options, Map<String, FilterBuilder> filters, QueryBuilder esQuery, SearchRequestBuilder esSearch) {
     if (options.isFacet()) {
       // Execute Term aggregations
-      esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.SEVERITY.field(), IssueFilterParameters.SEVERITIES));
-      esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.STATUS.field(), IssueFilterParameters.STATUSES));
-      esSearch.addAggregation(getResolutionFacet(query, options, filters, esQuery));
-      esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.ACTION_PLAN.field(), IssueFilterParameters.ACTION_PLANS));
-      esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.PROJECT.field(), IssueFilterParameters.COMPONENT_ROOTS,
-        query.componentRoots().toArray()));
-      esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.RULE_KEY.field(), IssueFilterParameters.RULES,
-        query.rules().toArray()));
-      esSearch.addAggregation(getAssigneesFacet(query, options, filters, esQuery));
-      esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.COMPONENT.field(), IssueFilterParameters.COMPONENTS,
-        query.components().toArray()));
-      esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.LANGUAGE.field(), IssueFilterParameters.LANGUAGES,
-        query.languages().toArray()));
+      if (options.facets().contains(IssueFilterParameters.SEVERITIES)) {
+        esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.SEVERITY.field(), IssueFilterParameters.SEVERITIES));
+      }
+      if (options.facets().contains(IssueFilterParameters.STATUSES)) {
+        esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.STATUS.field(), IssueFilterParameters.STATUSES));
+      }
+      if (options.facets().contains(IssueFilterParameters.RESOLUTIONS)) {
+        esSearch.addAggregation(getResolutionFacet(query, options, filters, esQuery));
+      }
+      if (options.facets().contains(IssueFilterParameters.ACTION_PLANS)) {
+        esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.ACTION_PLAN.field(), IssueFilterParameters.ACTION_PLANS));
+      }
+      if (options.facets().contains(IssueFilterParameters.COMPONENT_ROOTS)) {
+        esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.PROJECT.field(), IssueFilterParameters.COMPONENT_ROOTS,
+          query.componentRoots().toArray()));
+      }
+      if (options.facets().contains(IssueFilterParameters.RULES)) {
+        esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.RULE_KEY.field(), IssueFilterParameters.RULES,
+          query.rules().toArray()));
+      }
+      if (options.facets().contains(IssueFilterParameters.ASSIGNEES)) {
+        esSearch.addAggregation(getAssigneesFacet(query, options, filters, esQuery));
+      }
+      if (options.facets().contains(IssueFilterParameters.COMPONENTS)) {
+        esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.COMPONENT.field(), IssueFilterParameters.COMPONENTS,
+          query.components().toArray()));
+      }
+      if (options.facets().contains(IssueFilterParameters.LANGUAGES)) {
+        esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.LANGUAGE.field(), IssueFilterParameters.LANGUAGES,
+          query.languages().toArray()));
+      }
     }
   }
 
index 0a4bc20d5bbd9493c4c7cb653bc5aea75d09d59b..c4c70a0b5f1a65fbbabbcffd5ab9e45e6e3b284a 100644 (file)
@@ -210,6 +210,22 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
     return Collections.emptyList();
   }
 
+  @Override
+  @CheckForNull
+  protected Collection<String> possibleFacets() {
+    return Arrays.asList(new String[]{
+      IssueFilterParameters.SEVERITIES,
+      IssueFilterParameters.STATUSES,
+      IssueFilterParameters.RESOLUTIONS,
+      IssueFilterParameters.ACTION_PLANS,
+      IssueFilterParameters.COMPONENT_ROOTS,
+      IssueFilterParameters.RULES,
+      IssueFilterParameters.ASSIGNEES,
+      IssueFilterParameters.COMPONENTS,
+      IssueFilterParameters.LANGUAGES
+    });
+  }
+
   @Override
   protected void doContextResponse(Request request, QueryContext context, Result<Issue> result, JsonWriter json) {
     List<String> issueKeys = newArrayList();
index b1d4c86cd7166342c915d86eb47ea6ece17a2e04..5055fb07b75d6032d6f494d6c01df884be831d22 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.rule.index;
 import com.google.common.base.Preconditions;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
 import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.search.SearchScrollRequestBuilder;
@@ -341,6 +342,7 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
     Map<String, FilterBuilder> filters = this.getFilters(query, options);
 
     if (options.isFacet()) {
+      Logger.getLogger(this.getClass()).info("Facets = " + options.facets());
       for (AggregationBuilder aggregation : getFacets(qb, filters).values()) {
         esSearch.addAggregation(aggregation);
       }
index 9f22915bbc699b1b2f322935cdab0182a6b30b51..8458fc7c159790c9cfe2d4d2ea21b89b041507b9 100644 (file)
@@ -38,6 +38,7 @@ import org.sonar.server.search.QueryContext;
 import org.sonar.server.search.Result;
 import org.sonar.server.search.ws.SearchOptions;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Map;
 
@@ -213,7 +214,9 @@ public class SearchAction implements RequestHandler {
     RuleQuery query = createRuleQuery(ruleService.newRuleQuery(), request);
     SearchOptions searchOptions = SearchOptions.create(request);
     QueryContext queryContext = mapping.newQueryOptions(searchOptions);
-    queryContext.setFacet(request.mandatoryParamAsBoolean(PARAM_FACETS));
+    if (Boolean.valueOf(request.paramAsBoolean("facets"))) {
+      queryContext.addFacets(Arrays.asList("languages", "repositories", "tags"));
+    }
 
     Result<Rule> results = ruleService.search(query, queryContext);
 
index 87901423b03d11a6e4a4868964f9e3583b1084f8..1364e6950d8ba68ad0f421a659ddde22c818b96e 100644 (file)
@@ -44,7 +44,7 @@ public class QueryContext {
 
   private int offset = DEFAULT_OFFSET;
   private int limit = DEFAULT_LIMIT;
-  private boolean facet = DEFAULT_FACET;
+  private Set<String> facets = newHashSet();
   private Set<String> fieldsToReturn = newHashSet();
   private boolean scroll = false;
   private boolean showFullResult = false;
@@ -57,20 +57,27 @@ public class QueryContext {
   }
 
   /**
-   * Whether or not the search returns facets for the domain. Defaults to {@link #DEFAULT_OFFSET}
+   * Whether or not the search returns facets for the domain. Defaults to {@link #DEFAULT_FACET}
    */
   public boolean isFacet() {
-    return facet;
+    return !facets.isEmpty();
   }
 
   /**
-   * Sets whether or not the search returns facets for the domain.
+   * Selects facets to return for the domain.
    */
-  public QueryContext setFacet(boolean facet) {
-    this.facet = facet;
+  public QueryContext addFacets(Collection<String> facets) {
+    this.facets.addAll(facets);
     return this;
   }
 
+  /**
+   * Lists selected facets.
+   */
+  public Collection<String> facets() {
+    return facets;
+  }
+
   /**
    * Whether or not the search result will be scrollable using an iterator
    */
index 50d936d265acf91e571d1af1475bc73eabff8ae3..223ebedf203852359c42113bde82c7cb5976f0ee 100644 (file)
@@ -32,6 +32,7 @@ import javax.annotation.CheckForNull;
 
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 public abstract class SearchRequestHandler<QUERY, DOMAIN> implements RequestHandler {
@@ -61,6 +62,9 @@ public abstract class SearchRequestHandler<QUERY, DOMAIN> implements RequestHand
   @CheckForNull
   protected abstract Collection<String> possibleFields();
 
+  @CheckForNull
+  protected abstract Collection<String> possibleFacets();
+
   public final void define(WebService.NewController controller) {
     WebService.NewAction action = controller.createAction(this.actionName)
       .setHandler(this);
@@ -79,10 +83,14 @@ public abstract class SearchRequestHandler<QUERY, DOMAIN> implements RequestHand
       .setExampleValue("20")
       .setDefaultValue("100");
 
-    action.createParam(PARAM_FACETS)
-      .setDescription("Compute predefined facets")
-      .setBooleanPossibleValues()
-      .setDefaultValue("false");
+    Collection<String> possibleFacets = possibleFacets();
+    WebService.NewParam paramFacets = action.createParam(PARAM_FACETS)
+      .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.")
+      .setPossibleValues(possibleFacets);
+    if (possibleFacets != null && possibleFacets.size() > 1) {
+      Iterator<String> it = possibleFacets.iterator();
+      paramFacets.setExampleValue(String.format("%s,%s", it.next(), it.next()));
+    }
 
     Collection<String> possibleFields = possibleFields();
     WebService.NewParam paramFields = action.createParam(PARAM_FIELDS)
@@ -113,8 +121,11 @@ public abstract class SearchRequestHandler<QUERY, DOMAIN> implements RequestHand
 
   private QueryContext getQueryContext(Request request) {
     int pageSize = request.mandatoryParamAsInt(PARAM_PAGE_SIZE);
-    QueryContext queryContext = new QueryContext().addFieldsToReturn(request.paramAsStrings(PARAM_FIELDS))
-      .setFacet(request.mandatoryParamAsBoolean(PARAM_FACETS));
+    QueryContext queryContext = new QueryContext().addFieldsToReturn(request.paramAsStrings(PARAM_FIELDS));
+    List<String> facets = request.paramAsStrings(PARAM_FACETS);
+    if(facets != null) {
+      queryContext.addFacets(facets);
+    }
     if (pageSize < 1) {
       queryContext.setPage(request.mandatoryParamAsInt(PARAM_PAGE), 0).setMaxLimit();
     } else {
index 9e2beb82ea5d68bae8fca887df799e5a64a7d911..2020691749006dbfe8593cdb7a07b5c03f71e72c 100644 (file)
@@ -56,6 +56,7 @@ import org.sonar.server.search.QueryContext;
 import org.sonar.server.tester.ServerTester;
 import org.sonar.server.user.MockUserSession;
 
+import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -140,8 +141,8 @@ public class IssueServiceMediumTest {
     assertThat(result.getHits()).hasSize(2);
     assertThat(result.getFacets()).isEmpty();
 
-    result = service.search(IssueQuery.builder().build(), new QueryContext().setFacet(true));
-    assertThat(result.getFacets().keySet()).hasSize(9);
+    result = service.search(IssueQuery.builder().build(), new QueryContext().addFacets(Arrays.asList("actionPlans", "assignees")));
+    assertThat(result.getFacets().keySet()).hasSize(2);
     assertThat(result.getFacetKeys("actionPlans")).hasSize(2);
     assertThat(result.getFacetKeys("assignees")).hasSize(1);
   }
index 13168957580afdaa87140f1b35bc8f6965a6689d..74c2988e1fd7e7b49987e6a0d2ab888f03aad71d 100644 (file)
@@ -345,7 +345,9 @@ public class SearchActionMediumTest {
     db.issueDao().insert(session, issue);
     session.commit();
 
-    WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).setParam(SearchAction.PARAM_FACETS, "true").execute();
+    WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(SearchAction.PARAM_FACETS, "statuses,severities,resolutions,componentRoots,rules,components,assignees,languages")
+      .execute();
     result.assertJson(this.getClass(), "display_facets.json", false);
   }
 
index 366dc93e070f0dd380940114e726633e4a9606b0..627314159fdb2a8b2e2cee745c59b4f8030cb8f1 100644 (file)
@@ -103,15 +103,15 @@ public class RuleIndexMediumTest extends SearchMediumTest {
 
     // should not have any facet!
     RuleQuery query = new RuleQuery();
-    Result result = index.search(query, new QueryContext().setFacet(false));
+    Result result = index.search(query, new QueryContext());
     assertThat(result.getFacets()).isEmpty();
 
     // should not have any facet on non matching query!
-    result = index.search(new RuleQuery().setQueryText("aeiou"), new QueryContext().setFacet(true));
+    result = index.search(new RuleQuery().setQueryText("aeiou"), new QueryContext().addFacets(Arrays.asList("repositories")));
     assertThat(result.getFacets()).isEmpty();
 
     // Repositories Facet is preset
-    result = index.search(query, new QueryContext().setFacet(true));
+    result = index.search(query, new QueryContext().addFacets(Arrays.asList("repositories", "tags")));
     assertThat(result.getFacets()).isNotNull();
     assertThat(result.getFacets()).hasSize(3);
 
@@ -967,7 +967,7 @@ public class RuleIndexMediumTest extends SearchMediumTest {
     assertThat(index.search(new RuleQuery(), new QueryContext()).getHits()).hasSize(9);
 
     // 1 Facet with no filters at all
-    Map<String, Collection<FacetValue>> facets = index.search(new RuleQuery(), new QueryContext().setFacet(true)).getFacets();
+    Map<String, Collection<FacetValue>> facets = index.search(new RuleQuery(), new QueryContext().addFacets(Arrays.asList("languages", "repositories", "tags"))).getFacets();
     assertThat(facets.keySet()).hasSize(3);
     assertThat(facets.get(RuleIndex.FACET_LANGUAGES)).onProperty("key").containsOnly("cpp", "java", "cobol");
     assertThat(facets.get(RuleIndex.FACET_REPOSITORIES)).onProperty("key").containsOnly("xoo", "foo");
@@ -977,7 +977,7 @@ public class RuleIndexMediumTest extends SearchMediumTest {
     // -- lang facet should still have all language
     Result<Rule> result = index.search(new RuleQuery()
       .setLanguages(ImmutableList.<String>of("cpp"))
-      , new QueryContext().setFacet(true));
+      , new QueryContext().addFacets(Arrays.asList("languages", "repositories", "tags")));
     assertThat(result.getHits()).hasSize(3);
     assertThat(result.getFacets()).hasSize(3);
     assertThat(result.getFacets().get(RuleIndex.FACET_LANGUAGES)).onProperty("key").containsOnly("cpp", "java", "cobol");
@@ -989,7 +989,7 @@ public class RuleIndexMediumTest extends SearchMediumTest {
     result = index.search(new RuleQuery()
       .setLanguages(ImmutableList.<String>of("cpp"))
       .setTags(ImmutableList.<String>of("T2"))
-      , new QueryContext().setFacet(true));
+      , new QueryContext().addFacets(Arrays.asList("languages", "repositories", "tags")));
     assertThat(result.getHits()).hasSize(1);
     assertThat(result.getFacets().keySet()).hasSize(3);
     assertThat(result.getFacets().get(RuleIndex.FACET_LANGUAGES)).onProperty("key").containsOnly("cpp", "java");
@@ -1003,7 +1003,7 @@ public class RuleIndexMediumTest extends SearchMediumTest {
     result = index.search(new RuleQuery()
       .setLanguages(ImmutableList.<String>of("cpp", "java"))
       .setTags(ImmutableList.<String>of("T2"))
-      , new QueryContext().setFacet(true));
+      , new QueryContext().addFacets(Arrays.asList("languages", "repositories", "tags")));
     assertThat(result.getHits()).hasSize(2);
     assertThat(result.getFacets().keySet()).hasSize(3);
     assertThat(result.getFacets().get(RuleIndex.FACET_LANGUAGES)).onProperty("key").containsOnly("cpp", "java");
index 2015329e9899e3d70d89284d63cf4540318bda76..2ac3cdfa51c858b18cc55df4531bc8fb4636a9d3 100644 (file)
@@ -142,7 +142,7 @@ public class QueryContextTest {
   public void do_not_request_facets_by_default() throws Exception {
     assertThat(options.isFacet()).isFalse();
 
-    options.setFacet(true);
+    options.addFacets(Arrays.asList("polop"));
     assertThat(options.isFacet()).isTrue();
   }
 }