mirror of
https://github.com/nushell/nushell
synced 2025-01-15 22:54:16 +00:00
8127b5dd24
# Description This PR adds the `merge deep` command. This allows you to merge nested records and tables/lists within records together, instead of overwriting them. The code for `merge` was reworked to support more general merging of values, so `merge` and `merge deep` use the same underlying code. `merge deep` mostly works like `merge`, except it recurses into inner records which exist in both the input and argument rather than just overwriting. For lists and by extension tables, `merge deep` has a couple different strategies for merging inner lists, which can be selected with the `--strategy` flag. These are: - `table`: Merges tables element-wise, similarly to the merge command. Non-table lists are not merged. - `overwrite`: Lists and tables are overwritten with their corresponding value from the argument, similarly to scalars. - `append`: Lists and tables in the input are appended with the corresponding list from the argument. - `prepend`: Lists and tables in the input are prepended with the corresponding list from the argument. This can also be used with the new config changes to write a monolithic record of _only_ the config values you want to change: ```nushell # in config file: const overrides = { history: { file_format: "sqlite", isolation: true } } # use append strategy for lists, e.g., menus keybindings $env.config = $env.config | merge deep --strategy=append $overrides # later, in REPL: $env.config.history # => ╭───────────────┬────────╮ # => │ max_size │ 100000 │ # => │ sync_on_enter │ true │ # => │ file_format │ sqlite │ # => │ isolation │ true │ # => ╰───────────────┴────────╯ ``` <details> <summary>Performance details</summary> For those interested, there was less than one standard deviation of difference in startup time when setting each config item individually versus using <code>merge deep</code>, so you can use <code>merge deep</code> in your config at no measurable performance cost. Here's my results: My normal config (in 0.101 style, with each `$env.config.[...]` value updated individually) ```nushell bench --pretty { ./nu -l -c '' } # => 45ms 976µs 983ns +/- 455µs 955ns ``` Equivalent config with a single `overrides` record and `merge deep -s append`: ```nushell bench --pretty { ./nu -l -c '' } # => 45ms 587µs 428ns +/- 702µs 944ns ``` </details> Huge thanks to @Bahex for designing the strategies API and helping finish up this PR while I was sick ❤️ Related: #12148 # User-Facing Changes Adds the `merge deep` command to recursively merge records. For example: ```nushell {a: {foo: 123 bar: "overwrite me"}, b: [1, 2, 3]} | merge deep {a: {bar: 456, baz: 789}, b: [4, 5, 6]} # => ╭───┬───────────────╮ # => │ │ ╭─────┬─────╮ │ # => │ a │ │ foo │ 123 │ │ # => │ │ │ bar │ 456 │ │ # => │ │ │ baz │ 789 │ │ # => │ │ ╰─────┴─────╯ │ # => │ │ ╭───┬───╮ │ # => │ b │ │ 0 │ 4 │ │ # => │ │ │ 1 │ 5 │ │ # => │ │ │ 2 │ 6 │ │ # => │ │ ╰───┴───╯ │ # => ╰───┴───────────────╯ ``` `merge deep` also has different strategies for merging inner lists and tables. For example, you can use the `append` strategy to _merge_ the inner `b` list instead of overwriting it. ```nushell {a: {foo: 123 bar: "overwrite me"}, b: [1, 2, 3]} | merge deep --strategy=append {a: {bar: 456, baz: 789}, b: [4, 5, 6]} # => ╭───┬───────────────╮ # => │ │ ╭─────┬─────╮ │ # => │ a │ │ foo │ 123 │ │ # => │ │ │ bar │ 456 │ │ # => │ │ │ baz │ 789 │ │ # => │ │ ╰─────┴─────╯ │ # => │ │ ╭───┬───╮ │ # => │ b │ │ 0 │ 1 │ │ # => │ │ │ 1 │ 2 │ │ # => │ │ │ 2 │ 3 │ │ # => │ │ │ 3 │ 4 │ │ # => │ │ │ 4 │ 5 │ │ # => │ │ │ 5 │ 6 │ │ # => │ │ ╰───┴───╯ │ # => ╰───┴───────────────╯ ``` **Note to release notes writers**: Please credit @Bahex for this PR as well 😄 # Tests + Formatting <!-- Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> Added tests for deep merge - 🟢 `toolkit fmt` - 🟢 `toolkit clippy` - 🟢 `toolkit test` - 🟢 `toolkit test stdlib` # 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. --> N/A --------- Co-authored-by: Bahex <bahey1999@gmail.com> |
||
---|---|---|
.. | ||
assignment | ||
base | ||
bytes | ||
conversions | ||
database | ||
date | ||
debug | ||
hash_ | ||
math | ||
move_ | ||
network | ||
path | ||
platform | ||
query | ||
random | ||
skip | ||
str_ | ||
take | ||
url | ||
alias.rs | ||
all.rs | ||
any.rs | ||
append.rs | ||
break_.rs | ||
cal.rs | ||
cd.rs | ||
chunk_by.rs | ||
chunks.rs | ||
compact.rs | ||
complete.rs | ||
config_env_default.rs | ||
config_nu_default.rs | ||
continue_.rs | ||
debug_info.rs | ||
def.rs | ||
default.rs | ||
detect_columns.rs | ||
do_.rs | ||
drop.rs | ||
du.rs | ||
each.rs | ||
echo.rs | ||
empty.rs | ||
error_make.rs | ||
every.rs | ||
exec.rs | ||
export_def.rs | ||
fill.rs | ||
filter.rs | ||
find.rs | ||
first.rs | ||
flatten.rs | ||
for_.rs | ||
format.rs | ||
generate.rs | ||
get.rs | ||
glob.rs | ||
griddle.rs | ||
group_by.rs | ||
headers.rs | ||
help.rs | ||
histogram.rs | ||
ignore.rs | ||
insert.rs | ||
inspect.rs | ||
interleave.rs | ||
into_datetime.rs | ||
into_filesize.rs | ||
into_int.rs | ||
join.rs | ||
last.rs | ||
length.rs | ||
let_.rs | ||
lines.rs | ||
loop_.rs | ||
ls.rs | ||
match_.rs | ||
merge.rs | ||
merge_deep.rs | ||
mktemp.rs | ||
mod.rs | ||
mut_.rs | ||
nu_check.rs | ||
open.rs | ||
par_each.rs | ||
parse.rs | ||
prepend.rs | ||
print.rs | ||
range.rs | ||
redirection.rs | ||
reduce.rs | ||
reject.rs | ||
rename.rs | ||
return_.rs | ||
reverse.rs | ||
rm.rs | ||
roll.rs | ||
rotate.rs | ||
run_external.rs | ||
save.rs | ||
select.rs | ||
semicolon.rs | ||
seq.rs | ||
seq_char.rs | ||
seq_date.rs | ||
sort.rs | ||
sort_by.rs | ||
source_env.rs | ||
split_by.rs | ||
split_column.rs | ||
split_row.rs | ||
table.rs | ||
tee.rs | ||
terminal.rs | ||
to_text.rs | ||
touch.rs | ||
transpose.rs | ||
try_.rs | ||
ucp.rs | ||
ulimit.rs | ||
umkdir.rs | ||
uname.rs | ||
uniq.rs | ||
uniq_by.rs | ||
update.rs | ||
upsert.rs | ||
use_.rs | ||
utouch.rs | ||
where_.rs | ||
which.rs | ||
while_.rs | ||
window.rs | ||
with_env.rs | ||
wrap.rs | ||
zip.rs |