@@ -10,10 +10,10 @@ impl Command for Compact {
1010
1111 fn signature ( & self ) -> Signature {
1212 Signature :: build ( "compact" )
13- . input_output_types ( vec ! [ (
14- Type :: List ( Box :: new ( Type :: Any ) ) ,
15- Type :: List ( Box :: new ( Type :: Any ) ) ,
16- ) ] )
13+ . input_output_types ( vec ! [
14+ ( Type :: record ( ) , Type :: record ( ) ) ,
15+ ( Type :: list ( Type :: Any ) , Type :: list ( Type :: Any ) ) ,
16+ ] )
1717 . switch (
1818 "empty" ,
1919 "also compact empty items like \" \" , {}, and []" ,
@@ -31,6 +31,10 @@ impl Command for Compact {
3131 "Creates a table with non-empty rows."
3232 }
3333
34+ fn extra_description ( & self ) -> & str {
35+ "Can be used to remove `null` or empty values from lists and records too."
36+ }
37+
3438 fn search_terms ( & self ) -> Vec < & str > {
3539 vec ! [ "empty" , "remove" ]
3640 }
@@ -40,10 +44,21 @@ impl Command for Compact {
4044 engine_state : & EngineState ,
4145 stack : & mut Stack ,
4246 call : & Call ,
43- input : PipelineData ,
47+ mut input : PipelineData ,
4448 ) -> Result < PipelineData , ShellError > {
4549 let empty = call. has_flag ( engine_state, stack, "empty" ) ?;
46- compact ( engine_state, stack, call, input, empty)
50+ let columns: Vec < String > = call. rest ( engine_state, stack, 0 ) ?;
51+
52+ match input {
53+ PipelineData :: Value ( Value :: Record { ref mut val, .. } , ..) => {
54+ val. to_mut ( ) . retain ( |_, val| do_keep_value ( val, empty) ) ;
55+ Ok ( input)
56+ }
57+ _ => input. filter (
58+ move |item| do_keep_row ( item, empty, columns. as_slice ( ) ) ,
59+ engine_state. signals ( ) ,
60+ ) ,
61+ }
4762 }
4863
4964 fn examples ( & self ) -> Vec < Example < ' _ > > {
@@ -80,74 +95,35 @@ impl Command for Compact {
8095 Value :: test_int( 5 ) ,
8196 ] ) ) ,
8297 } ,
98+ Example {
99+ description: "Filter out all instances of null from a record" ,
100+ example: r#"{a: 1, b: null, c: 3} | compact"# ,
101+ result: Some ( Value :: test_record( record! {
102+ "a" => Value :: test_int( 1 ) ,
103+ "c" => Value :: test_int( 3 ) ,
104+ } ) ) ,
105+ } ,
83106 ]
84107 }
85108}
86109
87- pub fn compact (
88- engine_state : & EngineState ,
89- stack : & mut Stack ,
90- call : & Call ,
91- input : PipelineData ,
92- compact_empties : bool ,
93- ) -> Result < PipelineData , ShellError > {
94- let columns: Vec < String > = call. rest ( engine_state, stack, 0 ) ?;
95- let metadata = input. metadata ( ) ;
96- input
97- . filter (
98- move |item| {
99- match item {
100- // Nothing is filtered out
101- Value :: Nothing { .. } => false ,
102- Value :: Record { val, .. } => {
103- for column in columns. iter ( ) {
104- match val. get ( column) {
105- None => return false ,
106- Some ( x) => {
107- if let Value :: Nothing { .. } = x {
108- return false ;
109- }
110- if compact_empties {
111- // check if the value is one of the empty value
112- if match x {
113- Value :: String { val, .. } => val. is_empty ( ) ,
114- Value :: Record { val, .. } => val. is_empty ( ) ,
115- Value :: List { vals, .. } => vals. is_empty ( ) ,
116- _ => false ,
117- } {
118- // one of the empty value found so skip now
119- return false ;
120- }
121- }
122- }
123- }
124- }
110+ fn do_keep_value ( value : & Value , compact_empties : bool ) -> bool {
111+ let remove = match compact_empties {
112+ true => value. is_empty ( ) ,
113+ false => value. is_nothing ( ) ,
114+ } ;
115+ !remove
116+ }
117+
118+ fn do_keep_row ( row : & Value , compact_empties : bool , columns : & [ impl AsRef < str > ] ) -> bool {
119+ let do_keep = move |value| do_keep_value ( value, compact_empties) ;
125120
126- if compact_empties && val. is_empty ( ) {
127- return false ;
128- }
129- // No defined columns contained Nothing
130- true
131- }
132- Value :: List { vals, .. } => {
133- if compact_empties && vals. is_empty ( ) {
134- return false ;
135- }
136- true
137- }
138- Value :: String { val, .. } => {
139- if compact_empties && val. is_empty ( ) {
140- return false ;
141- }
142- true
143- }
144- // Any non-Nothing, non-record should be kept
145- _ => true ,
146- }
147- } ,
148- engine_state. signals ( ) ,
149- )
150- . map ( |m| m. set_metadata ( metadata) )
121+ do_keep ( row)
122+ && row. as_record ( ) . map_or ( true , |record| {
123+ columns
124+ . iter ( )
125+ . all ( |col| record. get ( col) . map ( do_keep) . unwrap_or ( false ) )
126+ } )
151127}
152128
153129#[ cfg( test) ]
0 commit comments