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

pl.touk.nussknacker.engine.api.graph.ScenarioGraph.scala Maven / Gradle / Ivy

The newest version!
package pl.touk.nussknacker.engine.api.graph

import io.circe.generic.JsonCodec
import io.circe.generic.extras.semiauto.deriveConfiguredDecoder
import io.circe.{Decoder, Encoder, HCursor}
import pl.touk.nussknacker.engine.api.process.ProcessName
import pl.touk.nussknacker.engine.api.{MetaData, ProcessAdditionalFields, TypeSpecificData}
import pl.touk.nussknacker.engine.graph.node.NodeData
import pl.touk.nussknacker.engine.graph.EdgeType
import pl.touk.nussknacker.engine.api.CirceUtil._

@JsonCodec final case class ScenarioGraph(
    properties: ProcessProperties,
    nodes: List[NodeData],
    edges: List[Edge]
) {

  def toMetaData(name: ProcessName): MetaData = properties.toMetaData(name)

}

@JsonCodec final case class Edge(from: String, to: String, edgeType: Option[EdgeType])

// We have the same additionalFields name as in NodeData because properties are treated as node on the FE side
// TODO: remove additionalFields nesting when we stop treating properties as a node on the FE side
final case class ProcessProperties(additionalFields: ProcessAdditionalFields) {

  def toMetaData(scenarioName: ProcessName): MetaData = MetaData(
    id = scenarioName.value,
    additionalFields = additionalFields
  )

  // TODO: remove typeSpecificData-related code after the migration is completed
  def typeSpecificProperties: TypeSpecificData = additionalFields.typeSpecificProperties

}

object ProcessProperties {

  def combineTypeSpecificProperties(
      typeSpecificProperties: TypeSpecificData,
      additionalFields: ProcessAdditionalFields
  ): ProcessProperties = {
    ProcessProperties(additionalFields.combineTypeSpecificProperties(typeSpecificProperties))
  }

  def apply(typeSpecificProperties: TypeSpecificData): ProcessProperties = {
    ProcessProperties.combineTypeSpecificProperties(
      typeSpecificProperties,
      ProcessAdditionalFields(None, Map(), typeSpecificProperties.metaDataType)
    )
  }

  implicit val encodeProcessProperties: Encoder[ProcessProperties] =
    Encoder.forProduct1("additionalFields") { p =>
      p.additionalFields
    }

  // This is a copy-paste from MetaData - see the comment there for the legacy consideration
  implicit val decoder: Decoder[ProcessProperties] = {
    val actualDecoder: Decoder[ProcessProperties] = deriveConfiguredDecoder[ProcessProperties]

    val legacyDecoder: Decoder[ProcessProperties] = {
      def legacyProcessAdditionalFieldsDecoder(metaDataType: String): Decoder[ProcessAdditionalFields] =
        (c: HCursor) =>
          for {
            description <- c.downField("description").as[Option[String]]
            properties  <- c.downField("properties").as[Option[Map[String, String]]]
          } yield {
            ProcessAdditionalFields(description, properties.getOrElse(Map.empty), metaDataType)
          }

      (c: HCursor) =>
        for {
          typeSpecificData <- c.downField("typeSpecificProperties").as[TypeSpecificData]
          additionalFields <- c
            .downField("additionalFields")
            .as[Option[ProcessAdditionalFields]](
              io.circe.Decoder.decodeOption(
                legacyProcessAdditionalFieldsDecoder(typeSpecificData.metaDataType)
              )
            )
            .map(_.getOrElse(ProcessAdditionalFields(None, Map.empty, typeSpecificData.metaDataType)))
        } yield {
          ProcessProperties.combineTypeSpecificProperties(typeSpecificData, additionalFields)
        }
    }

    actualDecoder or legacyDecoder
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy