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

pl.touk.nussknacker.ui.initialization.Initialization.scala Maven / Gradle / Ivy

There is a newer version: 1.17.0
Show newest version
package pl.touk.nussknacker.ui.initialization

import cats.instances.list._
import cats.syntax.traverse._
import com.typesafe.scalalogging.LazyLogging
import db.util.DBIOActionInstances._
import pl.touk.nussknacker.engine.api.graph.ScenarioGraph
import pl.touk.nussknacker.engine.canonicalgraph.CanonicalProcess
import pl.touk.nussknacker.engine.migration.ProcessMigrations
import pl.touk.nussknacker.ui.db.entity.EnvironmentsEntityData
import pl.touk.nussknacker.ui.db.{DbRef, NuTables}
import pl.touk.nussknacker.ui.process.ScenarioQuery
import pl.touk.nussknacker.ui.process.migrate.ProcessModelMigrator
import pl.touk.nussknacker.ui.process.processingtype.ProcessingTypeDataProvider
import pl.touk.nussknacker.ui.process.repository._
import pl.touk.nussknacker.ui.security.api.{LoggedUser, NussknackerInternalUser}
import slick.dbio.DBIOAction
import slick.jdbc.JdbcProfile

import scala.concurrent.duration._
import scala.concurrent.{Await, ExecutionContext}

object Initialization {

  implicit val nussknackerUser: LoggedUser = NussknackerInternalUser.instance

  def init(
      migrations: ProcessingTypeDataProvider[ProcessMigrations, _],
      db: DbRef,
      fetchingRepository: DBFetchingProcessRepository[DB],
      commentRepository: CommentRepository,
      environment: String
  )(implicit ec: ExecutionContext): Unit = {
    val processRepository = new DBProcessRepository(db, commentRepository, migrations.mapValues(_.version))

    val operations: List[InitialOperation] = List(
      new EnvironmentInsert(environment, db),
      new AutomaticMigration(migrations.mapValues(new ProcessModelMigrator(_)), processRepository, fetchingRepository)
    )

    runOperationsTransactionally(db, operations)
  }

  private def runOperationsTransactionally(db: DbRef, operations: List[InitialOperation])(
      implicit ec: ExecutionContext
  ): List[Unit] = {

    import db.profile.api._

    val result    = operations.map(_.runOperation).sequence[DB, Unit]
    val runFuture = DBIOActionRunner(db).run(result.transactionally)

    // TODO: make it more configurable...
    Await.result(runFuture, 10 minute)
  }

}

trait InitialOperation extends LazyLogging {

  def runOperation(implicit ec: ExecutionContext, lu: LoggedUser): DB[Unit]

}

class EnvironmentInsert(environmentName: String, dbRef: DbRef) extends InitialOperation {

  override def runOperation(implicit ec: ExecutionContext, lu: LoggedUser): DB[Unit] = {
    // `insertOrUpdate` in Slick v.3.2.0-M1 seems not to work
    import dbRef.profile.api._
    val nuTables = new NuTables {
      override implicit val profile: JdbcProfile = dbRef.profile
    }
    val uppsertEnvironmentAction = for {
      alreadyExists <- nuTables.environmentsTable.filter(_.name === environmentName).exists.result
      _ <-
        if (alreadyExists) {
          DBIO.successful(())
        } else {
          nuTables.environmentsTable += EnvironmentsEntityData(environmentName)
        }
    } yield ()
    uppsertEnvironmentAction
  }

}

class AutomaticMigration(
    migrators: ProcessingTypeDataProvider[ProcessModelMigrator, _],
    processRepository: DBProcessRepository,
    fetchingProcessRepository: DBFetchingProcessRepository[DB]
) extends InitialOperation {

  def runOperation(implicit ec: ExecutionContext, lu: LoggedUser): DB[Unit] = {
    val results: DB[List[Unit]] = for {
      allToMigrate <- fetchingProcessRepository.fetchLatestProcessesDetails[ScenarioGraph](
        ScenarioQuery.unarchived
      )
      migrated <- allToMigrate.map(migrateOne).sequence[DB, Unit]
    } yield migrated
    results.map(_ => ())
  }

  private def migrateOne(
      processDetails: ScenarioWithDetailsEntity[ScenarioGraph]
  )(implicit ec: ExecutionContext, lu: LoggedUser): DB[Unit] = {
    DBIOAction
      .sequenceOption(for {
        migrator        <- migrators.forProcessingType(processDetails.processingType)
        migrationResult <- migrator.migrateProcess(processDetails, skipEmptyMigrations = true)
        updateAction = migrationResult.toUpdateAction(processDetails.processId)
      } yield {
        processRepository.updateProcess(updateAction)
      })
      .map(_ => ())
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy