AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Kora Database Jdbc

skill-kora-projects-kora-skills-kora-database-jdbc · by kora-projects

JDBC relational database integration for Kora. Builds compile-time @Repository interfaces extending JdbcRepository with @Query, @EntityJdbc records, @Table/@Column/@Id mapping, SQL macros (%{return#selects}, %{entity#inserts}, %{entity#where = @id}), @Batch, UpdateCount, @Id-on-method generated identifiers, transactions via JdbcConnectionFactory.inTx(), and custom JdbcResultSetMapper/JdbcRowMappe…

No reviews yet
0 installs
18 views
0.0% view→install

Install

$ agentstack add skill-kora-projects-kora-skills-kora-database-jdbc

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-kora-projects-kora-skills-kora-database-jdbc)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Kora Database Jdbc? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Kora Database JDBC

JDBC-based relational database access (PostgreSQL, MySQL, Oracle) with HikariCP. Repositories are @Repository interfaces whose implementations are generated at compile time by the annotation processor — no reflection, no runtime proxies.

> Prefer synchronous repository signatures (Entity, @Nullable Entity, List, UpdateCount). The blocking JDBC driver runs on the executor bound to JdbcDatabase; virtual threads or a fixed pool handle blocking efficiently. Reach for CompletionStage/Mono only when a downstream contract requires it.


Quick Start

1. Dependencies (build.gradle)

dependencies {
    koraBom platform("ru.tinkoff.kora:kora-parent:1.2.17")
    annotationProcessor "ru.tinkoff.kora:annotation-processors"  // mandatory: generates *RepositoryImpl

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

    implementation "org.postgresql:postgresql:42.7.7"  // JDBC driver is required (not bundled)
}

All ru.tinkoff.kora:* artifacts inherit their version from the kora-parent BOM — never pin them individually.

Kotlin: use ksp "ru.tinkoff.kora:symbol-processors" instead of annotationProcessor, and implementation("...") syntax.

2. Plug the module into @KoraApp

@KoraApp
public interface Application extends
        HoconConfigModule,
        LogbackModule,
        JdbcDatabaseModule { }

JdbcDatabaseModule provides JdbcDatabase, its JdbcConnectionFactory, and the JdbcDatabaseConfig reader bound to the db config section.

3. Define an entity with @EntityJdbc

@EntityJdbc
@Table("entities")
public record Entity(
        @Id @Column("id") Long id,
        @Column("value1") int field1,
        @Column("value2") String value2,
        @Nullable @Column("value3") String value3) {}

@EntityJdbc (from ru.tinkoff.kora.database.jdbc) makes the processor generate an optimized result converter. @Table/@Column/@Id come from ru.tinkoff.kora.database.common.annotation.

4. Repository with SQL macros

@Repository
public interface EntityRepository extends JdbcRepository {

    @Query("SELECT %{return#selects} FROM %{return#table} WHERE id = :id")
    @Nullable
    Entity findById(Long id);

    @Query("SELECT %{return#selects} FROM %{return#table}")
    List findAll();

    @Query("INSERT INTO %{entity#inserts}")
    UpdateCount insert(Entity entity);

    @Query("UPDATE %{entity#table} SET %{entity#updates} WHERE %{entity#where = @id}")
    UpdateCount update(Entity entity);

    @Query("DELETE FROM entities WHERE id = :id")
    UpdateCount deleteById(Long id);
}

5. Generated identifier (auto-increment / sequence)

When the database assigns the key, annotate the method with @Id and return the id type, or use RETURNING:

@Query("INSERT INTO %{entity#inserts-= @id}")
@Id
Long insert(Entity entity);          // returns DB-generated key (works for @Batch too)

@Query("INSERT INTO entities(name) VALUES (:entity.name) RETURNING id")
long insertReturning(Entity entity); // explicit RETURNING projection

6. Transactions in a service

@Component
public final class EntityService {
    private final EntityRepository repository;

    public EntityService(EntityRepository repository) {
        this.repository = repository;
    }

    public List saveAll(Entity one, Entity two) {
        return repository.getJdbcConnectionFactory().inTx(() -> {
            repository.insert(one);
            repository.insert(two);
            return List.of(one, two);
        });
    }
}

Every repository method called inside the inTx() lambda joins the same transaction; an exception rolls the whole block back. JdbcConnectionFactory is reachable via repository.getJdbcConnectionFactory() or by injecting JdbcConnectionFactory directly.


Configuration (application.conf)

db {
    jdbcUrl = ${POSTGRES_JDBC_URL}   // required, e.g. "jdbc:postgresql://localhost:5432/postgres"
    username = ${POSTGRES_USER}      // required
    password = ${POSTGRES_PASS}      // required
    poolName = "kora"                // required: Hikari pool name
    maxPoolSize = 10
    minIdle = 0
    connectionTimeout = "10s"        // durations are strings, not millisecond numbers
    idleTimeout = "10m"
    maxLifetime = "15m"
    telemetry.logging.enabled = false
    telemetry.metrics.enabled = true
    telemetry.tracing.enabled = true
}

Externalize every credential with ${VAR} / ${?VAR} / ${?VAR:default}. Full key list and YAML form: [database-jdbc-config-reference.md](references/database-jdbc-config-reference.md).


SQL macros

Macros expand at compile time into SQL the developer could have written by hand. Target a method argument by name or the result via return; separate target and command with #.

| Macro | Expands to | Example result | |-------|-----------|----------------| | %{return#selects} | column list of the return entity | id, value1, value2, value3 | | %{return#table} / %{entity#table} | @Table name (or snake_case class name) | entities | | %{entity#inserts} | full INSERT INTO table(cols) VALUES(:entity...) | see below | | %{entity#updates} | col = :entity.field, ... for SET | value1 = :entity.field1, ... | | %{entity#where = @id} | WHERE by the @Id field(s) | id = :entity.id | | %{id#where} | WHERE for a composite-key argument named id | a = :id.a AND b = :id.b |

Field enumeration after a command: = keeps only the listed fields, -= excludes them; the @id keyword refers to the @Id field(s).

@Query("INSERT INTO %{entity#inserts-= @id}")   // every column except the @Id
@Id Long insert(Entity entity);

@Query("INSERT INTO %{entity#inserts = value1,value2}")  // only these columns
UpdateCount insertPartial(Entity entity);

The only macro commands are table, selects, inserts, updates, where. There is no deletes command — write DELETE FROM ... WHERE ... explicitly.


Repository method signatures

T is the return type, List, Void, or UpdateCount.

| Signature | Use | |-----------|-----| | T find(...) | row must exist (throws otherwise) | | @Nullable T find(...) | optional single row — preferred over Optional (no allocation) | | Optional find(...) | optional single row, Optional flavor | | List find(...) | zero-or-many (empty list, never null) | | UpdateCount write(...) | number of affected rows for INSERT/UPDATE/DELETE | | void write(...) | result not needed | | @Id Long insert(...) | database-generated identifier | | CompletionStage | async — requires an Executor bound to JdbcDatabase | | Mono | reactive — add io.projectreactor:reactor-core and an Executor |

Kotlin adds suspend fun ...(): T and T? / Unit returns.


References

| Topic | File | |-------|------| | @Repository, @Query, macros, batch, inheritance, multiple databases | [repository-pattern-reference.md](references/repository-pattern-reference.md) | | @Table/@Column/@Id/@Embedded, naming strategy, type mapping, generated ids | [entity-mapping-reference.md](references/entity-mapping-reference.md) | | inTx(), post-commit/rollback actions, isolation, locking | [transactions-reference.md](references/transactions-reference.md) | | JdbcResultSetMapper/JdbcRowMapper/JdbcResultColumnMapper/JdbcParameterColumnMapper, enum/array/JSONB | [custom-mappers-reference.md](references/custom-mappers-reference.md) | | HikariCP config, drivers, telemetry, YAML | [database-jdbc-config-reference.md](references/database-jdbc-config-reference.md) | | HikariCP pool tuning by workload, leak detection | [connection-pool-reference.md](references/connection-pool-reference.md) | | Flyway / Liquibase schema migrations | [migrations-reference.md](references/migrations-reference.md) |


Assets

| Template | Purpose | |----------|---------| | jdbc-entity-single-id.{java,kt}.template | entity with a single-field id | | jdbc-entity-composite-id.{java,kt}.template | entity with an @Embedded composite key | | jdbc-crud-single-id-repository.{java,kt}.template | full CRUD repository (single id) | | jdbc-crud-composite-id-repository.{java,kt}.template | full CRUD repository (composite id) | | jdbc-crud-abstract-macros-repository.java.template / jdbc-crud-abstract-single-id-macros-repository.kt.template | reusable generic CRUD base interface | | jdbc-repository-with-enum-mapper.{java,kt}.template | entity + enum column/parameter mappers | | jdbc-repository-with-array-mapper.java.template | PostgreSQL array parameter mapper | | jdbc-service-with-transactions.java.template | @Component service using inTx() |

Generate a starter entity + repository:

python scripts/generate_repository.py --entity User --table users --id-type Long --lang java --package com.example.model

Testing

Use @KoraAppTest with test-junit5 plus a Testcontainers PostgreSQL extension; inject the real repository with @TestComponent and point the config at the container.

@TestcontainersPostgreSQL(mode = ContainerMode.PER_RUN,
        migration = @Migration(engine = Migration.Engines.FLYWAY,
                apply = Migration.Mode.PER_METHOD, drop = Migration.Mode.PER_METHOD))
@KoraAppTest(Application.class)
class EntityRepositoryTest implements KoraAppTestConfigModifier {

    @ConnectionPostgreSQL
    private JdbcConnection connection;

    @TestComponent
    private EntityRepository repository;

    @Override
    public KoraConfigModification config() {
        return KoraConfigModification.ofSystemProperty("POSTGRES_JDBC_URL", connection.params().jdbcUrl())
                .withSystemProperty("POSTGRES_USER", connection.params().username())
                .withSystemProperty("POSTGRES_PASS", connection.params().password());
    }

    @Test
    void insertThenFind() {
        repository.insert(new Entity(null, 1, "two", null));
        assertFalse(repository.findAll().isEmpty());
    }
}

Test dependencies: testImplementation "ru.tinkoff.kora:test-junit5" and testImplementation "io.goodforgod:testcontainers-extensions-postgres:0.13.1".


Common pitfalls

| Symptom | Fix | |---------|-----| | Graph build: "required dependency JdbcRepository / Entity not found" | @KoraApp must extend JdbcDatabaseModule; entity needs @EntityJdbc | | *RepositoryImpl not generated | annotation processor missing (annotation-processors / KSP symbol-processors) | | Generated id is always null | use @Id on the method (and exclude it via inserts-= @id) or add RETURNING id | | Macro renders literally / fails | use # not . (%{entity#inserts}); only table/selects/inserts/updates/where exist | | List parameter treated as one value | annotate with @Batch | | Driver ClassNotFoundException | add the JDBC driver dependency (it is not bundled) | | Operations outside inTx() not rolled back | wrap all related calls in one inTx() block | | connectionTimeout = 30000 ignored | durations are strings: "10s", "10m" | | @Column on every field looks mandatory | Column names default to snake_lower_case@Column only for non-standard names (see [Custom Mappers Advanced](references/custom-mappers-advanced-reference.md)) | | @Mapping required for custom types | @Component mappers are auto-discovered by type (see [Custom Mappers Advanced](references/custom-mappers-advanced-reference.md)) | | @Batch with RETURNING doesn't return rows | Use default method with inTx() for multi-row INSERT…RETURNING (see [Custom Mappers Advanced](references/custom-mappers-advanced-reference.md)) |


Column Mappers

For advanced mapper patterns (auto-discovery, generic enum mappers, @Batch limitations), see [Custom Mappers Advanced](references/custom-mappers-advanced-reference.md).


Version compatibility

| Component | Version | |-----------|---------| | Kora BOM (kora-parent) | 1.2.17 | | Java | 21+ | | Gradle | 9+ | | PostgreSQL driver | 42.7.x |

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.