All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.leancloud.AVQuery Maven / Gradle / Ivy

package cn.leancloud;

import cn.leancloud.cache.QueryResultCache;
import cn.leancloud.core.PaasClient;
import cn.leancloud.query.AVCloudQueryResult;
import cn.leancloud.query.QueryConditions;
import cn.leancloud.query.QueryOperation;
import cn.leancloud.types.AVGeoPoint;
import cn.leancloud.types.AVNull;
import cn.leancloud.utils.AVUtils;
import cn.leancloud.utils.LogUtil;
import cn.leancloud.utils.StringUtil;

import java.util.*;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Function;

public class AVQuery implements Cloneable {
  private static final AVLogger LOGGER = LogUtil.getLogger(AVQuery.class);

  public enum CachePolicy {
    CACHE_ELSE_NETWORK, CACHE_ONLY, CACHE_THEN_NETWORK, IGNORE_CACHE, NETWORK_ELSE_CACHE,
    NETWORK_ONLY;
  }

  private Class clazz;
  private String className;
  private java.lang.Boolean isRunning;
  private CachePolicy cachePolicy = CachePolicy.IGNORE_CACHE;
  private long maxCacheAge = -1;

  QueryConditions conditions;

  /**
   * Constructs a query. A default query with no further parameters will retrieve all AVObjects of
   * the provided class.
   *
   * @param theClassName The name of the class to retrieve AVObjects for.
   */
  public AVQuery(String theClassName) {
    this(theClassName, null);
  }

  /**
   * Clone a new query object, which fully same to this.
   *
   * @return a new AVQuery object.
   */
  public AVQuery clone() throws CloneNotSupportedException {
    AVQuery query = (AVQuery) super.clone();

    query.isRunning = false;
    query.cachePolicy = this.cachePolicy;
    query.maxCacheAge = this.maxCacheAge;
    query.conditions = null != this.conditions? this.conditions.clone(): null;
    return query;
  }

  AVQuery(String theClassName, Class clazz) {
    Transformer.checkClassName(theClassName);
    this.className = theClassName;
    this.clazz = clazz;
    this.conditions = new QueryConditions();
  }

  /**
   * Constructs a query. A default query with no further parameters will retrieve all AVObjects of
   * the provided class.
   *
   * @param theClassName The name of the class to retrieve AVObjects for.
   * @param  template type.
   * @return the query object.
   */
  public static  AVQuery getQuery(String theClassName) {
    return new AVQuery(theClassName);
  }

  /**
   * Create a AVQuery with special sub-class.
   *
   * @param clazz The AVObject subclass
   * @param  template type.
   * @return The AVQuery
   */
  public static  AVQuery getQuery(Class clazz) {
    return new AVQuery(Transformer.getSubClassName(clazz), clazz);
  }

  Class getClazz() {
    return clazz;
  }

  void setClazz(Class clazz) {
    this.clazz = clazz;
  }

  List getInclude() {
    return conditions.getInclude();
  }

  void setInclude(List include) {
    conditions.setInclude(include);
  }

  Set getSelectedKeys() {
    return conditions.getSelectedKeys();
  }

  void setSelectedKeys(Set selectedKeys) {
    conditions.setSelectedKeys(selectedKeys);
  }

  Map getParameters() {
    return conditions.getParameters();
  }

  void setParameters(Map parameters) {
    conditions.setParameters(parameters);
  }

  Map> getWhere() {
    return conditions.getWhere();
  }

  /**
   * Get class name
   * @return class name.
   */
  public String getClassName() {
    return className;
  }

  /**
   * Set class name
   * @param className class name.
   * @return current instance.
   */
  public AVQuery setClassName(String className) {
    this.className = className;
    return this;
  }

  /**
   * Accessor for the caching policy.
   * @return cache policy
   */
  public CachePolicy getCachePolicy() {
    return cachePolicy;
  }

  /**
   * Change the caching policy of this query.
   *
   * @param cachePolicy  cache policy.
   * @return this query.
   */
  public AVQuery setCachePolicy(CachePolicy cachePolicy) {
    this.cachePolicy = cachePolicy;
    return this;
  }

  /**
   * Get cache policy.
   * @return cache policy.
   */
  public CachePolicy getPolicy() {
    return cachePolicy;
  }

  /**
   * Change the caching policy of this query.
   *
   * @param policy cache policy.
   * @return this query.
   */
  public AVQuery setPolicy(CachePolicy policy) {
    this.cachePolicy = policy;
    return this;
  }

  /**
   * Gets the maximum age of cached data that will be considered in this query. The returned value
   * is in milliseconds
   * @return max cache age(milliseconds).
   */
  public long getMaxCacheAge() {
    return maxCacheAge;
  }

  /**
   * Sets the maximum age of cached data that will be considered in this query.
   *
   * @param maxCacheAge  mac cached age.
   * @return this query.
   */
  public AVQuery setMaxCacheAge(long maxCacheAge) {
    this.maxCacheAge = maxCacheAge;
    return this;
  }

  /**
   * Clears the cached result for all queries.
   */
  public static void clearAllCachedResults() {
    QueryResultCache.getInstance().clearAllCachedFiles();
  }

  /**
   * Removes the previously cached result for this query, forcing the next find() to hit the
   * network. If there is no cached result for this query, then this is a no-op.
   */
  public void clearCachedResult() {
    Map query = assembleParameters();
    String cacheKey = QueryResultCache.generateKeyForQueryCondition(getClassName(), query);
    QueryResultCache.getInstance().clearCachedFile(cacheKey);

    // clear result for getFirstInBackground().
    query.put("limit", "1");
    cacheKey = QueryResultCache.generateKeyForQueryCondition(getClassName(), query);
    QueryResultCache.getInstance().clearCachedFile(cacheKey);
  }

  /**
   * Accessor for the limit.
   * @return query limit.
   */
  public int getLimit() {
    return conditions.getLimit();
  }

  /**
   * Controls the maximum number of results that are returned. Setting a negative limit denotes
   * retrieval without a limit. The default limit is 100, with a maximum of 1000 results being
   * returned at a time.
   *
   * @param limit query limit.
   * @return this query.
   */
  public AVQuery setLimit(int limit) {
    conditions.setLimit(limit);
    return this;
  }

  /**
   * @see #setLimit(int)
   * @param limit query limit
   * @return this query.
   */
  public AVQuery limit(int limit) {
    this.setLimit(limit);
    return this;
  }

  /**
   * @see #setSkip(int)
   * @param skip qury skip
   * @return this query.
   */
  public AVQuery skip(int skip) {
    setSkip(skip);
    return this;
  }

  /**
   * Accessor for the skip value.
   * @return current skip value.
   */
  public int getSkip() {
    return conditions.getSkip();
  }

  /**
   * Controls the number of results to skip before returning any results. This is useful for
   * pagination. Default is to skip zero results.
   *
   * @param skip query skip.
   * @return this query
   */
  public AVQuery setSkip(int skip) {
    conditions.setSkip(skip);
    return this;
  }

  /**
   * Get order string.
   * @return order string.
   */
  public String getOrder() {
    return conditions.getOrder();
  }

  /**
   * Set query order fields.
   *
   * @param order order string.
   * @return this query.
   */
  public AVQuery setOrder(String order) {
    conditions.setOrder(order);
    return this;
  }

  /**
   * @see #setOrder(String)
   * @param order order string.
   * @return this query.
   */
  public AVQuery order(String order) {
    setOrder(order);
    return this;
  }

  /**
   * Also sorts the results in ascending order by the given key. The previous sort keys have
   * precedence over this key.
   *
   * @param key The key to order by
   * @return Returns the query so you can chain this call.
   */
  public AVQuery addAscendingOrder(String key) {
    conditions.addAscendingOrder(key);
    return this;
  }

  /**
   * Also sorts the results in descending order by the given key. The previous sort keys have
   * precedence over this key.
   *
   * @param key The key to order by
   * @return Returns the query so you can chain this call.
   */
  public AVQuery addDescendingOrder(String key) {
    conditions.addDescendingOrder(key);
    return this;
  }

  /**
   * Flag to indicate need ACL returned in result.
   * @return include flag.
   */
  public boolean isIncludeACL() {
    return conditions.isIncludeACL();
  }

  /**
   * set include ACL or not.
   * @param includeACL Flag to indicate need ACL returned in result.
   * @return this query.
   */
  public AVQuery includeACL(boolean includeACL) {
    conditions.includeACL(includeACL);
    return this;
  }

  /**
   * Include nested AVObjects for the provided key. You can use dot notation to specify which fields
   * in the included object that are also fetched.
   *
   * @param key The key that should be included.
   * @return this query.
   */
  public AVQuery include(String key) {
    conditions.include(key);
    return this;
  }

  /**
   * Restrict the fields of returned AVObjects to only include the provided keys. If this is called
   * multiple times, then all of the keys specified in each of the calls will be included.
   *
   * @param keys The set of keys to include in the result.
   * @return this query.
   */
  public AVQuery selectKeys(Collection keys) {
    conditions.selectKeys(keys);
    return this;
  }

  /**
   * Sorts the results in ascending order by the given key.
   *
   * @param key The key to order by.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery orderByAscending(String key) {
    conditions.orderByAscending(key);
    return this;
  }

  /**
   * Sorts the results in descending order by the given key.
   *
   * @param key The key to order by.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery orderByDescending(String key) {
    conditions.orderByDescending(key);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value to be contained in the
   * provided list of values.
   *
   * @param key The key to check.
   * @param values The values that will match.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereContainedIn(String key, Collection values) {
    conditions.whereContainedIn(key, values);
    return this;
  }

  /**
   * Add a constraint for finding string values that contain a provided string. This will be slow
   * for large datasets.
   *
   * @param key The key that the string to match is stored in.
   * @param substring The substring that the value must contain.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereContains(String key, String substring) {
    conditions.whereContains(key, substring);
    return this;
  }

  /**
   * 添加查询约束条件,查找key类型是数组,该数组的长度匹配提供的数值。
   *
   * @since 2.0.2
   * @param key 查询的key
   * @param size 数组的长度
   * @return this query.
   */
  public AVQuery whereSizeEqual(String key, int size) {
    conditions.whereSizeEqual(key, size);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value match another AVQuery.
   * This only works on keys whose values are AVObjects or lists of AVObjects. Add a constraint to
   * the query that requires a particular key's value to contain every one of the provided list of
   * values.
   *
   * @param key The key to check. This key's value must be an array.
   * @param values The values that will match.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereContainsAll(String key, Collection values) {
    conditions.whereContainsAll(key, values);
    return this;
  }

  /**
   * Add a constraint for finding objects that do not contain a given key.
   *
   * @param key The key that should not exist
   * @return this query.
   */
  public AVQuery whereDoesNotExist(String key) {
    conditions.whereDoesNotExist(key);
    return this;
  }



  /**
   * Add a constraint for finding string values that end with a provided string. This will be slow
   * for large datasets.
   *
   * @param key The key that the string to match is stored in.
   * @param suffix The substring that the value must end with.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereEndsWith(String key, String suffix) {
    conditions.whereEndsWith(key, suffix);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value to be equal to the
   * provided value.
   *
   * @param key The key to check.
   * @param value The value that the AVObject must contain.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereEqualTo(String key, Object value) {
    conditions.whereEqualTo(key, value);
    return this;
  }

  private AVQuery addOrItems(QueryOperation op) {
    conditions.addOrItems(op);
    return this;
  }

  private AVQuery addAndItems(AVQuery query) {
    conditions.addAndItems(query.conditions);
    return this;
  }

  protected AVQuery addWhereItem(String key, String op, Object value) {
    conditions.addWhereItem(key, op, value);
    return this;
  }

  /**
   * Add a constraint for finding objects that contain the given key.
   *
   * @param key The key that should exist.
   * @return this query.
   */
  public AVQuery whereExists(String key) {
    conditions.whereExists(key);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value to be greater than the
   * provided value.
   *w
   * @param key The key to check.
   * @param value The value that provides an lower bound.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereGreaterThan(String key, Object value) {
    conditions.whereGreaterThan(key, value);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value to be greater or equal to
   * than the provided value.
   *
   * @param key The key to check.
   * @param value The value that provides an lower bound.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereGreaterThanOrEqualTo(String key, Object value) {
    conditions.whereGreaterThanOrEqualTo(key, value);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value to be less than the
   * provided value.
   *
   * @param key The key to check.
   * @param value The value that provides an upper bound.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereLessThan(String key, Object value) {
    conditions.whereLessThan(key, value);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value to be less or equal to
   * than the provided value.
   *
   * @param key The key to check.
   * @param value The value that provides an lower bound.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereLessThanOrEqualTo(String key, Object value) {
    conditions.whereLessThanOrEqualTo(key, value);
    return this;
  }

  /**
   * Add a regular expression constraint for finding string values that match the provided regular
   * expression. This may be slow for large datasets.
   *
   * @param key The key that the string to match is stored in.
   * @param regex The regular expression pattern to match.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereMatches(String key, String regex) {
    conditions.whereMatches(key, regex);
    return this;
  }

  /**
   * Add a regular expression constraint for finding string values that match the provided regular
   * expression. This may be slow for large datasets.
   *
   * @param key The key that the string to match is stored in.
   * @param regex The regular expression pattern to match.
   * @param modifiers Any of the following supported PCRE modifiers: i - Case insensitive search m -
   *          Search across multiple lines of input
   * @return this query.
   */
  public AVQuery whereMatches(String key, String regex, String modifiers) {
    conditions.whereMatches(key, regex, modifiers);
    return this;
  }

  /**
   * Add a proximity based constraint for finding objects with key point values near the point
   * given.
   *
   * @param key The key that the AVGeoPoint is stored in.
   * @param point The reference AVGeoPoint that is used.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereNear(String key, AVGeoPoint point) {
    conditions.whereNear(key, point);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value not be contained in the
   * provided list of values.
   *
   * @param key The key to check.
   * @param values The values that will not match.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereNotContainedIn(String key, Collection values) {
    conditions.whereNotContainedIn(key, values);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value to be not equal to the
   * provided value.
   *
   * @param key The key to check.
   * @param value The value that must not be equalled.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereNotEqualTo(String key, Object value) {
    conditions.whereNotEqualTo(key, value);
    return this;
  }

  /**
   * Add a constraint for finding string values that start with a provided string. This query will
   * use the backend index, so it will be fast even for large datasets.
   *
   * @param key The key that the string to match is stored in.
   * @param prefix The substring that the value must start with.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereStartsWith(String key, String prefix) {
    conditions.whereStartsWith(key, prefix);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's coordinates be contained within
   * a given rectangular geographic bounding box.
   *
   * @param key The key to be constrained.
   * @param southwest The lower-left inclusive corner of the box.
   * @param northeast The upper-right inclusive corner of the box.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereWithinGeoBox(String key, AVGeoPoint southwest, AVGeoPoint northeast) {
    conditions.whereWithinGeoBox(key, southwest, northeast);
    return this;
  }

  /**
   * Add a proximity based constraint for finding objects with key point values near the point given
   * and within the maximum distance given. Radius of earth used is 6371.0 kilometers.
   *
   * @param key The key that the AVGeoPoint is stored in.
   * @param point The reference AVGeoPoint that is used.
   * @param maxDistance Maximum distance (in kilometers) of results to return.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereWithinKilometers(String key, AVGeoPoint point, double maxDistance) {
    conditions.whereWithinKilometers(key, point, maxDistance);
    return this;
  }

  /**
   * Add a proximity based constraint for finding objects with key point values near the point given
   * and within the given ring area
   *
   * Radius of earth used is 6371.0 kilometers.
   *
   * @param key The key that the AVGeoPoint is stored in.
   * @param point The reference AVGeoPoint that is used.
   * @param maxDistance outer radius of the given ring in kilometers
   * @param minDistance inner radius of the given ring in kilometers
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereWithinKilometers(String key, AVGeoPoint point, double maxDistance,
                                          double minDistance) {
    conditions.whereWithinKilometers(key, point, maxDistance, minDistance);
    return this;
  }

  /**
   * Add a proximity based constraint for finding objects with key point values near the point given
   * and within the maximum distance given. Radius of earth used is 3958.8 miles.
   * @param key The key that the AVGeoPoint is stored in.
   * @param maxDistance outer radius of the given ring in miles.
   * @param point The reference AVGeoPoint that is used.
   * @return  Returns the query, so you can chain this call.
   */
  public AVQuery whereWithinMiles(String key, AVGeoPoint point, double maxDistance) {
    conditions.whereWithinMiles(key, point, maxDistance);
    return this;
  }

  /**
   * Add a proximity based constraint for finding objects with key point values near the point
   * given and within the given ring.
   *
   * Radius of earth used is 3958.8 miles.
   *
   * @param key The key that the AVGeoPoint is stored in.
   * @param point The reference AVGeoPoint that is used.
   * @param maxDistance outer radius of the given ring in miles.
   * @param minDistance inner radius of the given ring in miles.
   * @return  Returns the query, so you can chain this call.
   */
  public AVQuery whereWithinMiles(String key, AVGeoPoint point, double maxDistance,
                                     double minDistance) {
    conditions.whereWithinMiles(key, point, maxDistance, minDistance);
    return this;
  }


  /**
   * Add a proximity based constraint for finding objects with key point values near the point given
   * and within the maximum distance given.
   *
   * @param key The key that the AVGeoPoint is stored in.
   * @param point The reference AVGeoPoint that is used.
   * @param maxDistance Maximum distance (in radians) of results to return.
   * @return Returns the query, so you can chain this call.
   */
  public AVQuery whereWithinRadians(String key, AVGeoPoint point, double maxDistance) {
    conditions.whereWithinRadians(key, point, maxDistance);
    return this;
  }

  /**
   * Add a proximity based constraint for finding objects with key point values near the point given
   * and within the maximum distance given.
   *
   * @param key The key that the AVGeoPoint is stored in.
   * @param point The reference AVGeoPoint that is used.
   * @param maxDistance outer radius of the given radians.
   * @param minDistance inner radius of the given radians.
   * @return  Returns the query, so you can chain this call.
   */

  public AVQuery whereWithinRadians(String key, AVGeoPoint point, double maxDistance,
                                       double minDistance) {
    conditions.whereWithinRadians(key, point, maxDistance, minDistance);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value matches a value for a key
   * in the results of another AVQuery
   *
   * @param key The key whose value is being checked
   * @param keyInQuery The key in the objects from the sub query to look in
   * @param query The sub query to run
   * @return Returns the query so you can chain this call.
   */
  public AVQuery whereMatchesKeyInQuery(String key, String keyInQuery, AVQuery query) {
    Map inner = new HashMap();
    inner.put("className", query.getClassName());
    inner.put("where", query.conditions.compileWhereOperationMap());
    if (query.conditions.getSkip() > 0) inner.put("skip", query.conditions.getSkip());
    if (query.conditions.getLimit() > 0) inner.put("limit", query.conditions.getLimit());
    if (!StringUtil.isEmpty(query.getOrder())) inner.put("order", query.getOrder());

    Map queryMap = new HashMap();
    queryMap.put("query", inner);
    queryMap.put("key", keyInQuery);
    return addWhereItem(key, "$select", queryMap);
  }

  /**
   * Add a constraint to the query that requires a particular key's value match another AVQuery.
   * This only works on keys whose values are AVObjects or lists of AVObjects.
   *
   * @param key The key to check.
   * @param query The query that the value should match
   * @return Returns the query so you can chain this call.
   */
  public AVQuery whereMatchesQuery(String key, AVQuery query) {
    Map map =
            AVUtils.createMap("where", query.conditions.compileWhereOperationMap());
    map.put("className", query.className);
    if (query.conditions.getSkip() > 0) map.put("skip", query.conditions.getSkip());
    if (query.conditions.getLimit() > 0) map.put("limit", query.conditions.getLimit());
    if (!StringUtil.isEmpty(query.getOrder())) map.put("order", query.getOrder());
    addWhereItem(key, "$inQuery", map);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value does not match any value
   * for a key in the results of another AVQuery.
   *
   * @param key The key whose value is being checked and excluded
   * @param keyInQuery The key in the objects from the sub query to look in
   * @param query The sub query to run
   * @return Returns the query so you can chain this call.
   */
  public AVQuery whereDoesNotMatchKeyInQuery(String key, String keyInQuery, AVQuery query) {
    Map map = AVUtils.createMap("className", query.className);
    map.put("where", query.conditions.compileWhereOperationMap());

    Map queryMap = AVUtils.createMap("query", map);
    queryMap.put("key", keyInQuery);

    addWhereItem(key, "$dontSelect", queryMap);
    return this;
  }

  /**
   * Add a constraint to the query that requires a particular key's value does not match another
   * AVQuery. This only works on keys whose values are AVObjects or lists of AVObjects.
   *
   * @param key The key to check.
   * @param query The query that the value should not match
   * @return Returns the query so you can chain this call.
   */
  public AVQuery whereDoesNotMatchQuery(String key, AVQuery query) {
    Map map = AVUtils.createMap("className", query.className);
    map.put("where", query.conditions.compileWhereOperationMap());

    addWhereItem(key, "$notInQuery", map);
    return this;
  }

  AVQuery setWhere(Map> value) {
    conditions.setWhere(value);
    return this;
  }

  /**
   * Constructs a query that is the or of the given queries.
   *
   * @param queries The list of AVQueries to 'or' together
   * @param  template type.
   * @return A AVQuery that is the 'or' of the passed in queries
   */
  public static  AVQuery or(List> queries) {
    if (null == queries || queries.isEmpty()) {
      throw new IllegalArgumentException("queries must be non-empty.");
    }
    String className = queries.get(0).getClassName();

    AVQuery result = new AVQuery(className);
    if (queries.size() > 1) {
      for (AVQuery query : queries) {
        if (!className.equals(query.getClassName())) {
          throw new IllegalArgumentException("All queries must be for the same class");
        }
        result.addOrItems(new QueryOperation("$or", "$or", query.conditions
                .compileWhereOperationMap()));
      }
    } else {
      result.setWhere(queries.get(0).conditions.getWhere());
    }

    return result;
  }

  /**
   * Constructs a query that is the and of the given queries.
   *
   * @param queries The list of AVQueries to 'and' together
   * @param  template type.
   * @return A AVQuery that is the 'and' of the passed in queries
   */
  public static  AVQuery and(List> queries) {
    if (null == queries || queries.isEmpty()) {
      throw new IllegalArgumentException("queries must be non-empty.");
    }
    String className = queries.get(0).getClassName();

    AVQuery result = new AVQuery(className);
    if (queries.size() > 1) {
      for (AVQuery query : queries) {
        if (!className.equals(query.getClassName())) {
          throw new IllegalArgumentException("All queries must be for the same class");
        }
        result.addAndItems(query);
      }
    } else {
      result.setWhere(queries.get(0).conditions.getWhere());
    }

    return result;
  }

  /**
   * Has cached result or not.
   * @return cache result existed or not.
   */
  public boolean hasCachedResult() {
    Map query = assembleParameters();
    return PaasClient.getStorageClient().hasCachedResult(getClassName(), query, this.getMaxCacheAge());
  }

  /**
   * Execute query in blocking mode.
   * @return result of list.
   */
  public List find() {
    return findInBackground().blockingLast();
  }

  /**
   * Execute query in async mode.
   * @return observable instance.
   */
  public Observable> findInBackground() {
    return findInBackground(0);
  }

  protected Observable> findInBackground(int explicitLimit) {
    Map query = assembleParameters();
    if (explicitLimit > 0) {
      query.put("limit", Integer.toString(explicitLimit));
    }
    LOGGER.d("Query: " + query);
    return PaasClient.getStorageClient().queryObjects(getClassName(), query, this.cachePolicy, this.maxCacheAge)
            .map(new Function, List>() {
              public List apply(List var1) throws Exception {
                LOGGER.d("invoke within AVQuery.findInBackground(). resultSize=" + var1.size());
                List result = new ArrayList(var1.size());
                for (AVObject obj: var1) {
                  T tmp = Transformer.transform(obj, getClassName());
                  result.add(tmp);
                }
                return result;
              }
            });
  }

  /**
   * Get Object with specified objectId in blocking mode.
   * @param objectId object id.
   * @return object instance.
   */
  public T get(String objectId) {
    return getInBackground(objectId).blockingFirst();
  }

  /**
   * Get Object with specified objectId in async mode.
   * @param objectId object id.
   * @return observable instance.
   */
  public Observable getInBackground(String objectId) {
    List include = getInclude();
    String includeKeys = null;
    if (null != include && include.size() > 0) {
      includeKeys = StringUtil.join(",", include);
    }
    return PaasClient.getStorageClient().fetchObject(getClassName(), objectId, includeKeys).map(new Function() {
      public T apply(AVObject avObject) throws Exception {
        if (null == avObject || StringUtil.isEmpty(avObject.getObjectId())) {
          throw new AVException(AVException.OBJECT_NOT_FOUND, "Object is not found.");
        }
        return Transformer.transform(avObject, getClassName());
      }
    });
  }

  /**
   * Get first result in blocking mode.
   * @return first result.
   */
  public T getFirst() {
    try {
      return getFirstInBackground().blockingFirst();
    } catch (NoSuchElementException ex) {
      return null;
    }
  }

  /**
   * Get first result in async mode.
   * @return observable instance.
   */
  public Observable getFirstInBackground() {
    return findInBackground(1).flatMap(new Function, ObservableSource>() {
      @Override
      public ObservableSource apply(List list) throws Exception {
        LOGGER.d("flatMap: " + list);
        return Observable.fromIterable(list);
      }
    });
  }

  /**
   * Get result count in blocking mode.
   * @return result count.
   */
  public int count() {
    return countInBackground().blockingFirst();
  }

  /**
   * Get result count in async mode.
   * @return observable instance.
   */
  public Observable countInBackground() {
    Map query = assembleParameters();
    query.put("count", "1");
    query.put("limit", "0");
    return PaasClient.getStorageClient().queryCount(getClassName(), query);
  }

  /**
   * Delete all query result in blocking mode.
   */
  public void deleteAll() {
    this.deleteAllInBackground().blockingSubscribe();
  }

  /**
   * Delete all query result in async mode.
   * @return observable instance.
   */
  public Observable deleteAllInBackground() {
    return findInBackground().flatMap(new Function, ObservableSource>() {
      @Override
      public ObservableSource apply(List list) {
        return AVObject.deleteAllInBackground(list);
      }
    });
  }

  /**
   * Assemble query parameters.
   * @return map of query parameters.
   */
  public Map assembleParameters() {
    conditions.assembleParameters();
    return conditions.getParameters();
  }

  protected Map assembleJsonParam() {
    Map result = conditions.assembleJsonParam();
    result.put("className", getClassName());
    return result;
  }

  /**
   * Cloud Query
   */
  /**
   * Do cloud query in async mode.
   * @param cql cql string
   * @return observable instance.
   */
  public static Observable doCloudQueryInBackground(String cql) {
    return AVCloudQuery.executeInBackground(cql);
  }

  /**
   * Do cloud query in async mode.
   * @param cql cql string
   * @param params query parameters.
   * @return observable instance.
   */
  public static Observable doCloudQueryInBackground(String cql, Object... params) {
    return AVCloudQuery.executeInBackground(cql, params);
  }

  /**
   * Do cloud query in async mode.
   * @param cql cql string
   * @param clazz result class.
   * @return observable instance.
   */
  public static Observable doCloudQueryInBackground(String cql, Class clazz) {
    return AVCloudQuery.executeInBackground(cql, clazz);
  }

  /**
   * Do cloud query in async mode.
   * @param cql  cql string
   * @param clazz result class.
   * @param params query parameters.
   * @return observable instance.
   */
  public static Observable doCloudQueryInBackground(String cql, final Class clazz,
                                                                        Object... params) {
    return AVCloudQuery.executeInBackground(cql, clazz, params);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy