Skip to content

Commit

Permalink
fixed empty value handling in DictParameterEditor optional parameters (
Browse files Browse the repository at this point in the history
  • Loading branch information
wrzontek committed Apr 5, 2024
1 parent 1c7d252 commit 14d189e
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 35 deletions.
Expand Up @@ -11,6 +11,7 @@ import pl.touk.nussknacker.engine.api.process.ProcessName
import pl.touk.nussknacker.engine.build.ScenarioBuilder
import pl.touk.nussknacker.engine.canonicalgraph.CanonicalProcess
import pl.touk.nussknacker.engine.graph.expression.Expression
import pl.touk.nussknacker.engine.graph.expression.Expression.Language
import pl.touk.nussknacker.engine.spel.Implicits._
import pl.touk.nussknacker.test.base.it.NuItTest
import pl.touk.nussknacker.test.config.WithSimplifiedDesignerConfig.TestCategory.Category1
Expand Down Expand Up @@ -76,7 +77,7 @@ class DictsFlowTest
"serviceWithDictParameterEditor",
"RGBDict" -> Expression.dictKeyWithLabel("H000000", Some("Black")),
"BooleanDict" -> Expression.dictKeyWithLabel("true", Some("OLD LABEL")),
"LongDict" -> Expression.dictKeyWithLabel("-1500100900", Some("large (negative) number")),
"LongDict" -> Expression(Language.DictKeyWithLabel, ""), // optional parameter left empty
"RGBDictRAW" -> Expression.spel("'someOtherColour'"),
)
.emptySink(EndNodeId, "dead-end-lite")
Expand All @@ -85,7 +86,7 @@ class DictsFlowTest
process,
expressionUsingDictWithLabel = None,
expectedResult = """RGBDict value to lowercase: h000000
|LongDict value + 1: Some(-1500100899)
|LongDict value + 1: None
|BooleanDict value negation: Some(false)
|RGBDictRAW value to lowercase: Some(someothercolour)""".stripMargin,
variableToCheck = "data"
Expand Down
Expand Up @@ -532,7 +532,10 @@ class UIProcessValidatorSpec extends AnyFunSuite with Matchers with TableDrivenP
hintText = None,
valueEditor = Some(
ValueInputWithFixedValuesProvided(
fixedValuesList = List(FixedExpressionValue("'someValue'", "someValue")),
fixedValuesList = List(
FixedExpressionValue("'someValue'", "someValue"),
FixedExpressionValue("", ""),
),
allowOtherValue = false
)
),
Expand Down Expand Up @@ -637,6 +640,19 @@ class UIProcessValidatorSpec extends AnyFunSuite with Matchers with TableDrivenP
)
),
valueCompileTimeValidation = None
),
FragmentParameter(
ParameterName("subParam5_valid"),
FragmentClazzRef[java.lang.String],
initialValue = Some(FixedExpressionValue("", "")),
hintText = None,
valueEditor = Some(
ValueInputWithDictEditor(
dictId = "someDictId",
allowOtherValue = false
)
),
valueCompileTimeValidation = None
)
)
)
Expand Down
Expand Up @@ -13,10 +13,7 @@ class ServiceWithDictParameterEditor extends Service with Serializable with Time
@MethodToInvoke
def invoke(
@ParamName("RGBDict")
@SimpleEditor(
`type` = SimpleEditorType.DICT_EDITOR,
dictId = "rgb"
)
@SimpleEditor(`type` = SimpleEditorType.DICT_EDITOR, dictId = "rgb")
rgb: String,
@ParamName("BooleanDict")
@DualEditor(
Expand All @@ -25,10 +22,7 @@ class ServiceWithDictParameterEditor extends Service with Serializable with Time
)
booleanDict: Option[java.lang.Boolean],
@ParamName("LongDict")
@SimpleEditor(
`type` = SimpleEditorType.DICT_EDITOR,
dictId = "long_dict"
)
@SimpleEditor(`type` = SimpleEditorType.DICT_EDITOR, dictId = "long_dict")
longDict: Option[java.lang.Long],
@ParamName("RGBDictRAW")
@DualEditor(
Expand Down
Expand Up @@ -18,6 +18,7 @@ import pl.touk.nussknacker.engine.api.typed.typing.{Typed, Unknown}
import pl.touk.nussknacker.engine.api.validation.Validations.validateVariableName
import pl.touk.nussknacker.engine.compile.ExpressionCompiler
import pl.touk.nussknacker.engine.graph.expression.Expression
import pl.touk.nussknacker.engine.graph.expression.Expression.Language
import pl.touk.nussknacker.engine.graph.node.FragmentInputDefinition.{FragmentClazzRef, FragmentParameter}
import pl.touk.nussknacker.engine.graph.node.{
DictIdFieldName,
Expand Down Expand Up @@ -83,10 +84,13 @@ object FragmentParameterValidator {
.map { fixedExpressionValue =>
val expr = fragmentParameter.valueEditor match {
case Some(ValueInputWithDictEditor(_, _)) =>
DictKeyWithLabelExpressionParser
.parseDictKeyWithLabelExpression(fixedExpressionValue.expression)
.leftMap(errs => errs.map(_.toProcessCompilationError(nodeId.id, fragmentParameter.name)))
.andThen(e => valid(Expression.dictKeyWithLabel(e.key, e.label)))
if (fixedExpressionValue.expression.isBlank)
valid(Expression(Language.DictKeyWithLabel, ""))
else
DictKeyWithLabelExpressionParser
.parseDictKeyWithLabelExpression(fixedExpressionValue.expression)
.leftMap(errs => errs.map(_.toProcessCompilationError(nodeId.id, fragmentParameter.name)))
.andThen(e => valid(Expression.dictKeyWithLabel(e.key, e.label)))
case _ => valid(Expression.spel(fixedExpressionValue.expression))
}

Expand Down
Expand Up @@ -45,7 +45,7 @@ class ProcessDictSubstitutor(
val nodeTypingInfo = processTypingInfo.getOrElse(nodeExpressionId.nodeId.id, Map.empty)
val optionalExpressionTypingInfo = nodeTypingInfo.get(nodeExpressionId.expressionId)

if (expr.language == Expression.Language.DictKeyWithLabel) {
if (expr.language == Expression.Language.DictKeyWithLabel && !expr.expression.isBlank) {
if (isReverse)
addLabelToDictKeyExpression(process, expr, optionalExpressionTypingInfo, nodeExpressionId)
else
Expand Down
Expand Up @@ -10,10 +10,12 @@ import pl.touk.nussknacker.engine.api.expression.ExpressionTypingInfo
import pl.touk.nussknacker.engine.api.generics.ExpressionParseError
import pl.touk.nussknacker.engine.api.typed.typing
import pl.touk.nussknacker.engine.api.typed.typing.{Typed, TypingResult}
import pl.touk.nussknacker.engine.expression.NullExpression
import pl.touk.nussknacker.engine.expression.parse.{CompiledExpression, ExpressionParser, TypedExpression}
import pl.touk.nussknacker.engine.graph.expression.Expression.Language
import pl.touk.nussknacker.engine.graph.expression.{DictKeyWithLabelExpression, Expression}
import pl.touk.nussknacker.engine.spel.SpelExpressionParseError.KeyWithLabelExpressionParsingError
import pl.touk.nussknacker.engine.spel.SpelExpressionParser

case class DictKeyWithLabelExpressionTypingInfo(key: String, label: Option[String], typingResult: TypingResult)
extends ExpressionTypingInfo
Expand All @@ -27,35 +29,42 @@ object DictKeyWithLabelExpressionParser extends ExpressionParser {
ctx: ValidationContext,
expectedType: typing.TypingResult
): Validated[NonEmptyList[ExpressionParseError], TypedExpression] =
parseDictKeyWithLabelExpression(keyWithLabel).map(expr =>
TypedExpression(
CompiledDictKeyExpression(expr.key, expectedType),
DictKeyWithLabelExpressionTypingInfo(expr.key, expr.label, expectedType)
if (keyWithLabel.isBlank)
Valid(
TypedExpression(
NullExpression(keyWithLabel, SpelExpressionParser.Standard),
DictKeyWithLabelExpressionTypingInfo("", None, expectedType)
)
)
else
parseDictKeyWithLabelExpression(keyWithLabel).map(expr =>
TypedExpression(
CompiledDictKeyExpression(expr.key, expectedType),
DictKeyWithLabelExpressionTypingInfo(expr.key, expr.label, expectedType)
)
)
)

override def parseWithoutContextValidation(
keyWithLabel: String,
expectedType: TypingResult
): Validated[NonEmptyList[ExpressionParseError], CompiledExpression] = {
parseDictKeyWithLabelExpression(keyWithLabel).map(expr => CompiledDictKeyExpression(expr.key, expectedType))
if (keyWithLabel.isBlank)
Valid(NullExpression(keyWithLabel, SpelExpressionParser.Standard))
else
parseDictKeyWithLabelExpression(keyWithLabel).map(expr => CompiledDictKeyExpression(expr.key, expectedType))
}

def parseDictKeyWithLabelExpression(
keyWithLabelJson: String
): Validated[NonEmptyList[KeyWithLabelExpressionParsingError], DictKeyWithLabelExpression] = {
if (keyWithLabelJson.isBlank)
Valid(DictKeyWithLabelExpression("", None))
else
parser.parse(keyWithLabelJson) match {
case Left(e) => invalidNel(KeyWithLabelExpressionParsingError(keyWithLabelJson, e.message))
case Right(json) =>
json.as[DictKeyWithLabelExpression] match {
case Right(expr) => Valid(expr)
case Left(e) => invalidNel(KeyWithLabelExpressionParsingError(keyWithLabelJson, e.message))
}
}
}
): Validated[NonEmptyList[KeyWithLabelExpressionParsingError], DictKeyWithLabelExpression] =
parser.parse(keyWithLabelJson) match {
case Left(e) => invalidNel(KeyWithLabelExpressionParsingError(keyWithLabelJson, e.message))
case Right(json) =>
json.as[DictKeyWithLabelExpression] match {
case Right(expr) => Valid(expr)
case Left(e) => invalidNel(KeyWithLabelExpressionParsingError(keyWithLabelJson, e.message))
}
}

case class CompiledDictKeyExpression(key: String, expectedType: TypingResult) extends CompiledExpression {
override def language: Language = languageId
Expand Down

0 comments on commit 14d189e

Please sign in to comment.