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

info.archinnov.achilles.query.slice.SliceQueryProperties Maven / Gradle / Ivy

There is a newer version: 6.1.0
Show newest version
/*
 * Copyright (C) 2012-2014 DuyHai DOAN
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package info.archinnov.achilles.query.slice;

import static com.datastax.driver.core.querybuilder.QueryBuilder.asc;
import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
import static com.datastax.driver.core.querybuilder.QueryBuilder.desc;
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
import static com.datastax.driver.core.querybuilder.QueryBuilder.gt;
import static com.datastax.driver.core.querybuilder.QueryBuilder.gte;
import static com.datastax.driver.core.querybuilder.QueryBuilder.in;
import static com.datastax.driver.core.querybuilder.QueryBuilder.lt;
import static com.datastax.driver.core.querybuilder.QueryBuilder.lte;
import static com.google.common.collect.FluentIterable.from;
import static info.archinnov.achilles.schemabuilder.Create.Options.ClusteringOrder;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.RegularStatement;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.querybuilder.Delete;
import com.datastax.driver.core.querybuilder.Select;
import com.google.common.base.Optional;
import com.google.common.util.concurrent.FutureCallback;
import info.archinnov.achilles.internal.metadata.holder.EntityMeta;
import info.archinnov.achilles.internal.validation.Validator;
import info.archinnov.achilles.type.ConsistencyLevel;

public class SliceQueryProperties {

    private static final Logger log = LoggerFactory.getLogger(SliceQueryProperties.class);


    private final EntityMeta entityMeta;
    private final Class entityClass;
    private final SliceType sliceType;

    private Optional limitO = Optional.absent();
    protected Optional fetchSizeO = Optional.absent();
    private BoundingMode boundingMode = BoundingMode.INCLUSIVE_BOUNDS;
    private Optional orderingModeO = Optional.absent();

    private ConsistencyLevel readConsistencyLevel;
    private ConsistencyLevel writeConsistencyLevel;

    private List partitionKeys = new LinkedList<>();
    private List partitionKeysName = new LinkedList<>();
    private List partitionKeysIn = new LinkedList<>();
    private String lastPartitionKeyName;
    private List fromClusteringKeys = new LinkedList<>();
    private List fromClusteringKeysName = new LinkedList<>();
    private List toClusteringKeys = new LinkedList<>();
    private List toClusteringKeysName = new LinkedList<>();
    private List withClusteringKeys = new LinkedList<>();
    private List withClusteringKeysName = new LinkedList<>();
    private List clusteringsKeysIn = new LinkedList<>();
    private String lastClusteringKeyName;

    private ClusteringOrder clusteringOrder;

    private FutureCallback[] asyncListeners;

    private boolean createProxy = false;

    private SliceQueryProperties(EntityMeta entityMeta, Class entityClass, SliceType sliceType) {
        this.entityMeta = entityMeta;
        this.entityClass = entityClass;
        this.sliceType = sliceType;
        this.clusteringOrder = entityMeta.forSliceQuery().getClusteringOrderForSliceQuery();
        this.readConsistencyLevel = entityMeta.config().getReadConsistencyLevel();
        this.writeConsistencyLevel = entityMeta.config().getWriteConsistencyLevel();
    }

    public static  SliceQueryProperties builder(EntityMeta entityMeta, Class entityClass, SliceType sliceType) {
        return new SliceQueryProperties<>(entityMeta, entityClass, sliceType);
    }

    protected SliceQueryProperties  limit(int limit) {
        Validator.validateTrue(limit > 0, "The limit '%s' should be strictly positive", limit);
        this.limitO = Optional.fromNullable(limit);
        return this;
    }

    protected SliceQueryProperties createProxy() {
        this.createProxy = true;
        return this;
    }

    protected SliceQueryProperties  fetchSize(int fetchSize) {
        Validator.validateTrue(fetchSize > 0, "The fetchSize '%s' should be strictly positive", fetchSize);
        this.fetchSizeO = Optional.fromNullable(fetchSize);
        if (CollectionUtils.isNotEmpty(partitionKeysIn)) {
            this.orderingModeO = Optional.absent();
            log.warn("Cannot page queries with both ORDER BY and a IN restriction on the partition key; you must either remove the ORDER BY or the IN and sort client side, or disable paging for this query");
        }
        return this;
    }

    protected SliceQueryProperties  bounding(BoundingMode boundingMode) {
        this.boundingMode = boundingMode;
        return this;
    }

    protected SliceQueryProperties  ordering(OrderingMode orderingMode) {
        this.orderingModeO = Optional.fromNullable(orderingMode);
        return this;
    }

    protected SliceQueryProperties readConsistency(ConsistencyLevel consistencyLevel) {
        Validator.validateNotNull(consistencyLevel, "The consistency level should not be null");
        this.readConsistencyLevel = consistencyLevel;
        return this;
    }

    protected SliceQueryProperties writeConsistency(ConsistencyLevel consistencyLevel) {
        Validator.validateNotNull(consistencyLevel, "The consistency level should not be null");
        this.writeConsistencyLevel = consistencyLevel;
        return this;
    }

    protected SliceQueryProperties  partitionKeys(List partitionKeys) {
        this.partitionKeys = partitionKeys;
        return this;
    }

    protected SliceQueryProperties  partitionKeysName(List partitionKeysName) {
        this.partitionKeysName = partitionKeysName;
        return this;
    }

    protected SliceQueryProperties andPartitionKeysIn(List partitionKeysIn) {
        this.partitionKeysIn = partitionKeysIn;
        return this;
    }

    protected SliceQueryProperties  lastPartitionKeyName(String lastPartitionKeyName) {
        this.lastPartitionKeyName = lastPartitionKeyName;
        return this;
    }

    protected SliceQueryProperties  fromClusteringKeys(List fromClusteringKeys) {
        this.fromClusteringKeys = fromClusteringKeys;
        return this;
    }

    protected SliceQueryProperties  fromClusteringKeysName(List fromClusteringKeysName) {
        this.fromClusteringKeysName = fromClusteringKeysName;
        return this;
    }

    protected SliceQueryProperties  toClusteringKeys(List toClusteringKeys) {
        this.toClusteringKeys = toClusteringKeys;
        return this;
    }

    protected SliceQueryProperties  toClusteringKeysName(List toClusteringKeysName) {
        this.toClusteringKeysName = toClusteringKeysName;
        return this;
    }

    protected SliceQueryProperties  withClusteringKeys(List withClusteringKeys) {
        this.withClusteringKeys = withClusteringKeys;
        return this;
    }

    protected SliceQueryProperties  withClusteringKeysName(List withClusteringKeysName) {
        this.withClusteringKeysName = withClusteringKeysName;
        return this;
    }

    protected SliceQueryProperties  andClusteringKeysIn(List clusteringsKeysIn) {
        this.clusteringsKeysIn = clusteringsKeysIn;
        return this;
    }

    protected SliceQueryProperties  lastClusteringKeyName(String lastClusteringKeyName) {
        this.lastClusteringKeyName = lastClusteringKeyName;
        return this;
    }

    protected SliceQueryProperties  asyncListeners(FutureCallback[] asyncListeners) {
        Validator.validateNotEmpty(asyncListeners,"The provided async listeners should not be null");
        this.asyncListeners = asyncListeners;
        return this;
    }

    // Public access

    public RegularStatement generateWhereClauseForSelect(Select from) {
        final Select.Where where = from.where();

        // Partition keys
        for (String partitionKeyName : partitionKeysName) {
            where.and(eq(partitionKeyName, bindMarker(partitionKeyName)));
        }

        if (isNotBlank(lastPartitionKeyName)) {
            where.and(in(lastPartitionKeyName, bindMarker("partitionComponentsIn")));
        }

        // Clustering keys
        if (isNotEmpty(withClusteringKeys)) {
            for (String withClusteringName : withClusteringKeysName) {
                where.and(eq(withClusteringName, bindMarker(withClusteringName)));
            }

            if (isNotBlank(lastClusteringKeyName)) {
                where.and(in(lastClusteringKeyName, bindMarker("clusteringKeysIn")));
            }
        } else {
            if (isNotEmpty(fromClusteringKeys)) {
                boundingMode.buildFromClusteringKeys(where, clusteringOrder, fromClusteringKeysName);
            }

            if (isNotEmpty(toClusteringKeys)) {
                boundingMode.buildToClusteringKeys(where, clusteringOrder, toClusteringKeysName);
            }
        }

        // ORDER BY
        if (orderingModeO.isPresent()) {

            final Select statement;
            final OrderingMode orderingMode = orderingModeO.get();
            if (orderingMode.isReverse()) {
                statement = where.orderBy(desc(clusteringOrder.getClusteringColumnName()));
            } else {
                statement = where.orderBy(asc(clusteringOrder.getClusteringColumnName()));
            }
            // LIMIT
            if (limitO.isPresent()) {
                statement.limit(bindMarker("limitSize"));
            }

            return statement;
        } else {
            // LIMIT
            if (limitO.isPresent()) {
                where.limit(bindMarker("limitSize"));
            }

            return where;

        }
    }

    public Delete.Where generateWhereClauseForDelete(Delete delete) {
        final Delete.Where where = delete.where();

        // Partition keys
        for (String partitionKeyName : partitionKeysName) {
            where.and(eq(partitionKeyName, bindMarker(partitionKeyName)));
        }

        if (isNotBlank(lastPartitionKeyName)) {
            where.and(in(lastPartitionKeyName, bindMarker("partitionComponentsIn")));
        }

        // Clustering keys
        if (isNotEmpty(withClusteringKeys)) {
            for (String withClusteringName : withClusteringKeysName) {
                where.and(eq(withClusteringName, bindMarker(withClusteringName)));
            }
        }
        return where;
    }

    public Object[] getBoundValues() {
        List boundValues = new LinkedList<>();
        // Partition keys
        boundValues.addAll(entityMeta.forTranscoding().encodePartitionComponents(partitionKeys));

        if (isNotEmpty(partitionKeysIn)) {
            boundValues.add(entityMeta.forTranscoding().encodePartitionComponentsIN(partitionKeysIn));
        }

        // Clustering keys
        if (isNotEmpty(withClusteringKeys)) {
            boundValues.addAll(entityMeta.forTranscoding().encodeClusteringKeys(withClusteringKeys));

            if (isNotEmpty(clusteringsKeysIn)) {
                boundValues.add(entityMeta.forTranscoding().encodeClusteringKeysIN(clusteringsKeysIn));
            }
        } else {
            if (isNotEmpty(fromClusteringKeys)) {
                boundValues.addAll(entityMeta.forTranscoding().encodeClusteringKeys(fromClusteringKeys));
            }

            if (isNotEmpty(toClusteringKeys)) {
                boundValues.addAll(entityMeta.forTranscoding().encodeClusteringKeys(toClusteringKeys));
            }
        }

        // LIMIT
        if (limitO.isPresent()) {
            boundValues.add(limitO.get());
        }

        return boundValues.toArray();
    }

    public void setFetchSizeToStatement(Statement statement) {
        if (fetchSizeO.isPresent()) {
            statement.setFetchSize(fetchSizeO.get());
        }
    }

    public ConsistencyLevel getReadConsistencyLevel() {
        return readConsistencyLevel;
    }

    public ConsistencyLevel getWriteConsistencyLevel() {
        return writeConsistencyLevel;
    }

    public Class getEntityClass() {
        return entityClass;
    }

    public EntityMeta getEntityMeta() {
        return entityMeta;
    }

    public List getPartitionKeys() {
        return partitionKeys;
    }

    public List getWithClusteringKeys() {
        return withClusteringKeys;
    }

    public FutureCallback[] getAsyncListeners() {
        return asyncListeners;
    }

    public boolean shouldCreateProxy() {
        return createProxy;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        SliceQueryProperties that = (SliceQueryProperties) o;

        return Objects.equals(this.sliceType, that.sliceType) &&
                Objects.equals(this.entityClass, that.entityClass) &&
                Objects.equals(this.partitionKeysName, that.partitionKeysName) &&
                Objects.equals(this.lastPartitionKeyName, that.lastPartitionKeyName) &&
                Objects.equals(this.fromClusteringKeysName, that.fromClusteringKeysName) &&
                Objects.equals(this.toClusteringKeysName, that.toClusteringKeysName) &&
                Objects.equals(this.withClusteringKeysName, that.withClusteringKeysName) &&
                Objects.equals(this.lastClusteringKeyName, that.lastClusteringKeyName) &&
                Objects.equals(this.boundingMode, that.boundingMode) &&
                Objects.equals(this.orderingModeO, that.orderingModeO) &&
                Objects.equals(this.limitO, that.limitO);
    }

    @Override
    public int hashCode() {
        return Objects.hash(this.sliceType,
                this.entityClass,
                this.partitionKeysName,
                this.lastPartitionKeyName,
                this.fromClusteringKeysName,
                this.toClusteringKeysName,
                this.withClusteringKeysName,
                this.lastClusteringKeyName,
                this.boundingMode,
                this.orderingModeO,
                this.limitO);
    }

    public static enum SliceType {
        SELECT, ITERATE, DELETE;
    }
}