Skip to content

Commit

Permalink
chore: refactors using resource and other improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
rodobarcaaa committed Oct 27, 2023
1 parent c276730 commit 08593fa
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 104 deletions.
2 changes: 2 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ sonar.sourceEncoding=UTF-8
sonar.java.binaries=target/scala-2.13
sonar.java.test.binaries=target/scala-2.13
sonar.scala.coverage.reportPaths=target/scala-2.13/scoverage-report/scoverage.xml
sonar.coverage.exclusions=**/Main.scala
sonar.exclusions=**/Main.scala
15 changes: 0 additions & 15 deletions src/main/scala/com/example/InitModule.scala

This file was deleted.

36 changes: 17 additions & 19 deletions src/main/scala/com/example/Main.scala
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
package com.example

import cats.effect.{ExitCode, IO, IOApp}
import com.example.global.infrastructure.slick.Fly4sMigrations
import com.typesafe.scalalogging.StrictLogging
import cats.effect.{IO, Resource, ResourceApp}
import com.example.global.infrastructure.slick.Fly4sModule

object Main extends IOApp with StrictLogging {
object Main extends ResourceApp.Forever {

override def run(args: List[String]): IO[ExitCode] = {
val module = MainModule.initialize

val migrateDb = Fly4sMigrations.migrateDb(module.dbConfig).use(_ => IO.unit)

val startHttpApi = module.httpApi.resource
.use { _ =>
val baseUrl = module.httpConfig.toUrl("http://")
logger.info(s"Documentation from $baseUrl/docs")
logger.info(s"Metrics from $baseUrl/metrics")
IO.never
}

migrateDb *> startHttpApi.as(ExitCode.Success)
}
/** Creating a resource that will be used to run the application composed of three steps:
*
* - the first creates the main module (which loads the configuration and initializes the prometheus metrics)
* - the second migrates the database if needed (it will create the new migration file if it don't exist)
* - the third allocates the http api resource (which starts the http server and exposes the endpoints)
*
* ResourceApp.Forever uses the last resource through a process without termination (so the http server will be
* available while our application is running).
*/
override def run(args: List[String]): Resource[IO, Unit] = for {
module <- MainModule.resource
_ <- Fly4sModule.migrateDbResource
_ <- module.httpApi.resource
} yield ()

}
29 changes: 16 additions & 13 deletions src/main/scala/com/example/MainModule.scala
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
package com.example

import cats.effect.{IO, Resource}
import com.example.books.BookModule
import com.example.global.infrastructure.http._
import com.example.shared.infrastructure.config.Config
import com.example.shared.infrastructure.config.ConfigModule
import com.softwaremill.macwire._
import io.prometheus.client.hotspot

/** To Initialised resources needed by the application to start.
*/
trait MainModule extends ConfigModule with BookModule {
def initialize(): MainModule = {
loadConfig()
hotspot.DefaultExports.initialize()
this
}

trait MainModule extends BookModule {

def config: Config

lazy val dbConfig: DBConfig = DBConfig(config.db.driver, config.db.url, config.db.user, config.db.password)
lazy val httpConfig: HttpConfig = HttpConfig(config.api.host, config.api.port)
lazy val dbConfig: DBConfig = config.db
lazy val apiConfig: HttpConfig = config.api

lazy val metricsApi: MetricsApi = wire[MetricsApi]
lazy val httpApi: HttpApi = wire[HttpApi]
}

object MainModule {
lazy val initialize: MainModule = new MainModule {}.initialize()

def initialize: MainModule = {
val initModule = new InitModule {}
initModule.initialize()
new MainModule { override def config: Config = initModule.config }
}

val resource: Resource[IO, MainModule] = Resource.make(IO(initialize))(_ => IO.unit)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.example.global.infrastructure.http

import com.example.shared.infrastructure.config.Sensitive

case class DBConfig(
driver: String,
url: String,
user: String,
password: String
password: Sensitive
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.example.global.infrastructure.slick

import cats.effect._
import cats.implicits._
import com.example.books.infrastructure.slick.BookMapping
import com.example.shared.infrastructure.slick.HasSlickPgProvider
import fly4s.core.Fly4s
import fly4s.core.data._

import java.io.{File, PrintWriter}
import java.nio.file.{Files, Paths}

object Fly4sModule extends HasSlickPgProvider with BookMapping {

private val migrationsFolder = "src/main/resources/db/migration"

import profile.api._
private val schemas = Books.schema // add more schemas on demand using ++ operator

private val migrationFile = migrationsFolder + "/V003__create_books_table.sql" // change name on demand

private val witterAssistant = Resource.make {
for {
folder <- IO(new File(migrationsFolder))
_ <- IO.unlessA(folder.exists())(IO(folder.mkdirs()).void)

_ <- IO.unlessA(Files.exists(Paths.get(migrationFile))) {
IO {
val w = new PrintWriter(migrationFile)
w.write(schemas.createStatements.mkString("\n"))
w.close()
}
}
} yield ()
}(_ => IO.unit)

private lazy val fly4sConfig = Fly4s.make[IO](
url = dbConfig.url,
user = dbConfig.user.some,
password = dbConfig.password.value.toCharArray.some,
config = Fly4sConfig(baselineOnMigrate = true)
)

def migrateDbResource: Resource[IO, MigrateResult] = witterAssistant *> fly4sConfig.evalMap(_.migrate)

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ trait ConfigModule extends StrictLogging {

def loadConfig(): Unit = {
val info = s"""
|Configuration:
|Load Configuration:
|-----------------------
|API: ${config.api}
|DB: ${config.db}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.example.shared.infrastructure.config

case class Sensitive(value: String) extends AnyVal {
final case class Sensitive(value: String) extends AnyVal {
override def toString: String = "***"
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import slick.jdbc.{ResultSetConcurrency, ResultSetType}

import scala.concurrent.ExecutionContext.Implicits.global

trait HasSlickPgProvider {

private val dbConfig = MainModule.initialize.dbConfig
trait HasSlickPgProvider extends MainModule {

val profile: PgProfile = PgProfile

Expand All @@ -19,7 +17,7 @@ trait HasSlickPgProvider {
val db: Database = Database.forURL(
url = dbConfig.url,
user = dbConfig.user,
password = dbConfig.password,
password = dbConfig.password.value,
driver = dbConfig.driver
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ class BookApiTest extends HasHttp4sRoutesSuite with BookCodecs with AuthorHelper
)
}

test(GET(uri"books?sort=isbn,year")).alias("LIST WITH SORT (isbn and year)") { response =>
assertEquals(response.status, Status.Ok)
}

test(GET(uri"books?sort=year")).alias("LIST WITH SORT (year)") { response =>
assertEquals(response.status, Status.Ok)
assertIO(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package com.example.shared.infrastructure.http

import cats.effect.IO
import com.example.MainModule
import com.example.global.infrastructure.slick.Fly4sMigrations
import com.example.global.infrastructure.slick.Fly4sModule

trait HasHttp4sRoutesSuite extends munit.Http4sHttpRoutesSuite {
lazy val module: MainModule = MainModule.initialize

Fly4sMigrations.migrateDb(module.dbConfig).use(_ => IO.unit).unsafeRunSync()
Fly4sModule.migrateDbResource.use(_ => IO.unit).unsafeRunSync()
}

0 comments on commit 08593fa

Please sign in to comment.