diff --git a/src/cmd/cat.rs b/src/cmd/cat.rs index 2f123c19d..34b3a374c 100644 --- a/src/cmd/cat.rs +++ b/src/cmd/cat.rs @@ -9,7 +9,8 @@ reversed with the '--pad' flag.) Concatenating by rows can be done in two ways: 'rows' subcommand: - All CSV data must have the same number of columns and in the same order. + All CSV data must have the same number of columns (unless --flexible is enabled) + and in the same order. If you need to rearrange the columns or fix the lengths of records, use the 'select' or 'fixlengths' commands. Also, only the headers of the *first* CSV data given are used. Headers in subsequent inputs are ignored. (This behavior @@ -34,6 +35,11 @@ cat options: all records to appear. It will pad each row if other CSV data isn't long enough. + ROWS OPTION: + --flexible When concatenating rows, this flag turns off validation + that the output CSV have the same number of columns. This is + faster, but may result in invalid CSV data. + ROWSKEY OPTIONS: -g, --group When concatenating with rowskey, use the file stem of each input file as a grouping value. A new column will be added @@ -69,6 +75,7 @@ struct Args { flag_group_name: String, arg_input: Vec, flag_pad: bool, + flag_flexible: bool, flag_output: Option, flag_no_headers: bool, flag_delimiter: Option, @@ -96,7 +103,9 @@ impl Args { fn cat_rows(&self) -> CliResult<()> { let mut row = csv::ByteRecord::new(); - let mut wtr = Config::new(&self.flag_output).writer()?; + let mut wtr = Config::new(&self.flag_output) + .flexible(self.flag_flexible) + .writer()?; let mut rdr; let mut configs = self.configs()?.into_iter(); diff --git a/tests/test_cat.rs b/tests/test_cat.rs index b450d883a..a705625a5 100644 --- a/tests/test_cat.rs +++ b/tests/test_cat.rs @@ -119,6 +119,58 @@ fn cat_rowskey() { assert_eq!(got, expected); } +#[test] +fn cat_rows_flexible() { + let wrk = Workdir::new("cat_rows_flexible"); + wrk.create( + "in1.csv", + vec![ + svec!["a", "b", "c"], + svec!["1", "2", "3"], + svec!["2", "3", "4"], + ], + ); + + wrk.create( + "in2.csv", + vec![ + svec!["a", "b", "c"], + svec!["3", "1", "2"], + svec!["4", "2", "3"], + ], + ); + + wrk.create( + "in3.csv", + vec![ + svec!["a", "b", "c", "d"], + svec!["1", "2", "4", "3"], + svec!["2", "3", "5", "4"], + svec!["z", "y", "w", "x"], + ], + ); + + let mut cmd = wrk.command("cat"); + cmd.arg("rows") + .arg("--flexible") + .arg("in1.csv") + .arg("in2.csv") + .arg("in3.csv"); + + let got: Vec> = wrk.read_stdout(&mut cmd); + let expected = vec![ + svec!["a", "b", "c"], + svec!["1", "2", "3"], + svec!["2", "3", "4"], + svec!["3", "1", "2"], + svec!["4", "2", "3"], + svec!["1", "2", "4", "3"], + svec!["2", "3", "5", "4"], + svec!["z", "y", "w", "x"], + ]; + assert_eq!(got, expected); +} + #[test] fn cat_rowskey_grouping() { let wrk = Workdir::new("cat_rowskey_grouping");