agentsclimarketplace

Kora database cassandra

Skill kora-projects/kora-skills/plugins/kora-v1/skills/kora-database-cassandra

Kora Cassandra/ScyllaDB repositories over the DataStax driver via CassandraDatabaseModule. Covers @Repository extends CassandraRepository, @Query CQL, @EntityCassandra DAO records, @Column/@Id, @UDT user-defined types, @Batch writes, @CassandraProfile per-method consistency, custom CassandraRowMapper/CassandraResultSetMapper/CassandraParameterColumnMapper, and async signatures (CompletionStage, Mono/Flux, Kotlin suspend/Flow). Use when adding a Cassandra repository, mapping rows or UDTs, tuning consistency/timeout under cassandra.basic.request, or wiring contact points and keyspace.From its SKILL.md

Install
npx -y skills add kora-projects/kora-skills --skill kora-database-cassandra

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • reads credentialsReads from 2 credential sources: `CASSANDRA_USER` and 1 more.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

10.9 KB, ~2.6k tokens by cl100k_base, as published. Nobody here has run it

Kora Database Cassandra Skill

Focus: Cassandra/ScyllaDB distributed database integration using DataStax Java Driver 4.x.

Use for: High-write-throughput, horizontally-scalable NoSQL workloads with tunable consistency levels, time-series data, event sourcing, and distributed systems requiring eventual consistency.

Read this first when:

  • Adding a Cassandra repository with @Repository and CQL queries
  • Modeling entities with @EntityCassandra, @UDT for user-defined types
  • Configuring profile-based consistency levels and request timeouts
  • Implementing async signatures with CompletionStage, Reactor, or Kotlin Flow

Quick Start

1. Add Dependency

All Kora artifacts inherit their version from the kora-parent BOM; never pin individual ru.tinkoff.kora:* versions. Annotation processing is mandatory — without it no repository implementation is generated.

dependencies {
    koraBom platform("ru.tinkoff.kora:kora-parent:1.2.17")
    annotationProcessor "ru.tinkoff.kora:annotation-processors"   // Java
    // ksp "ru.tinkoff.kora:symbol-processors"                    // Kotlin (instead of annotationProcessor)

    implementation "ru.tinkoff.kora:database-cassandra"
    implementation "ru.tinkoff.kora:config-hocon"
    implementation "ru.tinkoff.kora:logging-logback"

    // Optional: only when repository methods return Mono/Flux
    implementation "io.projectreactor:reactor-core:3.6.18"
}

2. Enable Module

@KoraApp
public interface Application extends CassandraDatabaseModule {}

3. Define Entity

@Table("users")
@EntityCassandra
public record User(
    @Column("id") @Id UUID id,
    @Column("name") String name,
    @Column("email") String email,
    @Column("created_at") Instant createdAt,
    @Column("nickname") @Nullable String nickname
) {}

4. Create Repository

@Repository
public interface UserRepository extends CassandraRepository {
    
    @Query("SELECT * FROM users WHERE id = :id")
    @Nullable
    User findById(UUID id);
    
    @Query("SELECT * FROM users")
    List<User> findAll();
    
    @Query("INSERT INTO users (id, name, email, created_at) VALUES (:user.id, :user.name, :user.email, :user.createdAt)")
    void insert(User user);
    
    @Query("DELETE FROM users WHERE id = :id")
    void deleteById(UUID id);
}

Entity parameter binding: when a method parameter is an entity object, each column is bound through the dotted accessor :param.field (e.g. :user.id), not a bare :id. A bare :id only resolves when id is itself the name of a method parameter (as in findById(UUID id)).

5. Configure Connection

cassandra {
    auth {
        login = ${CASSANDRA_USER}
        password = ${CASSANDRA_PASS}
    }
    basic {
        contactPoints = ["localhost:9042"]
        dc = "datacenter1"
        sessionKeyspace = "mykeyspace"
        request {
            timeout = 5s
        }
    }
    telemetry {
        logging {
            enabled = true
        }
    }
}

Basic CRUD Patterns

Insert

@Query("INSERT INTO users (id, name, email) VALUES (:user.id, :user.name, :user.email)")
void insert(User user);

// Batch insert: one single-row INSERT bound to entity fields, parameter marked @Batch
@Query("INSERT INTO users (id, name, email) VALUES (:user.id, :user.name, :user.email)")
void insertBatch(@Batch List<User> user);

// Conditional insert (LWT)
@Query("INSERT INTO users (id, name) VALUES (:user.id, :user.name) IF NOT EXISTS")
boolean insertIfNotExists(User user);

Select

@Query("SELECT * FROM users WHERE id = :id")
@Nullable
User findById(UUID id);

@Query("SELECT * FROM users WHERE id IN :ids")
List<User> findByIds(List<UUID> ids);

@Query("SELECT * FROM users LIMIT 100")
List<User> findFirst100();

Update

@Query("UPDATE users SET name = :user.name, email = :user.email WHERE id = :user.id")
void update(User user);

// Conditional update (LWT)
@Query("UPDATE users SET email = :email WHERE id = :id IF email = :oldEmail")
boolean updateIfEmailMatches(UUID id, String email, String oldEmail);

Delete

@Query("DELETE FROM users WHERE id = :id")
void deleteById(UUID id);

@Query("TRUNCATE users")
void deleteAll();

Async Signatures

CompletionStage (Recommended)

@Query("SELECT * FROM users WHERE id = :id")
CompletableFuture<User> findByIdAsync(UUID id);

@Query("INSERT INTO users (id, name) VALUES (:user.id, :user.name)")
CompletionStage<Void> insertAsync(User user);

Project Reactor

@Query("SELECT * FROM users WHERE id = :id")
Mono<User> findByIdReactive(UUID id);

@Query("SELECT * FROM users")
Flux<User> findAllReactive();

Kotlin Coroutines

@Query("SELECT * FROM users WHERE id = :id")
suspend fun findByIdAsync(id: UUID): User?

@Query("SELECT * FROM users")
fun findAllFlow(): Flow<User>

UDT Support

@UDT
public record AddressUDT(
    @Column("street") String street,
    @Column("city") String city,
    @Column("zipCode") String zipCode
) {}

@Table("users")
@EntityCassandra
public record User(
    @Column("id") @Id UUID id,
    @Column("name") String name,
    @Column("address") AddressUDT address
) {}

Profile-Based Consistency

All request-level tuning (consistency, timeout, page size) lives under basic.request. A profile overrides any basic.request.* (and advanced.*) key for the queries that reference it.

Configuration

cassandra {
    basic {
        request {
            consistency = "QUORUM"        // default consistency for all queries
            serialConsistency = "SERIAL"  // consistency for lightweight transactions
            timeout = "5s"
        }
    }
    profiles {
        analytics {
            basic.request.consistency = "ONE"
            basic.request.timeout = "30s"
        }
        critical {
            basic.request.consistency = "ALL"
            basic.request.timeout = "5s"
        }
    }
}

Using Profiles

@CassandraProfile targets methods only (@Target(ElementType.METHOD)). It cannot be placed on the repository interface — apply it per @Query method.

@Repository
public interface EventRepository extends CassandraRepository {

    @CassandraProfile("analytics")
    @Query("SELECT * FROM events WHERE type = :type ALLOW FILTERING")
    List<Event> findByType(String type);
}

Assets

Entity Templates

TemplateLanguageDescription
cassandra-entity-single-id.java.templateJavaEntity with single-field ID
cassandra-entity-single-id.kt.templateKotlinData class with single-field ID
cassandra-entity-composite-id.java.templateJavaEntity with composite partition key
cassandra-entity-composite-id.kt.templateKotlinData class with composite key
cassandra-entity-with-udt.java.templateJavaEntity with UDT and List<UDT>

Repository Templates

TemplateLanguageDescription
cassandra-crud-single-id-repository.java.templateJavaCRUD with LWT support
cassandra-crud-single-id-repository.kt.templateKotlinKotlin CRUD repository
cassandra-crud-composite-id-repository.java.templateJavaCRUD for composite key
cassandra-crud-composite-id-repository.kt.templateKotlinKotlin composite key CRUD
cassandra-async-repository.java.templateJavaCompletionStage async
cassandra-async-repository.kt.templateKotlinKotlin async
cassandra-lwt-repository.java.templateJavaLightweight transactions
cassandra-lwt-repository.kt.templateKotlinKotlin LWT
cassandra-kotlin-coroutine-repository.kt.templateKotlinKotlin coroutines + Flow

UDT Templates

TemplateLanguageDescription
cassandra-udt.java.templateJavaBasic UDT (Address example)
cassandra-udt.kt.templateKotlinKotlin UDT data class
cassandra-nested-udt.java.templateJavaNested UDT structure

Reference Documents

DocumentDescription
CQL Repository Reference@EntityCassandra, CQL queries, custom mappers, return types
UDT Mapping Reference@UDT, nested types, collections of UDTs
Consistency ReferenceConsistency levels, profiles, retry policies
Async Patterns ReferenceCompletionStage, Reactor, Kotlin Flow
Cassandra Config ReferenceConnection, timeouts, load balancing, multiple keyspaces

Best Practices

  1. Use @EntityCassandra on DAO records — generates the Cassandra row and result-set mappers eagerly at compile time instead of in a late generation round.
  2. Add @Column to every component — makes the CQL column name explicit (e.g. Java createdAt -> column created_at).
  3. @Id is optional — Cassandra needs no special primary-key marker; add @Id only when you use SQL macros.
  4. Use @Nullable, not Optional — for nullable single-row return values.
  5. Extend CassandraRepository — required base interface for the generator.
  6. Keep DTOs and DAOs separate — HTTP @Json DTOs are not Cassandra entities.
  7. Apply @CassandraProfile per method — separate analytics from critical reads.
  8. Model tables from query patterns — avoid unbounded SELECT ... FROM table scans in production.

Common Pitfalls

SymptomFix
@CassandraProfile rejected on the interfaceIt is @Target(METHOD) — move it onto each @Query method.
Config key basic.consistency ignoredConsistency lives under basic.request.consistency.
Profile timeout ignored (requestTimeout)Override basic.request.timeout inside the profile, not a flat key.
Complex field not mappedNested types need @UDT; collections of UDTs need FROZEN in CQL.
Required field is not nullable but row has nullAdd @Nullable to the optional record component.
Repository method not generatedAnnotation processor missing, or the interface does not extend CassandraRepository.

What ships with it: 25 files

83.4 KB alongside SKILL.md

evals/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.