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

com.datastax.driver.core.querybuilder.Select Maven / Gradle / Ivy

There is a newer version: 3.6.0-1
Show newest version
/*
 *      Copyright (C) 2012-2015 DataStax Inc.
 *
 *   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 com.datastax.driver.core.querybuilder;

import com.datastax.driver.core.CodecRegistry;
import com.datastax.driver.core.ColumnMetadata;
import com.datastax.driver.core.DataType;
import com.datastax.driver.core.TableMetadata;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * A built SELECT statement.
 */
public class Select extends BuiltStatement {

    private static final List COUNT_ALL = Collections.singletonList(new Utils.FCall("count", new Utils.RawString("*")));

    private final String table;
    private final boolean isDistinct;
    private final boolean isJson;
    private final List columnNames;
    private final Where where;
    private List orderings;
    private Object limit;
    private Object perPartitionLimit;
    private boolean allowFiltering;

    Select(String keyspace, String table, List columnNames, boolean isDistinct, boolean isJson) {
        this(keyspace, table, null, null, columnNames, isDistinct, isJson);
    }

    Select(TableMetadata table, List columnNames, boolean isDistinct, boolean isJson) {
        this(escapeId(table.getKeyspace().getName()),
                escapeId(table.getName()),
                Arrays.asList(new Object[table.getPartitionKey().size()]),
                table.getPartitionKey(),
                columnNames,
                isDistinct,
                isJson);
    }

    Select(String keyspace,
           String table,
           List routingKeyValues,
           List partitionKey,
           List columnNames,
           boolean isDistinct,
           boolean isJson) {
        super(keyspace, partitionKey, routingKeyValues);
        this.table = table;
        this.columnNames = columnNames;
        this.isDistinct = isDistinct;
        this.isJson = isJson;
        this.where = new Where(this);
    }

    @Override
    StringBuilder buildQueryString(List variables, CodecRegistry codecRegistry) {
        StringBuilder builder = new StringBuilder();

        builder.append("SELECT ");

        if (isJson)
            builder.append("JSON ");

        if (isDistinct)
            builder.append("DISTINCT ");

        if (columnNames == null) {
            builder.append('*');
        } else {
            Utils.joinAndAppendNames(builder, codecRegistry, ",", columnNames);
        }
        builder.append(" FROM ");
        if (keyspace != null)
            Utils.appendName(keyspace, builder).append('.');
        Utils.appendName(table, builder);

        if (!where.clauses.isEmpty()) {
            builder.append(" WHERE ");
            Utils.joinAndAppend(builder, codecRegistry, " AND ", where.clauses, variables);
        }

        if (orderings != null) {
            builder.append(" ORDER BY ");
            Utils.joinAndAppend(builder, codecRegistry, ",", orderings, variables);
        }

        if (perPartitionLimit != null) {
            builder.append(" PER PARTITION LIMIT ").append(perPartitionLimit);
        }

        if (limit != null) {
            builder.append(" LIMIT ").append(limit);
        }

        if (allowFiltering) {
            builder.append(" ALLOW FILTERING");
        }

        return builder;
    }

    /**
     * Adds a WHERE clause to this statement.
     * 

* This is a shorter/more readable version for {@code where().and(clause)}. * * @param clause the clause to add. * @return the where clause of this query to which more clause can be added. */ public Where where(Clause clause) { return where.and(clause); } /** * Returns a Where statement for this query without adding clause. * * @return the where clause of this query to which more clause can be added. */ public Where where() { return where; } /** * Adds an ORDER BY clause to this statement. * * @param orderings the orderings to define for this query. * @return this statement. * @throws IllegalStateException if an ORDER BY clause has already been * provided. */ public Select orderBy(Ordering... orderings) { if (this.orderings != null) throw new IllegalStateException("An ORDER BY clause has already been provided"); this.orderings = Arrays.asList(orderings); for (int i = 0; i < orderings.length; i++) checkForBindMarkers(orderings[i]); return this; } /** * Adds a {@code LIMIT} clause to this statement. * * @param limit the limit to set. * @return this statement. * @throws IllegalArgumentException if {@code limit <= 0}. * @throws IllegalStateException if a {@code LIMIT} clause has already been * provided. */ public Select limit(int limit) { if (limit <= 0) throw new IllegalArgumentException("Invalid LIMIT value, must be strictly positive"); if (this.limit != null) throw new IllegalStateException("A LIMIT value has already been provided"); this.limit = limit; setDirty(); return this; } /** * Adds a prepared {@code LIMIT} clause to this statement. * * @param marker the marker to use for the limit. * @return this statement. * @throws IllegalStateException if a {@code LIMIT} clause has already been * provided. */ public Select limit(BindMarker marker) { if (this.limit != null) throw new IllegalStateException("A LIMIT value has already been provided"); this.limit = marker; checkForBindMarkers(marker); return this; } /** * Adds a {@code PER PARTITION LIMIT} clause to this statement. *

* Note: support for {@code PER PARTITION LIMIT} clause is only available from * Cassandra 3.6 onwards. * * @param perPartitionLimit the limit to set per partition. * @return this statement. * @throws IllegalArgumentException if {@code perPartitionLimit <= 0}. * @throws IllegalStateException if a {@code PER PARTITION LIMIT} clause has already been * provided. * @throws IllegalStateException if this statement is a {@code SELECT DISTINCT} statement. */ public Select perPartitionLimit(int perPartitionLimit) { if (perPartitionLimit <= 0) throw new IllegalArgumentException("Invalid PER PARTITION LIMIT value, must be strictly positive"); if (this.perPartitionLimit != null) throw new IllegalStateException("A PER PARTITION LIMIT value has already been provided"); if (isDistinct) throw new IllegalStateException("PER PARTITION LIMIT is not allowed with SELECT DISTINCT queries"); this.perPartitionLimit = perPartitionLimit; setDirty(); return this; } /** * Adds a prepared {@code PER PARTITION LIMIT} clause to this statement. *

* Note: support for {@code PER PARTITION LIMIT} clause is only available from * Cassandra 3.6 onwards. * * @param marker the marker to use for the limit per partition. * @return this statement. * @throws IllegalStateException if a {@code PER PARTITION LIMIT} clause has already been * provided. * @throws IllegalStateException if this statement is a {@code SELECT DISTINCT} statement. */ public Select perPartitionLimit(BindMarker marker) { if (this.perPartitionLimit != null) throw new IllegalStateException("A PER PARTITION LIMIT value has already been provided"); if (isDistinct) throw new IllegalStateException("PER PARTITION LIMIT is not allowed with SELECT DISTINCT queries"); this.perPartitionLimit = marker; checkForBindMarkers(marker); return this; } /** * Adds an ALLOW FILTERING directive to this statement. * * @return this statement. */ public Select allowFiltering() { allowFiltering = true; return this; } /** * The WHERE clause of a SELECT statement. */ public static class Where extends BuiltStatement.ForwardingStatement