mirror of
https://github.com/nushell/nushell
synced 2024-12-28 05:53:09 +00:00
Rename: change the SyntaxShape of -c
flag from list to record (#10526)
# Description Fixes: #7085 Also closes: #7526 # User-Facing Changes After this change, we need to use `-c` flag like this: ```nushell [[a, b, c]; [1, 2, 3]] | rename -c { a: ham } ``` But we can rename many columns easily, here is another example: ```nushell [[a, b, c]; [1, 2, 3]] | rename -c { a: ham, b: ham2 } ```
This commit is contained in:
parent
85d6529f0d
commit
d34581db4a
2 changed files with 44 additions and 38 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
use indexmap::IndexMap;
|
||||||
use nu_engine::{eval_block_with_early_return, CallExt};
|
use nu_engine::{eval_block_with_early_return, CallExt};
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
|
||||||
|
@ -5,6 +6,7 @@ use nu_protocol::{
|
||||||
Category, Example, IntoPipelineData, PipelineData, Record, ShellError, Signature, Span,
|
Category, Example, IntoPipelineData, PipelineData, Record, ShellError, Signature, Span,
|
||||||
SyntaxShape, Type, Value,
|
SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Rename;
|
pub struct Rename;
|
||||||
|
@ -22,7 +24,7 @@ impl Command for Rename {
|
||||||
])
|
])
|
||||||
.named(
|
.named(
|
||||||
"column",
|
"column",
|
||||||
SyntaxShape::List(Box::new(SyntaxShape::String)),
|
SyntaxShape::Record(vec![]),
|
||||||
"column name to be changed",
|
"column name to be changed",
|
||||||
Some('c'),
|
Some('c'),
|
||||||
)
|
)
|
||||||
|
@ -76,7 +78,7 @@ impl Command for Rename {
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Rename a specific column",
|
description: "Rename a specific column",
|
||||||
example: "[[a, b, c]; [1, 2, 3]] | rename -c [a ham]",
|
example: "[[a, b, c]; [1, 2, 3]] | rename -c { a: ham }",
|
||||||
result: Some(Value::list(
|
result: Some(Value::list(
|
||||||
vec![Value::test_record(Record {
|
vec![Value::test_record(Record {
|
||||||
cols: vec!["ham".to_string(), "b".to_string(), "c".to_string()],
|
cols: vec!["ham".to_string(), "b".to_string(), "c".to_string()],
|
||||||
|
@ -111,34 +113,35 @@ fn rename(
|
||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let specified_column: Option<Vec<String>> = call.get_flag(engine_state, stack, "column")?;
|
let specified_column: Option<Record> = call.get_flag(engine_state, stack, "column")?;
|
||||||
// get the span for the column's name to be changed and for the given list
|
// convert from Record to HashMap for easily query.
|
||||||
let column_flag: Option<Value> = call.get_flag(engine_state, stack, "column")?;
|
let specified_column: Option<IndexMap<String, String>> = match specified_column {
|
||||||
let (specified_col_span, list_span) = match column_flag {
|
Some(query) => {
|
||||||
Some(column_flag) => {
|
let mut columns = IndexMap::new();
|
||||||
let column_span = column_flag.span();
|
for (col, val) in query {
|
||||||
match column_flag {
|
let val_span = val.span();
|
||||||
Value::List { vals: columns, .. } => {
|
match val {
|
||||||
if columns.is_empty() {
|
Value::String { val, .. } => {
|
||||||
return Err(ShellError::TypeMismatch { err_message: "The column list cannot be empty and must contain only two values: the column's name and its replacement value"
|
columns.insert(col, val);
|
||||||
.to_string(), span: column_span });
|
}
|
||||||
} else {
|
_ => {
|
||||||
(Some(columns[0].span()), column_span)
|
return Err(ShellError::TypeMismatch {
|
||||||
|
err_message: "new column name must be a string".to_owned(),
|
||||||
|
span: val_span,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (None, call.head),
|
|
||||||
}
|
}
|
||||||
|
if columns.is_empty() {
|
||||||
|
return Err(ShellError::TypeMismatch {
|
||||||
|
err_message: "The column info cannot be empty".to_owned(),
|
||||||
|
span: call.head,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Some(columns)
|
||||||
}
|
}
|
||||||
None => (None, call.head),
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ref cols) = specified_column {
|
|
||||||
if cols.len() != 2 {
|
|
||||||
return Err(ShellError::TypeMismatch { err_message: "The column list must contain only two values: the column's name and its replacement value"
|
|
||||||
.to_string(), span: list_span });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let redirect_stdout = call.redirect_stdout;
|
let redirect_stdout = call.redirect_stdout;
|
||||||
let redirect_stderr = call.redirect_stderr;
|
let redirect_stderr = call.redirect_stderr;
|
||||||
let block_info =
|
let block_info =
|
||||||
|
@ -195,29 +198,32 @@ fn rename(
|
||||||
} else {
|
} else {
|
||||||
match &specified_column {
|
match &specified_column {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
// check if the specified column to be renamed exists
|
let mut column_to_rename: HashSet<String> = HashSet::from_iter(c.keys().cloned());
|
||||||
if !record.cols.contains(&c[0]) {
|
for val in record.cols.iter_mut() {
|
||||||
|
if c.contains_key(val) {
|
||||||
|
column_to_rename.remove(val);
|
||||||
|
*val = c.get(val).expect("already check exists").to_owned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !column_to_rename.is_empty() {
|
||||||
|
let not_exists_column =
|
||||||
|
column_to_rename.into_iter().next().expect(
|
||||||
|
"already checked column to rename still exists",
|
||||||
|
);
|
||||||
return Value::error(
|
return Value::error(
|
||||||
ShellError::UnsupportedInput(
|
ShellError::UnsupportedInput(
|
||||||
format!(
|
format!(
|
||||||
"The column '{}' does not exist in the input",
|
"The column '{not_exists_column}' does not exist in the input",
|
||||||
&c[0]
|
|
||||||
),
|
),
|
||||||
"value originated from here".into(),
|
"value originated from here".into(),
|
||||||
// Arrow 1 points at the specified column name,
|
// Arrow 1 points at the specified column name,
|
||||||
specified_col_span.unwrap_or(head_span),
|
head_span,
|
||||||
// Arrow 2 points at the input value.
|
// Arrow 2 points at the input value.
|
||||||
span,
|
span,
|
||||||
),
|
),
|
||||||
span,
|
span,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for (idx, val) in record.cols.iter_mut().enumerate() {
|
|
||||||
if *val == c[0] {
|
|
||||||
record.cols[idx] = c[1].to_string();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
for (idx, val) in columns.iter().enumerate() {
|
for (idx, val) in columns.iter().enumerate() {
|
||||||
|
|
|
@ -107,10 +107,10 @@ fn errors_if_columns_param_is_empty() {
|
||||||
| lines
|
| lines
|
||||||
| wrap name
|
| wrap name
|
||||||
| default "arepa!" hit
|
| default "arepa!" hit
|
||||||
| rename -c []
|
| rename -c {}
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(actual.err.contains("The column list cannot be empty"));
|
assert!(actual.err.contains("The column info cannot be empty"));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue