mirror of
https://github.com/nushell/nushell.git
synced 2025-06-30 22:50:14 +02:00
Add new operators has
and not-has
(#14841)
# Description This PR add 2 new operators, `has` and `not-has`. They are basically `in` and `not-in` with the order of operands swapped. Motivation for this was the awkward way of searching for rows that contain an item using `where` ```nushell [[name, children]; [foo, [a, b, c]], [bar [d, e, f]]] | where ("e" in $it.children) ``` vs ```nushell [[name, children]; [foo, [a, b, c]], [bar [d, e, f]]] | where children has "e" ``` # User-Facing Changes Added `has` and `not-has` operators, mirroring `in` and `not-in`. # Tests + Formatting - 🟢 toolkit fmt - 🟢 toolkit clippy - 🟢 toolkit test - 🟢 toolkit test stdlib # After Submitting
This commit is contained in:
@ -5147,6 +5147,8 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi
|
||||
b"//" => Operator::Math(Math::FloorDivision),
|
||||
b"in" => Operator::Comparison(Comparison::In),
|
||||
b"not-in" => Operator::Comparison(Comparison::NotIn),
|
||||
b"has" => Operator::Comparison(Comparison::Has),
|
||||
b"not-has" => Operator::Comparison(Comparison::NotHas),
|
||||
b"mod" => Operator::Math(Math::Modulo),
|
||||
b"bit-or" => Operator::Bits(Bits::BitOr),
|
||||
b"bit-xor" => Operator::Bits(Bits::BitXor),
|
||||
@ -5187,7 +5189,7 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi
|
||||
b"contains" => {
|
||||
working_set.error(ParseError::UnknownOperator(
|
||||
"contains",
|
||||
"Did you mean '$string =~ $pattern' or '$element in $container'?",
|
||||
"Did you mean 'has'?",
|
||||
span,
|
||||
));
|
||||
return garbage(working_set, span);
|
||||
|
@ -821,7 +821,7 @@ pub fn math_result_type(
|
||||
)
|
||||
}
|
||||
},
|
||||
Operator::Comparison(Comparison::In) => match (&lhs.ty, &rhs.ty) {
|
||||
Operator::Comparison(Comparison::In | Comparison::NotIn) => match (&lhs.ty, &rhs.ty) {
|
||||
(t, Type::List(u)) if type_compatible(t, u) => (Type::Bool, None),
|
||||
(Type::Int | Type::Float | Type::Number, Type::Range) => (Type::Bool, None),
|
||||
(Type::String, Type::String) => (Type::Bool, None),
|
||||
@ -859,44 +859,48 @@ pub fn math_result_type(
|
||||
)
|
||||
}
|
||||
},
|
||||
Operator::Comparison(Comparison::NotIn) => match (&lhs.ty, &rhs.ty) {
|
||||
(t, Type::List(u)) if type_compatible(t, u) => (Type::Bool, None),
|
||||
(Type::Int | Type::Float | Type::Number, Type::Range) => (Type::Bool, None),
|
||||
(Type::String, Type::String) => (Type::Bool, None),
|
||||
(Type::String, Type::Record(_)) => (Type::Bool, None),
|
||||
Operator::Comparison(Comparison::Has | Comparison::NotHas) => {
|
||||
let container = lhs;
|
||||
let element = rhs;
|
||||
match (&element.ty, &container.ty) {
|
||||
(t, Type::List(u)) if type_compatible(t, u) => (Type::Bool, None),
|
||||
(Type::Int | Type::Float | Type::Number, Type::Range) => (Type::Bool, None),
|
||||
(Type::String, Type::String) => (Type::Bool, None),
|
||||
(Type::String, Type::Record(_)) => (Type::Bool, None),
|
||||
|
||||
(Type::Custom(a), Type::Custom(b)) if a == b => (Type::Custom(a.clone()), None),
|
||||
(Type::Custom(a), _) => (Type::Custom(a.clone()), None),
|
||||
(Type::Custom(a), Type::Custom(b)) if a == b => (Type::Custom(a.clone()), None),
|
||||
(Type::Custom(a), _) => (Type::Custom(a.clone()), None),
|
||||
|
||||
(Type::Any, _) => (Type::Bool, None),
|
||||
(_, Type::Any) => (Type::Bool, None),
|
||||
(Type::Int | Type::Float | Type::String, _) => {
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
"subset comparison".into(),
|
||||
op.span,
|
||||
lhs.span,
|
||||
lhs.ty.clone(),
|
||||
rhs.span,
|
||||
rhs.ty.clone(),
|
||||
)),
|
||||
)
|
||||
(Type::Any, _) => (Type::Bool, None),
|
||||
(_, Type::Any) => (Type::Bool, None),
|
||||
(Type::Int | Type::Float | Type::String, _) => {
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
"subset comparison".into(),
|
||||
op.span,
|
||||
element.span,
|
||||
element.ty.clone(),
|
||||
)),
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
"subset comparison".into(),
|
||||
op.span,
|
||||
element.span,
|
||||
element.ty.clone(),
|
||||
container.span,
|
||||
container.ty.clone(),
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
"subset comparison".into(),
|
||||
op.span,
|
||||
lhs.span,
|
||||
lhs.ty.clone(),
|
||||
)),
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
Operator::Bits(Bits::ShiftLeft)
|
||||
| Operator::Bits(Bits::ShiftRight)
|
||||
| Operator::Bits(Bits::BitOr)
|
||||
|
Reference in New Issue
Block a user