1use super::{cli_result::CliResult, constants::TERMINATOR};
2use calamine::Data;
3use chrono::Timelike;
4use std::{
5 fs::{File, OpenOptions},
6 io::{stdout, BufWriter, Error, Write},
7 path::Path,
8 process,
9};
10
11pub struct Writer(pub Box<dyn Write>);
12
13impl Writer {
14 pub fn new(path: &Path) -> Result<Self, Error> {
15 let wtr = Box::new(BufWriter::new(File::create(path)?));
16
17 Ok(Writer(wtr))
18 }
19
20 pub fn file_or_stdout(export: bool, path: &Path) -> Result<Self, Error> {
21 let wtr = match export {
22 true => Box::new(BufWriter::new(File::create(path)?)) as Box<dyn Write>,
23 false => Box::new(stdout()) as Box<dyn Write>,
24 };
25
26 Ok(Writer(wtr))
27 }
28
29 pub fn stdout() -> Result<Self, Error> {
30 let wtr = Box::new(stdout()) as Box<dyn Write>;
31 Ok(Writer(wtr))
32 }
33
34 pub fn append_to(out: &Path) -> Result<Self, Error> {
35 let f = OpenOptions::new()
37 .write(true)
38 .append(true)
39 .create(true)
40 .open(out)?;
41
42 let wtr = Box::new(BufWriter::new(f));
43
44 Ok(Writer(wtr))
45 }
46
47 pub fn write_bytes(&mut self, bytes: &[u8]) -> CliResult {
48 self.0.write_all(bytes)?;
49 Ok(())
50 }
51
52 pub fn write_bytes_unchecked(&mut self, bytes: &[u8]) {
53 if self.0.write_all(bytes).is_err() {
54 process::exit(0)
55 }
56 }
57
58 pub fn write_header(&mut self, row: &str) -> CliResult {
59 if !row.is_empty() {
60 self.write_str(row)?;
61 }
62 Ok(())
63 }
64
65 pub fn write_str<T: AsRef<str>>(&mut self, row: T) -> CliResult {
72 self.0.write_all(row.as_ref().as_bytes())?;
73 self.0.write_all(TERMINATOR)?;
74 Ok(())
75 }
76
77 pub fn write_str_unchecked<T: AsRef<str>>(&mut self, row: T) {
78 if self.write_str(row).is_err() {
79 process::exit(0)
80 }
81 }
82
83 pub fn write_strings<T: AsRef<str>>(&mut self, lines: &[T]) -> CliResult {
84 for l in lines {
85 self.write_str(l)?;
86 }
87 Ok(())
88 }
89
90 pub fn write_strings_unchecked<T: AsRef<str>>(&mut self, lines: &[T]) {
91 if self.write_strings(lines).is_err() {
92 process::exit(0)
93 }
94 }
95
96 pub fn write_fields<T: AsRef<str>>(&mut self, line: &[T]) -> CliResult {
97 let mut l = line.iter().peekable();
98 while let Some(f) = l.next() {
99 self.0.write_all(f.as_ref().as_bytes())?;
100 let sep = if l.peek().is_none() { TERMINATOR } else { b"," };
101 self.0.write_all(sep)?;
102 }
103
104 Ok(())
105 }
106
107 pub fn write_fields_unchecked<T: AsRef<str>>(&mut self, line: &[T]) {
108 if self.write_fields(line).is_err() {
109 process::exit(0)
110 }
111 }
112
113 pub fn write_selected_fields<T: AsRef<str>>(
114 &mut self,
115 line: &[T],
116 cols: &[usize],
117 sep: Option<&[u8]>,
118 ) -> CliResult {
119 let mut l = cols.iter().peekable();
120 while let Some(&i) = l.next() {
121 self.0.write_all(line[i].as_ref().as_bytes())?;
122 let sep = if l.peek().is_none() {
123 TERMINATOR
124 } else {
125 sep.unwrap_or(b",")
126 };
127 self.0.write_all(sep)?;
128 }
129
130 Ok(())
131 }
132
133 pub fn write_selected_fields_unchecked<T: AsRef<str>>(
134 &mut self,
135 line: &[T],
136 cols: &[usize],
137 sep: Option<&[u8]>,
138 ) {
139 if self.write_selected_fields(line, cols, sep).is_err() {
140 process::exit(0)
141 }
142 }
143
144 pub fn write_fields_of_lines_unchecked<T: AsRef<str>>(&mut self, lines: &Vec<Vec<T>>) {
145 for line in lines {
146 if self.write_fields(line).is_err() {
147 process::exit(0)
148 }
149 }
150 }
151
152 pub fn write_excel_field(&mut self, data: &Data) -> CliResult {
153 match data {
154 Data::DateTime(v) => {
155 if let Some(a) = v.as_datetime() {
156 if a.hour() == 0 && a.minute() == 0 && a.second() == 0 {
157 write!(&mut self.0, "{}", a.format("%Y-%m-%d"))?
158 } else {
159 write!(&mut self.0, "{}", a.format("%Y-%m-%d %H:%M:%S"))?
160 }
161 }
162 }
163
164 Data::String(v) => {
165 let double_quote_escape_field = if v.contains("\\\"") {
171 v
172 } else if v.contains("\"") {
173 &v.replace("\"", "\\\"")
174 } else {
175 v
176 };
177
178 if v.contains(',') {
179 write!(&mut self.0, "\"{}\"", double_quote_escape_field)?
180 } else {
181 write!(&mut self.0, "{}", double_quote_escape_field)?
182 }
183 }
184
185 _ => write!(&mut self.0, "{}", data)?,
186 }
187
188 Ok(())
189 }
190
191 pub fn write_excel_line(&mut self, line: &[Data], sep: &[u8]) -> CliResult {
192 let mut l = line.iter().peekable();
193 while let Some(f) = l.next() {
194 self.write_excel_field(f)?;
195
196 if l.peek().is_some() {
197 self.0.write_all(sep)?;
198 } else {
199 self.0.write_all(TERMINATOR)?;
200 }
201 }
202
203 Ok(())
204 }
205
206 pub fn write_excel_line_unchecked(&mut self, line: &[Data], sep: &[u8]) {
207 if self.write_excel_line(line, sep).is_err() {
208 process::exit(0)
209 }
210 }
211
212 pub fn write_excel_selected_fields(
213 &mut self,
214 line: &[Data],
215 cols: &[usize],
216 sep: &[u8],
217 ) -> CliResult {
218 let mut l = cols.iter().peekable();
219 while let Some(&i) = l.next() {
220 self.write_excel_field(&line[i])?;
221
222 if l.peek().is_some() {
223 self.0.write_all(sep)?;
224 } else {
225 self.0.write_all(TERMINATOR)?;
226 }
227 }
228
229 Ok(())
230 }
231
232 pub fn write_excel_selected_fields_unchecked(
233 &mut self,
234 line: &[Data],
235 cols: &[usize],
236 sep: &[u8],
237 ) {
238 if self.write_excel_selected_fields(line, cols, sep).is_err() {
239 process::exit(0)
240 }
241 }
242
243 pub fn write_excel_lines(&mut self, lines: &[Vec<Data>], sep: &[u8]) -> CliResult {
244 for l in lines {
245 self.write_excel_line(l, sep)?;
246 }
247
248 Ok(())
249 }
250
251 pub fn write_excel_lines_by_ref(&mut self, lines: &[&Vec<Data>], sep: &[u8]) -> CliResult {
252 for &l in lines {
253 self.write_excel_line(l, sep)?;
254 }
255
256 Ok(())
257 }
258}