mirror of
https://github.com/Dannecron/spring-boot-demo.git
synced 2025-12-25 16:22:35 +03:00
move repositories to separate db package
replace jacoco with kover
This commit is contained in:
@@ -1,40 +1,85 @@
|
|||||||
plugins {
|
plugins {
|
||||||
|
idea
|
||||||
|
alias(libs.plugins.kotlin.kover)
|
||||||
alias(libs.plugins.kotlin.jpa)
|
alias(libs.plugins.kotlin.jpa)
|
||||||
alias(libs.plugins.kotlin.jvm)
|
alias(libs.plugins.kotlin.jvm)
|
||||||
alias(libs.plugins.kotlin.serialization)
|
alias(libs.plugins.kotlin.serialization)
|
||||||
alias(libs.plugins.kotlin.spring)
|
alias(libs.plugins.kotlin.spring)
|
||||||
alias(libs.plugins.spring.boot)
|
alias(libs.plugins.spring.boot)
|
||||||
alias(libs.plugins.spring.dependencyManagement)
|
alias(libs.plugins.spring.dependencyManagement)
|
||||||
|
|
||||||
jacoco
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "com.github.dannecron.demo"
|
group = "com.github.dannecron.demo"
|
||||||
version = "single-version"
|
version = "single-version"
|
||||||
|
|
||||||
java {
|
allprojects {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
apply {
|
||||||
|
plugin(rootProject.libs.plugins.kotlin.jvm.get().pluginId)
|
||||||
|
plugin(rootProject.libs.plugins.kotlin.serialization.get().pluginId)
|
||||||
|
plugin(rootProject.libs.plugins.kotlin.kover.get().pluginId)
|
||||||
|
|
||||||
|
plugin("java")
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins.withId("org.jetbrains.kotlinx.kover") {
|
||||||
|
tasks.named("koverXmlReport") {
|
||||||
|
dependsOn(tasks.test)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
kotlin {
|
||||||
|
compilerOptions {
|
||||||
|
freeCompilerArgs.addAll("-Xjsr305=strict")
|
||||||
|
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(rootProject.libs.kotlin.reflect)
|
||||||
|
implementation(rootProject.libs.kotlinx.serialization.json)
|
||||||
|
implementation(rootProject.libs.spring.aspects)
|
||||||
|
|
||||||
|
testImplementation(rootProject.libs.kotlin.test.junit)
|
||||||
|
testImplementation(rootProject.libs.mockito.kotlin)
|
||||||
|
testImplementation(rootProject.libs.spring.boot.starter.test)
|
||||||
|
|
||||||
|
kover(project(":db"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
finalizedBy("koverXmlReport")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
subprojects {
|
||||||
mavenCentral()
|
apply {
|
||||||
|
plugin(rootProject.libs.plugins.kotlin.spring.get().pluginId)
|
||||||
|
plugin(rootProject.libs.plugins.spring.boot.get().pluginId)
|
||||||
|
plugin(rootProject.libs.plugins.spring.dependencyManagement.get().pluginId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":db"))
|
||||||
|
|
||||||
runtimeOnly(libs.micrometer.registry.prometheus)
|
runtimeOnly(libs.micrometer.registry.prometheus)
|
||||||
|
|
||||||
implementation(libs.bundles.tracing)
|
implementation(libs.bundles.tracing)
|
||||||
implementation(libs.flyway.core)
|
|
||||||
implementation(libs.jackson.datatype.jsr)
|
implementation(libs.jackson.datatype.jsr)
|
||||||
implementation(libs.jackson.module.kotlin)
|
implementation(libs.jackson.module.kotlin)
|
||||||
implementation(libs.json.schema.validator)
|
implementation(libs.json.schema.validator)
|
||||||
implementation(libs.kotlin.reflect)
|
|
||||||
implementation(libs.kotlinx.serialization.json)
|
|
||||||
implementation(libs.ktor.client.cio)
|
implementation(libs.ktor.client.cio)
|
||||||
implementation(libs.ktor.client.core)
|
implementation(libs.ktor.client.core)
|
||||||
implementation(libs.logback.encoder)
|
implementation(libs.logback.encoder)
|
||||||
implementation(libs.postgres)
|
implementation(libs.postgres)
|
||||||
implementation(libs.spring.aspects)
|
|
||||||
implementation(libs.spring.boot.starter.actuator)
|
implementation(libs.spring.boot.starter.actuator)
|
||||||
implementation(libs.spring.boot.starter.jdbc)
|
implementation(libs.spring.boot.starter.jdbc)
|
||||||
implementation(libs.spring.boot.starter.mustache)
|
implementation(libs.spring.boot.starter.mustache)
|
||||||
@@ -43,33 +88,10 @@ dependencies {
|
|||||||
implementation(libs.spring.doc.openapi.starter)
|
implementation(libs.spring.doc.openapi.starter)
|
||||||
implementation(libs.spring.kafka)
|
implementation(libs.spring.kafka)
|
||||||
|
|
||||||
testImplementation(libs.kotlin.test.junit)
|
|
||||||
testImplementation(libs.mockito.kotlin)
|
|
||||||
testImplementation(libs.spring.boot.starter.test)
|
|
||||||
testImplementation(libs.spring.kafka.test)
|
testImplementation(libs.spring.kafka.test)
|
||||||
testImplementation(libs.testcontainers)
|
testImplementation(libs.testcontainers)
|
||||||
testImplementation(libs.testcontainers.junit.jupiter)
|
testImplementation(libs.testcontainers.junit.jupiter)
|
||||||
testImplementation(libs.testcontainers.postgresql)
|
|
||||||
testImplementation(libs.ktor.client.mock)
|
testImplementation(libs.ktor.client.mock)
|
||||||
|
|
||||||
developmentOnly(libs.spring.boot.devtools)
|
developmentOnly(libs.spring.boot.devtools)
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
|
||||||
compilerOptions {
|
|
||||||
freeCompilerArgs.addAll("-Xjsr305=strict")
|
|
||||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType<Test> {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.test {
|
|
||||||
finalizedBy(tasks.jacocoTestReport) // report is always generated after tests run
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.jacocoTestReport {
|
|
||||||
dependsOn(tasks.test) // tests are required to run before generating the report
|
|
||||||
}
|
|
||||||
|
|||||||
16
db/build.gradle.kts
Normal file
16
db/build.gradle.kts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
plugins {
|
||||||
|
alias(libs.plugins.kotlin.jpa)
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.github.dannecron.demo"
|
||||||
|
version = "single-version"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(rootProject.libs.flyway.core)
|
||||||
|
implementation(rootProject.libs.postgres)
|
||||||
|
implementation(rootProject.libs.spring.boot.starter.jdbc)
|
||||||
|
|
||||||
|
testImplementation(libs.testcontainers)
|
||||||
|
testImplementation(libs.testcontainers.junit.jupiter)
|
||||||
|
testImplementation(libs.testcontainers.postgresql)
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.github.dannecron.demo.db.entity
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.serialialization.OffsetDateTimeSerialization
|
||||||
|
import com.github.dannecron.demo.db.serialialization.UuidSerialization
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import org.springframework.data.annotation.Id
|
||||||
|
import org.springframework.data.relational.core.mapping.Column
|
||||||
|
import org.springframework.data.relational.core.mapping.Table
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Table("city")
|
||||||
|
@Serializable
|
||||||
|
data class City(
|
||||||
|
@Id
|
||||||
|
val id: Long?,
|
||||||
|
@Serializable(with = UuidSerialization::class)
|
||||||
|
val guid: UUID,
|
||||||
|
val name: String,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "created_at")
|
||||||
|
val createdAt: OffsetDateTime,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "updated_at")
|
||||||
|
val updatedAt: OffsetDateTime?,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "deleted_at")
|
||||||
|
val deletedAt: OffsetDateTime?,
|
||||||
|
) {
|
||||||
|
fun isDeleted(): Boolean = deletedAt != null
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.github.dannecron.demo.db.entity
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.serialialization.OffsetDateTimeSerialization
|
||||||
|
import com.github.dannecron.demo.db.serialialization.UuidSerialization
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import org.springframework.data.annotation.Id
|
||||||
|
import org.springframework.data.relational.core.mapping.Column
|
||||||
|
import org.springframework.data.relational.core.mapping.Table
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Table("customer")
|
||||||
|
@Serializable
|
||||||
|
data class Customer(
|
||||||
|
@Id
|
||||||
|
val id: Long?,
|
||||||
|
@Serializable(with = UuidSerialization::class)
|
||||||
|
val guid: UUID,
|
||||||
|
val name: String,
|
||||||
|
val cityId: Long?,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "created_at")
|
||||||
|
val createdAt: OffsetDateTime,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "updated_at")
|
||||||
|
val updatedAt: OffsetDateTime?,
|
||||||
|
)
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.github.dannecron.demo.db.entity
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.serialialization.OffsetDateTimeSerialization
|
||||||
|
import com.github.dannecron.demo.db.serialialization.UuidSerialization
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import org.springframework.data.annotation.Id
|
||||||
|
import org.springframework.data.relational.core.mapping.Column
|
||||||
|
import org.springframework.data.relational.core.mapping.Table
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlin.math.pow
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@Table(value = "product")
|
||||||
|
@Serializable
|
||||||
|
data class Product(
|
||||||
|
@Id
|
||||||
|
val id: Long?,
|
||||||
|
@Serializable(with = UuidSerialization::class)
|
||||||
|
val guid: UUID,
|
||||||
|
val name: String,
|
||||||
|
val description: String?,
|
||||||
|
val price: Long,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "created_at")
|
||||||
|
val createdAt: OffsetDateTime,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "updated_at")
|
||||||
|
val updatedAt: OffsetDateTime?,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "deleted_at")
|
||||||
|
val deletedAt: OffsetDateTime?,
|
||||||
|
) {
|
||||||
|
fun getPriceDouble(): Double = (price.toDouble() / 100).roundTo(2)
|
||||||
|
|
||||||
|
fun isDeleted(): Boolean = deletedAt != null
|
||||||
|
|
||||||
|
private fun Double.roundTo(numFractionDigits: Int): Double {
|
||||||
|
val factor = 10.0.pow(numFractionDigits.toDouble())
|
||||||
|
return (this * factor).roundToInt() / factor
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.github.dannecron.demo.db.entity.order
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.serialialization.OffsetDateTimeSerialization
|
||||||
|
import com.github.dannecron.demo.db.serialialization.UuidSerialization
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import org.springframework.data.annotation.Id
|
||||||
|
import org.springframework.data.relational.core.mapping.Column
|
||||||
|
import org.springframework.data.relational.core.mapping.Table
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Table(value = "order")
|
||||||
|
@Serializable
|
||||||
|
data class Order(
|
||||||
|
@Id
|
||||||
|
val id: Long?,
|
||||||
|
@Serializable(with = UuidSerialization::class)
|
||||||
|
val guid: UUID,
|
||||||
|
val customerId: Long,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "delivered_at")
|
||||||
|
val deliveredAt: OffsetDateTime?,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "created_at")
|
||||||
|
val createdAt: OffsetDateTime,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "updated_at")
|
||||||
|
val updatedAt: OffsetDateTime?
|
||||||
|
) {
|
||||||
|
fun isDelivered(): Boolean = deliveredAt != null
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.github.dannecron.demo.db.entity.order
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.serialialization.OffsetDateTimeSerialization
|
||||||
|
import com.github.dannecron.demo.db.serialialization.UuidSerialization
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import org.springframework.data.annotation.Id
|
||||||
|
import org.springframework.data.annotation.Transient
|
||||||
|
import org.springframework.data.domain.Persistable
|
||||||
|
import org.springframework.data.relational.core.mapping.Column
|
||||||
|
import org.springframework.data.relational.core.mapping.Table
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Table(value = "order_product")
|
||||||
|
@Serializable
|
||||||
|
data class OrderProduct(
|
||||||
|
@Id
|
||||||
|
@Serializable(with = UuidSerialization::class)
|
||||||
|
val guid: UUID,
|
||||||
|
@Column(value = "order_id")
|
||||||
|
val orderId: Long,
|
||||||
|
@Column(value = "product_id")
|
||||||
|
val productId: Long,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "created_at")
|
||||||
|
val createdAt: OffsetDateTime,
|
||||||
|
@Serializable(with = OffsetDateTimeSerialization::class)
|
||||||
|
@Column(value = "updated_at")
|
||||||
|
val updatedAt: OffsetDateTime?,
|
||||||
|
): Persistable<UUID> {
|
||||||
|
@Transient
|
||||||
|
var isNewInstance: Boolean? = null
|
||||||
|
|
||||||
|
override fun getId(): UUID {
|
||||||
|
return guid
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isNew(): Boolean {
|
||||||
|
return isNewInstance ?: true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.github.dannecron.demo.db.repository
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.entity.City
|
||||||
|
import org.springframework.data.jdbc.repository.query.Query
|
||||||
|
import org.springframework.data.repository.CrudRepository
|
||||||
|
import org.springframework.data.repository.query.Param
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
interface CityRepository: CrudRepository<City, Long> {
|
||||||
|
fun findByGuid(guid: UUID): City?
|
||||||
|
|
||||||
|
@Query(value = "UPDATE city SET deleted_at = :deletedAt WHERE guid = :guid RETURNING *")
|
||||||
|
fun softDelete(@Param("guid") guid: UUID, @Param("deletedAt") deletedAt: OffsetDateTime): City?
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.github.dannecron.demo.db.repository
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.entity.Customer
|
||||||
|
import org.springframework.data.repository.CrudRepository
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
interface CustomerRepository: CrudRepository<Customer, Long> {
|
||||||
|
fun findByGuid(guid: UUID): Customer?
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.github.dannecron.demo.db.repository
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.entity.order.OrderProduct
|
||||||
|
import org.springframework.data.repository.CrudRepository
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
interface OrderProductRepository: CrudRepository<OrderProduct, UUID> {
|
||||||
|
fun findByOrderId(orderId: Long): List<OrderProduct>
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.github.dannecron.demo.db.repository
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.entity.order.Order
|
||||||
|
import org.springframework.data.repository.CrudRepository
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
interface OrderRepository: CrudRepository<Order, Long> {
|
||||||
|
fun findByCustomerId(customerId: Long): List<Order>
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.github.dannecron.demo.db.repository
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.entity.Product
|
||||||
|
import org.springframework.data.jdbc.repository.query.Query
|
||||||
|
import org.springframework.data.repository.CrudRepository
|
||||||
|
import org.springframework.data.repository.PagingAndSortingRepository
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
interface ProductRepository: CrudRepository<Product, Long>, PagingAndSortingRepository<Product, Long> {
|
||||||
|
fun findByGuid(guid: UUID): Product?
|
||||||
|
|
||||||
|
@Query(value = "UPDATE Product SET deleted_at = :deletedAt WHERE guid = :guid RETURNING *")
|
||||||
|
fun softDelete(guid: UUID, deletedAt: OffsetDateTime): Product?
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.github.dannecron.demo.db.serialialization
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
object OffsetDateTimeSerialization: KSerializer<OffsetDateTime> {
|
||||||
|
override val descriptor = PrimitiveSerialDescriptor("Time", PrimitiveKind.STRING)
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): OffsetDateTime = OffsetDateTime.parse(decoder.decodeString())
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: OffsetDateTime) {
|
||||||
|
encoder.encodeString(value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.github.dannecron.demo.db.serialialization
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
object UuidSerialization: KSerializer<UUID> {
|
||||||
|
override val descriptor = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING)
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): UUID = UUID.fromString(decoder.decodeString())
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: UUID) {
|
||||||
|
encoder.encodeString(value.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.github.dannecron.demo.db
|
||||||
|
|
||||||
|
import org.springframework.boot.test.autoconfigure.data.jdbc.DataJdbcTest
|
||||||
|
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
|
||||||
|
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories
|
||||||
|
import org.springframework.test.context.ActiveProfiles
|
||||||
|
import org.testcontainers.junit.jupiter.Testcontainers
|
||||||
|
|
||||||
|
@ActiveProfiles("db")
|
||||||
|
@DataJdbcTest
|
||||||
|
@Testcontainers(disabledWithoutDocker = false)
|
||||||
|
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
||||||
|
@EnableJdbcRepositories
|
||||||
|
class BaseDbTest
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.github.dannecron.demo.db.repository
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.BaseDbTest
|
||||||
|
import com.github.dannecron.demo.db.entity.City
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.test.context.ContextConfiguration
|
||||||
|
import org.springframework.test.context.jdbc.Sql
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
|
@ContextConfiguration(classes = [CityRepository::class])
|
||||||
|
class CityRepositoryTest : BaseDbTest() {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var cityRepository: CityRepository
|
||||||
|
|
||||||
|
private val cityGuid = UUID.fromString("21a1a3a8-621a-40f7-b64f-7e118aa241b9")
|
||||||
|
private val city = City(
|
||||||
|
id = 1000,
|
||||||
|
guid = cityGuid,
|
||||||
|
name = "Tokyo",
|
||||||
|
createdAt = OffsetDateTime.parse("2025-01-01T12:10:05+00:00"),
|
||||||
|
updatedAt = null,
|
||||||
|
deletedAt = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Sql(scripts = ["/sql/insert_city.sql"])
|
||||||
|
fun findByGuid() {
|
||||||
|
val result = cityRepository.findByGuid(cityGuid)
|
||||||
|
assertEquals(city, result)
|
||||||
|
|
||||||
|
val emptyResult = cityRepository.findByGuid(UUID.randomUUID())
|
||||||
|
assertNull(emptyResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Sql(scripts = ["/sql/insert_city.sql"])
|
||||||
|
fun softDelete() {
|
||||||
|
val deletedAt = OffsetDateTime.parse("2025-01-02T12:10:05+00:00")
|
||||||
|
val expectedCity = city.copy(deletedAt = deletedAt)
|
||||||
|
|
||||||
|
val result = cityRepository.softDelete(cityGuid, deletedAt)
|
||||||
|
assertEquals(expectedCity, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.github.dannecron.demo.db.repository
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.BaseDbTest
|
||||||
|
import com.github.dannecron.demo.db.entity.Customer
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.test.context.ContextConfiguration
|
||||||
|
import org.springframework.test.context.jdbc.Sql
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
|
@ContextConfiguration(classes = [CustomerRepository::class])
|
||||||
|
class CustomerRepositoryTest : BaseDbTest() {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var customerRepository: CustomerRepository
|
||||||
|
|
||||||
|
private val customerGuid = UUID.fromString("823c50de-4c81-49bd-a69a-2d52be42b728")
|
||||||
|
private val customer = Customer(
|
||||||
|
id = 1000,
|
||||||
|
guid = customerGuid,
|
||||||
|
name = "Customer",
|
||||||
|
cityId = 1000,
|
||||||
|
createdAt = OffsetDateTime.parse("2025-01-01T12:10:05+00:00"),
|
||||||
|
updatedAt = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Sql(scripts = ["/sql/insert_city.sql", "/sql/insert_customer.sql"])
|
||||||
|
fun findByGuid() {
|
||||||
|
val result = customerRepository.findByGuid(customerGuid)
|
||||||
|
assertEquals(customer, result)
|
||||||
|
|
||||||
|
val emptyResult = customerRepository.findByGuid(UUID.randomUUID())
|
||||||
|
assertNull(emptyResult)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.github.dannecron.demo.db.repository
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.BaseDbTest
|
||||||
|
import com.github.dannecron.demo.db.entity.order.OrderProduct
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.test.context.ContextConfiguration
|
||||||
|
import org.springframework.test.context.jdbc.Sql
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ContextConfiguration(classes = [OrderProductRepository::class])
|
||||||
|
class OrderProductRepositoryTest : BaseDbTest() {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var orderProductRepository: OrderProductRepository
|
||||||
|
|
||||||
|
private val orderId = 1000L
|
||||||
|
private val orderProduct = OrderProduct(
|
||||||
|
guid = UUID.fromString("930f54e2-c60d-448e-83b1-0d259ff2c2d3"),
|
||||||
|
orderId = orderId,
|
||||||
|
productId = 1000,
|
||||||
|
createdAt = OffsetDateTime.parse("2025-01-01T12:10:05+00:00"),
|
||||||
|
updatedAt = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Sql(
|
||||||
|
scripts = [
|
||||||
|
"/sql/insert_city.sql",
|
||||||
|
"/sql/insert_customer.sql",
|
||||||
|
"/sql/insert_order.sql",
|
||||||
|
"/sql/insert_product.sql",
|
||||||
|
"/sql/insert_order_product.sql",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
fun findByOrderId() {
|
||||||
|
val result = orderProductRepository.findByOrderId(orderId)
|
||||||
|
assertEquals(1, result.size)
|
||||||
|
assertEquals(orderProduct, result[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.github.dannecron.demo.db.repository
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.BaseDbTest
|
||||||
|
import com.github.dannecron.demo.db.entity.order.Order
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.test.context.ContextConfiguration
|
||||||
|
import org.springframework.test.context.jdbc.Sql
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ContextConfiguration(classes = [OrderRepository::class])
|
||||||
|
class OrderRepositoryTest : BaseDbTest() {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var orderRepository: OrderRepository
|
||||||
|
|
||||||
|
private val orderGuid = UUID.fromString("2c960a08-7187-4e91-9ef3-275c91b1342c")
|
||||||
|
private val customerId = 1000L
|
||||||
|
private val order = Order(
|
||||||
|
id = 1000,
|
||||||
|
guid = orderGuid,
|
||||||
|
customerId = customerId,
|
||||||
|
deliveredAt = null,
|
||||||
|
createdAt = OffsetDateTime.parse("2025-01-01T12:10:05+00:00"),
|
||||||
|
updatedAt = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Sql(
|
||||||
|
scripts = [
|
||||||
|
"/sql/insert_city.sql",
|
||||||
|
"/sql/insert_customer.sql",
|
||||||
|
"/sql/insert_order.sql",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
fun findByGuid() {
|
||||||
|
val result = orderRepository.findByCustomerId(customerId)
|
||||||
|
assertEquals(1, result.size)
|
||||||
|
assertEquals(order, result[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.github.dannecron.demo.db.repository
|
||||||
|
|
||||||
|
import com.github.dannecron.demo.db.BaseDbTest
|
||||||
|
import com.github.dannecron.demo.db.entity.Product
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.test.context.ContextConfiguration
|
||||||
|
import org.springframework.test.context.jdbc.Sql
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
|
@ContextConfiguration(classes = [ProductRepository::class])
|
||||||
|
class ProductRepositoryTest : BaseDbTest() {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var productRepository: ProductRepository
|
||||||
|
|
||||||
|
private val productGuid = UUID.fromString("1fb5c7e4-8ce2-43b8-8ca7-1089b04959b9")
|
||||||
|
private val product = Product(
|
||||||
|
id = 1000,
|
||||||
|
guid = productGuid,
|
||||||
|
name = "product",
|
||||||
|
description = "description",
|
||||||
|
price = 10000,
|
||||||
|
createdAt = OffsetDateTime.parse("2025-01-01T12:10:05+00:00"),
|
||||||
|
updatedAt = null,
|
||||||
|
deletedAt = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Sql(scripts = ["/sql/insert_product.sql"])
|
||||||
|
fun findByGuid() {
|
||||||
|
val result = productRepository.findByGuid(productGuid)
|
||||||
|
assertEquals(product, result)
|
||||||
|
|
||||||
|
val emptyResult = productRepository.findByGuid(UUID.randomUUID())
|
||||||
|
assertNull(emptyResult)
|
||||||
|
}
|
||||||
|
}
|
||||||
10
db/src/test/resources/application-db.yml
Normal file
10
db/src/test/resources/application-db.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
spring:
|
||||||
|
datasource:
|
||||||
|
url: jdbc:tc:postgresql:14-alpine:///test
|
||||||
|
driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
|
||||||
|
hikari:
|
||||||
|
maximum-pool-size: 2
|
||||||
|
flyway:
|
||||||
|
enabled: true
|
||||||
|
locations: classpath:migration/structure, classpath:migration/data
|
||||||
3
db/src/test/resources/sql/insert_city.sql
Normal file
3
db/src/test/resources/sql/insert_city.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
insert into "city" (id, guid, name, created_at) values
|
||||||
|
(1000, '21a1a3a8-621a-40f7-b64f-7e118aa241b9', 'Tokyo', '2025-01-01 12:10:05 +00:00')
|
||||||
|
;
|
||||||
3
db/src/test/resources/sql/insert_customer.sql
Normal file
3
db/src/test/resources/sql/insert_customer.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
insert into "customer" (id, guid, name, city_id, created_at) values
|
||||||
|
(1000, '823c50de-4c81-49bd-a69a-2d52be42b728', 'Customer', 1000, '2025-01-01 12:10:05 +00:00')
|
||||||
|
;
|
||||||
3
db/src/test/resources/sql/insert_order.sql
Normal file
3
db/src/test/resources/sql/insert_order.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
insert into "order" (id, guid, customer_id, created_at) values
|
||||||
|
(1000, '2c960a08-7187-4e91-9ef3-275c91b1342c', 1000, '2025-01-01 12:10:05 +00:00')
|
||||||
|
;
|
||||||
3
db/src/test/resources/sql/insert_order_product.sql
Normal file
3
db/src/test/resources/sql/insert_order_product.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
insert into "order_product" (guid, order_id, product_id, created_at) values
|
||||||
|
('930f54e2-c60d-448e-83b1-0d259ff2c2d3', 1000, 1000, '2025-01-01 12:10:05 +00:00')
|
||||||
|
;
|
||||||
3
db/src/test/resources/sql/insert_product.sql
Normal file
3
db/src/test/resources/sql/insert_product.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
insert into "product" (id, guid, name, description, price, created_at) values
|
||||||
|
(1000, '1fb5c7e4-8ce2-43b8-8ca7-1089b04959b9', 'product', 'description', 10000, '2025-01-01 12:10:05 +00:00')
|
||||||
|
;
|
||||||
@@ -42,9 +42,10 @@ testcontainers-postgresql = { module = "org.testcontainers:postgresql", version.
|
|||||||
tracing = ["micrometer-bridge-otel", "otel-exporter"]
|
tracing = ["micrometer-bridge-otel", "otel-exporter"]
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
|
kotlin-kover = { id = "org.jetbrains.kotlinx.kover", version = "0.8.3" }
|
||||||
|
kotlin-jpa = { id = "org.jetbrains.kotlin.plugin.jpa", version.ref = "kotlin" }
|
||||||
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||||
kotlin-jpa = { id = "org.jetbrains.kotlin.plugin.jpa", version.ref = "kotlin" }
|
|
||||||
kotlin-spring = { id = "org.jetbrains.kotlin.plugin.spring", version.ref = "kotlin" }
|
kotlin-spring = { id = "org.jetbrains.kotlin.plugin.spring", version.ref = "kotlin" }
|
||||||
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
|
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
|
||||||
spring-dependencyManagement = { id = "io.spring.dependency-management", version = "1.1.6"}
|
spring-dependencyManagement = { id = "io.spring.dependency-management", version = "1.1.6"}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
rootProject.name = "demo"
|
rootProject.name = "demo"
|
||||||
|
include("db")
|
||||||
|
|||||||
Reference in New Issue
Block a user