springcassandradatastax-java-driverspring-data-cassandra

Create Statement in Spring Data Cassandra


How can I create a Statement using Spring Data Cassandra in a way that spring would handle type conversion as well?

If I have a simple query with simple types, I could write something like this:

SimpleStatement.newInstance("UPDATE User SET name = ? WHERE id = ?", "Soheil", 1);

But when I have a UserDefinedType and I want to create a more complex query, Say table User has a field pictures with type of List<frozen<MyPicture>>, and I want to append to this list using this query:

List<MyPicture> pictures = ...;
SimpleStatement.newInstance("UPDATE User SET profilePictures = profilePictures + ? WHERE id = ?", pictures, userId);

I get a error complaining it cant bind pictures parameter correctly.

Codec not found for requested operation: [null <-> path.to.package.MyPicture]

As I had already tested this query using CassandraRepository and @Query and succeeded, I noticed that somewhere along the way Spring uses MappingCassandraConverter to convert List<MyPicture> into something usable. So I attempted to @Autowire a instance of the converter and converted my List<MyPicture>:

List<MyPicture> pictures = ...;
Object converted = mappingCassandraConverter.convertToColumnType(pictures);
SimpleStatement.newInstance("UPDATE User SET profilePictures = profilePictures + ? WHERE id = ?", converted, userId);

And now it works fine with no error. I was wondering if there's a straightforward way to create a Statement without having to manually inject converter and converting fields?


Solution

  • You are mixing spring-data-cassandra layer and the cassandra-drivers layer, both are working with different sets of objects and annotations and as such mapping will always be needed to move from one layer to another (you already know but mentionning for future reader).

    Cassandra Driver Custom Mappings

    At DataStax driver level it is always possible to map an object into the column you want but you have to define a custom codec and register it in the codec registry, that would explain why you have the codec not found error. https://docs.datastax.com/en/developer/java-driver/4.17/manual/core/custom_codecs/index.html

    Note that the driver also provides an Object Mapping layer, different from Spring data which is out of scope here so get not tricked by things like ObjectMapper and Dao from the drivers documentation

    Spring Data Cassandra

    To explicitly map the Spring entity to Cassandra table the solution is indeed the CassandraConverter as stated in the documentation https://docs.spring.io/spring-data/cassandra/reference/object-mapping.html

    Your Question:

    SimpleStatement is part of the drivers layers so to map with objects it needs some custom codec. You can build your own and add it to the registry but it is better to reuse the one Spring Data team put in place.