001package com.box.sdk;
002
003import static java.util.stream.Collectors.toList;
004
005import com.eclipsesource.json.Json;
006import com.eclipsesource.json.JsonArray;
007import com.eclipsesource.json.JsonObject;
008import com.eclipsesource.json.JsonValue;
009import java.util.ArrayList;
010import java.util.Arrays;
011import java.util.List;
012
013/** Represents Metadata Query. */
014public class MetadataQuery {
015  static final String FROM = "from";
016  static final String LIMIT = "limit";
017  static final String QUERY = "query";
018  static final String ANCESTOR_FOLDER_ID = "ancestor_folder_id";
019  static final String MARKER = "marker";
020  static final String ORDER_BY = "order_by";
021  static final String FIELDS = "fields";
022  static final String QUERY_PARAMS = "query_params";
023  private final String from;
024  private final int limit;
025  private String query;
026  private JsonObject queryParameters = new JsonObject();
027  private String ancestorFolderId = "0";
028  private List<OrderBy> orderBy = new ArrayList<>();
029  private String marker;
030  private List<String> fields = new ArrayList<>();
031
032  /**
033   * Creates Metadata Query
034   *
035   * @param from The template used in the query. Must be in the form scope_enterpriseID.templateKey
036   * @param limit Max results to return for a single request (0-100 inclusive)
037   */
038  public MetadataQuery(String from, int limit) {
039    this.from = from;
040    this.limit = limit;
041  }
042
043  /**
044   * Creates Metadata Query
045   *
046   * @param from The template used in the query. Must be in the form scope.templateKey
047   */
048  public MetadataQuery(String from) {
049    this(from, 100);
050  }
051
052  /**
053   * The logical expression of the query
054   *
055   * @param query Query string
056   * @return Returns current MetadataQuery object
057   */
058  public MetadataQuery setQuery(String query) {
059    this.query = query;
060    return this;
061  }
062
063  /**
064   * Sets the folder_id to which to restrain the query. If not set query starts at root level.
065   *
066   * @param ancestorFolderId The folder id
067   * @return Returns current MetadataQuery object
068   */
069  public MetadataQuery setAncestorFolderId(String ancestorFolderId) {
070    this.ancestorFolderId = ancestorFolderId;
071    return this;
072  }
073
074  /**
075   * The marker to use for requesting the next page
076   *
077   * @param marker Marker string.
078   * @return Returns current MetadataQuery object
079   */
080  public MetadataQuery setMarker(String marker) {
081    this.marker = marker;
082    return this;
083  }
084
085  /**
086   * The field_key(s) to order on and the corresponding direction(s)
087   *
088   * @param fields Fields with sort order
089   * @return Returns current MetadataQuery object
090   */
091  public MetadataQuery setOrderBy(OrderBy... fields) {
092    this.orderBy = new ArrayList<>();
093    this.orderBy.addAll(Arrays.asList(fields));
094    return this;
095  }
096
097  MetadataQuery setOrderBy(JsonArray orderBy) {
098    if (orderBy != null) {
099      this.orderBy = orderBy.values().stream().map(OrderBy::fromJson).collect(toList());
100    }
101    return this;
102  }
103
104  /**
105   * The fields to retrieve.
106   *
107   * @param fields Field names
108   * @return Returns current MetadataQuery object
109   */
110  public MetadataQuery setFields(String... fields) {
111    this.fields = new ArrayList<>();
112    this.fields.addAll(Arrays.asList(fields));
113    return this;
114  }
115
116  /**
117   * Adds parameter to query
118   *
119   * @param name Parameter name
120   * @param value Parameter value
121   * @return Returns current MetadataQuery object
122   */
123  public MetadataQuery addParameter(String name, String value) {
124    this.queryParameters.add(name, value);
125    return this;
126  }
127
128  /**
129   * Adds parameter to query
130   *
131   * @param name Parameter name
132   * @param value Parameter value
133   * @return Returns current MetadataQuery object
134   */
135  public MetadataQuery addParameter(String name, int value) {
136    this.queryParameters.add(name, value);
137    return this;
138  }
139
140  /**
141   * Adds parameter to query
142   *
143   * @param name Parameter name
144   * @param value Parameter value
145   * @return Returns current MetadataQuery object
146   */
147  public MetadataQuery addParameter(String name, boolean value) {
148    this.queryParameters.add(name, value);
149    return this;
150  }
151
152  /**
153   * Adds parameter to query
154   *
155   * @param name Parameter name
156   * @param value Parameter value
157   * @return Returns current MetadataQuery object
158   */
159  public MetadataQuery addParameter(String name, float value) {
160    this.queryParameters.add(name, value);
161    return this;
162  }
163
164  /**
165   * Adds parameter to query
166   *
167   * @param name Parameter name
168   * @param value Parameter value
169   * @return Returns current MetadataQuery object
170   */
171  public MetadataQuery addParameter(String name, long value) {
172    this.queryParameters.add(name, value);
173    return this;
174  }
175
176  /**
177   * Adds parameter to query
178   *
179   * @param name Parameter name
180   * @param value Parameter value
181   * @return Returns current MetadataQuery object
182   */
183  public MetadataQuery addParameter(String name, double value) {
184    this.queryParameters.add(name, value);
185    return this;
186  }
187
188  /**
189   * Adds parameter to query
190   *
191   * @param name Parameter name
192   * @param value Parameter value
193   * @return Returns current MetadataQuery object
194   */
195  public MetadataQuery addParameter(String name, JsonValue value) {
196    this.queryParameters.add(name, Json.parse(value.toString()));
197    return this;
198  }
199
200  MetadataQuery setQueryParams(JsonObject queryParameters) {
201    this.queryParameters = new JsonObject(queryParameters);
202    return this;
203  }
204
205  JsonObject toJsonObject() {
206    JsonObject jsonObject = new JsonObject().add(FROM, from).add(LIMIT, limit);
207    if (query != null) {
208      jsonObject.add(QUERY, query);
209    }
210    if (ancestorFolderId != null) {
211      jsonObject.add(ANCESTOR_FOLDER_ID, ancestorFolderId);
212    }
213    if (marker != null) {
214      jsonObject.add(MARKER, marker);
215    }
216    if (!orderBy.isEmpty()) {
217      JsonArray orderByJson = new JsonArray();
218      orderBy.stream().map(OrderBy::toJsonObject).forEach(orderByJson::add);
219      jsonObject.add(ORDER_BY, orderByJson);
220    }
221    if (!fields.isEmpty()) {
222      JsonArray fieldsJson = new JsonArray();
223      fields.forEach(fieldsJson::add);
224      jsonObject.add(FIELDS, fieldsJson);
225    }
226    if (queryParameters.iterator().hasNext()) {
227      jsonObject.add(QUERY_PARAMS, new JsonObject(queryParameters));
228    }
229    return jsonObject;
230  }
231
232  int getLimit() {
233    return limit;
234  }
235
236  String getMarker() {
237    return marker;
238  }
239
240  public static final class OrderBy {
241
242    static final String FIELD_KEY = "field_key";
243    static final String DIRECTION = "direction";
244    static final String DIRECTION_ASCENDING = "asc";
245    static final String DIRECTION_DESCENDING = "desc";
246    private final String fieldName;
247    private final String direction;
248
249    private OrderBy(String fieldName, String direction) {
250      this.fieldName = fieldName;
251      this.direction = direction;
252    }
253
254    JsonObject toJsonObject() {
255      return new JsonObject().add(FIELD_KEY, fieldName).add(DIRECTION, direction);
256    }
257
258    /**
259     * Creates OrderBy for ascending sort with a specified field.
260     *
261     * @param fieldName Name of a field
262     * @return OrderBy instance
263     */
264    public static OrderBy ascending(String fieldName) {
265      return new OrderBy(fieldName, DIRECTION_ASCENDING);
266    }
267
268    /**
269     * Creates OrderBy for descending sort with a specified field.
270     *
271     * @param fieldName Name of a field
272     * @return OrderBy instance
273     */
274    public static OrderBy descending(String fieldName) {
275      return new OrderBy(fieldName, DIRECTION_DESCENDING);
276    }
277
278    static OrderBy fromJson(JsonValue jsonValue) {
279      if (jsonValue.isObject()) {
280        JsonObject object = jsonValue.asObject();
281        String fieldName = object.get(FIELD_KEY).asString();
282        String direction = object.get(DIRECTION).asString().toLowerCase(java.util.Locale.ROOT);
283        if (!DIRECTION_ASCENDING.equals(direction) && !DIRECTION_DESCENDING.equals(direction)) {
284          throw new RuntimeException(
285              String.format(
286                  "Unsupported sort direction [%s] for field [%s]", direction, fieldName));
287        }
288        return object.getString(DIRECTION, "").equals(DIRECTION_ASCENDING)
289            ? ascending(fieldName)
290            : descending(fieldName);
291      }
292      throw new RuntimeException("Unsupported json " + jsonValue);
293    }
294  }
295}