Was this page helpful?
ScyllaDB Java Driver is available under the Apache v2 License. ScyllaDB Java Driver is a fork of DataStax Java Driver. See Copyright here.
Annotate a DAO method with @QueryProvider to delegate the execution of the query to one of your own classes:
@Dao
public interface SensorDao {
@QueryProvider(providerClass = FindSliceProvider.class, entityHelpers = SensorReading.class)
PagingIterable<SensorReading> findSlice(int id, Integer month, Integer day);
}
/* Schema:
CREATE TABLE sensor_reading(sensor_id int, month int, day int, value double,
PRIMARY KEY (id, month, day)
WITH CLUSTERING ORDER BY (month DESC, day DESC);
*/
Use this for requests that can’t be expressed as static query strings. For example, we want the
month
and day
parameters above to be optional:
if both are present, we query for a particular day: WHERE id = ? AND month = ? AND day = ?
if day
is null, we query for the whole month: WHERE id = ? AND month = ?
if month
is also null, we query the whole partition: WHERE id = ?
We assume that you’ve already written a corresponding entity class:
@Entity
public class SensorReading {
@PartitionKey private int id;
@ClusteringColumn(1) private int month;
@ClusteringColumn(2) private int day;
private double value;
// constructors, getters and setters omitted for conciseness
}
@QueryProvider.providerClass() indicates which class to delegate to. The mapper will create one instance for each DAO instance.
This class must expose a constructor that is accessible from the DAO interface’s package.
The first constructor argument must always be MapperContext. This is a utility type that provides access to mapper- and DAO-level state. In particular, this is how you get hold of the session.
If @QueryProvider.entityHelpers() is specified, the constructor must take an
additional EntityHelper argument for each provided entity class. We specified
SensorReading.class
so our argument types are (MapperContext, EntityHelper<SensorReading>)
.
An entity helper is a utility type generated by the mapper. One thing it can do is construct query
templates (with the query builder). We want to retrieve entities so we
use selectStart()
, chain a first WHERE clause for the id (which is always present), and store the
result in a field for later use:
public class FindSliceProvider {
private final CqlSession session;
private final EntityHelper<SensorReading> sensorReadingHelper;
private final Select selectStart;
public FindSliceProvider(
MapperContext context, EntityHelper<SensorReading> sensorReadingHelper) {
this.session = context.getSession();
this.sensorReadingHelper = sensorReadingHelper;
this.selectStart =
sensorReadingHelper.selectStart().whereColumn("id").isEqualTo(bindMarker());
}
... // (to be continued)
@QueryProvider.providerMethod() indicates which method to invoke on the provider class. When it’s not specified (as is our case), it defaults to the same name as the DAO method.
The provider method must be accessible from the DAO interface’s package, and have the same parameters and return type as the DAO method.
Here is the full implementation:
... // public class FindSliceProvider (continued)
public PagingIterable<SensorReading> findSlice(int id, Integer month, Integer day) {
// (1) complete the query
Select select = this.selectStart;
if (month != null) {
select = select.whereColumn("month").isEqualTo(bindMarker());
if (day != null) {
select = select.whereColumn("day").isEqualTo(bindMarker());
}
}
// (2) prepare
PreparedStatement preparedStatement = session.prepare(select.build());
// (3) bind
BoundStatementBuilder boundStatementBuilder =
preparedStatement.boundStatementBuilder().setInt("id", id);
if (month != null) {
boundStatementBuilder = boundStatementBuilder.setInt("month", month);
if (day != null) {
boundStatementBuilder = boundStatementBuilder.setInt("day", day);
}
}
// (4) execute and map the results
return session.execute(boundStatementBuilder.build()).map(sensorReadingHelper::get);
}
}
Retrieve the SELECT query that was started in the constructor, and append additional WHERE clauses as appropriate.
Note that all query builder objects are immutable, so this creates a new instance every time, there is no risk of corrupting the original field.
Prepare the resulting statement.
session.prepare
caches its results, so if we already prepared that particular combination,
there is no network call at this step.
Bind the parameters, according to the WHERE clauses we’ve generated.
Execute the request.
Another useful helper feature is mapping entities to/from low-level driver data structures:
get
extracts a SensorReading
from a Row
, so by mapping it to the ResultSet we get back
the desired PagingIterable
Was this page helpful?
ScyllaDB Java Driver is available under the Apache v2 License. ScyllaDB Java Driver is a fork of DataStax Java Driver. See Copyright here.