瀏覽代碼

feat: Optionally comparing fields in Var.contains, e.g. on rx.Base based types. (#3375)

* feat: Optionally comparing fields, e.g. on rx.Base based types.

* feat: Minimally invasive change.
Leave the current implementation as is. Added test.

* fix: Supporting old-school python versions.

* fix: Adding masenf's suggestions to use var instead of string.
abulvenz 1 年之前
父節點
當前提交
7c2056e960
共有 2 個文件被更改,包括 20 次插入8 次删除
  1. 17 8
      reflex/vars.py
  2. 3 0
      tests/test_var.py

+ 17 - 8
reflex/vars.py

@@ -838,19 +838,19 @@ class Var:
                 if invoke_fn:
                 if invoke_fn:
                     # invoke the function on left operand.
                     # invoke the function on left operand.
                     operation_name = (
                     operation_name = (
-                        f"{left_operand_full_name}.{fn}({right_operand_full_name})"  # type: ignore
-                    )
+                        f"{left_operand_full_name}.{fn}({right_operand_full_name})"
+                    )  # type: ignore
                 else:
                 else:
                     # pass the operands as arguments to the function.
                     # pass the operands as arguments to the function.
                     operation_name = (
                     operation_name = (
-                        f"{left_operand_full_name} {op} {right_operand_full_name}"  # type: ignore
-                    )
+                        f"{left_operand_full_name} {op} {right_operand_full_name}"
+                    )  # type: ignore
                     operation_name = f"{fn}({operation_name})"
                     operation_name = f"{fn}({operation_name})"
             else:
             else:
                 # apply operator to operands (left operand <operator> right_operand)
                 # apply operator to operands (left operand <operator> right_operand)
                 operation_name = (
                 operation_name = (
-                    f"{left_operand_full_name} {op} {right_operand_full_name}"  # type: ignore
-                )
+                    f"{left_operand_full_name} {op} {right_operand_full_name}"
+                )  # type: ignore
                 operation_name = format.wrap(operation_name, "(")
                 operation_name = format.wrap(operation_name, "(")
         else:
         else:
             # apply operator to left operand (<operator> left_operand)
             # apply operator to left operand (<operator> left_operand)
@@ -1353,11 +1353,12 @@ class Var:
             "'in' operator not supported for Var types, use Var.contains() instead."
             "'in' operator not supported for Var types, use Var.contains() instead."
         )
         )
 
 
-    def contains(self, other: Any) -> Var:
+    def contains(self, other: Any, field: Union[Var, None] = None) -> Var:
         """Check if a var contains the object `other`.
         """Check if a var contains the object `other`.
 
 
         Args:
         Args:
             other: The object to check.
             other: The object to check.
+            field: Optionally specify a field to check on both object and the other var.
 
 
         Raises:
         Raises:
             VarTypeError: If the var is not a valid type: dict, list, tuple or str.
             VarTypeError: If the var is not a valid type: dict, list, tuple or str.
@@ -1393,8 +1394,16 @@ class Var:
                 raise VarTypeError(
                 raise VarTypeError(
                     f"'in <string>' requires string as left operand, not {other._var_type}"
                     f"'in <string>' requires string as left operand, not {other._var_type}"
                 )
                 )
+
+            _var_name = None
+            if field is None:
+                _var_name = f"{self._var_name}.includes({other._var_full_name})"
+            else:
+                field = Var.create_safe(field, _var_is_string=isinstance(field, str))
+                _var_name = f"{self._var_name}.some(e=>e[{field._var_name_unwrapped}]==={other._var_full_name})"
+
             return self._replace(
             return self._replace(
-                _var_name=f"{self._var_name}.includes({other._var_full_name})",
+                _var_name=_var_name,
                 _var_type=bool,
                 _var_type=bool,
                 _var_is_string=False,
                 _var_is_string=False,
                 merge_var_data=other._var_data,
                 merge_var_data=other._var_data,

+ 3 - 0
tests/test_var.py

@@ -454,6 +454,9 @@ def test_str_contains(var, expected):
     other_var = BaseVar(_var_name="other", _var_type=str)
     other_var = BaseVar(_var_name="other", _var_type=str)
     assert str(var.contains(other_state_var)) == f"{{{expected}.includes(state.other)}}"
     assert str(var.contains(other_state_var)) == f"{{{expected}.includes(state.other)}}"
     assert str(var.contains(other_var)) == f"{{{expected}.includes(other)}}"
     assert str(var.contains(other_var)) == f"{{{expected}.includes(other)}}"
+    assert (
+        str(var.contains("1", "hello")) == f'{{{expected}.some(e=>e[`hello`]==="1")}}'
+    )
 
 
 
 
 @pytest.mark.parametrize(
 @pytest.mark.parametrize(