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

pl.touk.nussknacker.restmodel.validation.ValidationResults.scala Maven / Gradle / Ivy

There is a newer version: 1.18.1
Show newest version
package pl.touk.nussknacker.restmodel.validation

import cats.implicits._
import io.circe.generic.JsonCodec
import io.circe.generic.extras.ConfiguredJsonCodec
import io.circe.{Decoder, Encoder, Json}
import pl.touk.nussknacker.engine.api.expression.ExpressionTypingInfo
import pl.touk.nussknacker.engine.api.typed.{TypeEncoders, typing}
import pl.touk.nussknacker.engine.api.typed.typing.TypingResult
import pl.touk.nussknacker.restmodel.definition.UIParameter
import pl.touk.nussknacker.engine.api.CirceUtil._

object ValidationResults {

  private implicit val typingResultDecoder: Decoder[TypingResult] = Decoder.decodeJson.map(_ => typing.Unknown)

  //TODO: consider extracting additional DTO class
  //TODO: we have ConfiguredJsonCodec to handle empty nodeResults for legacy reasons, remove it after successful NK migration
  @ConfiguredJsonCodec case class ValidationResult(errors: ValidationErrors, warnings: ValidationWarnings,
                                                   nodeResults: Map[String, NodeTypingData] = Map.empty) {
    val isOk: Boolean = errors == ValidationErrors.success && warnings == ValidationWarnings.success
    val saveAllowed: Boolean = allErrors.forall(_.errorType == NodeValidationErrorType.SaveAllowed)

    def add(other: ValidationResult): ValidationResult = ValidationResult(
      ValidationErrors(
        errors.invalidNodes.combine(other.errors.invalidNodes),
        errors.processPropertiesErrors ++ other.errors.processPropertiesErrors,
        errors.globalErrors ++ other.errors.globalErrors),
      ValidationWarnings(
        warnings.invalidNodes.combine(other.warnings.invalidNodes)
      ),
      nodeResults ++ other.nodeResults
    )

    def withNodeResults(nodeResults: Map[String, NodeTypingData]): ValidationResult
    = copy(nodeResults = nodeResults)

    def renderNotAllowedErrors: List[NodeValidationError] = {
      allErrors.filter(_.errorType == NodeValidationErrorType.RenderNotAllowed)
    }

    def saveNotAllowedErrors: List[NodeValidationError] = {
      allErrors.filter(_.errorType == NodeValidationErrorType.SaveNotAllowed)
    }

    def typingInfo: Map[String, Map[String, ExpressionTypingInfo]] = nodeResults.mapValues(_.typingInfo)

    private def allErrors: List[NodeValidationError] = {
      (errors.invalidNodes.values.flatten ++ errors.processPropertiesErrors ++ errors.globalErrors).toList
    }

  }

  object NodeTypingData {
    implicit val typingInfoEncoder: Encoder[ExpressionTypingInfo] = TypeEncoders.typingResultEncoder.contramap(_.typingResult)
    implicit val typingInfoDecoder: Decoder[ExpressionTypingInfo] = Decoder.failedWithMessage("typingInfo shouldn't be decoded")
  }

  @JsonCodec case class NodeTypingData(variableTypes: Map[String, TypingResult],
                                       parameters: Option[List[UIParameter]],
                                       // currently we not showing typing info in gui but maybe in near future will
                                       // be used for enhanced typing in FE
                                       typingInfo: Map[String, ExpressionTypingInfo])

  @JsonCodec case class ValidationErrors(invalidNodes: Map[String, List[NodeValidationError]],
                                         processPropertiesErrors: List[NodeValidationError],
                                         globalErrors: List[NodeValidationError]) {
    def isEmpty: Boolean = invalidNodes.isEmpty && processPropertiesErrors.isEmpty && globalErrors.isEmpty
  }

  @JsonCodec case class ValidationWarnings(invalidNodes: Map[String, List[NodeValidationError]])

  @JsonCodec case class NodeValidationError(typ: String,
                                            message: String,
                                            description: String,
                                            fieldName: Option[String],
                                            errorType: NodeValidationErrorType.Value)

  object ValidationErrors {
    val success = ValidationErrors(Map.empty, List(), List())
  }

  object ValidationWarnings {
    val success = ValidationWarnings(Map.empty)
  }

  object ValidationResult {
    val success = ValidationResult(ValidationErrors.success, ValidationWarnings.success, Map.empty)

    def errors(invalidNodes: Map[String, List[NodeValidationError]],
               processPropertiesErrors: List[NodeValidationError],
               globalErrors: List[NodeValidationError]): ValidationResult = {
      ValidationResult(
        ValidationErrors(invalidNodes = invalidNodes, processPropertiesErrors = processPropertiesErrors,
          globalErrors = globalErrors
        ),
        ValidationWarnings.success,
        Map.empty
      )
    }

    def warnings(invalidNodes: Map[String, List[NodeValidationError]]): ValidationResult = {
      ValidationResult(
        ValidationErrors.success,
        ValidationWarnings(invalidNodes = invalidNodes), Map.empty
      )
    }

  }

  object NodeValidationErrorType extends Enumeration {

    type NodeValidationErrorType = Value
    implicit val encoder: Encoder[NodeValidationErrorType.Value] = Encoder.enumEncoder(NodeValidationErrorType)
    implicit val decoder: Decoder[NodeValidationErrorType.Value] = Decoder.enumDecoder(NodeValidationErrorType)
    val RenderNotAllowed, SaveNotAllowed, SaveAllowed = Value
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy