feat(each): noop on single null input, map-null equivalent (#16396)

# Description
Basically, now `null | each { "something" }` will be `null` instead of
`"something"`. Thanks to this, `each` can be used to map values similar
to `map-null` custom commands, for example:
- Before
```nu
let args = if $delay != null {
    ["--delay" ($delay | format duration sec | parse '{secs} {_}' | get 0.secs)]
} else {
    []
}
```
- After
```nu
let args = (
    $delay
    | each { ["--delay" ($in | format duration sec | parse '{secs} {_}' | get 0.secs)] }
    | default []
)
```

Please let me know if this change messes something up I'm not seeing.
# User-Facing Changes
- Before
```nu
→ null | each { "something" }
something
```
- After
```nu
→ null | each { "something" }
null
```
# Tests + Formatting
Added a test to check for this.

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->

---------

Co-authored-by: Bahex <17417311+Bahex@users.noreply.github.com>
This commit is contained in:
Tyarel8
2025-08-13 22:22:24 +02:00
committed by GitHub
parent 43992f5b6f
commit 3fe9c7c00c
3 changed files with 16 additions and 2 deletions

View File

@@ -90,6 +90,11 @@ with 'transpose' first."#
Value::nothing(Span::test_data()),
])),
},
Example {
example: r#"$env.name? | each { $"hello ($in)" } | default "bye""#,
description: "Update value if not null, otherwise do nothing",
result: None,
},
]
}
@@ -107,6 +112,7 @@ with 'transpose' first."#
let metadata = input.metadata();
match input {
PipelineData::Empty => Ok(PipelineData::empty()),
PipelineData::Value(Value::Nothing { .. }, ..) => Ok(input),
PipelineData::Value(Value::Range { .. }, ..)
| PipelineData::Value(Value::List { .. }, ..)
| PipelineData::ListStream(..) => {

View File

@@ -63,3 +63,10 @@ fn errors_in_nested_each_show() {
let actual = nu!("[[1,2]] | each {|x| $x | each {|y| error make {msg: \"oh noes\"} } }");
assert!(actual.err.contains("oh noes"))
}
#[test]
fn each_noop_on_single_null() {
let actual = nu!("null | each { \"test\" } | describe");
assert_eq!(actual.out, "nothing");
}