We now support Optimistic Locking for insert, update and delete operations leveraging Cassandra's lightweight transaction support. Modifying statements are enhanced with IF conditions to conditionally insert and modify rows and to prevent concurrent modifications by throwing OptimisticLockingFailureException.
@Table
class Person {
@Id String id;
String firstname;
String lastname;
@Version Long version;
}
Person daenerys = template.insert(new Person("Daenerys"));
Person tmp = template.findOne(query(where("id").is(daenerys.getId())), Person.class);
daenerys.setLastname("Targaryen");
template.save(daenerys);
template.save(tmp); // throws OptimisticLockingFailureException
We promote the usage of reified Kotlin API usage (myMethod<Person>() instead of myMethod(Person::class)) to facilitate a single and more idiomatic approach to Kotlin API usage.
Extension methods accepting KClass are deprecated now.
We now support conditions in lightweight transactions for UPDATE and DELETE statements. Conditions are Filter objects similar to the WHERE clause. Conditions are supported for entity and query-based update/delete methods.
UpdateOptions options = UpdateOptions.builder().ifCondition(where("firstname").is("Walter")).build();
User user = new User("heisenberg", "Walter", "White");
template.update(user, options);
DeleteOptions options = DeleteOptions.builder().ifCondition(where("counter").is(42)).build();
Query query = Query.query(where("id").is("heisenberg")).queryOptions(options);
template.delete(query, User.class);
BasicCassandraPersistentEntity.doWithAssociations(…) now no longer throws UnsupportedCassandraOperationException when trying to traverse associations. Calling doWithAssociations results in a no-op as there are no associations.
Related ticket: DATAREST-1337.
This commit introduces Coroutines support for ReactiveFluentCassandraOperations API via Kotlin extensions that provide suspendable functions prefixed by `await` or suffixed by `AndAwait` for Mono based APIs.
Extensions for Flux will be added when Kotlin/kotlinx.coroutines#254 is fixed.
We now support derived queries using the Between keyword. Between query parts map to either two simple parameters (findByAgeBetween(int from, int to)) or a Range<T> parameter that defines inclusive/exclusive boundary comparison (findByAgeBetween(Range<Integer> age)).
Between queries use are issued by default as exclusive ranges so findByAgeBetween(int from, int to) maps to age > from AND age < to.
Guava has removed Futures#transform method without the Executor parameter in version 26.0-jre
DefaultBridgeReactiveSession fails with NoSuchMethod exception when used with Guava 26.0-jre+.
Original pull request: #137.
We now support read-only properties by annotating such properties with @ReadOnlyProperty. Read-only properties are read from results but never written (i.e. through INSERT or UPDATE) back to Cassandra.
Read-only properties can still be updated by using the Update/Query API.
class Person {
@Id String id;
String firstname;
String lastname;
@ReadOnlyProperty String externallyUpdatedProperty;
}
CassandraTemplate template = …
Person person = …
template.insert(person);
We now limit the selected fields when using projections in repository query methods and by using query operations. Queries that return either a closed interface projection or DTO projection are inspected for the select fields and only these fields are included in the SELECT list.
CassandraBatchOperations.delete(…) and ReactiveCassandraBatchOperations.delete(…) methods now accept WriteOptions and subclasses (such as DeleteOptions) to adjust delete behavior.
Related ticket: DATACASS-606.
We now support lightweight transactions for entity deletion through DeleteOptions.
User user = …
DeleteOptions options = DeleteOptions.builder().withIfExists().build();
boolean applied = template.delete(user, options);
We now apply custom conversions for collection elements if a read converter is registered. Previously, we used the presence/absence of a write converter to initiate conversion for collections.
cassandraTemplate(…) and cqlTemplate(…) bean methods now use the template implementation class as their return type to provide the most specific type information for the bean declaration.
Previously, we declared the bean type using their interface which made it impossible to resolve beans using the template class.