From 27494e6fb1909dc657d21f5528426e6e6ec71817 Mon Sep 17 00:00:00 2001 From: Swordsteel Date: Thu, 11 Sep 2025 17:53:32 +0200 Subject: [PATCH] update AccountService with getForUpdateById and save --- .../ltd/lulz/repository/AccountRepository.kt | 8 +++- .../kotlin/ltd/lulz/service/AccountService.kt | 9 +++++ .../ltd/lulz/service/AccountServiceTest.kt | 38 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ltd/lulz/repository/AccountRepository.kt b/src/main/kotlin/ltd/lulz/repository/AccountRepository.kt index 350b996..76af633 100644 --- a/src/main/kotlin/ltd/lulz/repository/AccountRepository.kt +++ b/src/main/kotlin/ltd/lulz/repository/AccountRepository.kt @@ -2,8 +2,14 @@ package ltd.lulz.repository import java.util.UUID import ltd.lulz.model.AccountEntity +import org.springframework.data.r2dbc.repository.Query import org.springframework.data.repository.reactive.ReactiveCrudRepository import org.springframework.stereotype.Repository +import reactor.core.publisher.Mono @Repository -interface AccountRepository : ReactiveCrudRepository +interface AccountRepository : ReactiveCrudRepository { + + @Query("SELECT * FROM accounts WHERE id = :id FOR UPDATE NOWAIT") + fun findByIdForUpdate(id: UUID): Mono +} diff --git a/src/main/kotlin/ltd/lulz/service/AccountService.kt b/src/main/kotlin/ltd/lulz/service/AccountService.kt index fa25bae..c80e4e9 100644 --- a/src/main/kotlin/ltd/lulz/service/AccountService.kt +++ b/src/main/kotlin/ltd/lulz/service/AccountService.kt @@ -5,6 +5,7 @@ import java.util.UUID import ltd.lulz.model.AccountEntity import ltd.lulz.repository.AccountRepository import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional import reactor.core.publisher.Mono private val log = KotlinLogging.logger {} @@ -20,4 +21,12 @@ class AccountService( fun getById(id: UUID): Mono = accountRepository.findById(id) .doOnNext { log.debug { "found account by id: ${it.id}" } } + + @Transactional + fun getForUpdateById(id: UUID): Mono = accountRepository.findByIdForUpdate(id) + .doOnNext { log.trace { "account with id: ${it.id} locked for update" } } + + @Transactional + fun save(entity: AccountEntity): Mono = accountRepository.save(entity) + .doOnNext { log.trace { "account with id: ${it.id} saved" } } } diff --git a/src/test/kotlin/ltd/lulz/service/AccountServiceTest.kt b/src/test/kotlin/ltd/lulz/service/AccountServiceTest.kt index 4b19be8..956f0ed 100644 --- a/src/test/kotlin/ltd/lulz/service/AccountServiceTest.kt +++ b/src/test/kotlin/ltd/lulz/service/AccountServiceTest.kt @@ -69,4 +69,42 @@ class AccountServiceTest { verify { repository.findById(any(UUID::class)) } } + + @Test + fun `get for update by id`() { + // given + val capture = slot() + every { repository.findByIdForUpdate(capture(capture)) } + .answers { Mono.just(AccountEntity(capture.captured, name, amount)) } + + // when stepped + StepVerifier.create(service.getForUpdateById(uuid)) + .assertNext { result -> + assertThat(result.id).isEqualTo(uuid) + assertThat(result.name).isEqualTo(name) + assertThat(result.amount).isEqualTo(amount) + } + .verifyComplete() + + verify { repository.findByIdForUpdate(any(UUID::class)) } + } + + @Test + fun `save change`() { + // given + val entity = AccountEntity(name = name, amount = amount) + + val capture = slot() + every { repository.save(capture(capture)) } + .answers { Mono.just(capture.captured) } + + // when stepped + StepVerifier.create(service.save(entity)) + .assertNext { result -> + assertThat(result).isEqualTo(entity) + } + .verifyComplete() + + verify { repository.save(any()) } + } }