From c1ca10ffd137bb49e5c618ac2ff2817506d13adc Mon Sep 17 00:00:00 2001 From: Darren Schroeder <343840+fdncred@users.noreply.github.com> Date: Wed, 1 Nov 2023 13:56:25 -0500 Subject: [PATCH] allow `compact` to also compact empty strings (#10912) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description This change allows `compact` to also compact things with empty strings, empty lists, and empty records if the `--empty` switch is used. Let's add a quality-of-life improvement here to just compact all this mess. If this is a bad idea, please cite examples demonstrating why. ``` ❯ [[name position]; [Francis Lead] [Igor TechLead] [Aya null]] | compact position ╭#┬─name──┬position╮ │0│Francis│Lead │ │1│Igor │TechLead│ ╰─┴───────┴────────╯ ❯ [[name position]; [Francis Lead] [Igor TechLead] [Aya ""]] | compact position --empty ╭#┬─name──┬position╮ │0│Francis│Lead │ │1│Igor │TechLead│ ╰─┴───────┴────────╯ ❯ [1, null, 2, "", 3, [], 4, {}, 5] | compact ╭─┬─────────────────╮ │0│ 1│ │1│ 2│ │2│ │ │3│ 3│ │4│[list 0 items] │ │5│ 4│ │6│{record 0 fields}│ │7│ 5│ ╰─┴─────────────────╯ ❯ [1, null, 2, "", 3, [], 4, {}, 5] | compact --empty ╭─┬─╮ │0│1│ │1│2│ │2│3│ │3│4│ │4│5│ ╰─┴─╯ ``` # User-Facing Changes # Tests + Formatting # After Submitting --- crates/nu-command/src/filters/compact.rs | 51 +++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/crates/nu-command/src/filters/compact.rs b/crates/nu-command/src/filters/compact.rs index 865c3bb9f1..46ca6237d3 100644 --- a/crates/nu-command/src/filters/compact.rs +++ b/crates/nu-command/src/filters/compact.rs @@ -27,6 +27,11 @@ impl Command for Compact { Type::List(Box::new(Type::Any)), ), ]) + .switch( + "empty", + "also compact empty items like \"\", {}, and []", + Some('e'), + ) .rest( "columns", SyntaxShape::Any, @@ -46,18 +51,19 @@ impl Command for Compact { call: &Call, input: PipelineData, ) -> Result { - compact(engine_state, stack, call, input) + let empty = call.has_flag("empty"); + compact(engine_state, stack, call, input, empty) } fn examples(&self) -> Vec { vec![ Example { - description: "Filter out all records where 'Hello' is null (returns nothing)", + description: "Filter out all records where 'Hello' is null", example: r#"[["Hello" "World"]; [null 3]] | compact Hello"#, result: Some(Value::test_list(vec![])), }, Example { - description: "Filter out all records where 'World' is null (Returns the table)", + description: "Filter out all records where 'World' is null", example: r#"[["Hello" "World"]; [null 3]] | compact World"#, result: Some(Value::test_list(vec![Value::test_record(record! { "Hello" => Value::nothing(Span::test_data()), @@ -65,13 +71,24 @@ impl Command for Compact { })])), }, Example { - description: "Filter out all instances of nothing from a list (Returns [1,2])", + description: "Filter out all instances of null from a list", example: r#"[1, null, 2] | compact"#, result: Some(Value::test_list(vec![ Value::test_int(1), Value::test_int(2), ])), }, + Example { + description: "Filter out all instances of null and empty items from a list", + example: r#"[1, null, 2, "", 3, [], 4, {}, 5] | compact --empty"#, + result: Some(Value::test_list(vec![ + Value::test_int(1), + Value::test_int(2), + Value::test_int(3), + Value::test_int(4), + Value::test_int(5), + ])), + }, ] } } @@ -81,6 +98,7 @@ pub fn compact( stack: &mut Stack, call: &Call, input: PipelineData, + compact_empties: bool, ) -> Result { let columns: Vec = call.rest(engine_state, stack, 0)?; let metadata = input.metadata(); @@ -90,7 +108,7 @@ pub fn compact( match item { // Nothing is filtered out Value::Nothing { .. } => false, - Value::Record { .. } => { + Value::Record { val, .. } => { for column in columns.iter() { match item.get_data_by_key(column) { None => return false, @@ -98,12 +116,35 @@ pub fn compact( if let Value::Nothing { .. } = x { return false; } + if compact_empties { + if let Value::String { val, .. } = x { + if val.is_empty() { + return false; + } + } + } } } } + + if compact_empties && val.is_empty() { + return false; + } // No defined columns contained Nothing true } + Value::List { vals, .. } => { + if compact_empties && vals.is_empty() { + return false; + } + true + } + Value::String { val, .. } => { + if compact_empties && val.is_empty() { + return false; + } + true + } // Any non-Nothing, non-record should be kept _ => true, }