rsv_lib/
args.rs

1use crate::utils::{
2    cli_result::E, file::is_excel, filename::full_path, row_split::CsvRowSplitter,
3    util::get_valid_sep,
4};
5use clap::Args;
6use std::path::PathBuf;
7
8#[derive(Debug, Args)]
9pub struct Count {
10    /// File to open
11    pub filename: Option<String>,
12    /// Whether the file has a header
13    #[arg(long, default_value_t = false)]
14    pub no_header: bool,
15    /// Get the nth worksheet of Excel file
16    #[arg(short = 'S', long, default_value_t = 0)]
17    pub sheet: usize,
18}
19
20#[derive(Debug, Args)]
21pub struct Size {
22    /// File to open
23    pub filename: Option<String>,
24}
25
26#[derive(Debug, Args)]
27pub struct Estimate {
28    /// File to open
29    pub filename: Option<String>,
30    /// Get the nth worksheet for an Excel file
31    #[arg(short = 'S', long, default_value_t = 0)]
32    pub sheet: usize,
33}
34
35#[derive(Debug, Args)]
36pub struct Head {
37    /// File to open
38    pub filename: Option<String>,
39    /// Whether the file has a header
40    #[arg(long, default_value_t = false)]
41    pub no_header: bool,
42    /// Number of records to show
43    #[arg(short, long, default_value_t = 10)]
44    pub n: usize,
45    /// Get the nth worksheet of EXCEL file
46    #[arg(short = 'S', long, default_value_t = 0)]
47    pub sheet: usize,
48    /// Export to a file named current-file-head.csv?
49    #[arg(short = 'E', long, default_value_t = false)]
50    pub export: bool,
51    /// Field separator
52    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
53    pub sep: char,
54    /// Quote char
55    #[arg(short, long, default_value_t = '"')]
56    pub quote: char,
57}
58
59#[derive(Debug, Args)]
60pub struct Tail {
61    /// File to open
62    pub filename: Option<String>,
63    /// Whether the file has a header
64    #[arg(long, default_value_t = false)]
65    pub no_header: bool,
66    /// Number of records to show
67    #[arg(short, long, default_value_t = 10)]
68    pub n: usize,
69    /// Get the nth worksheet of EXCEL file
70    #[arg(short = 'S', long, default_value_t = 0)]
71    pub sheet: usize,
72    /// Export to a file named current-file-head.csv?
73    #[arg(short = 'E', long, default_value_t = false)]
74    pub export: bool,
75}
76
77#[derive(Debug, Args)]
78pub struct Headers {
79    /// File to open
80    pub filename: Option<String>,
81    /// Field separator
82    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
83    pub sep: char,
84    /// Quote char
85    #[arg(short, long, default_value_t = '"')]
86    pub quote: char,
87    /// Get the nth worksheet of EXCEL file
88    #[arg(short = 'S', long, default_value_t = 0)]
89    pub sheet: usize,
90}
91
92#[derive(Debug, Args)]
93pub struct Clean {
94    /// File to open
95    pub filename: Option<String>,
96    /// Output file, default to current-file-cleaned.csv
97    #[arg(short, long, default_value_t = String::from(""), hide_default_value=true)]
98    pub output: String,
99    /// Escape char to clean
100    #[arg(short, long, default_value_t = String::from("\""))]
101    pub escape: String,
102}
103
104#[derive(Debug, Args)]
105pub struct Flatten {
106    /// File to open
107    pub filename: Option<String>,
108    /// Separator
109    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
110    pub sep: char,
111    /// Quote char
112    #[arg(short, long, default_value_t = '"')]
113    pub quote: char,
114    /// Whether the file has a header
115    #[arg(long, default_value_t = false)]
116    pub no_header: bool,
117    /// Line delimiter for printing
118    #[arg(short, long, default_value_t = String::from("#"))]
119    pub delimiter: String,
120    /// Number of records to show, n=-1 to show all
121    #[arg(short, long, default_value_t = 5)]
122    pub n: i32,
123    /// Get the nth worksheet of EXCEL file
124    #[arg(short = 'S', long, default_value_t = 0)]
125    pub sheet: usize,
126}
127
128#[derive(Debug, Args)]
129pub struct Frequency {
130    /// File to open
131    pub filename: Option<String>,
132    /// Separator
133    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
134    pub sep: char,
135    /// Quote char
136    #[arg(short, long, default_value_t = '"')]
137    pub quote: char,
138    /// Whether the file has a header
139    #[arg(long, default_value_t = false)]
140    pub no_header: bool,
141    /// Columns to generate frequency table
142    #[arg(short, long, default_value_t = String::from("0"), allow_hyphen_values=true)]
143    pub cols: String,
144    /// Ascending order or not
145    #[arg(short, long, default_value_t = false)]
146    pub ascending: bool,
147    /// Export result to a frequency.csv?
148    #[arg(short = 'E', long, default_value_t = false)]
149    pub export: bool,
150    /// Top N to keep in frequency table
151    #[arg(short, long, default_value_t = -1)]
152    pub n: i32,
153    /// Get the nth worksheet of EXCEL file
154    #[arg(short = 'S', long, default_value_t = 0)]
155    pub sheet: usize,
156}
157
158#[derive(Debug, Args)]
159pub struct Split {
160    /// File to open
161    pub filename: Option<String>,
162    /// Separator
163    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
164    pub sep: char,
165    /// Quote char
166    #[arg(short, long, default_value_t = '"')]
167    pub quote: char,
168    /// Whether the file has a header
169    #[arg(long, default_value_t = false)]
170    pub no_header: bool,
171    /// Column to split upon
172    #[arg(short, long, default_value_t = 0)]
173    pub col: usize,
174    /// Get the nth worksheet of EXCEL file
175    #[arg(short = 'S', long, default_value_t = 0)]
176    pub sheet: usize,
177    /// Number of records to write in each separate file
178    #[arg(long)]
179    pub size: Option<usize>,
180}
181
182#[derive(Debug, Args)]
183pub struct Slice {
184    /// File to open
185    pub filename: Option<String>,
186    /// Start index of CSV
187    #[arg(short, long, default_value_t = 0)]
188    pub start: usize,
189    /// End index of CSV
190    #[arg(short, long)]
191    pub end: Option<usize>,
192    /// Slice length
193    #[arg(short, long)]
194    pub length: Option<usize>,
195    /// Index for single record of CSV
196    #[arg(short, long)]
197    pub index: Option<usize>,
198    /// Whether the file has a header
199    #[arg(long, default_value_t = false)]
200    pub no_header: bool,
201    /// Export data to a current-file-slice.csv?
202    #[arg(short = 'E', long, default_value_t = false)]
203    pub export: bool,
204    /// Get the nth worksheet of EXCEL file
205    #[arg(short = 'S', long, default_value_t = 0)]
206    pub sheet: usize,
207}
208
209#[derive(Debug, Args)]
210pub struct Select {
211    /// File to open
212    pub filename: Option<String>,
213    /// Separator
214    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
215    pub sep: char,
216    /// Separator
217    #[arg(short, long, default_value_t = ',')]
218    pub quote: char,
219    /// Whether the file has a header
220    #[arg(long, default_value_t = false)]
221    pub no_header: bool,
222    /// Columns to select, support syntax 0,1,3 or 0-4, including 4; Default to select all columns
223    #[arg(short, long, default_value_t = String::from(""), allow_hyphen_values=true)]
224    pub cols: String,
225    /// Row filter, support syntax 0=a,b,c or 0=a,b&1=c,d; Default to None
226    #[arg(short, long, default_value_t = String::from(""), allow_hyphen_values=true)]
227    pub filter: String,
228    /// Export results to a file named current-file-selected.csv?
229    #[arg(short = 'E', long, default_value_t = false)]
230    pub export: bool,
231    /// Get the nth worksheet of EXCEL file
232    #[arg(short = 'S', long, default_value_t = 0)]
233    pub sheet: usize,
234}
235
236#[derive(Debug, Args)]
237pub struct Stats {
238    /// File to open
239    pub filename: Option<String>,
240    /// Separator
241    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
242    pub sep: char,
243    /// Quote Char
244    #[arg(short, long, default_value_t = ',')]
245    pub quote: char,
246    /// Whether the file has a header
247    #[arg(long, default_value_t = false)]
248    pub no_header: bool,
249    /// Columns to generate statistics, support syntax 0,1,3 or 0-4, including 4; Default to select all columns
250    #[arg(short, long, default_value_t = String::from(""), allow_hyphen_values=true)]
251    pub cols: String,
252    /// Export results to a file named current-file-selected.csv?
253    #[arg(short = 'E', long, default_value_t = false)]
254    pub export: bool,
255    /// Get the nth worksheet of EXCEL file
256    #[arg(short = 'S', long, default_value_t = 0)]
257    pub sheet: usize,
258}
259
260#[derive(Debug, Args)]
261pub struct Excel2csv {
262    /// File to open
263    pub filename: Option<String>,
264    /// Get the nth worksheet of EXCEL file
265    #[arg(short = 'S', long, default_value_t = 0)]
266    pub sheet: usize,
267    /// Separator Char
268    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
269    pub sep: char,
270    /// Quote Char
271    #[arg(short, long, default_value_t = '"')]
272    pub quote: char,
273}
274
275#[derive(Debug, Args)]
276pub struct Table {
277    /// File to open
278    pub filename: Option<String>,
279    /// Get the nth worksheet of EXCEL file
280    #[arg(short = 'S', long, default_value_t = 0)]
281    pub sheet: usize,
282    /// Separator Char
283    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
284    pub sep: char,
285    /// Quote Char
286    #[arg(short, long, default_value_t = '"')]
287    pub quote: char,
288}
289
290#[derive(Debug, Args)]
291pub struct Search {
292    /// Regex pattern to search
293    pub pattern: String,
294    /// File to open
295    pub filename: Option<String>,
296    /// Whether the file has a header
297    #[arg(long, default_value_t = false)]
298    pub no_header: bool,
299    /// Separator Char
300    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
301    pub sep: char,
302    /// Quote Char
303    #[arg(short, long, default_value_t = '"')]
304    pub quote: char,
305    /// Search specific columns, e.g. -f=0,1 to search first two columns; Default to all columns
306    #[arg(short, long, default_value_t = String::from(""), allow_hyphen_values=true)]
307    pub filter: String,
308    /// Columns to select in output, support syntax 0,1,3 or 0-4, including 4; Default to select all columns
309    #[arg(short, long, default_value_t = String::from(""), allow_hyphen_values=true)]
310    pub cols: String,
311    /// Get the nth worksheet of EXCEL file
312    #[arg(short = 'S', long, default_value_t = String::from("0"), allow_hyphen_values = true)]
313    pub sheet: String,
314    /// Export to a file named current-file-searched.csv?
315    #[arg(short = 'E', long, default_value_t = false)]
316    pub export: bool,
317}
318
319#[derive(Debug, Args)]
320pub struct Sort {
321    /// File to open
322    pub filename: Option<String>,
323    /// Separator
324    #[arg(short, long, default_value_t=',', value_parser=get_valid_sep )]
325    pub sep: char,
326    /// Quote Char
327    #[arg(short, long, default_value_t = '"')]
328    pub quote: char,
329    /// Whether the file has a header
330    #[arg(long, default_value_t = false)]
331    pub no_header: bool,
332    /// Columns to sort by, support syntax 0 (first column),
333    /// "-0" (descending), "-0N" (as numeric) or "0N,-1" (two columns)
334    #[arg(short, long, default_value_t = String::from("0"), allow_hyphen_values=true)]
335    pub cols: String,
336    /// Get the nth worksheet of EXCEL file
337    #[arg(short = 'S', long, default_value_t = 0)]
338    pub sheet: usize,
339    /// Export to a file named current-file-searched.csv?
340    #[arg(short = 'E', long, default_value_t = false)]
341    pub export: bool,
342}
343
344#[derive(Debug, Args)]
345pub struct Sample {
346    /// File to open
347    pub filename: Option<String>,
348    /// Whether the file has a header
349    #[arg(long, default_value_t = false)]
350    pub no_header: bool,
351    /// Get the nth worksheet of EXCEL file
352    #[arg(short = 'S', long, default_value_t = 0)]
353    pub sheet: usize,
354    /// Sample size
355    #[arg(short, long, default_value_t = 10)]
356    pub n: usize,
357    /// Get the nth worksheet of EXCEL file
358    #[arg(long)]
359    pub seed: Option<usize>,
360    /// Export to a file named current-file-searched.csv?
361    #[arg(short = 'E', long, default_value_t = false)]
362    pub export: bool,
363    /// Show line number
364    #[arg(long, long, default_value_t = false)]
365    pub show_number: bool,
366    /// Time limit
367    #[arg(short, long, default_value_t = 0.0)]
368    pub time_limit: f32,
369}
370
371#[derive(Debug, Args)]
372pub struct To {
373    /// Output file, a file name or a file format
374    pub out: String,
375    /// File to open
376    pub filename: Option<String>,
377    /// Whether the file has a header
378    #[arg(long, default_value_t = false)]
379    pub no_header: bool,
380    /// Input file Separator
381    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
382    pub sep: char,
383    /// Quote char
384    #[arg(short, long, default_value_t = '"')]
385    pub quote: char,
386    /// Get the nth worksheet of EXCEL file
387    #[arg(short = 'S', long, default_value_t = 0)]
388    pub sheet: usize,
389}
390
391#[derive(Debug, Args)]
392pub struct Unique {
393    /// File to open
394    pub filename: Option<String>,
395    /// Separator
396    #[arg(short, long, default_value_t = ',', value_parser=get_valid_sep)]
397    pub sep: char,
398    /// Separator
399    #[arg(short, long, default_value_t = '"')]
400    pub quote: char,
401    /// Whether the file has a header
402    #[arg(long, default_value_t = false)]
403    pub no_header: bool,
404    /// Columns to filter
405    #[arg(short, long, default_value_t = String::from("-1"), allow_hyphen_values=true)]
406    pub cols: String,
407    /// keep first or last
408    #[arg(long, default_value_t = false)]
409    pub keep_last: bool,
410    /// Get the nth worksheet of EXCEL file
411    #[arg(short = 'S', long, default_value_t = 0)]
412    pub sheet: usize,
413    /// Export to a file named drop-duplicates.csv?
414    #[arg(short = 'E', long, default_value_t = false)]
415    pub export: bool,
416}
417
418macro_rules! command_run {
419    ($method:ident) => {
420        impl $method {
421            pub fn path(&self) -> PathBuf {
422                let p = self.filename.as_ref().unwrap();
423                full_path(p)
424            }
425
426            pub fn run(&self) {
427                match &self.filename {
428                    Some(f) => match is_excel(&full_path(f)) {
429                        true => self.excel_run(),
430                        false => self.csv_run(),
431                    },
432                    None => self.io_run(),
433                }
434                .handle_err()
435            }
436        }
437    };
438}
439
440command_run!(Count);
441command_run!(Estimate);
442command_run!(Head);
443command_run!(Tail);
444command_run!(Headers);
445command_run!(Clean);
446command_run!(Flatten);
447command_run!(Frequency);
448command_run!(Split);
449command_run!(Slice);
450command_run!(Select);
451command_run!(Stats);
452command_run!(Excel2csv);
453command_run!(Table);
454command_run!(Sort);
455command_run!(Search);
456command_run!(Sample);
457command_run!(To);
458command_run!(Unique);
459command_run!(Size);
460
461macro_rules! impl_row_split {
462    ($cmd:ident) => {
463        impl $cmd {
464            #[allow(dead_code)]
465            pub fn split<'a>(&self, row: &'a str) -> CsvRowSplitter<'a> {
466                CsvRowSplitter::new(row, self.sep, self.quote)
467            }
468
469            #[allow(dead_code)]
470            pub fn split_row_to_vec<'a>(&self, row: &'a str) -> Vec<&'a str> {
471                CsvRowSplitter::new(row, self.sep, self.quote).collect()
472            }
473
474            #[allow(dead_code)]
475            pub fn split_row_to_owned_vec<'a>(&self, row: &'a str) -> Vec<String> {
476                CsvRowSplitter::new(row, self.sep, self.quote)
477                    .map(|i| i.to_owned())
478                    .collect::<Vec<_>>()
479            }
480
481            #[allow(dead_code)]
482            pub fn row_field_count<'a>(&self, row: &'a str) -> usize {
483                CsvRowSplitter::new(row, self.sep, self.quote).count()
484            }
485        }
486    };
487}
488
489impl_row_split!(Head);
490impl_row_split!(Headers);
491impl_row_split!(Frequency);
492impl_row_split!(Select);
493impl_row_split!(Stats);
494impl_row_split!(To);
495impl_row_split!(Flatten);
496impl_row_split!(Unique);
497impl_row_split!(Search);
498impl_row_split!(Table);
499impl_row_split!(Split);
500impl_row_split!(Excel2csv);