diff --git a/crates/nu-command/src/filters/flatten.rs b/crates/nu-command/src/filters/flatten.rs index 7d9683233..59046ba66 100644 --- a/crates/nu-command/src/filters/flatten.rs +++ b/crates/nu-command/src/filters/flatten.rs @@ -22,6 +22,7 @@ impl Command for Flatten { SyntaxShape::String, "optionally flatten data by column", ) + .switch("all", "flatten inner table out", Some('a')) .category(Category::Filters) } @@ -63,17 +64,17 @@ impl Command for Flatten { }, Example { description: "flatten a column having a nested table", - example: "[[origin, people]; [Ecuador, ([[name, meal]; ['Andres', 'arepa']])]] | flatten | get meal", + example: "[[origin, people]; [Ecuador, ([[name, meal]; ['Andres', 'arepa']])]] | flatten --all | get meal", result: None,//Some(Value::test_string("arepa")), }, Example { description: "restrict the flattening by passing column names", - example: "[[origin, crate, versions]; [World, ([[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten versions | last | get versions", + example: "[[origin, crate, versions]; [World, ([[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten versions --all | last | get versions", result: None, //Some(Value::test_string("0.22")), }, Example { description: "Flatten inner table", - example: "{ a: b, d: [ 1 2 3 4 ], e: [ 4 3 ] } | flatten", + example: "{ a: b, d: [ 1 2 3 4 ], e: [ 4 3 ] } | flatten --all", result: Some(Value::List{ vals: vec![ Value::Record{ @@ -113,10 +114,11 @@ fn flatten( let tag = call.head; let columns: Vec = call.rest(engine_state, stack, 0)?; let metadata = input.metadata(); + let flatten_all = call.has_flag("all"); input .flat_map( - move |item| flat_value(&columns, &item, tag), + move |item| flat_value(&columns, &item, tag, flatten_all), engine_state.ctrlc.clone(), ) .map(|x| x.set_metadata(metadata)) @@ -139,7 +141,7 @@ enum TableInside<'a> { }, } -fn flat_value(columns: &[CellPath], item: &Value, _name_tag: Span) -> Vec { +fn flat_value(columns: &[CellPath], item: &Value, _name_tag: Span, all: bool) -> Vec { let tag = match item.span() { Ok(x) => x, Err(e) => return vec![Value::Error { error: e }], @@ -211,7 +213,9 @@ fn flat_value(columns: &[CellPath], item: &Value, _name_tag: Span) -> Vec }) } } - Value::List { vals, span: _ } if vals.iter().all(|f| f.as_record().is_ok()) => { + Value::List { vals, span: _ } + if all && vals.iter().all(|f| f.as_record().is_ok()) => + { // it's a table (a list of record, we can flatten inner record) let mut cs = vec![]; let mut vs = vec![]; diff --git a/crates/nu-command/tests/commands/flatten.rs b/crates/nu-command/tests/commands/flatten.rs index 6e5504217..f5df5fa0d 100644 --- a/crates/nu-command/tests/commands/flatten.rs +++ b/crates/nu-command/tests/commands/flatten.rs @@ -9,7 +9,7 @@ fn flatten_nested_tables_with_columns() { r#" echo [[origin, people]; [Ecuador, ('Andres' | wrap name)]] [[origin, people]; [Nu, ('nuno' | wrap name)]] - | flatten | flatten + | flatten --all | flatten --all | get name | str collect ',' "# @@ -25,7 +25,7 @@ fn flatten_nested_tables_that_have_many_columns() { r#" echo [[origin, people]; [Ecuador, (echo [[name, meal]; ['Andres', 'arepa']])]] [[origin, people]; [USA, (echo [[name, meal]; ['Katz', 'nurepa']])]] - | flatten | flatten + | flatten --all | flatten --all | get meal | str collect ',' "# @@ -71,7 +71,7 @@ fn flatten_row_column_explicitly() { let actual = nu!( cwd: dirs.test(), - "open katz.json | flatten people | where name == Andres | length" + "open katz.json | flatten people --all | where name == Andres | length" ); assert_eq!(actual.out, "1"); @@ -105,7 +105,7 @@ fn flatten_row_columns_having_same_column_names_flats_separately() { let actual = nu!( cwd: dirs.test(), - "open katz.json | flatten | flatten people city | get city_name | length" + "open katz.json | flatten --all | flatten people city | get city_name | length" ); assert_eq!(actual.out, "4"); @@ -139,7 +139,7 @@ fn flatten_table_columns_explicitly() { let actual = nu!( cwd: dirs.test(), - "open katz.json | flatten city | where people.name == Katz | length" + "open katz.json | flatten city --all | where people.name == Katz | length" ); assert_eq!(actual.out, "2"); @@ -175,7 +175,7 @@ fn flatten_more_than_one_column_that_are_subtables_not_supported() { let actual = nu!( cwd: dirs.test(), - "open katz.json | flatten tags city" + "open katz.json | flatten tags city --all" ); assert!(actual.err.contains("tried flattening")); diff --git a/src/tests/test_table_operations.rs b/src/tests/test_table_operations.rs index bde2e86db..661bb6c40 100644 --- a/src/tests/test_table_operations.rs +++ b/src/tests/test_table_operations.rs @@ -36,7 +36,7 @@ fn flatten_get_simple_list() -> TestResult { #[test] fn flatten_table_get() -> TestResult { run_test( - "[[origin, people]; [Ecuador, ([[name, meal]; ['Andres', 'arepa']])]] | flatten | get meal.0", + "[[origin, people]; [Ecuador, ([[name, meal]; ['Andres', 'arepa']])]] | flatten --all | get meal.0", "arepa", ) } @@ -44,11 +44,27 @@ fn flatten_table_get() -> TestResult { #[test] fn flatten_table_column_get_last() -> TestResult { run_test( - "[[origin, crate, versions]; [World, ([[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten versions | last | get versions", + "[[origin, crate, versions]; [World, ([[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten versions --all | last | get versions", "0.22", ) } +#[test] +fn flatten_should_just_flatten_one_level() -> TestResult { + run_test( + "[[origin, crate, versions]; [World, ([[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten crate | get crate.name.0", + "nu-cli" + ) +} + +#[test] +fn flatten_nest_table_when_all_provided() -> TestResult { + run_test( + "[[origin, crate, versions]; [World, ([[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten crate --all | get name.0", + "nu-cli" + ) +} + #[test] fn get_table_columns_1() -> TestResult { run_test( @@ -65,7 +81,7 @@ fn get_table_columns_2() -> TestResult { #[test] fn flatten_should_flatten_inner_table() -> TestResult { run_test( - "[[[name, value]; [abc, 123]]] | flatten | get value.0", + "[[[name, value]; [abc, 123]]] | flatten --all | get value.0", "123", ) }