From dfeb045f1ab0d351c000211e538b95c952320c66 Mon Sep 17 00:00:00 2001 From: Josha von Gizycki Date: Fri, 18 Jul 2025 14:28:00 +0200 Subject: [PATCH] switch to spring data jdbc --- pom.xml | 14 +--- .../wanijo/wanijo2/db/DocumentDaoAdapter.kt | 49 ------------ .../kotlin/wanijo/wanijo2/domain/Document.kt | 10 ++- .../wanijo/wanijo2/domain/DocumentDao.kt | 12 ++- .../wanijo2/http/controller/ListController.kt | 2 +- .../wanijo2/http/controller/ShowController.kt | 2 +- .../wanijo/wanijo2/spring/JdbiConfig.kt | 51 ------------- src/main/resources/application-dev.properties | 2 + .../wanijo/wanijo2/domain/DocumentDaoTest.kt | 74 +++++++++++++++++++ src/test/resources/application.properties | 5 ++ src/test/resources/banner-test.txt | 4 + 11 files changed, 107 insertions(+), 118 deletions(-) delete mode 100644 src/main/kotlin/wanijo/wanijo2/db/DocumentDaoAdapter.kt delete mode 100644 src/main/kotlin/wanijo/wanijo2/spring/JdbiConfig.kt create mode 100644 src/test/kotlin/wanijo/wanijo2/domain/DocumentDaoTest.kt create mode 100644 src/test/resources/application.properties create mode 100644 src/test/resources/banner-test.txt diff --git a/pom.xml b/pom.xml index fd03e71..7960c49 100644 --- a/pom.xml +++ b/pom.xml @@ -58,16 +58,10 @@ org.springframework.boot spring-boot-starter-jdbc - - org.jdbi - jdbi3-kotlin-sqlobject - ${jdbi.version} - - - org.jdbi - jdbi3-spring5 - ${jdbi.version} - + + org.springframework.boot + spring-boot-starter-data-jdbc + diff --git a/src/main/kotlin/wanijo/wanijo2/db/DocumentDaoAdapter.kt b/src/main/kotlin/wanijo/wanijo2/db/DocumentDaoAdapter.kt deleted file mode 100644 index 4813680..0000000 --- a/src/main/kotlin/wanijo/wanijo2/db/DocumentDaoAdapter.kt +++ /dev/null @@ -1,49 +0,0 @@ -package wanijo.wanijo2.db - -import org.jdbi.v3.core.Jdbi -import org.springframework.stereotype.Service -import wanijo.wanijo2.domain.Document -import wanijo.wanijo2.domain.DocumentDao -import kotlin.jvm.optionals.getOrNull - -@Service -class DocumentDaoAdapter( - private val jdbi: Jdbi -) : DocumentDao { - - override fun all(): List = - jdbi.open().use { - it.createQuery( - """ - SELECT tdoc.id, - tdoc.created_at, - tdoc.updated_at, - tdoc.name, - tdoc.description - FROM t_document tdoc - ORDER BY tdoc.updated_at DESC - """.trimIndent() - ) - .mapTo(Document::class.java) - .list() - } - - override fun forId(id: Int): Document? = - jdbi.open().use { - it.createQuery( - """ - SELECT tdoc.id, - tdoc.created_at, - tdoc.updated_at, - tdoc.name, - tdoc.description - FROM t_document tdoc - WHERE tdoc.id = :id - """.trimIndent() - ) - .bind("id", id) - .mapTo(Document::class.java) - .findOne() - }.getOrNull() - -} diff --git a/src/main/kotlin/wanijo/wanijo2/domain/Document.kt b/src/main/kotlin/wanijo/wanijo2/domain/Document.kt index e16cd2d..06624e4 100644 --- a/src/main/kotlin/wanijo/wanijo2/domain/Document.kt +++ b/src/main/kotlin/wanijo/wanijo2/domain/Document.kt @@ -1,11 +1,15 @@ package wanijo.wanijo2.domain +import org.springframework.data.annotation.Id +import org.springframework.data.relational.core.mapping.Table import java.time.ZonedDateTime +@Table("T_DOCUMENT") data class Document( - val id: Int, - val createdAt: ZonedDateTime, - val updatedAt: ZonedDateTime, + @Id + val id: Int = 0, + val createdAt: ZonedDateTime = ZonedDateTime.now(), + val updatedAt: ZonedDateTime = ZonedDateTime.now(), val name: String, val description: String ) diff --git a/src/main/kotlin/wanijo/wanijo2/domain/DocumentDao.kt b/src/main/kotlin/wanijo/wanijo2/domain/DocumentDao.kt index 8387170..66d6957 100644 --- a/src/main/kotlin/wanijo/wanijo2/domain/DocumentDao.kt +++ b/src/main/kotlin/wanijo/wanijo2/domain/DocumentDao.kt @@ -1,9 +1,15 @@ package wanijo.wanijo2.domain -interface DocumentDao { +import org.springframework.data.repository.Repository - fun all(): List +interface DocumentDao: Repository { - fun forId(id: Int): Document? + fun findAll(): List + + fun findById(id: Int): Document? + + fun findByName(name: String): List + + fun save(doc: Document) } diff --git a/src/main/kotlin/wanijo/wanijo2/http/controller/ListController.kt b/src/main/kotlin/wanijo/wanijo2/http/controller/ListController.kt index 120cae0..a3d077b 100644 --- a/src/main/kotlin/wanijo/wanijo2/http/controller/ListController.kt +++ b/src/main/kotlin/wanijo/wanijo2/http/controller/ListController.kt @@ -15,7 +15,7 @@ class ListController( fun list( model: Model ): String { - model["documents"] = docDao.all() + model["documents"] = docDao.findAll() return "list" } diff --git a/src/main/kotlin/wanijo/wanijo2/http/controller/ShowController.kt b/src/main/kotlin/wanijo/wanijo2/http/controller/ShowController.kt index 6769b9f..5ff7660 100644 --- a/src/main/kotlin/wanijo/wanijo2/http/controller/ShowController.kt +++ b/src/main/kotlin/wanijo/wanijo2/http/controller/ShowController.kt @@ -20,7 +20,7 @@ class ShowController( model: Model, @PathVariable id: Int ): String { - val document = docDao.forId(id) ?: throw DocumentNotFound() + val document = docDao.findById(id) ?: throw DocumentNotFound() model["document"] = document val descHtml = Parser.builder().build().parse(document.description).let { diff --git a/src/main/kotlin/wanijo/wanijo2/spring/JdbiConfig.kt b/src/main/kotlin/wanijo/wanijo2/spring/JdbiConfig.kt deleted file mode 100644 index b823166..0000000 --- a/src/main/kotlin/wanijo/wanijo2/spring/JdbiConfig.kt +++ /dev/null @@ -1,51 +0,0 @@ -package wanijo.wanijo2.spring - -import org.jdbi.v3.core.Jdbi -import org.jdbi.v3.core.kotlin.KotlinPlugin -import org.jdbi.v3.core.statement.SqlLogger -import org.jdbi.v3.core.statement.StatementContext -import org.jdbi.v3.sqlobject.kotlin.KotlinSqlObjectPlugin -import org.slf4j.LoggerFactory -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import javax.sql.DataSource - -@Configuration -class JdbiConfig { - - @Bean - fun jdbi(ds: DataSource): Jdbi = - Jdbi.create(ds).run { - installPlugin(KotlinPlugin()) - installPlugin(KotlinSqlObjectPlugin()) - setSqlLogger(object : SqlLogger { - private val logger = LoggerFactory.getLogger("org.jdbi.sql") - - override fun logBeforeExecution(context: StatementContext) { - if (logger.isDebugEnabled) { - logger.debug( - "Query: {}, Params: {}", - context.parsedSql.sql.lines() - .joinToString(separator = " ") { it.trim() }, - context.binding - ) - } - } - - override fun logAfterExecution(context: StatementContext) { - if (logger.isDebugEnabled) { - logger.debug( - "Duration: {}ms, Query: {}, Params: {}", - context.completionMoment.toEpochMilli() - context.executionMoment.toEpochMilli(), - context.parsedSql.sql.lines() - .joinToString(separator = " ") { it.trim() }, - context.binding - ) - } - } - }) - - this - } - -} diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index c89adf7..e8ab086 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -1,3 +1,5 @@ spring.datasource.url=jdbc:h2:file:./wanijo2-dev.h2 +logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG + spring.banner.location=banner-dev.txt diff --git a/src/test/kotlin/wanijo/wanijo2/domain/DocumentDaoTest.kt b/src/test/kotlin/wanijo/wanijo2/domain/DocumentDaoTest.kt new file mode 100644 index 0000000..370cdb1 --- /dev/null +++ b/src/test/kotlin/wanijo/wanijo2/domain/DocumentDaoTest.kt @@ -0,0 +1,74 @@ +package wanijo.wanijo2.domain + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertNotNull +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.annotation.DirtiesContext +import kotlin.test.assertEquals + +@SpringBootTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +class DocumentDaoTest { + + @Autowired + lateinit var adapter: DocumentDao + + @Test + fun insertWorks() { + assertEquals(0, adapter.findAll().count()) + + adapter.save( + Document( + name = "name", + description = "desc" + ) + ) + + assertEquals(1, adapter.findAll().count()) + } + + @Test + fun findByIdWorks() { + val doc = Document( + name = "name", + description = "desc" + ) + + adapter.save(doc) + + val savedDoc = adapter.findById(1) + assertNotNull(savedDoc) + } + + @Test + fun idsAreGeneratedSequentially() { + adapter.save( + Document( + name = "name1", + description = "desc" + ) + ) + + adapter.save( + Document( + name = "name2", + description = "desc" + ) + ) + + assertNotNull(adapter.findById(1)) + assertNotNull(adapter.findById(2)) + } + + @Test + fun findByNameWorks() + { + adapter.save( + Document(name = "findmich", description = "") + ) + + assertNotNull(adapter.findByName("findmich")) + } + +} diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 0000000..2bd81a1 --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1,5 @@ +spring.datasource.url=jdbc:h2:mem:testdb + +logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG + +spring.banner.location=banner-test.txt diff --git a/src/test/resources/banner-test.txt b/src/test/resources/banner-test.txt new file mode 100644 index 0000000..d06e183 --- /dev/null +++ b/src/test/resources/banner-test.txt @@ -0,0 +1,4 @@ +▗▄▄▄▖▗▄▄▄▖ ▗▄▄▖▗▄▄▄▖▗▄▄▄▖▗▖ ▗▖ ▗▄▄▖ + █ ▐▌ ▐▌ █ █ ▐▛▚▖▐▌▐▌ + █ ▐▛▀▀▘ ▝▀▚▖ █ █ ▐▌ ▝▜▌▐▌▝▜▌ + █ ▐▙▄▄▖▗▄▄▞▘ █ ▗▄█▄▖▐▌ ▐▌▝▚▄▞▘