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