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

pl.touk.nussknacker.engine.api.context.ValidationContext.scala Maven / Gradle / Ivy

There is a newer version: 1.18.0
Show newest version
package pl.touk.nussknacker.engine.api.context

import cats.data.Validated.{Invalid, Valid}
import cats.data._
import cats.implicits._
import pl.touk.nussknacker.engine.api.context.ProcessCompilationError.OverwrittenVariable
import pl.touk.nussknacker.engine.api.context.ValidationContext.empty
import pl.touk.nussknacker.engine.api.typed.typing.TypingResult
import pl.touk.nussknacker.engine.api.NodeId
import pl.touk.nussknacker.engine.api.VariableConstants.KeyVariableName
import pl.touk.nussknacker.engine.api.parameter.ParameterName
import pl.touk.nussknacker.engine.api.validation.Validations.validateVariableName

object ValidationContext {

  def empty: ValidationContext = ValidationContext()

}

case class ValidationContext(
    localVariables: Map[String, TypingResult] = Map.empty,
    // TODO global variables should not be part of ValidationContext
    globalVariables: Map[String, TypingResult] = Map.empty,
    parent: Option[ValidationContext] = None
) {

  val variables: Map[String, TypingResult] = localVariables ++ globalVariables

  def apply(name: String): TypingResult =
    get(name).getOrElse(throw new RuntimeException(s"Unknown variable: $name"))

  def get(name: String): Option[TypingResult] =
    variables.get(name)

  def contains(name: String): Boolean = variables.contains(name)

  def withVariableUnsafe(name: String, value: TypingResult): ValidationContext =
    withVariable(name, value, None)(NodeId("dumbNodeId")).valueOr(err =>
      throw new IllegalStateException(s"ValidationContext with duplicated variable [$KeyVariableName]")
    )

  def withVariable(name: String, value: TypingResult, paramName: Option[ParameterName])(
      implicit nodeId: NodeId
  ): ValidatedNel[PartSubGraphCompilationError, ValidationContext] = {

    List(validateVariableExists(name, paramName), validateVariableName(name, paramName)).sequence
      .map(_ => copy(localVariables = localVariables + (name -> value)))
  }

  def withVariable(outputVar: OutputVar, value: TypingResult)(
      implicit nodeId: NodeId
  ): ValidatedNel[PartSubGraphCompilationError, ValidationContext] =
    withVariable(outputVar.outputName, value, Some(ParameterName(outputVar.fieldName)))

  def withVariableOverriden(name: String, value: TypingResult, paramName: Option[ParameterName])(
      implicit nodeId: NodeId
  ): ValidatedNel[PartSubGraphCompilationError, ValidationContext] = {
    validateVariableName(name, paramName)
      .map(_ => copy(localVariables = localVariables + (name -> value)))
  }

  private def validateVariableExists(name: String, paramName: Option[ParameterName])(
      implicit nodeId: NodeId
  ): ValidatedNel[PartSubGraphCompilationError, String] =
    if (variables.contains(name)) Invalid(OverwrittenVariable(name, paramName)).toValidatedNel else Valid(name)

  def clearVariables: ValidationContext = copy(localVariables = Map.empty, parent = None)

  def pushNewContext(): ValidationContext =
    ValidationContext(Map.empty, globalVariables, Some(this))

  def popContextOrEmptyWithGlobals(): ValidationContext =
    parent.getOrElse(empty.copy(globalVariables = globalVariables))
}

/**
  * Right now we have a few different ways to name output param in node.. OutputVar allows us to skip using strings.
  * The fieldName should be consistent with field path in model in pl.touk.nussknacker.engine.graph.node,
  * so that errors are displayed correctly
  */
case class OutputVar(fieldName: String, outputName: String)

object OutputVar {

  val VariableFieldName = "varName"

  val EnricherFieldName = "output"

  val SwitchFieldName = "exprVal"

  val CustomNodeFieldName = "outputVar"

  def variable(outputName: String): OutputVar =
    OutputVar(VariableFieldName, outputName)

  def enricher(outputName: String): OutputVar =
    OutputVar(EnricherFieldName, outputName)

  def fragmentOutput(outputName: String, varName: String): OutputVar =
    OutputVar(s"ref.outputVariableNames.$outputName", varName)

  def switch(outputName: String): OutputVar =
    OutputVar(SwitchFieldName, outputName)

  def customNode(outputName: String): OutputVar =
    OutputVar(CustomNodeFieldName, outputName)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy