com.datastax.driver.core.querybuilder.QueryBuilder Maven / Gradle / Ivy
/*
* Copyright 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.DataType;
import com.datastax.driver.core.Metadata;
import com.datastax.driver.core.RegularStatement;
import com.datastax.driver.core.TableMetadata;
import com.datastax.driver.core.exceptions.InvalidQueryException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Builds CQL3 query via a fluent API.
*
* The queries built by this builder will provide a value for the {@link
* com.datastax.driver.core.Statement#getRoutingKey} method only when a {@link
* com.datastax.driver.core.TableMetadata} is provided to the builder. It is thus advised to do so
* if a {@link com.datastax.driver.core.policies.TokenAwarePolicy} is in use.
*
*
The provider builders perform very little validation of the built query. There is thus no
* guarantee that a built query is valid, and it is definitively possible to create invalid queries.
*
*
Note that it could be convenient to use an 'import static' to bring the static methods of this
* class into scope.
*/
public final class QueryBuilder {
private QueryBuilder() {}
/**
* Starts building a new {@code SELECT} query that selects the provided names.
*
*
Note that {@code select(c1, c2)} is just a shortcut for {@code
* select().column(c1).column(c2)}.
*
* @param columns the columns names that should be selected by the query.
* @return an in-construction {@code SELECT} query (you will need to provide at least a {@code
* FROM} clause to complete the query).
*/
public static Select.Builder select(String... columns) {
return select((Object[]) columns);
}
/**
* Starts building a new {@code SELECT} query that selects the provided names.
*
*
Note that {@code select(c1, c2)} is just a shortcut for {@code
* select().column(c1).column(c2)}.
*
* @param columns the columns names that should be selected by the query.
* @return an in-construction {@code SELECT} query (you will need to provide at least a {@code
* FROM} clause to complete the query).
*/
public static Select.Builder select(Object... columns) {
return new Select.Builder(Arrays.asList(columns));
}
/**
* Starts building a new {@code SELECT} query.
*
* @return an in-construction {@code SELECT} query (you will need to provide a column selection
* and at least a {@code FROM} clause to complete the query).
*/
public static Select.Selection select() {
// Note: the fact we return Select.Selection as return type is on purpose.
return new Select.SelectionOrAlias();
}
/**
* Starts building a new {@code INSERT} query.
*
* @param table the name of the table in which to insert.
* @return an in-construction {@code INSERT} query.
*/
public static Insert insertInto(String table) {
return new Insert(null, table);
}
/**
* Starts building a new {@code INSERT} query.
*
* @param keyspace the name of the keyspace to use.
* @param table the name of the table to insert into.
* @return an in-construction {@code INSERT} query.
*/
public static Insert insertInto(String keyspace, String table) {
return new Insert(keyspace, table);
}
/**
* Starts building a new {@code INSERT} query.
*
* @param table the name of the table to insert into.
* @return an in-construction {@code INSERT} query.
*/
public static Insert insertInto(TableMetadata table) {
return new Insert(table);
}
/**
* Starts building a new {@code UPDATE} query.
*
* @param table the name of the table to update.
* @return an in-construction {@code UPDATE} query (at least a {@code SET} and a {@code WHERE}
* clause needs to be provided to complete the query).
*/
public static Update update(String table) {
return new Update(null, table);
}
/**
* Starts building a new {@code UPDATE} query.
*
* @param keyspace the name of the keyspace to use.
* @param table the name of the table to update.
* @return an in-construction {@code UPDATE} query (at least a {@code SET} and a {@code WHERE}
* clause needs to be provided to complete the query).
*/
public static Update update(String keyspace, String table) {
return new Update(keyspace, table);
}
/**
* Starts building a new {@code UPDATE} query.
*
* @param table the name of the table to update.
* @return an in-construction {@code UPDATE} query (at least a {@code SET} and a {@code WHERE}
* clause needs to be provided to complete the query).
*/
public static Update update(TableMetadata table) {
return new Update(table);
}
/**
* Starts building a new {@code DELETE} query that deletes the provided names.
*
* @param columns the columns names that should be deleted by the query.
* @return an in-construction {@code DELETE} query (At least a {@code FROM} and a {@code WHERE}
* clause needs to be provided to complete the query).
*/
public static Delete.Builder delete(String... columns) {
return new Delete.Builder(columns);
}
/**
* Starts building a new {@code DELETE} query.
*
* @return an in-construction {@code DELETE} query (you will need to provide a column selection
* and at least a {@code FROM} and a {@code WHERE} clause to complete the query).
*/
public static Delete.Selection delete() {
return new Delete.Selection();
}
/**
* Builds a new {@code BATCH} query on the provided statements.
*
*
This method will build a logged batch (this is the default in CQL3). To create unlogged
* batches, use {@link #unloggedBatch}. Also note that for convenience, if the provided statements
* are counter statements, this method will create a {@code COUNTER} batch even though COUNTER
* batches are never logged (so for counters, using this method is effectively equivalent to using
* {@link #unloggedBatch}).
*
* @param statements the statements to batch.
* @return a new {@code RegularStatement} that batch {@code statements}.
*/
public static Batch batch(RegularStatement... statements) {
return new Batch(statements, true);
}
/**
* Builds a new {@code UNLOGGED BATCH} query on the provided statements.
*
*
Compared to logged batches (the default), unlogged batch don't use the distributed batch log
* server side and as such are not guaranteed to be atomic. In other words, if an unlogged batch
* timeout, some of the batched statements may have been persisted while some have not. Unlogged
* batch will however be slightly faster than logged batch.
*
*
If the statements added to the batch are counter statements, the resulting batch will be a
* {@code COUNTER} one.
*
* @param statements the statements to batch.
* @return a new {@code RegularStatement} that batch {@code statements} without using the batch
* log.
*/
public static Batch unloggedBatch(RegularStatement... statements) {
return new Batch(statements, false);
}
/**
* Creates a new {@code TRUNCATE} query.
*
* @param table the name of the table to truncate.
* @return the truncation query.
*/
public static Truncate truncate(String table) {
return new Truncate(null, table);
}
/**
* Creates a new {@code TRUNCATE} query.
*
* @param keyspace the name of the keyspace to use.
* @param table the name of the table to truncate.
* @return the truncation query.
*/
public static Truncate truncate(String keyspace, String table) {
return new Truncate(keyspace, table);
}
/**
* Creates a new {@code TRUNCATE} query.
*
* @param table the table to truncate.
* @return the truncation query.
*/
public static Truncate truncate(TableMetadata table) {
return new Truncate(table);
}
/**
* Quotes a column name to make it case sensitive.
*
* @param columnName the column name to quote.
* @return the quoted column name.
* @see Metadata#quote(String)
*/
public static String quote(String columnName) {
return Metadata.quote(columnName);
}
/**
* The token of a column name.
*
* @param columnName the column name to take the token of.
* @return {@code "token(" + columnName + ")"}.
*/
public static String token(String columnName) {
StringBuilder sb = new StringBuilder();
sb.append("token(");
Utils.appendName(columnName, sb);
sb.append(')');
return sb.toString();
}
/**
* The token of column names.
*
*
This variant is most useful when the partition key is composite.
*
* @param columnNames the column names to take the token of.
* @return a string representing the token of the provided column names.
*/
public static String token(String... columnNames) {
StringBuilder sb = new StringBuilder();
sb.append("token(");
Utils.joinAndAppendNames(sb, null, Arrays.asList(columnNames));
sb.append(')');
return sb.toString();
}
/**
* Returns a generic {@code token} function call.
*
* @param values the arguments of the {@code token} function.
* @return {@code token} function call.
*/
public static Object token(Object... values) {
return new Utils.FCall("token", values);
}
/**
* Creates an "equal" {@code WHERE} clause stating the provided column must be equal to the
* provided value.
*
* @param name the column name
* @param value the value
* @return the corresponding where clause.
*/
public static Clause eq(String name, Object value) {
return new Clause.SimpleClause(name, "=", value);
}
/**
* Creates an "equal" {@code WHERE} clause for a group of clustering columns.
*
*
For instance, {@code eq(Arrays.asList("a", "b"), Arrays.asList(2, "test"))} will generate
* the CQL {@code WHERE} clause {@code (a, b) = (2, 'test') }.
*
*
Please note that this variant is only supported starting with Cassandra 2.0.6.
*
* @param names the column names
* @param values the values
* @return the corresponding where clause.
* @throws IllegalArgumentException if {@code names.size() != values.size()}.
*/
public static Clause eq(Iterable names, Iterable values) {
return new Clause.CompoundClause(names, "=", values);
}
/**
* Creates a "not equal" {@code WHERE} clause stating the provided column must be different from
* the provided value.
*
* @param name the column name
* @param value the value
* @return the corresponding where clause.
*/
public static Clause ne(String name, Object value) {
return new Clause.SimpleClause(name, "!=", value);
}
/**
* Creates an "not equal" {@code WHERE} clause for a group of clustering columns.
*
* For instance, {@code eq(Arrays.asList("a", "b"), Arrays.asList(2, "test"))} will generate
* the CQL {@code WHERE} clause {@code (a, b) != (2, 'test') }.
*
* @param names the column names
* @param values the values
* @return the corresponding where clause.
* @throws IllegalArgumentException if {@code names.size() != values.size()}.
*/
public static Clause ne(Iterable names, Iterable values) {
return new Clause.CompoundClause(names, "!=", values);
}
/**
* Creates an "IS NOT NULL" {@code WHERE} clause for the provided column.
*
* @param name the column name
* @return the corresponding where clause.
*/
public static Clause notNull(String name) {
return new Clause.IsNotNullClause(name);
}
/**
* Creates a "like" {@code WHERE} clause stating that the provided column must be equal to the
* provided value.
*
* @param name the column name.
* @param value the value.
* @return the corresponding where clause.
*/
public static Clause like(String name, Object value) {
return new Clause.SimpleClause(name, " LIKE ", value);
}
/**
* Create an "in" {@code WHERE} clause stating the provided column must be equal to one of the
* provided values.
*
* @param name the column name
* @param values the values
* @return the corresponding where clause.
*/
public static Clause in(String name, Object... values) {
return new Clause.InClause(name, Arrays.asList(values));
}
/**
* Create an "in" {@code WHERE} clause stating the provided column must be equal to one of the
* provided values.
*
* @param name the column name
* @param values the values
* @return the corresponding where clause.
*/
public static Clause in(String name, Iterable values) {
return new Clause.InClause(name, values);
}
/**
* Creates an "in" {@code WHERE} clause for a group of clustering columns (a.k.a. "multi-column IN
* restriction").
*
* For instance, {@code in(Arrays.asList("a", "b"), Arrays.asList(Arrays.asList(1, "foo"),
* Arrays.asList(2, "bar")))} will generate the CQL {@code WHERE} clause {@code (a, b) IN ((1,
* 'foo'), (2, 'bar'))}.
*
*
Each element in {@code values} must be either an {@link Iterable iterable} containing
* exactly as many values as there are columns to match in {@code names}, or a {@link
* #bindMarker() bind marker} – in which case, that marker is to be considered as a placeholder
* for one whole tuple of values to match.
*
*
Please note that this variant is only supported starting with Cassandra 2.0.9.
*
* @param names the column names
* @param values the values
* @return the corresponding where clause.
* @throws IllegalArgumentException if the size of any tuple in {@code values} is not equal to
* {@code names.size()}, or if {@code values} contains elements that are neither {@link List
* lists} nor {@link #bindMarker() bind markers}.
*/
public static Clause in(Iterable names, Iterable values) {
return new Clause.CompoundInClause(names, values);
}
/**
* Creates a "contains" {@code WHERE} clause stating the provided column must contain the value
* provided.
*
* @param name the column name
* @param value the value
* @return the corresponding where clause.
*/
public static Clause contains(String name, Object value) {
return new Clause.ContainsClause(name, value);
}
/**
* Creates a "contains key" {@code WHERE} clause stating the provided column must contain the key
* provided.
*
* @param name the column name
* @param key the key
* @return the corresponding where clause.
*/
public static Clause containsKey(String name, Object key) {
return new Clause.ContainsKeyClause(name, key);
}
/**
* Creates a "lesser than" {@code WHERE} clause stating the provided column must be less than the
* provided value.
*
* @param name the column name
* @param value the value
* @return the corresponding where clause.
*/
public static Clause lt(String name, Object value) {
return new Clause.SimpleClause(name, "<", value);
}
/**
* Creates a "lesser than" {@code WHERE} clause for a group of clustering columns.
*
* For instance, {@code lt(Arrays.asList("a", "b"), Arrays.asList(2, "test"))} will generate
* the CQL {@code WHERE} clause {@code (a, b) < (2, 'test') }.
*
*
Please note that this variant is only supported starting with Cassandra 2.0.6.
*
* @param names the column names
* @param values the values
* @return the corresponding where clause.
* @throws IllegalArgumentException if {@code names.size() != values.size()}.
*/
public static Clause lt(Iterable names, Iterable values) {
return new Clause.CompoundClause(names, "<", values);
}
/**
* Creates a "lesser than or equal" {@code WHERE} clause stating the provided column must be
* lesser than or equal to the provided value.
*
* @param name the column name
* @param value the value
* @return the corresponding where clause.
*/
public static Clause lte(String name, Object value) {
return new Clause.SimpleClause(name, "<=", value);
}
/**
* Creates a "lesser than or equal" {@code WHERE} clause for a group of clustering columns.
*
* For instance, {@code lte(Arrays.asList("a", "b"), Arrays.asList(2, "test"))} will generate
* the CQL {@code WHERE} clause {@code (a, b) <e; (2, 'test') }.
*
*
Please note that this variant is only supported starting with Cassandra 2.0.6.
*
* @param names the column names
* @param values the values
* @return the corresponding where clause.
* @throws IllegalArgumentException if {@code names.size() != values.size()}.
*/
public static Clause lte(Iterable names, Iterable values) {
return new Clause.CompoundClause(names, "<=", values);
}
/**
* Creates a "greater than" {@code WHERE} clause stating the provided column must be greater to
* the provided value.
*
* @param name the column name
* @param value the value
* @return the corresponding where clause.
*/
public static Clause gt(String name, Object value) {
return new Clause.SimpleClause(name, ">", value);
}
/**
* Creates a "greater than" {@code WHERE} clause for a group of clustering columns.
*
* For instance, {@code gt(Arrays.asList("a", "b"), Arrays.asList(2, "test"))} will generate
* the CQL {@code WHERE} clause {@code (a, b) > (2, 'test') }.
*
*
Please note that this variant is only supported starting with Cassandra 2.0.6.
*
* @param names the column names
* @param values the values
* @return the corresponding where clause.
* @throws IllegalArgumentException if {@code names.size() != values.size()}.
*/
public static Clause gt(Iterable names, Iterable values) {
return new Clause.CompoundClause(names, ">", values);
}
/**
* Creates a "greater than or equal" {@code WHERE} clause stating the provided column must be
* greater than or equal to the provided value.
*
* @param name the column name
* @param value the value
* @return the corresponding where clause.
*/
public static Clause gte(String name, Object value) {
return new Clause.SimpleClause(name, ">=", value);
}
/**
* Creates a "greater than or equal" {@code WHERE} clause for a group of clustering columns.
*
* For instance, {@code gte(Arrays.asList("a", "b"), Arrays.asList(2, "test"))} will generate
* the CQL {@code WHERE} clause {@code (a, b) >e; (2, 'test') }.
*
*
Please note that this variant is only supported starting with Cassandra 2.0.6.
*
* @param names the column names
* @param values the values
* @return the corresponding where clause.
* @throws IllegalArgumentException if {@code names.size() != values.size()}.
*/
public static Clause gte(Iterable names, Iterable values) {
return new Clause.CompoundClause(names, ">=", values);
}
/**
* Ascending ordering for the provided column.
*
* @param columnName the column name
* @return the corresponding ordering
*/
public static Ordering asc(String columnName) {
return new Ordering(columnName, false);
}
/**
* Descending ordering for the provided column.
*
* @param columnName the column name
* @return the corresponding ordering
*/
public static Ordering desc(String columnName) {
return new Ordering(columnName, true);
}
/**
* Option to set the timestamp for a modification query (insert, update or delete).
*
* @param timestamp the timestamp (in microseconds) to use.
* @return the corresponding option
* @throws IllegalArgumentException if {@code timestamp < 0}.
*/
public static Using timestamp(long timestamp) {
if (timestamp < 0) throw new IllegalArgumentException("Invalid timestamp, must be positive");
return new Using.WithValue("TIMESTAMP", timestamp);
}
/**
* Option to prepare the timestamp (in microseconds) for a modification query (insert, update or
* delete).
*
* @param marker bind marker to use for the timestamp.
* @return the corresponding option.
*/
public static Using timestamp(BindMarker marker) {
return new Using.WithMarker("TIMESTAMP", marker);
}
/**
* Option to set the ttl for a modification query (insert, update or delete).
*
* @param ttl the ttl (in seconds) to use.
* @return the corresponding option
* @throws IllegalArgumentException if {@code ttl < 0}.
*/
public static Using ttl(int ttl) {
if (ttl < 0) throw new IllegalArgumentException("Invalid ttl, must be positive");
return new Using.WithValue("TTL", ttl);
}
/**
* Option to prepare the ttl (in seconds) for a modification query (insert, update or delete).
*
* @param marker bind marker to use for the ttl.
* @return the corresponding option
*/
public static Using ttl(BindMarker marker) {
return new Using.WithMarker("TTL", marker);
}
/**
* Simple "set" assignment of a value to a column.
*
* This will generate:
*
*
* name = value
*
*
* The column name will only be quoted if it contains special characters, as in:
*
*
* "a name that contains spaces" = value
*
*
* Otherwise, if you want to force case sensitivity, use {@link #quote(String)}:
*
*
* set(quote("aCaseSensitiveName"), value)
*
*
* This method won't work to set UDT fields; use {@link #set(Object, Object)} with a {@link
* #path(String...) path} instead:
*
*
* set(path("udt", "field"), value)
*
*
* @param name the column name
* @param value the value to assign
* @return the correspond assignment (to use in an update query)
*/
public static Assignment set(String name, Object value) {
return new Assignment.SetAssignment(name, value);
}
/**
* Advanced "set" assignment of a value to a column or a {@link com.datastax.driver.core.UserType
* UDT} field.
*
* This method is seldom preferable to {@link #set(String, Object)}; it is only useful:
*
*
* - when assigning values to individual fields of a UDT (see {@link #path(String...)}):
*
* set(path("udt", "field"), value)
*
* - if you wish to pass a "raw" string that will get appended as-is to the query (see {@link
* #raw(String)}). There is no practical usage for this the time of writing, but it will
* serve as a workaround if new features are added to Cassandra and you're using a older
* driver version that is not yet aware of them:
*
* set(raw("some custom string"), value)
*
*
*
* If the runtime type of {@code name} is {@code String}, this method is equivalent to {@link
* #set(String, Object)}.
*
* @param name the column or UDT field name
* @param value the value to assign
* @return the correspond assignment (to use in an update query)
*/
public static Assignment set(Object name, Object value) {
return new Assignment.SetAssignment(name, value);
}
/**
* Incrementation of a counter column.
*
* This will generate: {@code name = name + 1}.
*
* @param name the column name to increment
* @return the correspond assignment (to use in an update query)
*/
public static Assignment incr(String name) {
return incr(name, 1L);
}
/**
* Incrementation of a counter column by a provided value.
*
*
This will generate: {@code name = name + value}.
*
* @param name the column name to increment
* @param value the value by which to increment
* @return the correspond assignment (to use in an update query)
*/
public static Assignment incr(String name, long value) {
return new Assignment.CounterAssignment(name, value, true);
}
/**
* Incrementation of a counter column by a provided value.
*
*
This will generate: {@code name = name + value}.
*
* @param name the column name to increment
* @param value a bind marker representing the value by which to increment
* @return the correspond assignment (to use in an update query)
*/
public static Assignment incr(String name, BindMarker value) {
return new Assignment.CounterAssignment(name, value, true);
}
/**
* Decrementation of a counter column.
*
*
This will generate: {@code name = name - 1}.
*
* @param name the column name to decrement
* @return the correspond assignment (to use in an update query)
*/
public static Assignment decr(String name) {
return decr(name, 1L);
}
/**
* Decrementation of a counter column by a provided value.
*
*
This will generate: {@code name = name - value}.
*
* @param name the column name to decrement
* @param value the value by which to decrement
* @return the correspond assignment (to use in an update query)
*/
public static Assignment decr(String name, long value) {
return new Assignment.CounterAssignment(name, value, false);
}
/**
* Decrementation of a counter column by a provided value.
*
*
This will generate: {@code name = name - value}.
*
* @param name the column name to decrement
* @param value a bind marker representing the value by which to decrement
* @return the correspond assignment (to use in an update query)
*/
public static Assignment decr(String name, BindMarker value) {
return new Assignment.CounterAssignment(name, value, false);
}
/**
* Prepend a value to a list column.
*
*
This will generate: {@code name = [ value ] + name}.
*
* @param name the column name (must be of type list).
* @param value the value to prepend. Using a BindMarker here is not supported. To use a
* BindMarker use {@code QueryBuilder#prependAll} with a singleton list.
* @return the correspond assignment (to use in an update query)
*/
public static Assignment prepend(String name, Object value) {
if (value instanceof BindMarker) {
throw new InvalidQueryException(
"binding a value in prepend() is not supported, use prependAll() and bind a singleton list");
}
return prependAll(name, Collections.singletonList(value));
}
/**
* Prepend a list of values to a list column.
*
*
This will generate: {@code name = list + name}.
*
* @param name the column name (must be of type list).
* @param list the list of values to prepend.
* @return the correspond assignment (to use in an update query)
*/
public static Assignment prependAll(String name, List list) {
return new Assignment.ListPrependAssignment(name, list);
}
/**
* Prepend a list of values to a list column.
*
*
This will generate: {@code name = list + name}.
*
* @param name the column name (must be of type list).
* @param list a bind marker representing the list of values to prepend.
* @return the correspond assignment (to use in an update query)
*/
public static Assignment prependAll(String name, BindMarker list) {
return new Assignment.ListPrependAssignment(name, list);
}
/**
* Append a value to a list column.
*
*
This will generate: {@code name = name + [value]}.
*
* @param name the column name (must be of type list).
* @param value the value to append. Using a BindMarker here is not supported. To use a BindMarker
* use {@code QueryBuilder#appendAll} with a singleton list.
* @return the correspond assignment (to use in an update query)
*/
public static Assignment append(String name, Object value) {
if (value instanceof BindMarker) {
throw new InvalidQueryException(
"Binding a value in append() is not supported, use appendAll() and bind a singleton list");
}
return appendAll(name, Collections.singletonList(value));
}
/**
* Append a list of values to a list column.
*
*
This will generate: {@code name = name + list}.
*
* @param name the column name (must be of type list).
* @param list the list of values to append
* @return the correspond assignment (to use in an update query)
*/
public static Assignment appendAll(String name, List list) {
return new Assignment.CollectionAssignment(name, list, true, false);
}
/**
* Append a list of values to a list column.
*
*
This will generate: {@code name = name + list}.
*
* @param name the column name (must be of type list).
* @param list a bind marker representing the list of values to append
* @return the correspond assignment (to use in an update query)
*/
public static Assignment appendAll(String name, BindMarker list) {
return new Assignment.CollectionAssignment(name, list, true, false);
}
/**
* Discard a value from a list column.
*
*
This will generate: {@code name = name - [value]}.
*
* @param name the column name (must be of type list).
* @param value the value to discard. Using a BindMarker here is not supported. To use a
* BindMarker use {@code QueryBuilder#discardAll} with a singleton list.
* @return the correspond assignment (to use in an update query)
*/
public static Assignment discard(String name, Object value) {
if (value instanceof BindMarker) {
throw new InvalidQueryException(
"Binding a value in discard() is not supported, use discardAll() and bind a singleton list");
}
return discardAll(name, Collections.singletonList(value));
}
/**
* Discard a list of values to a list column.
*
*
This will generate: {@code name = name - list}.
*
* @param name the column name (must be of type list).
* @param list the list of values to discard
* @return the correspond assignment (to use in an update query)
*/
public static Assignment discardAll(String name, List list) {
return new Assignment.CollectionAssignment(name, list, false);
}
/**
* Discard a list of values to a list column.
*
*
This will generate: {@code name = name - list}.
*
* @param name the column name (must be of type list).
* @param list a bind marker representing the list of values to discard
* @return the correspond assignment (to use in an update query)
*/
public static Assignment discardAll(String name, BindMarker list) {
return new Assignment.CollectionAssignment(name, list, false);
}
/**
* Sets a list column value by index.
*
*
This will generate: {@code name[idx] = value}.
*
* @param name the column name (must be of type list).
* @param idx the index to set
* @param value the value to set
* @return the correspond assignment (to use in an update query)
*/
public static Assignment setIdx(String name, int idx, Object value) {
return new Assignment.ListSetIdxAssignment(name, idx, value);
}
/**
* Adds a value to a set column.
*
*
This will generate: {@code name = name + {value}}.
*
* @param name the column name (must be of type set).
* @param value the value to add. Using a BindMarker here is not supported. To use a BindMarker
* use {@code QueryBuilder#addAll} with a singleton set.
* @return the correspond assignment (to use in an update query)
*/
public static Assignment add(String name, Object value) {
if (value instanceof BindMarker) {
throw new InvalidQueryException(
"Binding a value in add() is not supported, use addAll() and bind a singleton list");
}
return addAll(name, Collections.singleton(value));
}
/**
* Adds a set of values to a set column.
*
*
This will generate: {@code name = name + set}.
*
* @param name the column name (must be of type set).
* @param set the set of values to append
* @return the correspond assignment (to use in an update query)
*/
public static Assignment addAll(String name, Set set) {
return new Assignment.CollectionAssignment(name, set, true);
}
/**
* Adds a set of values to a set column.
*
*
This will generate: {@code name = name + set}.
*
* @param name the column name (must be of type set).
* @param set a bind marker representing the set of values to append
* @return the correspond assignment (to use in an update query)
*/
public static Assignment addAll(String name, BindMarker set) {
return new Assignment.CollectionAssignment(name, set, true);
}
/**
* Remove a value from a set column.
*
*
This will generate: {@code name = name - {value}}.
*
* @param name the column name (must be of type set).
* @param value the value to remove. Using a BindMarker here is not supported. To use a BindMarker
* use {@code QueryBuilder#removeAll} with a singleton set.
* @return the correspond assignment (to use in an update query)
*/
public static Assignment remove(String name, Object value) {
if (value instanceof BindMarker) {
throw new InvalidQueryException(
"Binding a value in remove() is not supported, use removeAll() and bind a singleton set");
}
return removeAll(name, Collections.singleton(value));
}
/**
* Remove a set of values from a set column.
*
*
This will generate: {@code name = name - set}.
*
* @param name the column name (must be of type set).
* @param set the set of values to remove
* @return the correspond assignment (to use in an update query)
*/
public static Assignment removeAll(String name, Set set) {
return new Assignment.CollectionAssignment(name, set, false);
}
/**
* Remove a set of values from a set column.
*
*
This will generate: {@code name = name - set}.
*
* @param name the column name (must be of type set).
* @param set a bind marker representing the set of values to remove
* @return the correspond assignment (to use in an update query)
*/
public static Assignment removeAll(String name, BindMarker set) {
return new Assignment.CollectionAssignment(name, set, false);
}
/**
* Puts a new key/value pair to a map column.
*
*
This will generate: {@code name[key] = value}.
*
* @param name the column name (must be of type map).
* @param key the key to put
* @param value the value to put
* @return the correspond assignment (to use in an update query)
*/
public static Assignment put(String name, Object key, Object value) {
return new Assignment.MapPutAssignment(name, key, value);
}
/**
* Puts a map of new key/value pairs to a map column.
*
*
This will generate: {@code name = name + map}.
*
* @param name the column name (must be of type map).
* @param map the map of key/value pairs to put
* @return the correspond assignment (to use in an update query)
*/
public static Assignment putAll(String name, Map map) {
return new Assignment.CollectionAssignment(name, map, true);
}
/**
* Puts a map of new key/value pairs to a map column.
*
*
This will generate: {@code name = name + map}.
*
* @param name the column name (must be of type map).
* @param map a bind marker representing the map of key/value pairs to put
* @return the correspond assignment (to use in an update query)
*/
public static Assignment putAll(String name, BindMarker map) {
return new Assignment.CollectionAssignment(name, map, true);
}
/**
* An object representing an anonymous bind marker (a question mark).
*
*
This can be used wherever a value is expected. For instance, one can do:
*
*
{@code
* Insert i = QueryBuilder.insertInto("test").value("k", 0)
* .value("c", QueryBuilder.bindMarker());
* PreparedStatement p = session.prepare(i.toString());
* }
*
* @return a new bind marker.
*/
public static BindMarker bindMarker() {
return BindMarker.ANONYMOUS;
}
/**
* An object representing a named bind marker.
*
* This can be used wherever a value is expected. For instance, one can do:
*
*
{@code
* Insert i = QueryBuilder.insertInto("test").value("k", 0)
* .value("c", QueryBuilder.bindMarker("c_val"));
* PreparedStatement p = session.prepare(i.toString());
* }
*
* Please note that named bind makers are only supported starting with Cassandra 2.0.1.
*
* @param name the name for the bind marker.
* @return an object representing a bind marker named {@code name}.
*/
public static BindMarker bindMarker(String name) {
return new BindMarker(name);
}
/**
* Protects a value from any interpretation by the query builder.
*
*
The following table exemplify the behavior of this function:
*
*
* Examples of use
* Code Resulting query string
* {@code select().from("t").where(eq("c", "C'est la vie!")); } {@code "SELECT * FROM t WHERE c='C''est la vie!';"}
* {@code select().from("t").where(eq("c", raw("C'est la vie!"))); } {@code "SELECT * FROM t WHERE c=C'est la vie!;"}
* {@code select().from("t").where(eq("c", raw("'C'est la vie!'"))); } {@code "SELECT * FROM t WHERE c='C'est la vie!';"}
* {@code select().from("t").where(eq("c", "now()")); } {@code "SELECT * FROM t WHERE c='now()';"}
* {@code select().from("t").where(eq("c", raw("now()"))); } {@code "SELECT * FROM t WHERE c=now();"}
*
*
* Note: the 2nd and 3rd examples in this table are not a valid CQL3 queries.
*
* The use of that method is generally discouraged since it lead to security risks. However, if
* you know what you are doing, it allows to escape the interpretations done by the QueryBuilder.
*
* @param str the raw value to use as a string
* @return the value but protected from being interpreted/escaped by the query builder.
*/
public static Object raw(String str) {
return new Utils.RawString(str);
}
/**
* Creates a function call.
*
* @param name the name of the function to call.
* @param parameters the parameters for the function.
* @return the function call.
*/
public static Object fcall(String name, Object... parameters) {
return new Utils.FCall(name, parameters);
}
/**
* Creates a Cast of a column using the given dataType.
*
* @param column the column to cast.
* @param dataType the data type to cast to.
* @return the casted column.
*/
public static Object cast(Object column, DataType dataType) {
return new Utils.Cast(column, dataType);
}
/**
* Creates a {@code now()} function call.
*
* @return the function call.
*/
public static Object now() {
return new Utils.FCall("now");
}
/**
* Creates a {@code uuid()} function call.
*
* @return the function call.
*/
public static Object uuid() {
return new Utils.FCall("uuid");
}
/**
* Declares that the name in argument should be treated as a column name.
*
*
This mainly meant for use with {@link Select.Selection#fcall} when a function should apply
* to a column name, not a string value.
*
* @param name the name of the column.
* @return the name as a column name.
*/
public static Object column(String name) {
return new Utils.CName(name);
}
/**
* Creates a path composed of the given path {@code segments}.
*
*
All provided path segments will be concatenated together with dots. If any segment contains
* an identifier that needs quoting, caller code is expected to call {@link #quote(String)} prior
* to invoking this method.
*
*
This method is currently only useful when accessing individual fields of a {@link
* com.datastax.driver.core.UserType user-defined type} (UDT), which is only possible since
* CASSANDRA-7423.
*
*
Note that currently nested UDT fields are not supported and will be rejected by the server
* as a {@link com.datastax.driver.core.exceptions.SyntaxError syntax error}.
*
* @param segments the segments of the path to create.
* @return the segments concatenated as a single path.
* @see CASSANDRA-7423
*/
public static Object path(String... segments) {
return new Utils.Path(segments);
}
/**
* Creates a {@code fromJson()} function call.
*
*
Support for JSON functions has been added in Cassandra 2.2. The {@code fromJson()} function
* is similar to {@code INSERT JSON} statements, but applies to a single column value instead of
* the entire row, and converts a JSON object into the normal Cassandra column value.
*
*
It may be used in {@code INSERT} and {@code UPDATE} statements, but NOT in the selection
* clause of a {@code SELECT} statement.
*
*
The provided object can be of the following types:
*
*
* - A raw string. In this case, it will be appended to the query string as is. It
* should NOT be surrounded by single quotes. Its format should generally match
* that returned by a {@code SELECT JSON} statement on the same table. Note that it is not
* possible to insert function calls nor bind markers in a JSON string.
*
- A {@link QueryBuilder#bindMarker() bind marker}. In this case, the statement is meant to
* be prepared and no JSON string will be appended to the query string, only a bind marker
* for the whole JSON parameter.
*
- Any object that can be serialized to JSON. Such objects can be used provided that a
* matching {@link com.datastax.driver.core.TypeCodec codec} is registered with the {@link
* com.datastax.driver.core.CodecRegistry CodecRegistry} in use. This allows the usage of
* JSON libraries, such as the Java API for
* JSON processing, the popular Jackson library, or Google's Gson library, for instance.
*
*
* When passing raw strings to this method, the following rules apply:
*
*
* - String values should be enclosed in double quotes.
*
- Double quotes appearing inside strings should be escaped with a backslash, but single
* quotes should be escaped in the CQL manner, i.e. by another single quote. For example,
* the column value {@code foo"'bar} should be inserted in the JSON string as {@code
* "foo\"''bar"}.
*
*
* @param json the JSON string, or a bind marker, or a JSON object handled by a specific {@link
* com.datastax.driver.core.TypeCodec codec}.
* @return the function call.
* @see JSON Support for CQL
* @see JSON
* Support in Cassandra 2.2
*/
public static Object fromJson(Object json) {
return fcall("fromJson", json);
}
/**
* Creates a {@code toJson()} function call. This is a shortcut for {@code fcall("toJson",
* QueryBuilder.column(name))}.
*
* Support for JSON functions has been added in Cassandra 2.2. The {@code toJson()} function is
* similar to {@code SELECT JSON} statements, but applies to a single column value instead of the
* entire row, and produces a JSON-encoded string representing the normal Cassandra column value.
*
*
It may only be used in the selection clause of a {@code SELECT} statement.
*
* @param column the column to retrieve JSON from.
* @return the function call.
* @see JSON Support for CQL
* @see JSON
* Support in Cassandra 2.2
*/
public static Object toJson(Object column) {
// consider a String literal as a column name for user convenience,
// as CQL literals are not allowed here.
if (column instanceof String) column = column(((String) column));
return new Utils.FCall("toJson", column);
}
/**
* Creates an alias for a given column.
*
*
This is most useful when used with the method {@link #select(Object...)}.
*
* @param column The column to create an alias for.
* @param alias The column alias.
* @return a column alias.
*/
public static Object alias(Object column, String alias) {
return new Utils.Alias(column, alias);
}
/**
* Creates a {@code count(x)} built-in function call.
*
* @return the function call.
*/
public static Object count(Object column) {
// consider a String literal as a column name for user convenience,
// as CQL literals are not allowed here.
if (column instanceof String) column = column(((String) column));
return new Utils.FCall("count", column);
}
/**
* Creates a {@code max(x)} built-in function call.
*
* @return the function call.
*/
public static Object max(Object column) {
// consider a String literal as a column name for user convenience,
// as CQL literals are not allowed here.
if (column instanceof String) column = column(((String) column));
return new Utils.FCall("max", column);
}
/**
* Creates a {@code min(x)} built-in function call.
*
* @return the function call.
*/
public static Object min(Object column) {
// consider a String literal as a column name for user convenience,
// as CQL literals are not allowed here.
if (column instanceof String) column = column(((String) column));
return new Utils.FCall("min", column);
}
/**
* Creates a {@code sum(x)} built-in function call.
*
* @return the function call.
*/
public static Object sum(Object column) {
// consider a String literal as a column name for user convenience,
// as CQL literals are not allowed here.
if (column instanceof String) column = column(((String) column));
return new Utils.FCall("sum", column);
}
/**
* Creates an {@code avg(x)} built-in function call.
*
* @return the function call.
*/
public static Object avg(Object column) {
// consider a String literal as a column name for user convenience,
// as CQL literals are not allowed here.
if (column instanceof String) column = column(((String) column));
return new Utils.FCall("avg", column);
}
}