nushell/crates/nu-command/tests/commands
Bahex c4dcfdb77b
feat!: Explicit cell-path case sensitivity syntax (#15692)
Related:
- #15683
- #14551
- #849
- #12701
- #11527

# Description
Currently various commands have differing behavior regarding cell-paths

```nushell
{a: 1, A: 2} | get a A
# => ╭───┬───╮
# => │ 0 │ 2 │
# => │ 1 │ 2 │
# => ╰───┴───╯
{a: 1, A: 2} | select a A
# => ╭───┬───╮
# => │ a │ 1 │
# => │ A │ 2 │
# => ╰───┴───╯
{A: 1} | update a 2
# => Error: nu:🐚:column_not_found
# => 
# =>   × Cannot find column 'a'
# =>    ╭─[entry #62:1:1]
# =>  1 │ {A: 1} | update a 2
# =>    · ───┬──          ┬
# =>    ·    │            ╰── cannot find column 'a'
# =>    ·    ╰── value originates here
# =>    ╰────
```

Proposal: making cell-path access case-sensitive by default and adding
new syntax for case-insensitive parts, similar to optional (?) parts.

```nushell
{FOO: BAR}.foo
# => Error: nu:🐚:name_not_found
# => 
# =>   × Name not found
# =>    ╭─[entry #60:1:21]
# =>  1 │ {FOO: BAR}.foo
# =>    ·            ─┬─
# =>    ·             ╰── did you mean 'FOO'?
# =>    ╰────
{FOO: BAR}.foo!
# => BAR
```

This would solve the problem of case sensitivity for all commands
without causing an explosion of flags _and_ make it more granular

Assigning to a field using a case-insensitive path is case-preserving.
```nushell
mut val = {FOO: "I'm FOO"}; $val
# => ╭─────┬─────────╮
# => │ FOO │ I'm FOO │
# => ╰─────┴─────────╯
$val.foo! = "I'm still FOO"; $val
# => ╭─────┬───────────────╮
# => │ FOO │ I'm still FOO │
# => ╰─────┴───────────────╯
```

For `update`, case-insensitive is case-preserving.
```nushell
{FOO: 1} | update foo! { $in + 1 }
# => ╭─────┬───╮
# => │ FOO │ 2 │
# => ╰─────┴───╯
```

`insert` can insert values into nested values so accessing into existing
columns is case-insensitive, but creating new columns uses the cell-path
as it is.
So `insert foo! ...` and `insert FOO! ...` would work exactly as they do
without `!`
```nushell
{FOO: {quox: 0}}
# => ╭─────┬──────────────╮
# => │     │ ╭──────┬───╮ │
# => │ FOO │ │ quox │ 0 │ │
# => │     │ ╰──────┴───╯ │
# => ╰─────┴──────────────╯
{FOO: {quox: 0}} | insert foo.bar 1
# => ╭─────┬──────────────╮
# => │     │ ╭──────┬───╮ │
# => │ FOO │ │ quox │ 0 │ │
# => │     │ ╰──────┴───╯ │
# => │     │ ╭─────┬───╮  │
# => │ foo │ │ bar │ 1 │  │
# => │     │ ╰─────┴───╯  │
# => ╰─────┴──────────────╯
{FOO: {quox: 0}} | insert foo!.bar 1
# => ╭─────┬──────────────╮
# => │     │ ╭──────┬───╮ │
# => │ FOO │ │ quox │ 0 │ │
# => │     │ │ bar  │ 1 │ │
# => │     │ ╰──────┴───╯ │
# => ╰─────┴──────────────╯
```

`upsert` is tricky, depending on the input, the data might end up with
different column names in rows. We can either forbid case-insensitive
cell-paths for `upsert` or trust the user to keep their data in a
sensible shape.

This would be a breaking change as it would make existing cell-path
accesses case-sensitive, however the case-sensitivity is already
inconsistent and any attempt at making it consistent would be a breaking
change.

> What about `$env`?

1. Initially special case it so it keeps its current behavior.
2. Accessing environment variables with non-matching paths gives a
deprecation warning urging users to either use exact casing or use the
new explicit case-sensitivity syntax
3. Eventuall remove `$env`'s special case, making `$env` accesses
case-sensitive by default as well.

> `$env.ENV_CONVERSIONS`?

In addition to `from_string` and `to_string` add an optional field to
opt into case insensitive/preserving behavior.

# User-Facing Changes

- `get`, `where` and other previously case-insensitive commands are now
case-sensitive by default.
- `get`'s `--sensitive` flag removed, similar to `--ignore-errors` there
is now an `--ignore-case` flag that treats all parts of the cell-path as
case-insensitive.
- Users can explicitly choose the case case-sensitivity of cell-path
accesses or commands.

# Tests + Formatting

Existing tests required minimal modification. ***However, new tests are
not yet added***.

- 🟢 toolkit fmt
- 🟢 toolkit clippy
- 🟢 toolkit test
- 🟢 toolkit test stdlib

# After Submitting

- Update the website to include the new syntax
- Update [tree-sitter-nu](https://github.com/nushell/tree-sitter-nu)

---------

Co-authored-by: Bahex <17417311+Bahex@users.noreply.github.com>
2025-05-18 12:19:09 +03:00
..
assignment Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
base Update rand and rand_chacha to 0.9 (#15463) 2025-04-01 07:15:39 -05:00
bytes fix range bugs in str substring, str index-of, slice, bytes at (#14863) 2025-01-30 06:50:01 -06:00
conversions Change behavior of into record on lists to be more useful (#13637) 2024-08-22 11:38:43 +02:00
database feat!: Explicit cell-path case sensitivity syntax (#15692) 2025-05-18 12:19:09 +03:00
date fix format date based on users locale (#11908) 2024-02-20 11:08:49 -06:00
debug Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
hash_ Replace the old encode base64 and decode base64 with new-base64 commands (#14018) 2024-10-08 11:01:43 +08:00
math Bugfix/loss of precision when parsing value with unit (#15606) 2025-04-19 17:02:40 -05:00
move_ Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
network Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
path Refactor I/O Errors (#14927) 2025-01-28 16:03:31 -06:00
platform Add ansi codes to move cursor position (#15221) 2025-03-01 11:30:00 -06:00
query Feature cleanup (#7182) 2022-11-22 16:58:11 -08:00
random feat(random uuid): add support for uuid versions other than 4. (#15239) 2025-03-06 14:21:52 +01:00
skip Add string/binary type color to ByteStream (#12897) 2024-05-20 00:35:32 +00:00
str_ fix ranges over zero-length input (#15062) 2025-02-08 19:57:28 -05:00
take Add string/binary type color to ByteStream (#12897) 2024-05-20 00:35:32 +00:00
url Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
alias.rs allow export alias in repl (#15054) 2025-02-10 15:32:05 +08:00
all.rs Rewrite run_external.rs (#12921) 2024-05-23 02:05:27 +00:00
any.rs Rewrite run_external.rs (#12921) 2024-05-23 02:05:27 +00:00
append.rs fix(nu-command/tests): further remove unnecessary pipeline() and cwd() (#8793) 2023-04-07 14:09:55 -07:00
break_.rs don't allow break/continue in each and items command (#13398) 2024-07-19 00:21:02 -07:00
cal.rs Suppress column index for default cal output (#13188) 2024-06-22 07:41:29 -05:00
cd.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
chunk_by.rs Implement chunk_by operation (#14410) 2024-11-29 13:37:27 -08:00
chunks.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
compact.rs fix compact to handle empty list or record in column (#15213) 2025-03-01 07:47:55 -05:00
complete.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
config_env_default.rs Command: Add config env/nu --default to print defaults (#10480) 2023-09-25 08:00:59 -05:00
config_nu_default.rs Command: Add config env/nu --default to print defaults (#10480) 2023-09-25 08:00:59 -05:00
continue_.rs fix(nu-command/tests): further remove unnecessary pipeline() and cwd() (#8793) 2023-04-07 14:09:55 -07:00
debug_info.rs Make debug info lazy (#10728) 2023-10-24 12:48:05 -05:00
def.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
default.rs Add lazy closure evaluation to default (#14160) (#15654) 2025-05-15 10:10:56 -04:00
detect_columns.rs Improves commands that support range input (#13113) 2024-06-18 07:19:13 -05:00
do_.rs remove -s, -p in do (#15456) 2025-04-01 07:17:05 -05:00
drop.rs Refactor drop columns to fix issues (#10903) 2023-11-09 13:51:46 +01:00
du.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
each.rs Remove group command (#14056) 2024-10-11 06:43:12 -05:00
echo.rs make echo const (#14997) 2025-02-06 06:56:30 -06:00
empty.rs fix(nu-command/tests): further remove unnecessary pipeline() and cwd() (#8793) 2023-04-07 14:09:55 -07:00
error_make.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
every.rs Avoid taking unnecessary ownership of intermediates (#12740) 2024-05-04 00:53:15 +00:00
exec.rs Isolate tests from user config (#12437) 2024-04-10 06:27:46 +08:00
export_def.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
fill.rs Removes unnecessary cwd and pipeline from various tests (#9202) 2023-05-17 18:55:26 -05:00
filter.rs feat: make to nuon raw option remove all white space (#15609) 2025-05-09 09:38:24 +08:00
find.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
first.rs Add string/binary type color to ByteStream (#12897) 2024-05-20 00:35:32 +00:00
flatten.rs Remove file I/O from tests that don't need it (#11182) 2023-11-29 23:21:34 +01:00
for_.rs Change echo to print when not redirected (#10338) 2023-09-13 06:35:01 +12:00
format.rs small refactoring around units and add tests (#15746) 2025-05-16 17:41:26 -05:00
generate.rs Add input support to generate (#14804) 2025-01-14 11:44:31 -06:00
get.rs Make get const (#14751) 2025-01-04 16:41:03 -05:00
glob.rs Add --follow-symlinks flag to glob command (fixes #15559) (#15626) 2025-04-23 10:47:48 -05:00
griddle.rs make grid throw an error when not enough columns (#12672) 2024-04-26 06:33:00 -05:00
group_by.rs Add run-time type checking for command pipeline input (#14741) 2025-01-08 23:09:47 +01:00
headers.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
help.rs Change the usage misnomer to "description" (#13598) 2024-08-22 12:02:08 +02:00
histogram.rs Remove file I/O from tests that don't need it (#11182) 2023-11-29 23:21:34 +01:00
ignore.rs Change the ignore command to use drain() instead of collecting a value (#12120) 2024-03-08 02:18:26 -05:00
insert.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
inspect.rs fix inspect and explore panics on empty records (#13893) 2024-09-25 07:48:16 -05:00
interleave.rs Isolate tests from user config (#12437) 2024-04-10 06:27:46 +08:00
into_datetime.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
into_duration.rs small refactoring around units and add tests (#15746) 2025-05-16 17:41:26 -05:00
into_filesize.rs Bump bytesize to fix into filesize (#15088) 2025-02-11 11:33:48 +01:00
into_int.rs add --signed flag for binary into int conversions (#11902) 2024-02-27 15:05:26 +00:00
job.rs Inter-Job direct messaging (#15253) 2025-04-26 23:24:35 +08:00
join.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
last.rs Add string/binary type color to ByteStream (#12897) 2024-05-20 00:35:32 +00:00
length.rs support binary input in length (#14224) 2024-11-04 03:39:24 +00:00
let_.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
lines.rs fix panic with lines on an error (#9967) 2023-08-09 14:12:58 +02:00
loop_.rs Change echo to print when not redirected (#10338) 2023-09-13 06:35:01 +12:00
ls.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
match_.rs prevent panic when parsing incomplete multi-expr (|) matches (#15230) 2025-03-04 05:34:34 -06:00
merge_deep.rs Add merge deep command (#14525) 2024-12-18 06:36:04 -06:00
merge.rs Remove file I/O from tests that don't need it (#11182) 2023-11-29 23:21:34 +01:00
mktemp.rs Path migration part 4: various tests (#13373) 2024-08-03 10:09:13 +02:00
mod.rs Bugfix/loss of precision when parsing value with unit (#15606) 2025-04-19 17:02:40 -05:00
mut_.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
nu_check.rs More precise ErrorKind::NotFound errors (#15149) 2025-02-22 11:42:44 -05:00
open.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
par_each.rs Fix: remove unnecessary r#"..."# (#8670) (#9764) 2023-07-21 17:32:37 +02:00
parse.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
prepend.rs Avoid taking unnecessary ownership of intermediates (#12740) 2024-05-04 00:53:15 +00:00
print.rs Add --raw switch to print for binary data (#13597) 2024-08-12 17:29:25 +08:00
redirection.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
reduce.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
reject.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
rename.rs Remove file I/O from tests that don't need it (#11182) 2023-11-29 23:21:34 +01:00
return_.rs Fix return setting last exit code (#14120) 2024-10-18 03:05:58 +00:00
reverse.rs Clean up tests containing unnecessary cwd: tokens (#9692) 2023-07-17 18:43:51 +02:00
rm.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
roll.rs Fix: remove unnecessary r#"..."# (#8670) (#9764) 2023-07-21 17:32:37 +02:00
rotate.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
run_external.rs run-external spreads command if it's a list (#15776) 2025-05-18 10:09:32 +02:00
save.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
select.rs fix: inefficient select with large row number (#15730) 2025-05-10 11:28:18 +03:00
semicolon.rs Slim down tests (#9021) 2023-04-28 13:25:44 +02:00
seq_char.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
seq_date.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
seq.rs Slim down tests (#9021) 2023-04-28 13:25:44 +02:00
slice.rs fix range bugs in str substring, str index-of, slice, bytes at (#14863) 2025-01-30 06:50:01 -06:00
sort_by.rs to json -r not removing whitespaces fix (#11948) 2024-03-20 22:14:31 +01:00
sort.rs Rework sorting and add cell path and closure comparators to sort-by (#13154) 2024-10-09 19:18:16 -07:00
source_env.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
split_column.rs Add --number flag to split column (#13831) 2024-09-12 07:16:33 -05:00
split_row.rs Avoid taking unnecessary ownership of intermediates (#12740) 2024-05-04 00:53:15 +00:00
start.rs check signals while printing values (#14980) 2025-02-07 06:56:07 -05:00
stor.rs Fix improperly escaped strings in stor update (#14921) 2025-01-26 07:20:39 -06:00
table.rs fix: empty tables now respect $env.config.use_ansi_coloring (closes #14896) (#15751) 2025-05-14 06:40:15 -05:00
tee.rs Make tee work more nicely with non-collections (#13652) 2024-09-01 19:03:46 +02:00
terminal.rs Add is-terminal to determine if stdin/out/err are a terminal (#10970) 2023-11-21 20:48:39 -06:00
to_text.rs Make to text line endings consistent for list (streams) (#14166) 2024-11-05 09:33:54 +01:00
transpose.rs Transpose now rejects streams with non-record values (#15151) 2025-02-20 23:34:26 -05:00
try_.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
ucp.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
ulimit.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
umkdir.rs [umkdir][tests] get umask instead of assuming it (#14046) 2024-10-11 14:13:42 +02:00
uname.rs Initial implementation for uutils uname (#11684) 2024-03-25 16:51:50 -05:00
uniq_by.rs Remove file I/O from tests that don't need it (#11182) 2023-11-29 23:21:34 +01:00
uniq.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
update.rs Remove lazy records (#12682) 2024-05-03 08:36:10 +08:00
upsert.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
use_.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
utouch.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
where_.rs feat(where): Support stored closure (#15697) 2025-05-13 22:24:45 +03:00
which.rs change the output of which to be more explicit (#9646) 2023-07-20 19:10:53 -05:00
while_.rs Change echo to print when not redirected (#10338) 2023-09-13 06:35:01 +12:00
window.rs Rust 1.85, edition=2024 (#15741) 2025-05-13 16:49:30 +02:00
with_env.rs Improve with-env robustness (#12523) 2024-04-16 19:08:58 +08:00
wrap.rs Remove file I/O from tests that don't need it (#11182) 2023-11-29 23:21:34 +01:00
zip.rs Avoid taking unnecessary ownership of intermediates (#12740) 2024-05-04 00:53:15 +00:00