001/*
002 * Copyright 2020 Global Biodiversity Information Facility (GBIF)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.gbif.api.model.common.search;
017
018import io.swagger.v3.oas.annotations.Hidden;
019import io.swagger.v3.oas.annotations.Parameter;
020import io.swagger.v3.oas.annotations.enums.Explode;
021import io.swagger.v3.oas.annotations.enums.ParameterIn;
022import io.swagger.v3.oas.annotations.media.ArraySchema;
023import io.swagger.v3.oas.annotations.media.Schema;
024
025import org.gbif.api.model.common.paging.Pageable;
026import org.gbif.api.model.common.paging.PagingRequest;
027
028import java.lang.annotation.Inherited;
029import java.lang.annotation.Retention;
030import java.lang.annotation.RetentionPolicy;
031import java.lang.annotation.Target;
032import java.util.Arrays;
033import java.util.HashMap;
034import java.util.HashSet;
035import java.util.Map;
036import java.util.Set;
037
038import static java.lang.annotation.ElementType.METHOD;
039
040/**
041 * Generic request class for search operations requesting facets.
042 * It extends a search request with a list of desired facets and optional settings.
043 */
044@SuppressWarnings("unused")
045public class FacetedSearchRequest<P extends SearchParameter> extends SearchRequest<P> {
046
047  @Hidden
048  private Set<P> facets = new HashSet<>();
049
050  @Hidden
051  private boolean facetMultiSelect;
052
053  @Hidden
054  private Integer facetMinCount;
055
056  @Hidden
057  private Integer facetLimit = 10;
058
059  @Hidden
060  private Integer facetOffset;
061
062  //Holds the paging configuration for each requested facet
063  @Hidden
064  private Map<P, Pageable> facetPages = new HashMap<>();
065
066  /**
067   * Annotation to document the facet query parameters.
068   */
069  @Target({METHOD})
070  @Retention(RetentionPolicy.RUNTIME)
071  @Inherited
072  @io.swagger.v3.oas.annotations.Parameters(
073    value = {
074      @Parameter(
075        name = "facet",
076        description = "A facet name used to retrieve the most frequent values for a field. This parameter may be " +
077          "repeated to request multiple facets.",
078        array = @ArraySchema(schema = @Schema(implementation = String.class)),
079        in = ParameterIn.QUERY,
080        explode = Explode.TRUE),
081      @Parameter(
082        name = "facetMinCount",
083        description =
084          "Used in combination with the facet parameter. Set `facetMinCount={#}` to exclude facets with a count less than `{#}`.",
085        schema = @Schema(implementation = Integer.class),
086        in = ParameterIn.QUERY),
087      @Parameter(
088        name = "facetMultiselect",
089        description =
090          "Used in combination with the facet parameter. Set `facetMultiselect=true` to still return counts for values that are not currently filtered.",
091        schema = @Schema(implementation = Boolean.class),
092        in = ParameterIn.QUERY),
093      @Parameter(
094        name = "facetLimit",
095        description =
096          "Facet parameters allow paging requests using the parameters facetOffset and facetLimit",
097        schema = @Schema(implementation = Integer.class),
098        in = ParameterIn.QUERY),
099      @Parameter(
100        name = "facetOffset",
101        description =
102          "Facet parameters allow paging requests using the parameters facetOffset and facetLimit",
103        schema = @Schema(implementation = Integer.class, minimum = "0"),
104        in = ParameterIn.QUERY)
105    }
106  )
107  public @interface FacetParameters {}
108
109  public FacetedSearchRequest() {
110  }
111
112  public FacetedSearchRequest(Pageable page) {
113    super(page);
114  }
115
116  public FacetedSearchRequest(SearchRequest<P> searchRequest) {
117    super(searchRequest);
118    setHighlight(searchRequest.isHighlight());
119    setParameters(searchRequest.getParameters());
120    setQ(searchRequest.getQ());
121  }
122
123  public FacetedSearchRequest(long offset, int limit) {
124    super(offset, limit);
125  }
126
127  /**
128   * Min count of facet to return, if the facet count is less than this number the facet won't be included.
129   */
130  public Integer getFacetMinCount() {
131    return facetMinCount;
132  }
133
134  public void setFacetMinCount(Integer facetMinCount) {
135    this.facetMinCount = facetMinCount;
136  }
137
138  /**
139   * Gets the list of requested facets by the search operation.
140   * The facets are a list of search parameters.
141   */
142  public Set<P> getFacets() {
143    return facets;
144  }
145
146  /**
147   * Sets the list of facets.
148   */
149  public void setFacets(Set<P> facets) {
150    this.facets = facets;
151  }
152
153  /**
154   * @return the facetMultiSelect
155   */
156  public boolean isFacetMultiSelect() {
157    return facetMultiSelect;
158  }
159
160  /**
161   * @param facetMultiSelect the facetMultiSelect to set
162   */
163  public void setFacetMultiSelect(boolean facetMultiSelect) {
164    this.facetMultiSelect = facetMultiSelect;
165  }
166
167  /**
168   * Page size of the facet request.
169   */
170  public Integer getFacetLimit() {
171    return facetLimit;
172  }
173
174  public void setFacetLimit(Integer facetLimit) {
175    this.facetLimit = facetLimit;
176  }
177
178  /**
179   * Holds the paging configuration for each requested facet.
180   */
181  public Map<P, Pageable> getFacetPages() {
182    return facetPages;
183  }
184
185  public void setFacetPages(Map<P, Pageable> facetPages) {
186    this.facetPages = facetPages;
187  }
188
189  /**
190   * Sets the paging setting of facet parameter.
191   */
192  public void addFacetPage(P parameter, int facetOffset, int facetLimit){
193    facetPages.put(parameter, new PagingRequest(facetOffset,facetLimit));
194  }
195
196  /**
197   * Gets the paging configuration of a facet parameter.
198   */
199  public Pageable getFacetPage(P parameter) {
200    return facetPages.get(parameter);
201  }
202
203  /**
204   * Offset of the facet request.
205   */
206  public Integer getFacetOffset() {
207    return facetOffset;
208  }
209
210  public void setFacetOffset(Integer facetOffset) {
211    this.facetOffset = facetOffset;
212  }
213
214  public void addFacets(P... facets) {
215    if (this.facets == null) {
216      this.facets = new HashSet<>(Arrays.asList(facets));
217    } else {
218      this.facets.addAll(new HashSet<>(Arrays.asList(facets)));
219    }
220  }
221}