krush alternatives and similar libraries
Based on the "Database" category.
Alternatively, view krush alternatives based on common mentions on social networks and blogs.
-
mapdb
MapDB provides concurrent Maps, Sets and Queues backed by disk storage or off-heap-memory. It is a fast and easy to use embedded Java database engine. -
DBFlow
A blazing fast, powerful, and very simple ORM android database library that writes database code for you. -
kotlin-gremlin-ogm
DISCONTINUED. Kotlin-gremlin-ogm is a type-safe object/graph mapping library for Gremlin enabled graph databases. -
kotlin-jpa-specification-dsl
This library provides a fluent DSL for querying spring data JPA repositories using spring data Specifications (i.e. the JPA Criteria API), without boilerplate code or a generated metamodel. -
zeko-sql-builder
Zeko SQL Builder is a high-performance lightweight SQL query library written for Kotlin language -
fluid-mongo
Kotlin coroutine support for MongoDB built on top of the official Reactive Streams Java Driver -
jds
Jenesis Data Store: a dynamic, cross platform, high performance, ORM data-mapper. Designed to assist in rapid development and data mining -
potassium-nitrite
Potassium Nitrite is a kotlin extension of nitrite database, an open source nosql embedded document store with mongodb like api.
CodeRabbit: AI Code Reviews for Developers

* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of krush or a related project?
README
Krush
Krush is a lightweight persistence layer for Kotlin based on Exposed SQL DSL. It’s similar to Requery and Micronaut-data jdbc, but designed to work idiomatically with Kotlin and immutable data classes.
It’s based on a compile-time JPA annotation processor that generates Exposed DSL table and objects mappings for you. This lets you instantly start writing type-safe SQL queries without need to write boilerplate infrastructure code.
Rationale
- (type-safe) SQL-first - use type-safe SQL-like DSL in your queries, no string or method name parsing
- Minimal changes to your domain model - no need to extend external interfaces and used special types - just add annotations to your existing domain model
- Explicit fetching - you specify explicitly in query what data you want to fetch, no additional fetching after data is loaded
- No runtime magic - no proxies, lazy loading, just data classes containing data fetched from DB
- Pragmatic - easy to start, but powerful even in not trivial cases (associations, grouping queries)
Example
Given a simple Book
class:
data class Book(
val id: Long? = null,
val isbn: String,
val title: String,
val author: String,
val publishDate: LocalDate
)
we can turn it into Krush entity by adding @Entity
and @Id
annotations:
@Entity
data class Book(
@Id @GeneratedValue
val id: Long? = null,
val isbn: String,
val title: String,
val author: String,
val publishDate: LocalDate
)
When we build the project we’ll have BookTable
mapping generated for us. So we can persist the Book
:
val book = Book(
isbn = "1449373321", publishDate = LocalDate.of(2017, Month.APRIL, 11),
title = "Designing Data-Intensive Applications", author = "Martin Kleppmann"
)
// insert method is generated by Krush
val persistedBook = BookTable.insert(book)
assertThat(persistedBook.id).isNotNull()
So we have now a Book
persisted in DB with autogenerated Book.id
field.
And now we can use type-safe SQL DSL to query the BookTable
:
val bookId = book.id ?: throw IllegalArgumentException()
// toBook method is generated by Krush
val fetchedBook = BookTable.select { BookTable.id eq bookId }.singleOrNull()?.toBook()
assertThat(fetchedBook).isEqualTo(book)
// toBookList method is generated by Krush
val selectedBooks = (BookTable)
.select { BookTable.author like "Martin K%" }
.toBookList()
assertThat(selectedBooks).containsOnly(persistedBook)
Installation
Gradle Groovy:
repositories {
mavenCentral()
}
apply plugin: 'kotlin-kapt'
dependencies {
api "pl.touk.krush:krush-annotation-processor:$krushVersion"
kapt "pl.touk.krush:krush-annotation-processor:$krushVersion"
api "pl.touk.krush:krush-runtime:$krushVersion"
}
Gradle Kotlin:
repositories {
mavenCentral()
}
plugins {
kotlin("kapt") version "$kotlinVersion"
}
dependencies {
api("pl.touk.krush:krush-annotation-processor:$krushVersion")
kapt("pl.touk.krush:krush-annotation-processor:$krushVersion")
api("pl.touk.krush:krush-runtime:$krushVersion")
}
Maven:
<dependencies>
<dependency>
<groupId>pl.touk.krush</groupId>
<artifactId>krush-runtime</artifactId>
<version>${krush.version}</version>
</dependency>
</dependencies>
...
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<executions>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
<configuration>
...
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>pl.touk.krush</groupId>
<artifactId>krush-annotation-processor</artifactId>
<version>${krush.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
...
</executions>
</plugin>
Dependencies
- JetBrains Exposed
- JPA annotations 2.1
Features
- generates table mappings and functions for mapping from/to data classes
- type-safe SQL DSL without reading schema from existing database (code-first)
- explicit association fetching (via
leftJoin
/innerJoin
) - multiple data types support, including type aliases
- custom data type support (with
@Converter
), also for wrapped auto-generated ids - you can still persist associations not directly reflected in domain model (eq. article favorites)
However, Krush is not a full-blown ORM library. This means following JPA features are not supported:
- lazy association fetching
- dirty checking
- caching
- versioning / optimistic locking
Updating
Given following entity:
@Entity
data class Reservation(
@Id
val uid: UUID = UUID.randomUUID(),
@Enumerated(EnumType.STRING)
val status: Status = Status.FREE,
val reservedAt: LocalDateTime? = null,
val freedAt: LocalDateTime? = null
) {
fun reserve() = copy(status = Status.RESERVED, reservedAt = LocalDateTime.now())
fun free() = copy(status = Status.FREE, freedAt = LocalDateTime.now())
}
enum class Status { FREE, RESERVED }
you can call Exposed update
with generated from
metod to overwrite it's data:
val reservation = Reservation().reserve().let(ReservationTable::insert)
val freedReservation = reservation.free()
ReservationTable.update({ ReservationTable.uid eq reservation.uid }) { it.from(freedReservation) }
val updatedReservation = ReservationTable.select({ ReservationTable.uid eq reservation.uid }).singleOrNull()?.toReservation()
assertThat(updatedReservation?.status).isEqualTo(Status.FREE)
assertThat(updatedReservation?.reservedAt).isEqualTo(reservation.reservedAt)
assertThat(updatedReservation?.freedAt).isEqualTo(freedReservation.freedAt)
For simple cases you can still use Exposed native update syntax:
val freedAt = LocalDateTime.now()
ReservationTable.update({ ReservationTable.uid eq reservation.uid }) {
it[ReservationTable.status] = Status.FREE
it[ReservationTable.freedAt] = freedAt
}
Other Exposed features are supported as well, like, replace
:
val reservation = Reservation().reserve()
ReservationTable.replace { it.from(reservation) }
val freedReservation = reservation.free()
ReservationTable.replace { it.from(freedReservation) }
val allReservations = ReservationTable.selectAll().toReservationList()
assertThat(allReservations).containsExactly(freedReservation)
and batchInsert
/batchReplace
:
val reservation1 = Reservation().reserve()
val reservation2 = Reservation().reserve()
ReservationTable.batchInsert(
listOf(reservation1, reservation2), body = { this.from(it) }
)
val allReservations = ReservationTable.selectAll().toReservationList()
assertThat(allReservations)
.containsExactly(reservation1, reservation2)
}
Associations
@Entity
@Table(name = "articles")
data class Article(
@Id @GeneratedValue
val id: Long? = null,
@Column(name = "title")
val title: String,
@ManyToMany
@JoinTable(name = "article_tags")
val tags: List<Tag> = emptyList()
)
@Entity
@Table(name = "tags")
data class Tag(
@Id @GeneratedValue
val id: Long? = null,
@Column(name = "name")
val name: String
)
Persisting
val tag1 = Tag(name = "jvm")
val tag2 = Tag(name = "spring")
val tags = listOf(tag1, tag2).map(TagTable::insert)
val article = Article(title = "Spring for dummies", tags = tags)
val persistedArticle = ArticleTable.insert(article)
Querying and fetching
val (selectedArticle) = (ArticleTable leftJoin ArticleTagsTable leftJoin TagTable)
.select { TagTable.name inList listOf("jvm", "spring") }
.toArticleList()
assertThat(selectedArticle).isEqualTo(persistedArticle)
Update logic for associations not implemented (yet!) - you have to manually add/remove records from ArticleTagsTable
.
Example projects
Contributors
Special thanks to Łukasz Jędrzejewski for original idea of using Exposed in our projects.
Licence
Krush is published under Apache License 2.0.
*Note that all licence references and agreements mentioned in the krush README section above
are relevant to that project's source code only.