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

pl.touk.nussknacker.engine.management.sample.global.ExampleFunctions.scala Maven / Gradle / Ivy

The newest version!
package pl.touk.nussknacker.engine.management.sample.global

import cats.data.{NonEmptyList, ValidatedNel}
import cats.implicits.catsSyntaxValidatedId
import pl.touk.nussknacker.engine.api.Documentation
import pl.touk.nussknacker.engine.api.generics.GenericFunctionTypingError.ArgumentTypeError
import pl.touk.nussknacker.engine.api.generics.{
  GenericFunctionTypingError,
  GenericType,
  MethodTypeInfo,
  Parameter,
  TypingFunction
}
import pl.touk.nussknacker.engine.api.typed.typing.{
  Typed,
  TypedClass,
  TypedObjectTypingResult,
  TypedObjectWithValue,
  TypingResult
}

import scala.annotation.varargs
import scala.jdk.CollectionConverters._

object ExampleFunctions {

  @Documentation(description = "returns first element of list")
  @GenericType(typingFunction = classOf[HeadHelper])
  def head[T >: Null](list: java.util.List[T]): T =
    list.asScala.headOption.orNull

  private class HeadHelper extends TypingFunction {
    private val listClass = classOf[java.util.List[_]]

    override def computeResultType(
        arguments: List[TypingResult]
    ): ValidatedNel[GenericFunctionTypingError, TypingResult] = arguments match {
      case TypedClass(`listClass`, t :: Nil) :: Nil => t.validNel
      case TypedClass(`listClass`, _) :: Nil        => throw new AssertionError("Lists must have one parameter")
      case _                                        => GenericFunctionTypingError.ArgumentTypeError.invalidNel
    }

  }

  @Documentation(description = "returns example of given type")
  @GenericType(typingFunction = classOf[ExampleOfTypeHelper])
  def exampleOfType(typeName: String): Object = ???

  private class ExampleOfTypeHelper extends TypingFunction {
    private val stringClass = classOf[String]
    private val expectedArgument =
      Typed(Typed.fromInstance("String"), Typed.fromInstance("Double"), Typed.fromInstance("Int"))
    private val expectedResult = Typed(Typed[String], Typed[Double], Typed[Int])

    override def signatures: Option[NonEmptyList[MethodTypeInfo]] =
      Some(NonEmptyList.one(MethodTypeInfo(List(Parameter("typeName", expectedArgument)), None, expectedResult)))

    override def computeResultType(
        arguments: List[TypingResult]
    ): ValidatedNel[GenericFunctionTypingError, TypingResult] = arguments match {
      case TypedObjectWithValue(TypedClass(`stringClass`, Nil), typ: String) :: Nil =>
        typ match {
          case "String" => Typed[String].validNel
          case "Int"    => Typed[Int].validNel
          case "Double" => Typed[Double].validNel
          case _        => GenericFunctionTypingError.ArgumentTypeError.invalidNel
        }
      case a @ TypedObjectWithValue(TypedClass(`stringClass`, _), _) :: Nil =>
        throw new AssertionError(s"Found illegal type $a")
      case TypedClass(`stringClass`, Nil) :: Nil =>
        GenericFunctionTypingError.OtherError("Expected string with known value").invalidNel
      case a @ TypedClass(`stringClass`, _) :: Nil =>
        throw new AssertionError(s"Found illegal type $a")
      case _ =>
        GenericFunctionTypingError.ArgumentTypeError.invalidNel
    }

  }

  @Documentation(description = "fails to compile when given object without field 'a'")
  @GenericType(typingFunction = classOf[RequiresFiledAHelper])
  def getFieldA(obj: Any): Any = ???

  private class RequiresFiledAHelper extends TypingFunction {

    override def computeResultType(
        arguments: List[TypingResult]
    ): ValidatedNel[GenericFunctionTypingError, TypingResult] = arguments match {
      case TypedObjectTypingResult(fields, _, _) :: Nil =>
        fields.get("a") match {
          case Some(x) => x.validNel
          case None    => GenericFunctionTypingError.OtherError("Given object does not have field 'a'").invalidNel
        }
      case _ =>
        GenericFunctionTypingError.ArgumentTypeError.invalidNel
    }

  }

  @Documentation(description = "adds field 'a' to given object")
  @GenericType(typingFunction = classOf[AddFieldAHelper])
  def addFieldA(obj: Any): Any = ???

  private class AddFieldAHelper extends TypingFunction {

    override def computeResultType(
        arguments: List[TypingResult]
    ): ValidatedNel[GenericFunctionTypingError, TypingResult] = arguments match {
      case TypedObjectTypingResult(fields, obj, info) :: Nil =>
        fields.get("a") match {
          case Some(_) => GenericFunctionTypingError.OtherError("Given object already has field 'a'").invalidNel
          case None    => Typed.record(fields + ("a" -> Typed[Int]), obj, info).validNel
        }
      case _ =>
        GenericFunctionTypingError.ArgumentTypeError.invalidNel
    }

  }

  @Documentation(description = "zips up to 3 numbers")
  @GenericType(typingFunction = classOf[ZipHelper])
  @varargs
  def zip(x: Number*): Any = ???

  private class ZipHelper extends TypingFunction {

    override def signatures: Option[NonEmptyList[MethodTypeInfo]] =
      Some(
        NonEmptyList.of(
          MethodTypeInfo(Parameter("arg", Typed[Number]) :: Nil, None, Typed[Number]),
          MethodTypeInfo(
            Parameter("left", Typed[Number]) :: Parameter("right", Typed[Number]) :: Nil,
            None,
            Typed[Number]
          ),
          MethodTypeInfo(
            Parameter("left", Typed[Number]) :: Parameter("mid", Typed[Number]) :: Parameter(
              "right",
              Typed[Number]
            ) :: Nil,
            None,
            Typed[Number]
          )
        )
      )

    override def computeResultType(
        arguments: List[TypingResult]
    ): ValidatedNel[GenericFunctionTypingError, TypingResult] = {
      if (arguments.exists(!_.canBeSubclassOf(Typed[Number]))) return ArgumentTypeError.invalidNel
      arguments match {
        case t :: Nil           => t.validNel
        case l :: r :: Nil      => Typed.record(Map("left" -> l, "right" -> r)).validNel
        case l :: m :: r :: Nil => Typed.record(Map("left" -> l, "mid" -> m, "right" -> r)).validNel
        case _                  => ArgumentTypeError.invalidNel
      }
    }

  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy