Underground-Digital/Workflow-Engine
0
1from collections.abc import Sequence2from typing import Any, Literal3 4from core.file import FileAttribute, file_manager5from core.variables import ArrayFileSegment6from core.workflow.entities.variable_pool import VariablePool7 8from .entities import Condition, SubCondition, SupportedComparisonOperator9 10 11class ConditionProcessor:12 def process_conditions(13 self,14 *,15 variable_pool: VariablePool,16 conditions: Sequence[Condition],17 operator: Literal["and", "or"],18 ):19 input_conditions = []20 group_results = []21 22 for condition in conditions:23 variable = variable_pool.get(condition.variable_selector)24 if variable is None:25 raise ValueError(f"Variable {condition.variable_selector} not found")26 27 if isinstance(variable, ArrayFileSegment) and condition.comparison_operator in {28 "contains",29 "not contains",30 "all of",31 }:32 # check sub conditions33 if not condition.sub_variable_condition:34 raise ValueError("Sub variable is required")35 result = _process_sub_conditions(36 variable=variable,37 sub_conditions=condition.sub_variable_condition.conditions,38 operator=condition.sub_variable_condition.logical_operator,39 )40 elif condition.comparison_operator in {41 "exists",42 "not exists",43 }:44 result = _evaluate_condition(45 value=variable.value,46 operator=condition.comparison_operator,47 expected=None,48 )49 else:50 actual_value = variable.value if variable else None51 expected_value = condition.value52 if isinstance(expected_value, str):53 expected_value = variable_pool.convert_template(expected_value).text54 input_conditions.append(55 {56 "actual_value": actual_value,57 "expected_value": expected_value,58 "comparison_operator": condition.comparison_operator,59 }60 )61 result = _evaluate_condition(62 value=actual_value,63 operator=condition.comparison_operator,64 expected=expected_value,65 )66 group_results.append(result)67 68 final_result = all(group_results) if operator == "and" else any(group_results)69 return input_conditions, group_results, final_result70 71 72def _evaluate_condition(73 *,74 operator: SupportedComparisonOperator,75 value: Any,76 expected: str | Sequence[str] | None,77) -> bool:78 match operator:79 case "contains":80 return _assert_contains(value=value, expected=expected)81 case "not contains":82 return _assert_not_contains(value=value, expected=expected)83 case "start with":84 return _assert_start_with(value=value, expected=expected)85 case "end with":86 return _assert_end_with(value=value, expected=expected)87 case "is":88 return _assert_is(value=value, expected=expected)89 case "is not":90 return _assert_is_not(value=value, expected=expected)91 case "empty":92 return _assert_empty(value=value)93 case "not empty":94 return _assert_not_empty(value=value)95 case "=":96 return _assert_equal(value=value, expected=expected)97 case "≠":98 return _assert_not_equal(value=value, expected=expected)99 case ">":100 return _assert_greater_than(value=value, expected=expected)101 case "<":102 return _assert_less_than(value=value, expected=expected)103 case "≥":104 return _assert_greater_than_or_equal(value=value, expected=expected)105 case "≤":106 return _assert_less_than_or_equal(value=value, expected=expected)107 case "null":108 return _assert_null(value=value)109 case "not null":110 return _assert_not_null(value=value)111 case "in":112 return _assert_in(value=value, expected=expected)113 case "not in":114 return _assert_not_in(value=value, expected=expected)115 case "all of" if isinstance(expected, list):116 return _assert_all_of(value=value, expected=expected)117 case "exists":118 return _assert_exists(value=value)119 case "not exists":120 return _assert_not_exists(value=value)121 case _:122 raise ValueError(f"Unsupported operator: {operator}")123 124 125def _assert_contains(*, value: Any, expected: Any) -> bool:126 if not value:127 return False128 129 if not isinstance(value, str | list):130 raise ValueError("Invalid actual value type: string or array")131 132 if expected not in value:133 return False134 return True135 136 137def _assert_not_contains(*, value: Any, expected: Any) -> bool:138 if not value:139 return True140 141 if not isinstance(value, str | list):142 raise ValueError("Invalid actual value type: string or array")143 144 if expected in value:145 return False146 return True147 148 149def _assert_start_with(*, value: Any, expected: Any) -> bool:150 if not value:151 return False152 153 if not isinstance(value, str):154 raise ValueError("Invalid actual value type: string")155 156 if not value.startswith(expected):157 return False158 return True159 160 161def _assert_end_with(*, value: Any, expected: Any) -> bool:162 if not value:163 return False164 165 if not isinstance(value, str):166 raise ValueError("Invalid actual value type: string")167 168 if not value.endswith(expected):169 return False170 return True171 172 173def _assert_is(*, value: Any, expected: Any) -> bool:174 if value is None:175 return False176 177 if not isinstance(value, str):178 raise ValueError("Invalid actual value type: string")179 180 if value != expected:181 return False182 return True183 184 185def _assert_is_not(*, value: Any, expected: Any) -> bool:186 if value is None:187 return False188 189 if not isinstance(value, str):190 raise ValueError("Invalid actual value type: string")191 192 if value == expected:193 return False194 return True195 196 197def _assert_empty(*, value: Any) -> bool:198 if not value:199 return True200 return False201 202 203def _assert_not_empty(*, value: Any) -> bool:204 if value:205 return True206 return False207 208 209def _assert_equal(*, value: Any, expected: Any) -> bool:210 if value is None:211 return False212 213 if not isinstance(value, int | float):214 raise ValueError("Invalid actual value type: number")215 216 if isinstance(value, int):217 expected = int(expected)218 else:219 expected = float(expected)220 221 if value != expected:222 return False223 return True224 225 226def _assert_not_equal(*, value: Any, expected: Any) -> bool:227 if value is None:228 return False229 230 if not isinstance(value, int | float):231 raise ValueError("Invalid actual value type: number")232 233 if isinstance(value, int):234 expected = int(expected)235 else:236 expected = float(expected)237 238 if value == expected:239 return False240 return True241 242 243def _assert_greater_than(*, value: Any, expected: Any) -> bool:244 if value is None:245 return False246 247 if not isinstance(value, int | float):248 raise ValueError("Invalid actual value type: number")249 250 if isinstance(value, int):251 expected = int(expected)252 else:253 expected = float(expected)254 255 if value <= expected:256 return False257 return True258 259 260def _assert_less_than(*, value: Any, expected: Any) -> bool:261 if value is None:262 return False263 264 if not isinstance(value, int | float):265 raise ValueError("Invalid actual value type: number")266 267 if isinstance(value, int):268 expected = int(expected)269 else:270 expected = float(expected)271 272 if value >= expected:273 return False274 return True275 276 277def _assert_greater_than_or_equal(*, value: Any, expected: Any) -> bool:278 if value is None:279 return False280 281 if not isinstance(value, int | float):282 raise ValueError("Invalid actual value type: number")283 284 if isinstance(value, int):285 expected = int(expected)286 else:287 expected = float(expected)288 289 if value < expected:290 return False291 return True292 293 294def _assert_less_than_or_equal(*, value: Any, expected: Any) -> bool:295 if value is None:296 return False297 298 if not isinstance(value, int | float):299 raise ValueError("Invalid actual value type: number")300 301 if isinstance(value, int):302 expected = int(expected)303 else:304 expected = float(expected)305 306 if value > expected:307 return False308 return True309 310 311def _assert_null(*, value: Any) -> bool:312 if value is None:313 return True314 return False315 316 317def _assert_not_null(*, value: Any) -> bool:318 if value is not None:319 return True320 return False321 322 323def _assert_in(*, value: Any, expected: Any) -> bool:324 if not value:325 return False326 327 if not isinstance(expected, list):328 raise ValueError("Invalid expected value type: array")329 330 if value not in expected:331 return False332 return True333 334 335def _assert_not_in(*, value: Any, expected: Any) -> bool:336 if not value:337 return True338 339 if not isinstance(expected, list):340 raise ValueError("Invalid expected value type: array")341 342 if value in expected:343 return False344 return True345 346 347def _assert_all_of(*, value: Any, expected: Sequence[str]) -> bool:348 if not value:349 return False350 351 if not all(item in value for item in expected):352 return False353 return True354 355 356def _assert_exists(*, value: Any) -> bool:357 return value is not None358 359 360def _assert_not_exists(*, value: Any) -> bool:361 return value is None362 363 364def _process_sub_conditions(365 variable: ArrayFileSegment,366 sub_conditions: Sequence[SubCondition],367 operator: Literal["and", "or"],368) -> bool:369 files = variable.value370 group_results = []371 for condition in sub_conditions:372 key = FileAttribute(condition.key)373 values = [file_manager.get_attr(file=file, attr=key) for file in files]374 sub_group_results = [375 _evaluate_condition(376 value=value,377 operator=condition.comparison_operator,378 expected=condition.value,379 )380 for value in values381 ]382 # Determine the result based on the presence of "not" in the comparison operator383 result = all(sub_group_results) if "not" in condition.comparison_operator else any(sub_group_results)384 group_results.append(result)385 return all(group_results) if operator == "and" else any(group_results)386 