RE

repository

Standardize database access and repository patterns using Kotlin and SQL transactions.

Install

mkdir -p .claude/skills/repository && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15048" && unzip -o skill.zip -d .claude/skills/repository && rm skill.zip

Installs to .claude/skills/repository

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Repository-mønster med Kotlin object og Connection/TransactionalSession extension-funksjoner, DBUtils-transaksjoner og ResultSet-mapping
136 charsno explicit “when” trigger
Intermediate

Key capabilities

  • Implement repository pattern with Kotlin objects
  • Use `Connection` and `TransactionalSession` extension functions
  • Manage database transactions via `DBUtils.asyncTransaction` or `DBUtils.transaction`
  • Centralize `ResultSet` to domain mapping in `RepositoryMappers.kt`
  • Handle database errors using `useAndHandleErrors`
  • Configure `PostgresDataSource` with HikariCP and Vault integration

How it works

The skill defines patterns for database access using Kotlin objects, extension functions, and `DBUtils` for transactions, centralizing data source configuration and result set mapping.

Inputs & outputs

You give it
Kotlin code requiring database access or transaction management
You get back
Database operations performed within transactions, with results mapped to domain objects, following repository patterns

When to use repository

  • Implementing repository-pattern data access
  • Configuring transactional database operations
  • Setting up SQL migration workflows

About this skill

Repository & Database Access Patterns

Repository- og databaseaksessmønstre: object-repositories med Connection-extensions, DBUtils-transaksjoner, ResultSet-mapping og feilhåndtering.

All database access goes through DBUtils.asyncTransaction {} (suspending) or DBUtils.transaction {} (blocking). Repositories are Kotlin objects with extension functions on Connection or TransactionalSession.

DataSource

PostgresDataSource is a singleton object using HikariCP. In non-local environments it integrates with Vault for credentials:

object PostgresDataSource {
    val dataSource: HikariDataSource by lazy { dataSource() }

    fun migrate() {
        dataSource(role = postgresConfig.adminUser).use { migrate(it) }
    }

    fun migrate(dataSource: HikariDataSource) {
        Flyway.configure()
            .dataSource(dataSource)
            .initSql("""SET ROLE "${postgresConfig.adminUser}"""")
            .lockRetryCount(-1)
            .validateMigrationNaming(true)
            .load()
            .migrate()
    }
}

Transactions via DBUtils

Always use DBUtils.asyncTransaction {} (suspending) or DBUtils.transaction {} (blocking). Never use bare JDBC connections directly.

// Suspending (use in coroutine context / service layer)
dataSource.asyncTransaction { session ->
    KravRepository.run { session.insertAllNewKrav(kravLinjer, filnavn) }
}

// Blocking (use in sync contexts)
dataSource.transaction { session ->
    KravRepository.run { session.updateStatus(corrId, status) }
}

Repository Pattern

Repositories are Kotlin objects with extension functions on Connection (raw JDBC) or TransactionalSession (kotliquery). Use RepositoryExtensions helpers:

object KravRepository {
    fun Connection.getAllUnsentKrav() =
        executeSelect(
            """select * from krav where status = ?""",
            Status.KRAV_IKKE_SENDT.value,
        ).toKrav()

    fun Connection.updateSentKrav(
        corrId: String,
        kravidentifikatorSKE: String,
        status: String,
    ) = executeUpdate(
        """update krav set kravidentifikator_ske = ?, status = ?, tidspunkt_sendt = now() where corr_id = ?""",
        kravidentifikatorSKE,
        status,
        corrId,
    )

    // For kotliquery TransactionalSession (e.g. when returnGeneratedKey is needed)
    fun getKravTableIdFromCorrelationId(
        tx: TransactionalSession,
        corrID: String,
    ): Long =
        tx.single(
            queryOf("select id from krav where corr_id = ?", corrID)
                .map { row -> row.long("id") }
                .asSingle,
        ) ?: throw IllegalStateException("Krav med corrId $corrID ikke funnet")
}

ResultSet Mapping

Centralise ResultSet → domain mapping in RepositoryMappers.kt using getColumn<T>():

fun ResultSet.toKrav() =
    toList {
        Krav(
            kravId = getColumn("id"),
            saksnummerNAV = getColumn("saksnummer_nav"),
            status = getColumn("status"),
            kravtype = getColumn("kravtype"),
            corrId = getColumn("corr_id"),
            kravidentifikatorSKE = getColumn("kravidentifikator_ske"),
            // ... remaining fields
        )
    }

private fun <T> ResultSet.toList(mapper: ResultSet.() -> T) =
    buildList {
        while (next()) { add(mapper()) }
    }

Error Handling

Wrap bare Connection usage with useAndHandleErrors:

dataSource.connection.useAndHandleErrors { con ->
    con.getAllUnsentKrav()
}

Boundaries

✅ Always

  • Use DBUtils.asyncTransaction {} / DBUtils.transaction {} — never bare Connection in service code
  • Use object + extension functions for repositories
  • Map ResultSet → domain in RepositoryMappers.kt using getColumn<T>()
  • Wrap Connection usage with useAndHandleErrors

🚫 Never

  • Skip Flyway migrations for schema changes
  • Use bare JDBC connections directly in service code
  • Scatter ResultSet mapping logic outside RepositoryMappers.kt

When not to use it

  • When skipping Flyway migrations for schema changes
  • When using bare JDBC connections directly in service code

Limitations

  • All database access must go through `DBUtils.asyncTransaction {}` or `DBUtils.transaction {}`
  • ResultSet mapping logic must be centralized in `RepositoryMappers.kt`
  • Bare JDBC connections are not to be used directly in service code

How it compares

This skill enforces a structured, transactional, and type-safe approach to database access in Kotlin, preventing common pitfalls like scattered ResultSet mapping or unmanaged connections, unlike direct JDBC usage.

Compared to similar skills

repository side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
repository (this skill)03moNo flagsIntermediate
drizzle-orm322moNo flagsIntermediate
database-migration32moNo flagsAdvanced
backend-dev16moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry