com.datastax.oss.driver.api.mapper.annotations.Update Maven / Gradle / Ivy
/*
* 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.
*/
package com.datastax.oss.driver.api.mapper.annotations;
import com.datastax.dse.driver.api.core.cql.reactive.ReactiveResultSet;
import com.datastax.oss.driver.api.core.CqlIdentifier;
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.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.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.Function;
import java.util.function.UnaryOperator;
/**
* Annotates a {@link Dao} method that updates one or more instances of an {@link Entity}-annotated
* class.
*
* Example:
*
*
* @Dao
* public interface ProductDao {
* @Update
* void update(Product product);
* }
*
*
* Parameters
*
* The first parameter must be an entity instance. All of its non-PK properties will be
* interpreted as values to update.
*
*
* - If {@link #customWhereClause()} is empty, the mapper defaults to an update by primary key
* (partition key + clustering columns). The WHERE clause is generated automatically, and
* bound with the PK components of the provided entity instance. The query will update at most
* one row.
*
- If {@link #customWhereClause()} is not empty, it completely replaces the WHERE clause. If
* the provided string contains placeholders, the method must have corresponding additional
* parameters (same name, and a compatible Java type):
*
* @Update(customWhereClause = "description LIKE :searchString")
* void updateIfDescriptionMatches(Product product, String searchString);
*
* The PK components of the provided entity are ignored. Multiple rows may be updated.
*
*
* If the query has a {@linkplain #ttl() TTL} or {@linkplain #timestamp() timestamp} with
* placeholders, the method must have corresponding additional parameters (same name, and a
* compatible Java type):
*
*
* @Update(ttl = ":ttl")
* void updateWithTtl(Product product, int ttl);
*
*
*
* @Update(timestamp = ":timestamp")
* void updateWithTimestamp(Product product, long timestamp);
*
*
* 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.
*
* @Update(ifExists = true)
* boolean updateIfExists(Product product);
*
* - a {@link ResultSet}. The method will return the raw query result, without any conversion.
* This is intended for queries with custom IF clauses; when those queries are not applied,
* they return the actual values of the tested columns.
*
* @Update(customIfClause = "description = :expectedDescription")
* ResultSet updateIfDescriptionMatches(Product product, String expectedDescription);
* // if the condition fails, the result set will contain columns '[applied]' and 'description'
*
* - a {@link BoundStatement}. This is intended for queries where you will execute this
* statement later or in a batch:
*
* @Update
* BoundStatement update(Product product);
*
* - a {@link CompletionStage} or {@link CompletableFuture} of any of the above. The mapper will
* execute the query asynchronously. Note that for result sets, you need to switch to the
* asynchronous equivalent {@link AsyncResultSet}.
*
* @Update
* CompletionStage<Void> update(Product product);
*
* @Update(ifExists = true)
* CompletableFuture<Boolean> updateIfExists(Product product);
*
* @Update(customIfClause = "description = :expectedDescription")
* CompletableFuture<AsyncResultSet> updateIfDescriptionMatches(Product product, String expectedDescription);
*
* - a {@link ReactiveResultSet}.
*
* @Update
* ReactiveResultSet updateReactive(Product product);
*
* - a {@linkplain MapperResultProducer custom type}.
*
*
* Target keyspace and table
*
* If a keyspace was specified when creating the DAO (see {@link DaoFactory}), then the generated
* query targets that keyspace. Otherwise, it doesn't specify a keyspace, and will only work if the
* mapper was built from a {@link Session} that has a {@linkplain
* SessionBuilder#withKeyspace(CqlIdentifier) default keyspace} set.
*
*
If a table was specified when creating the DAO, then the generated query targets that table.
* Otherwise, it uses the default table name for the entity (which is determined by the name of the
* entity class and the naming convention).
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Update {
/**
* A custom WHERE clause for the UPDATE query.
*
*
If this is not empty, it completely replaces the WHERE clause in the generated query. Note
* that the provided string must not contain the {@code WHERE} keyword.
*
*
This clause can contain placeholders that will be bound with the method's parameters; see
* the top-level javadocs of this class for more explanations.
*/
String customWhereClause() default "";
/**
* Whether to append an IF EXISTS clause at the end of the generated UPDATE query.
*
*
This is mutually exclusive with {@link #customIfClause()} (if both are set, the mapper
* processor will generate a compile-time error).
*/
boolean ifExists() default false;
/**
* A custom IF clause for the UPDATE query.
*
*
This is mutually exclusive with {@link #ifExists()} (if both are set, the mapper processor
* will generate a compile-time error).
*
*
If this is not empty, it gets added to the generated query. Note that the provided string
* must not contain the {@code IF} keyword.
*
*
This clause can contain placeholders that will be bound with the method's parameters; see
* the top-level javadocs of this class for more explanations.
*/
String customIfClause() default "";
/**
* The TTL (time to live) to use in the generated INSERT query.
*
*
If this starts with ":", it is interpreted as a named placeholder (that must have a
* corresponding parameter in the method signature). Otherwise, it must be a literal integer value
* (representing a number of seconds).
*
*
If the placeholder name is invalid or the literal can't be parsed as an integer (according
* to the rules of {@link Integer#parseInt(String)}), the mapper will issue a compile-time
* warning.
*/
String ttl() default "";
/**
* The timestamp to use in the generated INSERT query.
*
*
If this starts with ":", it is interpreted as a named placeholder (that must have a
* corresponding parameter in the method signature). Otherwise, it must be literal long value
* (representing a number of microseconds since epoch).
*
*
If the placeholder name is invalid or the literal can't be parsed as a long (according to
* the rules of {@link Long#parseLong(String)}), the mapper will issue a compile-time warning.
*/
String timestamp() default "";
/**
* The timeout to use in the generated UPDATE query. Equivalent to {@code USING TIMEOUT
* } clause.
*
* If this starts with ":", it is interpreted as a named placeholder (that must have a
* corresponding parameter in the method signature). Otherwise, it must be a String representing a
* valid CqlDuration.
*
*
If the placeholder name is invalid or the literal can't be parsed as a CqlDuration
* (according to the rules of {@link
* com.datastax.oss.driver.api.core.data.CqlDuration#from(String)}), the mapper will issue a
* compile-time error.
*/
String usingTimeout() default "";
/**
* How to handle null entity properties during the update.
*
*
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;
}