What it is
Ktorm is a lightweight Kotlin ORM with a strongly-typed DSL whose operators mirror SQL closely, plus an optional entity-object layer.
Declare table objects, then build queries with a fluent DSL. Ktorm's operators make conditions read naturally while staying type-checked.
Installation
implementation("org.ktorm:ktorm-core:4.1.1")Getting started
The smallest useful thing you can do with it, and what each part means.
kotlin
object Books : Table<Nothing>("books") {
val id = int("id").primaryKey()
val title = varchar("title")
val year = int("year")
val authorId = int("author_id")
}
val database = Database.connect(dataSource)
val results = database
.from(Books)
.innerJoin(Authors, on = Books.authorId eq Authors.id)
.select(Books.title, Authors.name)
.where { (Books.year greaterEq 1990) and (Authors.country eq "US") }
.orderBy(Books.year.desc())
.limit(10)
.map { row -> row[Books.title] to row[Authors.name] }Advanced usage
Where the library earns its place over a simpler alternative.
kotlin
val countsByYear = database
.from(Books)
.select(Books.year, count(Books.id))
.groupBy(Books.year)
.having { count(Books.id) greater 5 }
.associate { it.getInt(1) to it.getInt(2) }
database.batchInsert(Books) {
incoming.forEach { book ->
item {
set(Books.title, book.title)
set(Books.year, book.year)
}
}
}
database.useTransaction {
database.update(Books) {
set(it.year, 1966)
where { it.id eq 42 }
}
}Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Column not found in the result row
- The column was not included in select(). Ktorm returns only what you asked for.
- Connection leaks
- Use a pooled DataSource such as HikariCP and useTransaction, rather than managing connections manually.
Best practices
- Use the SQL DSL rather than the entity layer for anything with joins or aggregation.
- Wrap multi-statement work in useTransaction.
- Use batchInsert and batchUpdate for bulk writes.
- Consider Exposed if you want JetBrains' backing and a larger community; Ktorm is smaller and more SQL-literal.
Background
Why it exists, and what it was reacting to.
Ktorm's distinguishing feature is operator overloading: comparisons and boolean combinations use ordinary Kotlin operators, so queries read like the SQL they generate.
