All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.oss.driver.api.mapper.annotations.Query 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.oss.driver.api.mapper.annotations;

import com.datastax.dse.driver.api.core.cql.reactive.ReactiveResultSet;
import com.datastax.dse.driver.api.mapper.reactive.MappedReactiveResultSet;
import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.MappedAsyncPagingIterable;
import com.datastax.oss.driver.api.core.PagingIterable;
import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
import com.datastax.oss.driver.api.core.cql.BoundStatement;
import com.datastax.oss.driver.api.core.cql.ResultSet;
import com.datastax.oss.driver.api.core.cql.Row;
import com.datastax.oss.driver.api.core.session.Session;
import com.datastax.oss.driver.api.core.session.SessionBuilder;
import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy;
import com.datastax.oss.driver.api.mapper.result.MapperResultProducer;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.Function;
import java.util.function.UnaryOperator;

/**
 * Annotates a {@link Dao} method that executes a user-provided query.
 *
 * 

Example: * *

 * @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 provided in {@link #value()} will typically contain CQL placeholders. The * method's parameters must match those placeholders: same name and a compatible Java type. * *
 * @Query("SELECT count(*) FROM sensor_readings WHERE id = :id AND year = :year")
 * long countByIdAndYear(int id, int year);
 * 
* *

A {@link Function Function<BoundStatementBuilder, BoundStatementBuilder>} or {@link * UnaryOperator 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. * *

Return type

* * The method can return: * *
    *
  • {@code void}. *
  • a {@code boolean} or {@link Boolean}, which will be mapped to {@link * ResultSet#wasApplied()}. This is intended for conditional queries. *
  • a {@code long} or {@link Long}, which will be mapped to the first column of the first row, * expecting CQL type {@code 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 {@link 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 {@code null} if the result set * is empty. *
  • a single instance of an {@link Entity} class. The method will extract the first row and * convert it, or return {@code null} if the result set is empty. *
  • an {@link Optional} of an entity class. The method will extract the first row and convert * it, or return {@code Optional.empty()} if the result set is empty. *
  • a {@link ResultSet}. The method will return the raw query result, without any conversion. *
  • a {@link BoundStatement}. This is intended for cases where you intend to execute this * statement later or in a batch: *
  • a {@link PagingIterable}. The method will convert each row into an entity instance. *
  • a {@link CompletionStage} or {@link 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 {@link AsyncResultSet} and {@link * MappedAsyncPagingIterable} respectively. *
  • a {@link ReactiveResultSet}, or a {@link MappedReactiveResultSet} of the entity class. *
  • a {@linkplain MapperResultProducer custom type}. *
* *

Target keyspace and table

* * To avoid hard-coding the keyspace and table name, the query string supports 3 additional * placeholders: {@code ${keyspaceId}}, {@code ${tableId}} and {@code ${qualifiedTableId}}. They get * substituted at DAO initialization time, with the keyspace and table that the DAO was built with * (see {@link DaoFactory}). * *

For example, given the following: * *

 * @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: * *
    *
  • {@code dao1.queryFromKeyspaceAndTable()} and {@code dao1.queryFromQualifiedTable()} both * execute {@code SELECT * FROM ks.t}. *
  • {@code dao2.queryFromKeyspaceAndTable()} fails: no keyspace was specified for this DAO, so * {@code ${keyspaceId}} can't be substituted. *
  • {@code dao1.queryFromQualifiedTable()} executes {@code SELECT * FROM t}. In other words, * {@code ${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 {@link * Session} that the mapper was built with has a {@linkplain * SessionBuilder#withKeyspace(CqlIdentifier) default keyspace}. *
*/ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Query { /** * The query string to execute. * *

It can contain CQL placeholders (e.g. {@code :id}) that will be bound with the method's * parameters; and also special text placeholders {@code ${keyspaceId}}, {@code ${tableId}} and * {@code ${qualifiedTableId}} that will be substituted with the keyspace and table that the DAO * was built with. See the top-level javadocs of this class for more explanations. */ String value(); /** * How to handle null query parameters. * *

This defaults either to the {@link DefaultNullSavingStrategy DAO-level strategy} (if set), * or {@link NullSavingStrategy#DO_NOT_SET}. */ NullSavingStrategy nullSavingStrategy() default NullSavingStrategy.DO_NOT_SET; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy