mirror of
https://github.com/nushell/nushell.git
synced 2024-12-23 15:39:06 +01:00
Make Record.cols
private (#12317)
# Description Makes the `cols` field in `Record` private and fixes the implementation of `rename` to account for this change.
This commit is contained in:
parent
e97368433b
commit
442faa5576
@ -1,7 +1,6 @@
|
|||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu_engine::{command_prelude::*, get_eval_block_with_early_return};
|
use nu_engine::{command_prelude::*, get_eval_block_with_early_return};
|
||||||
use nu_protocol::engine::Closure;
|
use nu_protocol::engine::Closure;
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Rename;
|
pub struct Rename;
|
||||||
@ -157,72 +156,85 @@ fn rename(
|
|||||||
move |item| {
|
move |item| {
|
||||||
let span = item.span();
|
let span = item.span();
|
||||||
match item {
|
match item {
|
||||||
Value::Record {
|
Value::Record { val: record, .. } => {
|
||||||
val: mut record, ..
|
let record =
|
||||||
} => {
|
if let Some((engine_state, block, mut stack, env_vars, env_hidden)) =
|
||||||
if let Some((engine_state, block, mut stack, env_vars, env_hidden)) =
|
block_info.clone()
|
||||||
block_info.clone()
|
{
|
||||||
{
|
record
|
||||||
for c in &mut record.cols {
|
.into_iter()
|
||||||
stack.with_env(&env_vars, &env_hidden);
|
.map(|(col, val)| {
|
||||||
|
stack.with_env(&env_vars, &env_hidden);
|
||||||
|
|
||||||
if let Some(var) = block.signature.get_positional(0) {
|
if let Some(var) = block.signature.get_positional(0) {
|
||||||
if let Some(var_id) = &var.var_id {
|
if let Some(var_id) = &var.var_id {
|
||||||
stack.add_var(*var_id, Value::string(c.clone(), span))
|
stack.add_var(
|
||||||
}
|
*var_id,
|
||||||
}
|
Value::string(col.clone(), span),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let eval_result = eval_block_with_early_return(
|
eval_block_with_early_return(
|
||||||
&engine_state,
|
&engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
Value::string(c.clone(), span).into_pipeline_data(),
|
Value::string(col, span).into_pipeline_data(),
|
||||||
);
|
)
|
||||||
|
.and_then(|data| data.collect_string_strict(span))
|
||||||
|
.map(|(col, _, _)| (col, val))
|
||||||
|
})
|
||||||
|
.collect::<Result<Record, _>>()
|
||||||
|
} else {
|
||||||
|
match &specified_column {
|
||||||
|
Some(columns) => {
|
||||||
|
// record columns are unique so we can track the number
|
||||||
|
// of renamed columns to check if any were missed
|
||||||
|
let mut renamed = 0;
|
||||||
|
let record = record.into_iter().map(|(col, val)| {
|
||||||
|
let col = if let Some(col) = columns.get(&col) {
|
||||||
|
renamed += 1;
|
||||||
|
col.clone()
|
||||||
|
} else {
|
||||||
|
col
|
||||||
|
};
|
||||||
|
|
||||||
match eval_result {
|
(col, val)
|
||||||
Err(e) => return Value::error(e, span),
|
}).collect::<Record>();
|
||||||
Ok(res) => match res.collect_string_strict(span) {
|
|
||||||
Err(e) => return Value::error(e, span),
|
let missing_column = if renamed < columns.len() {
|
||||||
Ok(new_c) => *c = new_c.0,
|
columns.iter().find_map(|(col, new_col)| {
|
||||||
},
|
(!record.contains(new_col)).then_some(col)
|
||||||
}
|
})
|
||||||
}
|
} else {
|
||||||
} else {
|
None
|
||||||
match &specified_column {
|
};
|
||||||
Some(c) => {
|
|
||||||
let mut column_to_rename: HashSet<String> = HashSet::from_iter(c.keys().cloned());
|
if let Some(missing) = missing_column {
|
||||||
for val in record.cols.iter_mut() {
|
Err(ShellError::UnsupportedInput {
|
||||||
if c.contains_key(val) {
|
msg: format!("The column '{missing}' does not exist in the input"),
|
||||||
column_to_rename.remove(val);
|
input: "value originated from here".into(),
|
||||||
*val = c.get(val).expect("already check exists").to_owned();
|
msg_span: head_span,
|
||||||
|
input_span: span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(record)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !column_to_rename.is_empty() {
|
None => Ok(record
|
||||||
let not_exists_column =
|
.into_iter()
|
||||||
column_to_rename.into_iter().next().expect(
|
.enumerate()
|
||||||
"already checked column to rename still exists",
|
.map(|(i, (col, val))| {
|
||||||
);
|
(columns.get(i).cloned().unwrap_or(col), val)
|
||||||
return Value::error(
|
})
|
||||||
ShellError::UnsupportedInput { msg: format!(
|
.collect()),
|
||||||
"The column '{not_exists_column}' does not exist in the input",
|
|
||||||
), input: "value originated from here".into(), msg_span: head_span, input_span: span },
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None => {
|
};
|
||||||
for (idx, val) in columns.iter().enumerate() {
|
|
||||||
if idx >= record.len() {
|
match record {
|
||||||
// skip extra new columns names if we already reached the final column
|
Ok(record) => Value::record(record, span),
|
||||||
break;
|
Err(err) => Value::error(err, span),
|
||||||
}
|
|
||||||
record.cols[idx] = val.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::record(*record, span)
|
|
||||||
}
|
}
|
||||||
// Propagate errors by explicitly matching them before the final case.
|
// Propagate errors by explicitly matching them before the final case.
|
||||||
Value::Error { .. } => item.clone(),
|
Value::Error { .. } => item.clone(),
|
||||||
|
@ -6,11 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct Record {
|
pub struct Record {
|
||||||
/// Don't use this field publicly!
|
cols: Vec<String>,
|
||||||
///
|
|
||||||
/// Only public as command `rename` is not reimplemented in a sane way yet
|
|
||||||
/// Using it or making `vals` public will draw shaming by @sholderbach
|
|
||||||
pub cols: Vec<String>,
|
|
||||||
vals: Vec<Value>,
|
vals: Vec<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user