|
1 | 1 | ## Built statements |
2 | 2 |
|
3 | | -*Coming soon... In the meantime, see the javadoc for [QueryBuilder].* |
| 3 | +Built statements are generated via [QueryBuilder]'s Fluent API. Use of Fluent API allows |
| 4 | +easier build of complex queries, as opposed to use of hardcoded query strings. |
4 | 5 |
|
5 | | -[QueryBuilder]: http://docs.datastax.com/en/drivers/java/3.5/com/datastax/driver/core/querybuilder/QueryBuilder.html |
| 6 | +Note: The provided builders perform very little validation of the built query. There is |
| 7 | +no guarantee that a built query is valid, and it is definitively possible to create |
| 8 | +invalid queries. |
| 9 | + |
| 10 | +Queries built with `QueryBuilder` are executed the same way as other queries--via |
| 11 | +`execute` or `executeAsync`. When a query is built with inlined values, then it doesn't |
| 12 | +differ much from a statement specified as a string. But it's also possible to build |
| 13 | +the query with bind markers inside it, and then convert it into a [prepared statement](../prepared/). |
| 14 | + |
| 15 | +### Basics |
| 16 | + |
| 17 | +Generation of `BuiltStatement` is easy--start by calling of one of the |
| 18 | +[QueryBuilder]'s methods that represent the CQL's "verb": `select`, `update`, `delete`, |
| 19 | +`insertInto`, or `truncate`, provide required parameters, and then call "verb"-specific |
| 20 | +functions to form a complete CQL statement (like, `where`, `from`, etc.). The statement's |
| 21 | +target table can be specified as a simple table name (if a default keyspace has been set |
| 22 | +when creating the `Session` object), as a combination of keyspace name and table name, or as |
| 23 | +a [TableMetadata] object. |
| 24 | + |
| 25 | +Note: The `QueryBuilder` doesn't provide support for the full set of CQL. For |
| 26 | +most of DDL operations (`CREATE TABLE`, etc.) you can use the [SchemaBuilder]. To perform other |
| 27 | +operations, for example, for role management, you still need to use [simple statements](../simple/). |
| 28 | + |
| 29 | +### Selecting data |
| 30 | + |
| 31 | +Selection of data is quite simple--at minimum you need to provide a list of columns to |
| 32 | +select, and then specify from which table to select these columns (you can also optionally |
| 33 | +specify a condition, as described in the next section): |
| 34 | + |
| 35 | +```java |
| 36 | +BuiltStatement selectAll1 = QueryBuilder.select("id", "t").from("test", "test"); |
| 37 | +ResultSet rs = session.execute(selectAll1); |
| 38 | +for (Row row: rs) { |
| 39 | + System.out.println(row); |
| 40 | +} |
| 41 | +``` |
| 42 | + |
| 43 | +Note: The call `select("column1", "column2")` is really a shortcut for a chain of calls |
| 44 | +`select().column("column1").column("column2")`. |
| 45 | + |
| 46 | +Please note that you can't pass the `*` as column name to select all columns--if you do |
<
D28D
tr class="diff-line-row"> | 47 | +this, you'll get an exception about unknown column. To select all columns you either need to use | | 48 | +`select` in combination with `all` function, or simply don't specify a list of columns: |
| 49 | + |
| 50 | +```java |
| 51 | +BuiltStatement selectAll2 = QueryBuilder.select().all().from("test", "test"); |
| 52 | +BuiltStatement selectAll3 = QueryBuilder.select().from("test", "test"); |
| 53 | +``` |
| 54 | + |
| 55 | +Besides selection of the specific columns, it's also possible to call arbitrary CQL |
| 56 | +function by using the `fcall` method (this is just example, don't do this on real data): |
| 57 | + |
| 58 | +```java |
| 59 | +BuiltStatement sum = QueryBuilder.select().fcall("sum", column("id")).as("sum_id") |
| 60 | + .from("test", "test"); |
| 61 | +``` |
| 62 | + |
| 63 | +Note: When using functions, Cassandra will generate aliases for you, but you can provide |
| 64 | +explicit aliases by using `as` right after a given selector. |
| 65 | + |
| 66 | +For often used functions, there are shortcuts, such as, `countAll`, `ttl`, `writeTime`, |
| 67 | +`uuid`, `now`, `toJson`, etc.: |
| 68 | + |
| 69 | +``` |
| 70 | +BuiltStatement count = QueryBuilder.select().countAll() |
| 71 | + .from("test", "test"); |
| 72 | +
|
| 73 | +BuiltStatement ttlAndWriteTime = QueryBuilder.select().column("id").column("t") |
| 74 | + .ttl("t").as("id_ttl").writeTime("t") |
| 75 | + .from("test", "test"); |
| 76 | +``` |
| 77 | + |
| 78 | +You can also cast the value of the given column to another type by using the `cast` function, |
| 79 | +[specifying](https://docs.datastax.com/en/drivers/java/3.5/com/datastax/driver/core/querybuilder/QueryBuilder.html#cast-java.lang.Object-com.datastax.driver.core.DataType-) |
| 80 | +the column for which it should be performed, and to what type it should be casted. |
| 81 | + |
| 82 | +#### Specifying conditions |
| 83 | + |
| 84 | +Selection of data rarely happen on the whole table--in most cases, people are interested |
| 85 | +in particular rows, located in one or several partitions. Conditions are specified by |
| 86 | +using the `where` call, like this: |
| 87 | + |
| 88 | +```java |
| 89 | +BuiltStatement selectOne = QueryBuilder.select().from("test", "test") |
| 90 | + .where(QueryBuilder.eq("id", 1)); |
| 91 | +``` |
| 92 | + |
| 93 | +The `where` function accepts the `Clause` object that is generated by calling |
| 94 | +`QueryBuilder`'s |
| 95 | +[functions](https://docs.datastax.com/en/drivers/java/3.5/com/datastax/driver/core/querybuilder/QueryBuilder.html#eq-java.lang.Iterable-java.lang.Iterable-), |
| 96 | +such as, `eq`, `ne`, `lt`, `in`, `contains`, `notNull`, etc. In most cases, these |
| 97 | +functions receive 2 arguments: the name of the column, and the value to compare, but there |
| 98 | +are also variants that receive 2 iterables for columns and values correspondingly. |
| 99 | + |
| 100 | +Note: as queries are becoming more and more complex, repeating `QueryBuilder` at all |
| 101 | +places will make code less readable. In this case to simplify the code you can import all |
| 102 | +(or only required) static functions of the `QueryBuilder` class (this is the same example |
| 103 | +from above): |
| 104 | + |
| 105 | +```java |
| 106 | +import static com.datastax.driver.core.querybuilder.QueryBuilder.*; |
| 107 | + |
| 108 | +//... |
| 109 | + |
| 110 | +BuiltStatement selectOne = QueryBuilder.select().from("test", "test") |
| 111 | + .where(eq("id", 1)); |
| 112 | +``` |
| 113 | + |
| 114 | +In case if you need to specify complex conditions, you can chain additional clauses |
| 115 | +together with the `and` operator, that accepts the same clauses as `where`: |
| 116 | + |
| 117 | +```java |
| 118 | +BuiltStatement select = QueryBuilder.select().from("test", "test") |
| 119 | + .where(eq("id", "1")).and(eq("txt", "test")); |
| 120 | +``` |
| 121 | + |
| 122 | +#### Other selection options |
| 123 | + |
| 124 | +For `SELECT` statements you can also specify a lot of different options: |
| 125 | + - `allowFiltering` generates a corresponding `ALLOW FILTERING` part of query (***only use if you know what you're doing!***); |
| 126 | + - `limit` and `perPartitionLimit` allows to specify the amount of data to fetch; |
| 127 | + - `groupBy` performs grouping of data; |
| 128 | + - `orderBy` allows to specify sorting direction for specified clustering columns; |
| 129 | + |
| 130 | +This very "artificial" example shows the use for some of them: |
| 131 | + |
| 132 | +```java |
| 133 | +BuiltStatement selectOne = QueryBuilder.select().from("test") |
| 134 | + .where(QueryBuilder.eq("id", 1)).limit(1).allowFiltering() |
| 135 | + .perPartitionLimit(1).orderBy(desc("id")); |
| 136 | +``` |
| 137 | + |
| 138 | +### Inserting data |
| 139 | + |
| 140 | +Insertion of data is straightforward--you specify the target table in a call to |
| 141 | +`insertInto`, and then provide values to insert either by chaining several calls to the |
| 142 | +`value` function, or by using the `values` function and passing lists or arrays of column |
| 143 | +names and their corresponding values. The following 2 examples are equivalent: |
| 144 | + |
| 145 | +```java |
| 146 | +QueryBuilder.insertInto("test").value("id", 4).value("t", "test 4"); |
| 147 | +QueryBuilder.insertInto("test").values(Arrays.asList("id", "t"), Arrays.asList(4, "test 4")); |
| 148 | +``` |
| 149 | + |
| 150 | +You can also insert JSON-formatted data by calling the `json` function & passing the data: |
| 151 | + |
| 152 | +```java |
| 153 | +QueryBuilder.insertInto("test").json("{\"id\":4, \"t\":\"test 4\"}"); |
| 154 | +``` |
| 155 | + |
| 156 | +`QueryBuilder` also allows generation of the statement that use lightweight |
| 157 | +transactions (LWT) to check that inserted data doesn't exist yet. You just need to add |
| 158 | +the call to `ifNotExists` to the statement: |
| 159 | + |
| 160 | +```java |
| 161 | +QueryBuilder.insertInto("test").value("id", 4).ifNotExists(); |
| 162 | +``` |
| 163 | + |
| 164 | +It is also possible to specify additional metadata for inserted data, such as TTL (time to live) or |
| 165 | +timestamp. This is achieved with the `using` method and providing the `Using` |
| 166 | +object that is generated either by `ttl`, or `timestamp` functions of the `QueryBuilder` class. If |
| 167 | +you want to specify both, you need to chain them together with the `and` operator: |
| 168 | + |
| 169 | +```java |
| 170 | +QueryBuilder.insertInto("test").value("id", 4).using(ttl(10)).and(timestamp(1000)); |
| 171 | +``` |
| 172 | + |
| 173 | +Besides this, for newer versions of Cassandra it's possible to specify additional |
| 174 | +parameters, such as `DEFAULT UNSET` & `DEFAULT NULL` in the `INSERT INTO ... JSON` |
| 175 | +statements, by using `defaultUnset` & `defaultNull` correspondingly. |
| 176 | + |
| 177 | +### Update statements |
| 178 | + |
| 179 | +Updating the data is also relatively straightforward: you specify the data to update, |
| 180 | +condition, and additional options if necessary: |
| 181 | + |
| 182 | +```java |
| 183 | +BuiltStatement updateStatement = QueryBuilder.update("test").with(set("test", 1)) |
| 184 | + .where(eq("id", 1)); |
| 185 | +``` |
| 186 | + |
| 187 | +The first update operation is passed as an argument to the `with` function, and additional |
| 188 | +operations could be chained via `and` calls: |
| 189 | + |
| 190 | +```java |
| 191 | +BuiltStatement updateStatement = QueryBuilder.update("test").with(set("t", "test 1")) |
| 192 | + .and(set("x", 10)).where(eq("id", 1)); |
| 193 | +``` |
| 194 | + |
| 195 | +Besides the most often used `set` operation, there is a lot of operations for work with |
| 196 | +all types of collections (lists, maps & sets): `add`, `discard`, `prepend`, `put`, |
| 197 | +`remove`, `setIdx`, etc. For the full list of operations, see the [QueryBuilder]'s documentation. |
| 198 | + |
| 199 | +To update counters you can use the `incr` & `decr` functions that take the column name, |
| 200 | +and the value by which column will be increased or decreased: |
| 201 | + |
| 202 | +```java |
| 203 | +BuiltStatement query = QueryBuilder.update("counters") |
| 204 | + .with(incr("counter", 1)).where(eq("id", 1)); |
| 205 | +``` |
| 206 | + |
| 207 | +Similarly to insert statements, it's also possible to perform conditional updates by |
| 208 | +calling either `ifExists` (to perform the update only if the entry exists), or by calling |
| 209 | +`onlyIf` with a `Clause` object--in this case the row will be updated only if the clause |
| 210 | +returns true: |
| 211 | + |
| 212 | +```java |
| 213 | +Statement updateStatement = QueryBuilder.update("test").with(set("t", "test 1")) |
| 214 | + .where(eq("id", 1)).ifExists(); |
| 215 | +``` |
| 216 | + |
| 217 | +Setting the TTL & write timestamp is done the same way as for insert statements. |
| 218 | + |
| 219 | +### Deleting data |
| 220 | + |
| 221 | +You can delete either the whole row matching your condition: |
| 222 | + |
| 223 | +```java |
| 224 | +BuiltStatement deleteStmt = QueryBuilder.delete().from("test") |
| 225 | + .where(eq("id", "1")).and(eq("txt", "test")); |
| 226 | +``` |
| 227 | + |
| 228 | +or specify a list of columns to delete: |
| 229 | + |
| 230 | +```java |
| 231 | +BuiltStatement deleteStmt = QueryBuilder.delete("col1", "col2").from("test") |
| 232 | + .where(eq("id", "1")).and(eq("txt", "test")); |
| 233 | +``` |
| 234 | + |
| 235 | +Specification of conditions is similar to the other operations described above, including |
| 236 | +conditional deletes with `ifExists` & `onlyIf`. |
| 237 | + |
| 238 | +### Prepared statements |
| 239 | + |
| 240 | +If you're repeating the same operation very often, the more effective way will be to |
| 241 | +create a [prepared statement](../prepared/) from the `BuiltStatement`. To do this, instead |
| 242 | +of the real values, use bind markers created either by calling `bindMarker` (which generates |
| 243 | +a positional placeholder), or by calling `bindMarker("name")` (which creates a named |
| 244 | +placeholder). After the statement is generated, just prepare it as usual, then bind, and |
| 245 | +execute: |
| 246 | + |
| 247 | +```java |
| 248 | +BuiltStatement selectOne2 = QueryBuilder.select().from("test", "test") |
| 249 | + .where(eq("id", bindMarker())); |
| 250 | +PreparedStatement preparedStatement = session.prepare(selectOne2); |
| 251 | +ResultSet rs = session.execute(preparedStatement.bind(1)); |
| 252 | +``` |
| 253 | + |
| 254 | +### Setting additional options |
| 255 | + |
| 256 | +As in the case of regular statements, you can also set options on built statements, |
| 257 | +such as the consistency level (with `setConsistencyLevel`), enable/disable tracing |
| 258 | +(with `enableTracing`/`disableTracing`), specify retry policy (with `setRetryPolicy`), etc. |
| 259 | + |
| 260 | +Note: the call to these functions changes the object type from `BuiltStatement` to |
| 261 | +`Statement` or `RegularStatement`, so you won't be able to use functions specific to |
| 262 | +`BuiltStatement` without explicit casting. |
| 263 | + |
| 264 | + |
| 265 | + |
| 266 | +[QueryBuilder]: https://docs.datastax.com/en/drivers/java/3.5/com/datastax/driver/core/querybuilder/QueryBuilder.html |
| 267 | +[TableMetadata]: https://docs.datastax.com/en/drivers/java/3.5/com/datastax/driver/core/TableMetadata.html |
| 268 | +[SchemaBuilder]: https://docs.datastax.com/en/drivers/java/3.5/com/datastax/driver/core/schemabuilder/SchemaBuilder.html |
0 commit comments