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