Change comparison operators to allow nulls (#8617)

Prior to this PR, the less/greater than operators (`<`, `>`, `<=`, `>=`)
would throw an error if either side was null. After this PR, these
operators return null if either side (or both) is null.

### Examples
```bash 
1 < 3       # true
1 < null    # null
null < 3    # null
null < null # null
```

### Motivation

JT [asked the C#
folks](https://discord.com/channels/601130461678272522/615329862395101194/1086137515053957140)
and this is apparently the approach they would choose for comparison
operators if they could start from scratch.

This PR makes `where` more convenient to use on jagged/missing data. For
example, we can now filter on columns that may not be present in every
row:
```
> [{foo: 123} {}] | where foo? > 10
╭───┬─────╮
│ # │ foo │
├───┼─────┤
│ 0 │ 123 │
╰───┴─────╯
```
This commit is contained in:
Reilly Wood
2023-03-25 16:10:09 -07:00
committed by GitHub
parent 0567407f85
commit d409171ba8
4 changed files with 94 additions and 0 deletions

View File

@ -295,6 +295,9 @@ pub fn math_result_type(
(Type::Custom(a), Type::Custom(b)) if a == b => (Type::Custom(a.to_string()), None),
(Type::Custom(a), _) => (Type::Custom(a.to_string()), None),
(Type::Nothing, _) => (Type::Nothing, None),
(_, Type::Nothing) => (Type::Nothing, None),
(Type::Any, _) => (Type::Bool, None),
(_, Type::Any) => (Type::Bool, None),
_ => {
@ -322,6 +325,9 @@ pub fn math_result_type(
(Type::Custom(a), Type::Custom(b)) if a == b => (Type::Custom(a.to_string()), None),
(Type::Custom(a), _) => (Type::Custom(a.to_string()), None),
(Type::Nothing, _) => (Type::Nothing, None),
(_, Type::Nothing) => (Type::Nothing, None),
(Type::Any, _) => (Type::Bool, None),
(_, Type::Any) => (Type::Bool, None),
_ => {
@ -351,6 +357,9 @@ pub fn math_result_type(
(Type::Any, _) => (Type::Bool, None),
(_, Type::Any) => (Type::Bool, None),
(Type::Nothing, _) => (Type::Nothing, None),
(_, Type::Nothing) => (Type::Nothing, None),
_ => {
*op = Expression::garbage(op.span);
(
@ -378,6 +387,9 @@ pub fn math_result_type(
(Type::Any, _) => (Type::Bool, None),
(_, Type::Any) => (Type::Bool, None),
(Type::Nothing, _) => (Type::Nothing, None),
(_, Type::Nothing) => (Type::Nothing, None),
_ => {
*op = Expression::garbage(op.span);
(