javaspring-bootcassandraproject-reactorspring-data-cassandra

Unable to access a Cassandra table with a Composite key using Reactive Cassandra


I am using Spring-Reactive and Reactive-Cassandra [spring-boot-starter-data-cassandra-reactive] to access tables on Cassandra. I am able to access simple tables with a single column representing the Primary Key such as:

user_name: partition_key
address: regular

But when it comes to a more complicated table such as the following, I am unable to fetch any info from Cassandra:

user_name: partition_key
department_name: clustering
address: regular

Following is how I have written my @Configuration and @Repository in Spring reactive:

Config:

@AllArgsConstructor
@Table(value = "user_table")
public class UserConfig {
    @Getter
    @PrimaryKey
    private UserKey key;

    @Column("address")
    @Getter
    private String address;
}

Primary Key Class:

@Getter
@PrimaryKeyClass
@AllArgsConstructor
public class UserKey {
    @PrimaryKeyColumn(name = "user_name", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
    private String userName;
    @PrimaryKeyColumn(name = "department_name", ordinal = 1, type = PrimaryKeyType.CLUSTERED)
    private String departmentName;
}

Repository:

@Repository
public interface UserRepository extends ReactiveCassandraRepository<UserConfig, UserKey> {
    Mono<UserConfig> findByKeyUserNameAndKeyDepartmentName(String userName, String departmentName);
}

My Cassandra config class is as follows:

@Configuration
@EnableReactiveCassandraRepositories
public class CassandraConfig extends AbstractReactiveCassandraConfiguration {
    @Value("${spring.cassandra.contact-points}")
    private String contactPoints;

    @Value("${spring.cassandra.local-datacenter}")
    private String localDatacenter;
    
    @Value("${spring.cassandra.port}")
    private int port;
    
    @Value("${spring.cassandra.keyspace-name}")
    private String keySpace;
    
    @Value("${spring.cassandra.username}")
    private String username;
    
    @Value("${spring.cassandra.password}")
    private String password;

    @Value("${spring.cassandra.schema-action}")
    private SchemaAction schemaAction;

    @Override
    protected String getContactPoints() {
        return contactPoints;
    }

    @Override
    protected int getPort() {
        return port;
    }

    @Override
    public SchemaAction getSchemaAction() {
        return schemaAction;
    }

    @Override
    protected String getKeyspaceName() {
        return keySpace;
    }

    @Bean
    @Override
    public CqlSessionFactoryBean cassandraSession() {
        CqlSessionFactoryBean cqlSessionFactoryBean = new CqlSessionFactoryBean();
        cqlSessionFactoryBean.setUsername(username);
        cqlSessionFactoryBean.setPassword(password);
        cqlSessionFactoryBean.setKeyspaceName(keySpace);
        cqlSessionFactoryBean.setLocalDatacenter(localDatacenter);
        cqlSessionFactoryBean.setPort(port);
        cqlSessionFactoryBean.setContactPoints(contactPoints);
        return cqlSessionFactoryBean;
    }
}

All the documentation I have followed does the exact same thing that I am doing above. What am I missing here? Kindly help.


Solution

  • This worked for me:

    Table Class:

    @Data
    @AllArgsConstructor
    @Table(value = "user_table")
    public class UserConfig implements Serializable {
        @PrimaryKeyColumn(name = "user_name", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
        private String userName;
        @PrimaryKeyColumn(name = "department_name", ordinal = 1, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.ASCENDING)
        private String departmentName;
        @Column(value = "address")
        private String address;
    }
    

    Repository:

    @Repository
    public interface UserRepository extends ReactiveCassandraRepository<UserConfig, String> {
    
        @Query("SELECT * from user_table where user_name=?0")
        Flux<UserConfig> findByUserName(String userName);
    
        @Query("SELECT * from user_table where user_name=?0 and department_name=?1")
        Flux<UserConfig> findByUserNameAndDepartmentName(String userName, String departmentName);
    }
    

    The change mainly here is with respect to how the Repository interface methods are defined with @Query.