8000 Add documentation about QueryBuilder (#1031) · exploder86/java-driver@ce29eea · GitHub
[go: up one dir, main page]

Skip to content

Commit ce29eea

Browse files
alexotttolbertam
authored andcommitted
Add documentation about QueryBuilder (apache#1031)
1 parent db6c9c2 commit ce29eea

File tree

1 file changed

+265
-2
lines changed

1 file changed

+265
-2
lines changed

manual/statements/built/README.md

Lines changed: 265 additions & 2 deletions
< D28D tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,268 @@
11
## Built statements
22

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.
45

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
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

Comments
 (0)
0