All Downloads are FREE. Search and download functionalities are using the official Maven repository.

slick.additions.codegen.BaseCodeGenerator.scala Maven / Gradle / Ivy

The newest version!
package slick.additions.codegen

import java.nio.file.{Files, Path}

import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.meta._

import slick.additions.codegen.ScalaMetaDsl._
import slick.dbio.DBIO
import slick.jdbc.{JdbcBackend, JdbcProfile}

import com.typesafe.config.Config
import org.scalafmt.Scalafmt
import org.scalafmt.config.ScalafmtConfig


/** Base trait for code generators. Code generators are responsible for producing actual code, but many of the details
  * are determined by the [[TableConfig]]s and [[ColumnConfig]]s produced by the instance of [[GenerationRules]] that is
  * passed in.
  *
  * @see
  *   [[GenerationRules]]
  */
trait BaseCodeGenerator {
  private def recursePathTerm[A <: C, C](xs: List[String], last: A)(g: (Term.Ref, A) => C): C =
    xs match {
      case Nil     => last
      case x :: xs => g(toTermRef0(x, xs), last)
    }

  private def toTermRef0(last: String, revInit: List[String]): Term.Ref =
    recursePathTerm[Term.Name, Term.Ref](revInit, term"$last")(_.termSelect(_))

  protected def toTermRef(s: String): Term.Ref =
    s.split('.').toList.reverse match {
      case Nil             => term"$s"
      case last :: revInit => toTermRef0(last, revInit)
    }

  protected def toTypeRef(s: String): Type.Ref =
    s.split('.').toList.reverse match {
      case Nil             => typ"$s"
      case last :: revInit => recursePathTerm[Type.Name, Type.Ref](revInit, typ"$last")(_.typeSelect(_))
    }

  protected def imports(strings: List[String]): List[Stat] =
    if (strings.isEmpty)
      Nil
    else
      List(Import(strings.map(_.parse[Importer].get)))

  def codeString(
    rules: GenerationRules,
    slickProfileClass: Class[_ <: JdbcProfile]
  )(implicit executionContext: ExecutionContext
  ): DBIO[String]

  def codeString(rules: GenerationRules, slickProfileClassName: String)(implicit executionContext: ExecutionContext)
    : DBIO[String] = codeString(rules, Class.forName(slickProfileClassName).asSubclass(classOf[JdbcProfile]))

  def codeStringFormatted(
    rules: GenerationRules,
    slickProfileClassName: String,
    scalafmtConfig: ScalafmtConfig = ScalafmtConfig.defaultWithAlign
  )(implicit executionContext: ExecutionContext
  ): DBIO[String] =
    codeString(rules, Class.forName(slickProfileClassName).asSubclass(classOf[JdbcProfile]))
      .flatMap { str =>
        val formatted = Scalafmt.format(str, scalafmtConfig)
        DBIO.from(Future.fromTry(formatted.toEither.toTry))
      }

  def writeToFileDBIO(
    baseDir: Path,
    slickConfig: Config,
    rules: GenerationRules
  )(implicit executionContext: ExecutionContext
  ) =
    codeStringFormatted(rules, slickConfig.getString("profile")).map { codeStr =>
      val path = rules.filePath(baseDir)
      Files.createDirectories(path.getParent)
      Files.write(path, codeStr.getBytes())
      path
    }

  def writeToFileSync(
    baseDir: Path,
    slickConfig: Config,
    rules: GenerationRules,
    timeout: Duration = Duration.Inf
  )(implicit executionContext: ExecutionContext
  ): Path = {
    val db = JdbcBackend.Database.forConfig("", slickConfig)

    try
      Await.result(db.run(writeToFileDBIO(baseDir, slickConfig, rules)), timeout)
    finally
      db.close()
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy