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 no_progress: bool,
33 #[arg(action, long)]
35 skip_row_count: bool,
36 },
37 Preview {
39 #[arg(value_hint = ValueHint::FilePath, value_parser)]
41 input: PathBuf,
42 #[arg(default_value = "10", long, value_parser)]
44 rows: u32,
45 #[arg(value_enum, ignore_case = true, long, value_parser)]
47 reader: Option<Reader>,
48 #[arg(long, value_parser)]
50 stream_rows: Option<u32>,
51 #[arg(action, long)]
53 no_progress: bool,
54 #[arg(long, value_delimiter = ',', num_args = 1..)]
56 columns: Option<Vec<String>>,
57 #[arg(long, value_hint = ValueHint::FilePath, conflicts_with = "columns")]
59 columns_file: Option<PathBuf>,
60 #[cfg(feature = "sql")]
62 #[arg(long, conflicts_with_all = ["columns", "columns_file"])]
63 sql: Option<String>,
64 #[cfg(feature = "sql")]
66 #[arg(long, value_hint = ValueHint::FilePath, conflicts_with_all = ["sql", "columns", "columns_file"])]
67 sql_file: Option<PathBuf>,
68 },
69 Data {
71 #[arg(value_hint = ValueHint::FilePath, value_parser)]
73 input: PathBuf,
74 #[arg(long, short = 'o', value_hint = ValueHint::FilePath, value_parser)]
76 output: Option<PathBuf>,
77 #[arg(ignore_case = true, long, short = 'f', value_enum, value_parser)]
79 format: Option<CliOutFormat>,
80 #[arg(action, long)]
82 overwrite: bool,
83 #[arg(long, value_parser)]
85 rows: Option<u32>,
86 #[arg(ignore_case = true, long, value_enum, value_parser)]
88 reader: Option<Reader>,
89 #[arg(long, value_parser)]
91 stream_rows: Option<u32>,
92 #[arg(action, long)]
94 no_progress: bool,
95 #[arg(action, long)]
97 parallel: bool,
98 #[arg(action, long)]
100 parallel_write: bool,
101 #[arg(long, value_parser = clap::value_parser!(u64).range(1..=10240), default_value = "100")]
103 parallel_write_buffer_mb: u64,
104 #[arg(long, value_enum, value_parser)]
106 compression: Option<CliParquetCompression>,
107 #[arg(long, value_parser = clap::value_parser!(u32).range(0..=22))]
109 compression_level: Option<u32>,
110 #[arg(long, value_delimiter = ',', num_args = 1..)]
112 columns: Option<Vec<String>>,
113 #[arg(long, value_hint = ValueHint::FilePath, conflicts_with = "columns")]
115 columns_file: Option<PathBuf>,
116 #[cfg(feature = "sql")]
118 #[arg(long, conflicts_with_all = ["columns", "columns_file"])]
119 sql: Option<String>,
120 #[cfg(feature = "sql")]
122 #[arg(long, value_hint = ValueHint::FilePath, conflicts_with_all = ["sql", "columns", "columns_file"])]
123 sql_file: Option<PathBuf>,
124 },
125}
126
127#[derive(Debug, Clone, Copy, ValueEnum)]
132pub enum CliOutFormat {
133 Csv,
135 Feather,
137 Ndjson,
139 Parquet,
141}
142
143impl From<CliOutFormat> for OutFormat {
144 fn from(f: CliOutFormat) -> Self {
145 match f {
146 CliOutFormat::Csv => Self::Csv,
147 CliOutFormat::Feather => Self::Feather,
148 CliOutFormat::Ndjson => Self::Ndjson,
149 CliOutFormat::Parquet => Self::Parquet,
150 }
151 }
152}
153
154impl fmt::Display for CliOutFormat {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 match self {
157 Self::Csv => f.write_str("csv"),
158 Self::Feather => f.write_str("feather"),
159 Self::Ndjson => f.write_str("ndjson"),
160 Self::Parquet => f.write_str("parquet"),
161 }
162 }
163}
164
165#[derive(Debug, Clone, Copy, ValueEnum)]
170pub enum Reader {
171 Mem,
173 Stream,
175}
176
177impl fmt::Display for Reader {
178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179 match self {
180 Self::Mem => f.write_str("mem"),
181 Self::Stream => f.write_str("stream"),
182 }
183 }
184}
185
186#[derive(Debug, Clone, Copy, ValueEnum)]
188pub enum CliParquetCompression {
189 Uncompressed,
191 Snappy,
193 Gzip,
195 Lz4Raw,
197 Brotli,
199 Zstd,
201}
202
203impl From<CliParquetCompression> for ParquetCompression {
204 fn from(c: CliParquetCompression) -> Self {
205 match c {
206 CliParquetCompression::Uncompressed => Self::Uncompressed,
207 CliParquetCompression::Snappy => Self::Snappy,
208 CliParquetCompression::Gzip => Self::Gzip,
209 CliParquetCompression::Lz4Raw => Self::Lz4Raw,
210 CliParquetCompression::Brotli => Self::Brotli,
211 CliParquetCompression::Zstd => Self::Zstd,
212 }
213 }
214}
215
216impl fmt::Display for CliParquetCompression {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 match self {
219 Self::Uncompressed => f.write_str("uncompressed"),
220 Self::Snappy => f.write_str("snappy"),
221 Self::Gzip => f.write_str("gzip"),
222 Self::Lz4Raw => f.write_str("lz4-raw"),
223 Self::Brotli => f.write_str("brotli"),
224 Self::Zstd => f.write_str("zstd"),
225 }
226 }
227}