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

com.netflix.astyanax.cql.reads.CFRowSliceQueryGen Maven / Gradle / Ivy

package com.netflix.astyanax.cql.reads;

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.lt;
import static com.datastax.driver.core.querybuilder.QueryBuilder.lte;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import com.datastax.driver.core.Session;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Select.Where;
import com.netflix.astyanax.cql.reads.model.CqlColumnSlice;
import com.netflix.astyanax.cql.schema.CqlColumnFamilyDefinitionImpl;
import com.netflix.astyanax.ddl.ColumnDefinition;
import com.netflix.astyanax.query.RowSliceQuery;
import com.netflix.astyanax.serializers.CompositeRangeBuilder.CompositeByteBufferRange;
import com.netflix.astyanax.serializers.CompositeRangeBuilder.RangeQueryOp;
import com.netflix.astyanax.serializers.CompositeRangeBuilder.RangeQueryRecord;

/**
 * Base class that contains the utilities for generating queries for read operations via the 
 * {@link RowSliceQuery} class. 
 * 
 * Note that this class is just a place holder for some useful generic utilities. 
 * See {@link CFRowKeysQueryGen} and {@link CFRowRangeQueryGen} which are the 2 extending classes 
 * for functionality that actually supports the queries. 
 * 
 * @author poberai
 */
public class CFRowSliceQueryGen {

	// Thread safe reference to the underlying session object. We need the session object to be able to "prepare" query statements
	protected final AtomicReference sessionRef = new AtomicReference(null);
	// the keyspace being queried. Used for all the underlying queries being generated
	protected final String keyspace; 
	// the cf definition which helps extending classes construct the right query as per the schema
	protected final CqlColumnFamilyDefinitionImpl cfDef;

	// Other useful derivatives of the cf definition that are frequently used by query generators
	protected final String partitionKeyCol;
	protected final String[] allPrimayKeyCols;
	protected final List clusteringKeyCols;
	protected final List regularCols;
	
	// Condition tracking whether the underlying schema uses composite columns. This is imp since it influences how 
	// a single Column (composite column) can be decomposed into it's individual components that form different parts of the query.
	protected boolean isCompositeColumn; 
	
	// bind marker for generating the prepared statements
	protected static final String BIND_MARKER = "?";
	
	public CFRowSliceQueryGen(Session session, String keyspaceName, CqlColumnFamilyDefinitionImpl cfDefinition) {

		this.keyspace = keyspaceName;
		this.cfDef = cfDefinition;
		this.sessionRef.set(session);

		partitionKeyCol = cfDef.getPartitionKeyColumnDefinition().getName();
		allPrimayKeyCols = cfDef.getAllPkColNames();
		clusteringKeyCols = cfDef.getClusteringKeyColumnDefinitionList();
		regularCols = cfDef.getRegularColumnDefinitionList();

		isCompositeColumn = (clusteringKeyCols.size() > 1);
	}
	
	/**
	 * 
	 *   SOME BASIC UTILITY METHODS USED BY ALL THE ROW SLICE QUERY GENERATORS
	 */
	
	protected Select selectAllColumnsFromKeyspaceAndCF() {

		Select.Selection select = QueryBuilder.select();
		for (int i=0; i columnSlice) {

		String clusteringKeyCol = clusteringKeyCols.get(0).getName();

		if (!columnSlice.isRangeQuery()) {
			return where;
		}
		if (columnSlice.getStartColumn() != null) {
			where.and(gte(clusteringKeyCol, columnSlice.getStartColumn()));
		}
		if (columnSlice.getEndColumn() != null) {
			where.and(lte(clusteringKeyCol, columnSlice.getEndColumn()));
		}

		if (columnSlice.getReversed()) {
			where.orderBy(desc(clusteringKeyCol));
		}

		if (columnSlice.getLimit() != -1) {
			where.limit(columnSlice.getLimit());
		}

		return where;
	}
	
	protected void bindWhereClauseForColumnRange(List values, CqlColumnSlice columnSlice) {

		if (!columnSlice.isRangeQuery()) {
			return;
		}
		if (columnSlice.getStartColumn() != null) {
			values.add(columnSlice.getStartColumn());
		}
		if (columnSlice.getEndColumn() != null) {
			values.add(columnSlice.getEndColumn());
		}

		if (columnSlice.getLimit() != -1) {
			values.add(columnSlice.getLimit());
		}

		return;
	}
	

	protected Where addWhereClauseForCompositeColumnRange(Where stmt, CompositeByteBufferRange compositeRange) {

		List records = compositeRange.getRecords();
		int componentIndex = 0; 

		for (RangeQueryRecord record : records) {

			for (RangeQueryOp op : record.getOps()) {

				String columnName = clusteringKeyCols.get(componentIndex).getName();

				switch (op.getOperator()) {

				case EQUAL:
					stmt.and(eq(columnName, BIND_MARKER));
					componentIndex++;
					break;
				case LESS_THAN :
					stmt.and(lt(columnName, BIND_MARKER));
					break;
				case LESS_THAN_EQUALS:
					stmt.and(lte(columnName, BIND_MARKER));
					break;
				case GREATER_THAN:
					stmt.and(gt(columnName, BIND_MARKER));
					break;
				case GREATER_THAN_EQUALS:
					stmt.and(gte(columnName, BIND_MARKER));
					break;
				default:
					throw new RuntimeException("Cannot recognize operator: " + op.getOperator().name());
				}; // end of switch stmt
			} // end of inner for for ops for each range query record
		}
		return stmt;
	}

	protected void bindWhereClauseForCompositeColumnRange(List values, CompositeByteBufferRange compositeRange) {

		List records = compositeRange.getRecords();

		for (RangeQueryRecord record : records) {
			for (RangeQueryOp op : record.getOps()) {
				values.add(op.getValue());
			}
		}
		return;
	}
	
	protected Object[] bindMarkerArray(int n) {
		
		Object[] arr = new Object[n];
		for (int i=0; i