mirror of
https://github.com/nushell/nushell.git
synced 2024-12-23 23:49:44 +01:00
Fix error message for headers
(#11809)
# Description Fixes #11780: `headers`: incorrect error
This commit is contained in:
parent
d77eeeb5dd
commit
779a3c075e
@ -1,8 +1,8 @@
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
record, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type,
|
||||
Value,
|
||||
record, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span,
|
||||
Type, Value,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -69,66 +69,38 @@ impl Command for Headers {
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let config = engine_state.get_config();
|
||||
let metadata = input.metadata();
|
||||
let value = input.into_value(call.head);
|
||||
let (old_headers, new_headers) = extract_headers(&value, config)?;
|
||||
let new_headers = replace_headers(value, &old_headers, &new_headers)?;
|
||||
let span = input.span().unwrap_or(call.head);
|
||||
let value = input.into_value(span);
|
||||
let Value::List { vals: table, .. } = value else {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "not a table".to_string(),
|
||||
span,
|
||||
});
|
||||
};
|
||||
|
||||
Ok(new_headers.into_pipeline_data_with_metadata(metadata))
|
||||
let (old_headers, new_headers) = extract_headers(&table, span, config)?;
|
||||
let value = replace_headers(table, span, &old_headers, &new_headers)?;
|
||||
|
||||
Ok(value.into_pipeline_data_with_metadata(metadata))
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_headers(
|
||||
value: Value,
|
||||
old_headers: &[String],
|
||||
new_headers: &[String],
|
||||
) -> Result<Value, ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Record { val, .. } => Ok(Value::record(
|
||||
val.into_iter()
|
||||
.filter_map(|(col, val)| {
|
||||
old_headers
|
||||
.iter()
|
||||
.position(|c| c == &col)
|
||||
.map(|i| (new_headers[i].clone(), val))
|
||||
})
|
||||
.collect(),
|
||||
span,
|
||||
)),
|
||||
Value::List { vals, .. } => {
|
||||
let vals = vals
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
.map(|value| replace_headers(value, old_headers, new_headers))
|
||||
.collect::<Result<Vec<Value>, ShellError>>()?;
|
||||
|
||||
Ok(Value::list(vals, span))
|
||||
}
|
||||
_ => Err(ShellError::TypeMismatch {
|
||||
err_message: "record".to_string(),
|
||||
span: value.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid_header(value: &Value) -> bool {
|
||||
matches!(
|
||||
value,
|
||||
Value::Nothing { .. }
|
||||
| Value::String { val: _, .. }
|
||||
| Value::Bool { val: _, .. }
|
||||
| Value::Float { val: _, .. }
|
||||
| Value::Int { val: _, .. }
|
||||
)
|
||||
}
|
||||
|
||||
fn extract_headers(
|
||||
value: &Value,
|
||||
table: &[Value],
|
||||
span: Span,
|
||||
config: &Config,
|
||||
) -> Result<(Vec<String>, Vec<String>), ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Record { val: record, .. } => {
|
||||
table
|
||||
.first()
|
||||
.ok_or_else(|| ShellError::GenericError {
|
||||
error: "Found empty list".into(),
|
||||
msg: "unable to extract headers".into(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
.and_then(Value::as_record)
|
||||
.and_then(|record| {
|
||||
for v in record.values() {
|
||||
if !is_valid_header(v) {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
@ -151,26 +123,57 @@ fn extract_headers(
|
||||
col
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
.collect();
|
||||
|
||||
Ok((old_headers, new_headers))
|
||||
}
|
||||
Value::List { vals, .. } => vals
|
||||
.iter()
|
||||
.map(|value| extract_headers(value, config))
|
||||
.next()
|
||||
.ok_or_else(|| ShellError::GenericError {
|
||||
error: "Found empty list".into(),
|
||||
msg: "unable to extract headers".into(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?,
|
||||
_ => Err(ShellError::TypeMismatch {
|
||||
err_message: "record".to_string(),
|
||||
span: value.span(),
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn is_valid_header(value: &Value) -> bool {
|
||||
matches!(
|
||||
value,
|
||||
Value::Nothing { .. }
|
||||
| Value::String { val: _, .. }
|
||||
| Value::Bool { val: _, .. }
|
||||
| Value::Float { val: _, .. }
|
||||
| Value::Int { val: _, .. }
|
||||
)
|
||||
}
|
||||
|
||||
fn replace_headers(
|
||||
rows: Vec<Value>,
|
||||
span: Span,
|
||||
old_headers: &[String],
|
||||
new_headers: &[String],
|
||||
) -> Result<Value, ShellError> {
|
||||
rows.into_iter()
|
||||
.skip(1)
|
||||
.map(|value| {
|
||||
let span = value.span();
|
||||
if let Value::Record { val: record, .. } = value {
|
||||
Ok(Value::record(
|
||||
record
|
||||
.into_iter()
|
||||
.filter_map(|(col, val)| {
|
||||
old_headers
|
||||
.iter()
|
||||
.position(|c| c == &col)
|
||||
.map(|i| (new_headers[i].clone(), val))
|
||||
})
|
||||
.collect(),
|
||||
span,
|
||||
))
|
||||
} else {
|
||||
Err(ShellError::CantConvert {
|
||||
to_type: "record".into(),
|
||||
from_type: value.get_type().to_string(),
|
||||
span,
|
||||
help: None,
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect::<Result<_, _>>()
|
||||
.map(|rows| Value::list(rows, span))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
Loading…
Reference in New Issue
Block a user