diff --git a/api/core/workflow/utils/condition/entities.py b/api/core/workflow/utils/condition/entities.py index 1d96743879..799c735f54 100644 --- a/api/core/workflow/utils/condition/entities.py +++ b/api/core/workflow/utils/condition/entities.py @@ -25,6 +25,9 @@ SupportedComparisonOperator = Literal[ "≤", "null", "not null", + # for file + "exists", + "not exists", ] diff --git a/api/core/workflow/utils/condition/processor.py b/api/core/workflow/utils/condition/processor.py index f4a80fa5e1..19473f39d2 100644 --- a/api/core/workflow/utils/condition/processor.py +++ b/api/core/workflow/utils/condition/processor.py @@ -2,7 +2,7 @@ from collections.abc import Sequence from typing import Any, Literal from core.file import FileAttribute, file_manager -from core.variables.segments import ArrayFileSegment +from core.variables import ArrayFileSegment from core.workflow.entities.variable_pool import VariablePool from .entities import Condition, SubCondition, SupportedComparisonOperator @@ -21,6 +21,8 @@ class ConditionProcessor: for condition in conditions: variable = variable_pool.get(condition.variable_selector) + if variable is None: + raise ValueError(f"Variable {condition.variable_selector} not found") if isinstance(variable, ArrayFileSegment) and condition.comparison_operator in { "contains", @@ -35,6 +37,15 @@ class ConditionProcessor: sub_conditions=condition.sub_variable_condition.conditions, operator=condition.sub_variable_condition.logical_operator, ) + elif condition.comparison_operator in { + "exists", + "not exists", + }: + result = _evaluate_condition( + value=variable.value, + operator=condition.comparison_operator, + expected=None, + ) else: actual_value = variable.value if variable else None expected_value = condition.value @@ -103,6 +114,10 @@ def _evaluate_condition( return _assert_not_in(value=value, expected=expected) case "all of" if isinstance(expected, list): return _assert_all_of(value=value, expected=expected) + case "exists": + return _assert_exists(value=value) + case "not exists": + return _assert_not_exists(value=value) case _: raise ValueError(f"Unsupported operator: {operator}") @@ -338,6 +353,14 @@ def _assert_all_of(*, value: Any, expected: Sequence[str]) -> bool: return True +def _assert_exists(*, value: Any) -> bool: + return value is not None + + +def _assert_not_exists(*, value: Any) -> bool: + return value is None + + def _process_sub_conditions( variable: ArrayFileSegment, sub_conditions: Sequence[SubCondition], diff --git a/api/tests/unit_tests/core/workflow/nodes/test_if_else.py b/api/tests/unit_tests/core/workflow/nodes/test_if_else.py index 8f38d3f280..d964d0e352 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_if_else.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_if_else.py @@ -55,6 +55,7 @@ def test_execute_if_else_result_true(): pool.add(["start", "less_than"], 21) pool.add(["start", "greater_than_or_equal"], 22) pool.add(["start", "less_than_or_equal"], 21) + pool.add(["start", "null"], None) pool.add(["start", "not_null"], "1212") node = IfElseNode(