1use clap::{Parser, Subcommand, ValueEnum, ValueHint};
4use readstat::{OutFormat, ParquetCompression};
5use std::fmt;
6use std::path::PathBuf;
7
8#[derive(Parser, Debug)]
12#[command(version)]
13#[command(propagate_version = true)]
14pub struct ReadStatCli {
15 #[command(subcommand)]
16 pub command: ReadStatCliCommands,
17}
18
19#[derive(Debug, Subcommand)]
21pub enum ReadStatCliCommands {
22 Metadata {
24 #[arg(value_hint = ValueHint::FilePath, value_parser)]
26 input: PathBuf,
27 #[arg(action, long)]
29 as_json: bool,
30 #[arg(action, long)]
32 skip_row_count: bool,
33 },
34 Preview {
36 #[arg(value_hint = ValueHint::FilePath, value_parser)]
38 input: PathBuf,
39 #[arg(default_value = "10", long, value_parser)]
41 rows: u32,
42 #[arg(value_enum, ignore_case = true, long, value_parser)]
44 reader: Option<Reader>,
45 #[arg(long, value_parser = clap::value_parser!(u32).range(1..))]
47 stream_rows: Option<u32>,
48 #[arg(action, long)]
50 no_progress: bool,
51 #[arg(long, value_delimiter = ',', num_args = 1..)]
53 columns: Option<Vec<String>>,
54 #[arg(long, value_hint = ValueHint::FilePath, conflicts_with = "columns")]
56 columns_file: Option<PathBuf>,
57 #[cfg(feature = "sql")]
59 #[arg(long, conflicts_with_all = ["columns", "columns_file"])]
60 sql: Option<String>,
61 #[cfg(feature = "sql")]
63 #[arg(long, value_hint = ValueHint::FilePath, conflicts_with_all = ["sql", "columns", "columns_file"])]
64 sql_file: Option<PathBuf>,
65 },
66 Data {
68 #[arg(value_hint = ValueHint::FilePath, value_parser)]
70 input: PathBuf,
71 #[arg(long, short = 'o', value_hint = ValueHint::FilePath, value_parser)]
73 output: Option<PathBuf>,
74 #[arg(ignore_case = true, long, short = 'f', value_enum, value_parser)]
76 format: Option<CliOutFormat>,
77 #[arg(action, long)]
79 overwrite: bool,
80 #[arg(long, value_parser)]
82 rows: Option<u32>,
83 #[arg(ignore_case = true, long, value_enum, value_parser)]
85 reader: Option<Reader>,
86 #[arg(long, value_parser = clap::value_parser!(u32).range(1..))]
88 stream_rows: Option<u32>,
89 #[arg(action, long)]
91 no_progress: bool,
92 #[arg(action, long)]
94 parallel: bool,
95 #[arg(action, long)]
97 parallel_write: bool,
98 #[arg(long, value_parser = clap::value_parser!(u64).range(1..=10240), default_value = "100")]
100 parallel_write_buffer_mb: u64,
101 #[arg(long, value_enum, value_parser)]
103 compression: Option<CliParquetCompression>,
104 #[arg(long, value_parser = clap::value_parser!(u32).range(0..=22), requires = "compression")]
106 compression_level: Option<u32>,
107 #[arg(long, value_delimiter = ',', num_args = 1..)]
109 columns: Option<Vec<String>>,
110 #[arg(long, value_hint = ValueHint::FilePath, conflicts_with = "columns")]
112 columns_file: Option<PathBuf>,
113 #[cfg(feature = "sql")]
115 #[arg(long, conflicts_with_all = ["columns", "columns_file"])]
116 sql: Option<String>,
117 #[cfg(feature = "sql")]
119 #[arg(long, value_hint = ValueHint::FilePath, conflicts_with_all = ["sql", "columns", "columns_file"])]
120 sql_file: Option<PathBuf>,
121 },
122}
123
124#[derive(Debug, Clone, Copy, ValueEnum)]
129pub enum CliOutFormat {
130 Csv,
132 Feather,
134 Ndjson,
136 Parquet,
138}
139
140impl From<CliOutFormat> for OutFormat {
141 fn from(f: CliOutFormat) -> Self {
142 match f {
143 CliOutFormat::Csv => Self::Csv,
144 CliOutFormat::Feather => Self::Feather,
145 CliOutFormat::Ndjson => Self::Ndjson,
146 CliOutFormat::Parquet => Self::Parquet,
147 }
148 }
149}
150
151impl fmt::Display for CliOutFormat {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 match self {
154 Self::Csv => f.write_str("csv"),
155 Self::Feather => f.write_str("feather"),
156 Self::Ndjson => f.write_str("ndjson"),
157 Self::Parquet => f.write_str("parquet"),
158 }
159 }
160}
161
162#[derive(Debug, Clone, Copy, ValueEnum)]
167pub enum Reader {
168 Mem,
170 Stream,
172}
173
174impl fmt::Display for Reader {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 match self {
177 Self::Mem => f.write_str("mem"),
178 Self::Stream => f.write_str("stream"),
179 }
180 }
181}
182
183#[derive(Debug, Clone, Copy, ValueEnum)]
185pub enum CliParquetCompression {
186 Uncompressed,
188 Snappy,
190 Gzip,
192 Lz4Raw,
194 Brotli,
196 Zstd,
198}
199
200impl From<CliParquetCompression> for ParquetCompression {
201 fn from(c: CliParquetCompression) -> Self {
202 match c {
203 CliParquetCompression::Uncompressed => Self::Uncompressed,
204 CliParquetCompression::Snappy => Self::Snappy,
205 CliParquetCompression::Gzip => Self::Gzip,
206 CliParquetCompression::Lz4Raw => Self::Lz4Raw,
207 CliParquetCompression::Brotli => Self::Brotli,
208 CliParquetCompression::Zstd => Self::Zstd,
209 }
210 }
211}
212
213impl fmt::Display for CliParquetCompression {
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 match self {
216 Self::Uncompressed => f.write_str("uncompressed"),
217 Self::Snappy => f.write_str("snappy"),
218 Self::Gzip => f.write_str("gzip"),
219 Self::Lz4Raw => f.write_str("lz4-raw"),
220 Self::Brotli => f.write_str("brotli"),
221 Self::Zstd => f.write_str("zstd"),
222 }
223 }
224}