Package com.google.appengine.api.datastore

Source Code of com.google.appengine.api.datastore.QueryRunnerV4

package com.google.appengine.api.datastore;

import com.google.appengine.api.datastore.DatastoreServiceConfig.ApiVersion;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.ReadPolicy.Consistency;
import com.google.apphosting.datastore.DatastoreV4;
import com.google.apphosting.datastore.DatastoreV4.CompositeFilter;
import com.google.apphosting.datastore.DatastoreV4.PropertyExpression;
import com.google.apphosting.datastore.DatastoreV4.PropertyFilter;
import com.google.apphosting.datastore.DatastoreV4.PropertyOrder;
import com.google.apphosting.datastore.DatastoreV4.PropertyReference;
import com.google.apphosting.datastore.DatastoreV4.ReadOptions.ReadConsistency;
import com.google.apphosting.datastore.DatastoreV4.RunQueryRequest;
import com.google.apphosting.datastore.DatastoreV4.RunQueryResponse;
import com.google.apphosting.datastore.EntityV4;
import com.google.apphosting.datastore.EntityV4.PartitionId;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;

import java.util.Collection;
import java.util.Set;
import java.util.concurrent.Future;

/**
* V4 service specific code for constructing and sending queries.
* This class is threadsafe and has no state.
*/
final class QueryRunnerV4 implements QueryRunner {

  private final DatastoreServiceConfig datastoreServiceConfig;
  private final DatastoreV4Proxy datastoreProxy;

  QueryRunnerV4(DatastoreServiceConfig datastoreServiceConfig, DatastoreV4Proxy datastoreProxy) {
    this.datastoreServiceConfig = datastoreServiceConfig;
    this.datastoreProxy = datastoreProxy;
  }

  @Override
  public QueryResultsSource runQuery(FetchOptions fetchOptions, Query query, Transaction txn) {

    RunQueryRequest.Builder queryBldr = toV4Query(query, fetchOptions);
    if (txn != null) {
      TransactionImpl.ensureTxnActive(txn);
      queryBldr.getReadOptionsBuilder()
          .setTransaction(InternalTransactionV4.getById(txn.getId()).getHandle());
    } else if (datastoreServiceConfig.getReadPolicy().getConsistency() == Consistency.EVENTUAL) {
      queryBldr.getReadOptionsBuilder().setReadConsistency(ReadConsistency.EVENTUAL);
    }

    RunQueryRequest request = queryBldr.build();
    Future<RunQueryResponse> result = datastoreProxy.runQuery(request);

    if (datastoreServiceConfig.getApiVersion() == ApiVersion.CLOUD_DATASTORE) {
      return new QueryResultsSourceCloudDatastore(datastoreServiceConfig.getDatastoreCallbacks(),
          fetchOptions, txn, query, request, result, datastoreProxy);
    } else {
      return new QueryResultsSourceV4(datastoreServiceConfig.getDatastoreCallbacks(),
          fetchOptions, txn, query, result, datastoreProxy);
    }
  }

  static RunQueryRequest.Builder toV4Query(Query query, FetchOptions fetchOptions) {

    Preconditions.checkArgument(query.getFullTextSearch() == null, "full-text search unsupported");

    Preconditions.checkArgument(query.getFilter() == null);

    RunQueryRequest.Builder requestBldr = RunQueryRequest.newBuilder();

    if (fetchOptions.getChunkSize() != null) {
      requestBldr.setSuggestedBatchSize(fetchOptions.getChunkSize());
    } else if (fetchOptions.getPrefetchSize() != null) {
      requestBldr.setSuggestedBatchSize(fetchOptions.getPrefetchSize());
    }

    PartitionId.Builder partitionId = requestBldr.getPartitionIdBuilder()
        .setDatasetId(query.getAppId());
    if (!query.getNamespace().isEmpty()) {
      partitionId.setNamespace(query.getNamespace());
    }

    DatastoreV4.Query.Builder queryBldr = requestBldr.getQueryBuilder();

    if (query.getKind() != null) {
      queryBldr.addKindBuilder().setName(query.getKind());
    }

    if (fetchOptions.getOffset() != null) {
      queryBldr.setOffset(fetchOptions.getOffset());
    }

    if (fetchOptions.getLimit() != null) {
      queryBldr.setLimit(fetchOptions.getLimit());
    }

    if (fetchOptions.getStartCursor() != null) {
      queryBldr.setStartCursor(fetchOptions.getStartCursor().convertToPb().toByteString());
    }

    if (fetchOptions.getEndCursor() != null) {
      queryBldr.setEndCursor(fetchOptions.getEndCursor().convertToPb().toByteString());
    }

    Set<String> groupByProperties = Sets.newHashSet();
    if (query.getDistinct()) {
      if (query.getProjections().isEmpty()) {
        throw new IllegalArgumentException(
            "Projected properties must be set to allow for distinct projections");
      }
      for (Projection projection : query.getProjections()) {
        String name = projection.getPropertyName();
        groupByProperties.add(name);
        queryBldr.addGroupByBuilder().setName(name);
      }
    }

    for (Projection projection : query.getProjections()) {
      String name = projection.getPropertyName();
      PropertyExpression.Builder projBuilder = queryBldr.addProjectionBuilder();
      projBuilder.getPropertyBuilder().setName(name);
      if (!groupByProperties.isEmpty() && !groupByProperties.contains(name)) {
        projBuilder.setAggregationFunction(PropertyExpression.AggregationFunction.FIRST);
      }
    }

    if (query.isKeysOnly()) {
      PropertyExpression.Builder projBuilder = queryBldr.addProjectionBuilder();
      projBuilder.getPropertyBuilder().setName(Entity.KEY_RESERVED_PROPERTY);
      if (!groupByProperties.isEmpty()
          && !groupByProperties.contains(Entity.KEY_RESERVED_PROPERTY)) {
        projBuilder.setAggregationFunction(PropertyExpression.AggregationFunction.FIRST);
      }
    }

    CompositeFilter.Builder compositeFilter = CompositeFilter.newBuilder();
    if (query.getAncestor() != null) {
      compositeFilter.addFilterBuilder().getPropertyFilterBuilder()
          .setOperator(PropertyFilter.Operator.HAS_ANCESTOR)
          .setProperty(PropertyReference.newBuilder().setName(Entity.KEY_RESERVED_PROPERTY))
          .setValue(EntityV4.Value.newBuilder()
              .setKeyValue(DataTypeTranslator.toV4Key(query.getAncestor())));
    }
    for (Query.FilterPredicate filterPredicate : query.getFilterPredicates()) {
      compositeFilter.addFilterBuilder().setPropertyFilter(toV4PropertyFilter(filterPredicate));
    }
    if (compositeFilter.getFilterCount() == 1) {
      queryBldr.setFilter(compositeFilter.getFilter(0));
    } else if (compositeFilter.getFilterCount() > 1) {
      queryBldr.getFilterBuilder()
          .setCompositeFilter(compositeFilter.setOperator(CompositeFilter.Operator.AND));
    }

    for (Query.SortPredicate sortPredicate : query.getSortPredicates()) {
      queryBldr.addOrder(toV4PropertyOrder(sortPredicate));
    }

    return requestBldr;
  }

  private static PropertyFilter.Builder toV4PropertyFilter(Query.FilterPredicate predicate) {
    PropertyFilter.Builder filter = PropertyFilter.newBuilder();
    FilterOperator operator = predicate.getOperator();
    Object value = predicate.getValue();
    if (operator == Query.FilterOperator.IN) {
      if (!(predicate.getValue() instanceof Collection<?>)) {
        throw new IllegalArgumentException("IN filter value is not a Collection.");
      }
      Collection<?> valueCollection = (Collection<?>) value;
      if (valueCollection.size() != 1) {
        throw new IllegalArgumentException("This service only supports 1 object for IN.");
      }
      operator = Query.FilterOperator.EQUAL;
      value = valueCollection.iterator().next();
    }
    filter.setOperator(toV4PropertyFilterOperator(operator));
    filter.getPropertyBuilder().setName(predicate.getPropertyName());
    filter.setValue(DataTypeTranslator.toV4Value(value, true));

    return filter;
  }

  private static PropertyFilter.Operator toV4PropertyFilterOperator(FilterOperator operator) {
    switch (operator) {
      case LESS_THAN:
        return PropertyFilter.Operator.LESS_THAN;
      case LESS_THAN_OR_EQUAL:
        return PropertyFilter.Operator.LESS_THAN_OR_EQUAL;
      case GREATER_THAN:
        return PropertyFilter.Operator.GREATER_THAN;
      case GREATER_THAN_OR_EQUAL:
        return PropertyFilter.Operator.GREATER_THAN_OR_EQUAL;
      case EQUAL:
        return PropertyFilter.Operator.EQUAL;
      default:
        throw new IllegalArgumentException("Can't convert: " + operator);
    }
  }

  private static PropertyOrder.Builder toV4PropertyOrder(Query.SortPredicate predicate) {
    return PropertyOrder.newBuilder()
        .setProperty(PropertyReference.newBuilder().setName(predicate.getPropertyName()))
        .setDirection(toV4PropertyOrderDirection(predicate.getDirection()));
  }

  private static PropertyOrder.Direction toV4PropertyOrderDirection(Query.SortDirection direction) {
    switch (direction) {
      case ASCENDING:
        return PropertyOrder.Direction.ASCENDING;
      case DESCENDING:
        return PropertyOrder.Direction.DESCENDING;
      default:
        throw new IllegalArgumentException("direction: " + direction);
    }
  }

}
TOP

Related Classes of com.google.appengine.api.datastore.QueryRunnerV4

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.