<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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.
-->

## Query methods

Annotate a DAO method with [@Query] to provide your own query string:

```java
@Dao
public interface SensorReadingDao {
  @Query("SELECT count(*) FROM sensor_readings WHERE id = :id")
  long countById(int id);
}
```

This is the equivalent of what was called "accessor methods" in the driver 3 mapper.

### Parameters

The query string will typically contain CQL placeholders. The method's parameters must match those
placeholders: same name and a compatible Java type.

```java
@Query("SELECT count(*) FROM sensor_readings WHERE id = :id AND year = :year")
long countByIdAndYear(int id, int year);
```

The annotation can define a [null saving strategy](../null_saving/README.md) that applies to the method
parameters.

A `Function<BoundStatementBuilder, BoundStatementBuilder>` or `UnaryOperator<BoundStatementBuilder>`
can be added as the **last** parameter. It will be applied to the statement before execution. This
allows you to customize certain aspects of the request (page size, timeout, etc) at runtime. See
[statement attributes](../statement_attributes/README.md).

### Return type

The method can return:

* `void`.

* a `boolean` or `Boolean`, which will be mapped to [ResultSet#wasApplied()]. This is intended for
  conditional queries.
  
* a `long` or `Long`, which will be mapped to the first column of the first row, expecting CQL type
  `BIGINT`. This is intended for count queries. The method will fail if the result set is empty, or
  does not match the expected format.
  
* a [Row]. This means the result is not converted, the mapper only extracts the first row of the
  result set and returns it. The method will return `null` if the result set is empty.

* a single instance of an [Entity](../../entities/README.md) class. The method will extract the first row and
  convert it, or return `null` if the result set is empty.
  
* an [Optional] of an entity class. The method will extract the first row and convert
    it, or return `Optional.empty()` if the result set is empty.

* a [ResultSet]. The method will return the raw query result, without any conversion.

* a [BoundStatement]. This is intended for queries where you will execute this statement later
  or in a batch.

* a [PagingIterable]. The method will convert each row into an entity instance.

* a [Stream]. The method will convert each row into an entity instance. For details about the
  stream's characteristics, see [PagingIterable.spliterator].

* a [CompletionStage] or [CompletableFuture] of any of the above. The method will execute the query
  asynchronously. Note that for result sets and iterables, you need to switch to the asynchronous
  equivalent [AsyncResultSet] and [MappedAsyncPagingIterable] respectively.
  
* a [ReactiveResultSet], or a [MappedReactiveResultSet] of the entity class.

* a [custom type](../custom_types/README.md).

### Target keyspace and table

To avoid hard-coding the keyspace and table name, the query string supports 3 additional
placeholders: `${keyspaceId}`, `${tableId}` and `${qualifiedTableId}`. They get substituted at DAO
initialization time, with the [keyspace and table that the DAO was built
with](../../mapper/README.md#dao-factory-methods).

For example, given the following:

```java
@Dao
public interface TestDao {
  @Query("SELECT * FROM ${keyspaceId}.${tableId}")
  ResultSet queryFromKeyspaceAndTable();

  @Query("SELECT * FROM ${qualifiedTableId}")
  ResultSet queryFromQualifiedTable();
}

@Mapper
public interface TestMapper {
  @DaoFactory
  TestDao dao(@DaoKeyspace String keyspace, @DaoTable String table);

  @DaoFactory
  TestDao dao(@DaoTable String table);
}

TestDao dao1 = mapper.dao("ks", "t");
TestDao dao2 = mapper.dao("t");
```

Then:

* `dao1.queryFromKeyspaceAndTable()` and `dao1.queryFromQualifiedTable()` both execute `SELECT *
  FROM ks.t`.
* `dao2.queryFromKeyspaceAndTable()` fails: no keyspace was specified for this DAO, so
  `${keyspaceId}` can't be substituted.
* `dao1.queryFromQualifiedTable()` executes `SELECT * FROM t`. In other words, `${qualifiedTableId}`
  uses the keyspace if it is available, but resolves to the table name only if it isn't. Whether the
  query succeeds or not depends on whether the session that the mapper was built with has a [default
  keyspace].

[default keyspace]:          https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/session/SessionBuilder.html#withKeyspace-com.datastax.oss.driver.api.core.CqlIdentifier-
[@Query]:                    https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/mapper/annotations/Query.html
[AsyncResultSet]:            https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/AsyncResultSet.html
[ResultSet]:                 https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html
[ResultSet#wasApplied()]:    https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/ResultSet.html#wasApplied--
[MappedAsyncPagingIterable]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/MappedAsyncPagingIterable.html
[PagingIterable]:            https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/PagingIterable.html
[PagingIterable.spliterator]: https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/PagingIterable.html#spliterator--
[Row]:                       https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/Row.html
[BoundStatement]:            https://docs.datastax.com/en/drivers/java/4.17/com/datastax/oss/driver/api/core/cql/BoundStatement.html
[ReactiveResultSet]:         https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/core/cql/reactive/ReactiveResultSet.html
[MappedReactiveResultSet]:   https://docs.datastax.com/en/drivers/java/4.17/com/datastax/dse/driver/api/mapper/reactive/MappedReactiveResultSet.html

[CompletionStage]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html
[CompletableFuture]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html
[Optional]: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
[Stream]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
