diff --git a/TODO.md b/TODO.md index a580743004..fd65445985 100644 --- a/TODO.md +++ b/TODO.md @@ -27,9 +27,9 @@ - [x] Source - [x] Error shortcircuit (stopping on first error). Revised: errors emit first, but can be seen by commands. - [x] Value serialization +- [x] Handling rows with missing columns during a cell path - [ ] Input/output types - [ ] Support for `$in` -- [ ] Handling rows with missing columns during a cell path - [ ] ctrl-c support - [ ] operator overflow - [ ] finish operator type-checking diff --git a/crates/nu-command/src/filters/select.rs b/crates/nu-command/src/filters/select.rs index 8611517e4d..7a828aca5f 100644 --- a/crates/nu-command/src/filters/select.rs +++ b/crates/nu-command/src/filters/select.rs @@ -52,7 +52,7 @@ impl Command for Select { fn select(span: Span, columns: Vec, input: Value) -> Result { if columns.is_empty() { - return Err(ShellError::CantFindColumn(span)); + return Err(ShellError::CantFindColumn(span, input.span()?)); } match input { diff --git a/crates/nu-protocol/src/shell_error.rs b/crates/nu-protocol/src/shell_error.rs index 405f0cc6d1..1329205c49 100644 --- a/crates/nu-protocol/src/shell_error.rs +++ b/crates/nu-protocol/src/shell_error.rs @@ -99,7 +99,10 @@ pub enum ShellError { #[error("Cannot find column")] #[diagnostic(code(nu::shell::column_not_found), url(docsrs))] - CantFindColumn(#[label = "cannot find column"] Span), + CantFindColumn( + #[label = "cannot find column"] Span, + #[label = "value originates here"] Span, + ), #[error("External command")] #[diagnostic(code(nu::shell::external_command), url(docsrs))] diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index c2e9b30803..e83bbee158 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -292,7 +292,8 @@ impl Value { val: column_name, span: origin_span, } => match &mut current { - Value::Record { cols, vals, .. } => { + Value::Record { cols, vals, span } => { + let span = *span; let mut found = false; for col in cols.iter().zip(vals.iter()) { if col.0 == column_name { @@ -303,19 +304,23 @@ impl Value { } if !found { - return Err(ShellError::CantFindColumn(*origin_span)); + return Err(ShellError::CantFindColumn(*origin_span, span)); } } Value::List { vals, span } => { let mut output = vec![]; for val in vals { - if let Value::Record { cols, vals, .. } = val { - for col in cols.iter().enumerate() { - if col.1 == column_name { - output.push(vals[col.0].clone()); - } - } - } + output.push(val.clone().follow_cell_path(&[PathMember::String { + val: column_name.clone(), + span: *origin_span, + }])?); + // if let Value::Record { cols, vals, .. } = val { + // for col in cols.iter().enumerate() { + // if col.1 == column_name { + // output.push(vals[col.0].clone()); + // } + // } + // } } current = Value::List { @@ -326,13 +331,17 @@ impl Value { Value::Stream { stream, span } => { let mut output = vec![]; for val in stream { - if let Value::Record { cols, vals, .. } = val { - for col in cols.iter().enumerate() { - if col.1 == column_name { - output.push(vals[col.0].clone()); - } - } - } + output.push(val.clone().follow_cell_path(&[PathMember::String { + val: column_name.clone(), + span: *origin_span, + }])?); + // if let Value::Record { cols, vals, .. } = val { + // for col in cols.iter().enumerate() { + // if col.1 == column_name { + // output.push(vals[col.0].clone()); + // } + // } + // } } current = Value::List { diff --git a/src/tests.rs b/src/tests.rs index f879214721..5da55fa5ae 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -666,3 +666,11 @@ fn earlier_errors() -> TestResult { "int", ) } + +#[test] +fn missing_column_error() -> TestResult { + fail_test( + r#"([([[name, size]; [ABC, 10], [DEF, 20]]).1, ([[name]; [HIJ]]).0]).size | table"#, + "cannot find column", + ) +}