Skip to content

Commit

Permalink
add upsert
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukas-Kaufmann committed Apr 12, 2024
1 parent a2ea3fe commit 72e18db
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changes

## Unreleased

### Feature

- added `DSLContext.upsert`

## 2024-03-26 / 0.3.0

### Feature
Expand Down
15 changes: 15 additions & 0 deletions src/main/kotlin/ls/jooq/execute/RecordMutators.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,18 @@ suspend fun <R : UpdatableRecord<R>> DSLContext.insertAndRefreshRecord(record: U
record.from(inserted)
return record
}

suspend fun <R : UpdatableRecord<R>> DSLContext.upsert(record: R): R =
insertInto(record.table)
.set(record)
.onDuplicateKeyUpdate()
.set(record)
.returning()
.awaitFirst()

suspend inline fun <reified R : UpdatableRecord<R>> DSLContext.upsert(init: R.() -> Unit): R {
val constructor = checkNotNull(R::class.java.getConstructor()) { "no default constructor found for ${R::class}" }
val record = constructor.newInstance()
record.init()
return upsert(record)
}
52 changes: 52 additions & 0 deletions src/test/kotlin/ls/jooq/execute/RecordMutatorsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import io.kotest.core.spec.style.FreeSpec
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
import ls.jooq.execute.awaitFirst
import kotlinx.coroutines.reactive.awaitFirst
import kotlinx.coroutines.reactive.awaitSingle
import ls.jooq.db.generated.Tables
import ls.jooq.db.generated.tables.records.AuthorRecord
Expand All @@ -15,6 +17,10 @@ class RecordMutatorsTest : FreeSpec({

val ctx = DBExtension.dslContext

afterTest {
ctx.deleteFrom(Tables.AUTHOR).awaitFirst()
}

"DSLContext.insertAndRefreshRecord" - {

"should insert the record" {
Expand Down Expand Up @@ -60,6 +66,52 @@ class RecordMutatorsTest : FreeSpec({
}
}

"DSLContext.upsert<R>()" - {

"should insert if the given primary key doesn't exist" {
val count: Int = ctx.selectCount().from(Tables.AUTHOR).awaitFirst()
count shouldBe 0
val author = ctx.upsert<AuthorRecord> {
id = 1
firstName = "Max"
lastName = "Muster"
}

val foundAuthor = ctx.selectFrom(Tables.AUTHOR).awaitFirst()
foundAuthor shouldBe author
}

"should insert if no primary key is set and the primary key is generated" {
ctx.selectCount().from(Tables.AUTHOR).awaitFirst() shouldBe 0
val author = ctx.upsert<AuthorRecord> {
firstName = "Max"
lastName = "Muster"
}

val foundAuthor = ctx.selectFrom(Tables.AUTHOR).awaitFirst()
foundAuthor shouldBe author
}

"should update values of existing record with same primary key" {
ctx.selectCount().from(Tables.AUTHOR).awaitFirst() shouldBe 0
val author = ctx.upsert<AuthorRecord> {
firstName = "Max"
lastName = "Muster"
}

val updatedAuthor = ctx.upsert<AuthorRecord> {
id = author.id
firstName = "Not max"
lastName = "Muster"
}

val foundAuthor = ctx.selectFrom(Tables.AUTHOR).awaitFirst()
foundAuthor.firstName shouldBe "Not max"
updatedAuthor.id shouldBe foundAuthor.id
author.id shouldBe foundAuthor.id
}
}

"DSLContext.updateAndExecute()" - {

"should create an update statement for the given record and execute it" {
Expand Down

0 comments on commit 72e18db

Please sign in to comment.