diff --git a/build.gradle.kts b/build.gradle.kts index b9ceeaf..72bbf39 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -76,7 +76,7 @@ tasks.register("copyEnv") { files.forEach { if (!it.exists()) { - it.writeText("") + it.writeText("changeit") } } } @@ -108,6 +108,8 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:$kotlin_serialization_version") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.2") implementation("redis.clients:jedis:5.2.0") + implementation("org.postgresql:postgresql:42.7.5") + implementation("com.zaxxer:HikariCP:6.3.0") // Force version of sub library (for security) implementation("commons-codec:commons-codec:1.13") diff --git a/src/main/kotlin/eventDemo/configuration/injection/ConfigureDI.kt b/src/main/kotlin/eventDemo/configuration/injection/ConfigureDI.kt index 4f9495d..5b22105 100644 --- a/src/main/kotlin/eventDemo/configuration/injection/ConfigureDI.kt +++ b/src/main/kotlin/eventDemo/configuration/injection/ConfigureDI.kt @@ -5,11 +5,18 @@ import org.koin.dsl.module fun appKoinModule(config: Configuration) = module { configureDIBusiness() - configureDIInfrastructure(config.redisUrl) + configureDIInfrastructure(config) configureDILibs() configureDICommandActions() } data class Configuration( val redisUrl: String, -) + val postgresql: Postgresql, +) { + data class Postgresql( + val url: String, + val username: String, + val password: String, + ) +} diff --git a/src/main/kotlin/eventDemo/configuration/injection/ConfigureDIInfrastructure.kt b/src/main/kotlin/eventDemo/configuration/injection/ConfigureDIInfrastructure.kt index c70e9cc..20adc94 100644 --- a/src/main/kotlin/eventDemo/configuration/injection/ConfigureDIInfrastructure.kt +++ b/src/main/kotlin/eventDemo/configuration/injection/ConfigureDIInfrastructure.kt @@ -1,5 +1,7 @@ package eventDemo.configuration.injection +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource import eventDemo.adapter.infrastructureLayer.event.GameEventBusInMemory import eventDemo.adapter.infrastructureLayer.event.GameEventStoreInMemory import eventDemo.adapter.infrastructureLayer.event.projection.GameListRepositoryInMemory @@ -16,12 +18,24 @@ import org.koin.core.module.dsl.singleOf import org.koin.dsl.bind import redis.clients.jedis.JedisPooled import redis.clients.jedis.UnifiedJedis +import javax.sql.DataSource -fun Module.configureDIInfrastructure(redisUrl: String) { +fun Module.configureDIInfrastructure(config: Configuration) { factory { - JedisPooled(redisUrl) + JedisPooled(config.redisUrl) } bind UnifiedJedis::class + single { + HikariConfig() + .apply { + jdbcUrl = config.postgresql.url + username = config.postgresql.username + password = config.postgresql.password + }.let { + HikariDataSource(it) + } + } bind DataSource::class + singleOf(::GameEventBusInMemory) bind GameEventBus::class singleOf(::GameEventStoreInMemory) bind GameEventStore::class singleOf(::GameProjectionBusInMemory) bind GameProjectionBus::class diff --git a/src/main/kotlin/eventDemo/configuration/ktor/ConfigureKoin.kt b/src/main/kotlin/eventDemo/configuration/ktor/ConfigureKoin.kt index 24d9d31..1486d87 100644 --- a/src/main/kotlin/eventDemo/configuration/ktor/ConfigureKoin.kt +++ b/src/main/kotlin/eventDemo/configuration/ktor/ConfigureKoin.kt @@ -4,6 +4,7 @@ import eventDemo.configuration.injection.Configuration import eventDemo.configuration.injection.appKoinModule import io.ktor.server.application.Application import io.ktor.server.application.install +import io.ktor.server.config.ApplicationConfig import org.koin.ktor.plugin.Koin import org.koin.logger.slf4jLogger @@ -11,7 +12,24 @@ fun Application.configureKoin() { install(Koin) { slf4jLogger() - val redisUrl = environment.config.propertyOrNull("redis.url")?.getString() ?: error("You must set the redis.url") - modules(appKoinModule(Configuration(redisUrl))) + modules( + appKoinModule( + environment.config.configuration(), + ), + ) } } + +fun ApplicationConfig.configuration() = + Configuration( + redisUrl = getProperty("redis.url"), + postgresql = + Configuration.Postgresql( + url = getProperty("postgresql.url"), + username = getProperty("postgresql.username"), + password = getProperty("postgresql.password"), + ), + ) + +private fun ApplicationConfig.getProperty(path: String): String = + propertyOrNull(path)?.getString() ?: error("You must set the $path") diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index c30e5ff..18e0be2 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -6,4 +6,15 @@ jwt { redis { url = "redis://localhost:6379" url = ${?REDIS_URL} +} + +postgresql { + url = "jdbc:postgresql://localhost:5432/event-demo" + url = ${?POSTGRESQL_URL} + + username = "event-demo" + username = ${?POSTGRESQL_USERNAME} + + password = "changeit" + password = ${?POSTGRESQL_PASSWORD} } \ No newline at end of file diff --git a/src/test/kotlin/eventDemo/adapter/infrastructureLayer/PostgresqlTest.kt b/src/test/kotlin/eventDemo/adapter/infrastructureLayer/PostgresqlTest.kt new file mode 100644 index 0000000..fa034b2 --- /dev/null +++ b/src/test/kotlin/eventDemo/adapter/infrastructureLayer/PostgresqlTest.kt @@ -0,0 +1,37 @@ +package eventDemo.adapter.infrastructureLayer + +import eventDemo.configuration.configure +import io.kotest.core.NamedTag +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.equals.shouldBeEqual +import io.ktor.server.testing.testApplication +import org.koin.core.context.stopKoin +import org.koin.ktor.ext.inject +import javax.sql.DataSource + +class PostgresqlTest : + FunSpec({ + tags(NamedTag("postgresql")) + + test("test connection with postgresql") { + testApplication { + application { + stopKoin() + configure() + + val datasource by inject() + datasource.connection.use { connection -> + connection + .prepareStatement( + """ + select 1; + """.trimIndent(), + ).execute() + .let { + it shouldBeEqual true + } + } + } + } + } + })