nu_command/filters/
compact.rs1use nu_engine::command_prelude::*;
2
3#[derive(Clone)]
4pub struct Compact;
5
6impl Command for Compact {
7 fn name(&self) -> &str {
8 "compact"
9 }
10
11 fn signature(&self) -> Signature {
12 Signature::build("compact")
13 .input_output_types(vec![(
14 Type::List(Box::new(Type::Any)),
15 Type::List(Box::new(Type::Any)),
16 )])
17 .switch(
18 "empty",
19 "also compact empty items like \"\", {}, and []",
20 Some('e'),
21 )
22 .rest(
23 "columns",
24 SyntaxShape::Any,
25 "The columns to compact from the table.",
26 )
27 .category(Category::Filters)
28 }
29
30 fn description(&self) -> &str {
31 "Creates a table with non-empty rows."
32 }
33
34 fn search_terms(&self) -> Vec<&str> {
35 vec!["empty", "remove"]
36 }
37
38 fn run(
39 &self,
40 engine_state: &EngineState,
41 stack: &mut Stack,
42 call: &Call,
43 input: PipelineData,
44 ) -> Result<PipelineData, ShellError> {
45 let empty = call.has_flag(engine_state, stack, "empty")?;
46 compact(engine_state, stack, call, input, empty)
47 }
48
49 fn examples(&self) -> Vec<Example> {
50 vec![
51 Example {
52 description: "Filter out all records where 'Hello' is null",
53 example: r#"[["Hello" "World"]; [null 3]] | compact Hello"#,
54 result: Some(Value::test_list(vec![])),
55 },
56 Example {
57 description: "Filter out all records where 'World' is null",
58 example: r#"[["Hello" "World"]; [null 3]] | compact World"#,
59 result: Some(Value::test_list(vec![Value::test_record(record! {
60 "Hello" => Value::nothing(Span::test_data()),
61 "World" => Value::test_int(3),
62 })])),
63 },
64 Example {
65 description: "Filter out all instances of null from a list",
66 example: r#"[1, null, 2] | compact"#,
67 result: Some(Value::test_list(vec![
68 Value::test_int(1),
69 Value::test_int(2),
70 ])),
71 },
72 Example {
73 description: "Filter out all instances of null and empty items from a list",
74 example: r#"[1, null, 2, "", 3, [], 4, {}, 5] | compact --empty"#,
75 result: Some(Value::test_list(vec![
76 Value::test_int(1),
77 Value::test_int(2),
78 Value::test_int(3),
79 Value::test_int(4),
80 Value::test_int(5),
81 ])),
82 },
83 ]
84 }
85}
86
87pub 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 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 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 return false;
120 }
121 }
122 }
123 }
124 }
125
126 if compact_empties && val.is_empty() {
127 return false;
128 }
129 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 _ => true,
146 }
147 },
148 engine_state.signals(),
149 )
150 .map(|m| m.set_metadata(metadata))
151}
152
153#[cfg(test)]
154mod tests {
155 use super::Compact;
156
157 #[test]
158 fn examples_work_as_expected() {
159 use crate::test_examples;
160 test_examples(Compact {})
161 }
162}