mirror of
https://github.com/nushell/nushell.git
synced 2025-06-30 14:40:06 +02:00
allow update cells
to work on single records (#16018)
# Description
The `update cells` command used to "work" on records by converting them
into single-row tables in the past, but strengthened input type checking
made it so that no longer worked. This commit introduces correct record
-> record functionality.
# User-Facing Changes
Users can now pipe records into `update cells`. An example inspired by a
conversation in the Discord:
```nushell
> version | update cells { split row ', ' } -c [features, installed_plugins]
╭────────────────────┬──────────────────────────────────────────╮
│ version │ 0.105.2 │
│ major │ 0 │
│ minor │ 105 │
│ patch │ 2 │
│ branch │ update-cells-record │
│ commit_hash │ 4f7e9aac62
│
│ build_os │ macos-x86_64 │
│ build_target │ x86_64-apple-darwin │
│ rust_version │ rustc 1.85.1 (4eb161250 2025-03-15) │
│ rust_channel │ 1.85.1-x86_64-apple-darwin │
│ cargo_version │ cargo 1.85.1 (d73d2caf9 2024-12-31) │
│ build_time │ 2025-06-21 12:02:06 -04:00 │
│ build_rust_channel │ debug │
│ allocator │ standard │
│ │ ╭───┬───────────────╮ │
│ features │ │ 0 │ default │ │
│ │ │ 1 │ plugin │ │
│ │ │ 2 │ rustls-tls │ │
│ │ │ 3 │ sqlite │ │
│ │ │ 4 │ trash-support │ │
│ │ ╰───┴───────────────╯ │
│ │ ╭───┬─────────────────╮ │
│ installed_plugins │ │ 0 │ formats 0.104.0 │ │
│ │ │ 1 │ polars 0.104.0 │ │
│ │ │ 2 │ query 0.104.0 │ │
│ │ │ 3 │ todotxt 0.3.0 │ │
│ │ ╰───┴─────────────────╯ │
╰────────────────────┴──────────────────────────────────────────╯
```
# Tests + Formatting
👍. Let me know if more tests besides the new example are needed.
# After Submitting
This commit is contained in:
@ -12,7 +12,10 @@ impl Command for UpdateCells {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("update cells")
|
||||
.input_output_types(vec![(Type::table(), Type::table())])
|
||||
.input_output_types(vec![
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.required(
|
||||
"closure",
|
||||
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
||||
@ -77,6 +80,15 @@ impl Command for UpdateCells {
|
||||
"2021-11-18" => Value::test_string(""),
|
||||
})])),
|
||||
},
|
||||
Example {
|
||||
example: r#"{a: 1, b: 2, c: 3} | update cells { $in + 10 }"#,
|
||||
description: "Update each value in a record.",
|
||||
result: Some(Value::test_record(record! {
|
||||
"a" => Value::test_int(11),
|
||||
"b" => Value::test_int(12),
|
||||
"c" => Value::test_int(13),
|
||||
})),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@ -85,7 +97,7 @@ impl Command for UpdateCells {
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
mut input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let closure: Closure = call.req(engine_state, stack, 0)?;
|
||||
@ -102,14 +114,51 @@ impl Command for UpdateCells {
|
||||
|
||||
let metadata = input.metadata();
|
||||
|
||||
Ok(UpdateCellIterator {
|
||||
iter: input.into_iter(),
|
||||
closure: ClosureEval::new(engine_state, stack, closure),
|
||||
columns,
|
||||
span: head,
|
||||
match input {
|
||||
PipelineData::Value(
|
||||
Value::Record {
|
||||
ref mut val,
|
||||
internal_span,
|
||||
},
|
||||
..,
|
||||
) => {
|
||||
let val = val.to_mut();
|
||||
update_record(
|
||||
val,
|
||||
&mut ClosureEval::new(engine_state, stack, closure),
|
||||
internal_span,
|
||||
columns.as_ref(),
|
||||
);
|
||||
Ok(input)
|
||||
}
|
||||
_ => Ok(UpdateCellIterator {
|
||||
iter: input.into_iter(),
|
||||
closure: ClosureEval::new(engine_state, stack, closure),
|
||||
columns,
|
||||
span: head,
|
||||
}
|
||||
.into_pipeline_data(head, engine_state.signals().clone())
|
||||
.set_metadata(metadata)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_record(
|
||||
record: &mut Record,
|
||||
closure: &mut ClosureEval,
|
||||
span: Span,
|
||||
cols: Option<&HashSet<String>>,
|
||||
) {
|
||||
if let Some(columns) = cols {
|
||||
for (col, val) in record.iter_mut() {
|
||||
if columns.contains(col) {
|
||||
*val = eval_value(closure, span, std::mem::take(val));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (_, val) in record.iter_mut() {
|
||||
*val = eval_value(closure, span, std::mem::take(val))
|
||||
}
|
||||
.into_pipeline_data(head, engine_state.signals().clone())
|
||||
.set_metadata(metadata))
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,18 +177,7 @@ impl Iterator for UpdateCellIterator {
|
||||
|
||||
let value = if let Value::Record { val, .. } = &mut value {
|
||||
let val = val.to_mut();
|
||||
if let Some(columns) = &self.columns {
|
||||
for (col, val) in val.iter_mut() {
|
||||
if columns.contains(col) {
|
||||
*val = eval_value(&mut self.closure, self.span, std::mem::take(val));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (_, val) in val.iter_mut() {
|
||||
*val = eval_value(&mut self.closure, self.span, std::mem::take(val))
|
||||
}
|
||||
}
|
||||
|
||||
update_record(val, &mut self.closure, self.span, self.columns.as_ref());
|
||||
value
|
||||
} else {
|
||||
eval_value(&mut self.closure, self.span, value)
|
||||
|
Reference in New Issue
Block a user