Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

25 changes: 17 additions & 8 deletions reflex/vars.py
Original file line number Diff line number Diff line change
Expand Up @@ -838,19 +838,19 @@ def get_operand_full_name(operand):
if invoke_fn:
# invoke the function on left operand.
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:
# pass the operands as arguments to the function.
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})"
else:
# apply operator to operands (left operand <operator> right_operand)
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, "(")
else:
# apply operator to left operand (<operator> left_operand)
Expand Down Expand Up @@ -1353,11 +1353,12 @@ def __contains__(self, _: Any) -> Var:
"'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`.

Args:
other: The object to check.
field: Optionally specify a field to check on both object and the other var.

Raises:
VarTypeError: If the var is not a valid type: dict, list, tuple or str.
Expand Down Expand Up @@ -1393,8 +1394,16 @@ def contains(self, other: Any) -> Var:
raise VarTypeError(
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(
_var_name=f"{self._var_name}.includes({other._var_full_name})",
_var_name=_var_name,
_var_type=bool,
_var_is_string=False,
merge_var_data=other._var_data,
Expand Down
3 changes: 3 additions & 0 deletions tests/test_var.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,9 @@ def test_str_contains(var, expected):
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_var)) == f"{{{expected}.includes(other)}}"
assert (
str(var.contains("1", "hello")) == f'{{{expected}.some(e=>e[`hello`]==="1")}}'
)


@pytest.mark.parametrize(
Expand Down
Loading