1use crate::TError;
2
3#[derive(Debug)]
4pub struct JsonSolver {
5 pub expression: Vec<String>,
6 pub pretty: bool,
7 pub recursive: bool,
8 pub json_line: bool,
9 pub skip_empty: bool,
10 pub skip_keys: Vec<String>,
11}
12
13impl From<&clap::ArgMatches<'_>> for JsonSolver {
14 fn from(input: &clap::ArgMatches<'_>) -> JsonSolver {
15 let expression = input
16 .value_of("expression")
17 .map(|s| s.split('.').map(String::from).collect::<_>())
19 .unwrap_or_default();
20 let pretty = input.is_present("pretty");
21 let recursive = input.is_present("recursive");
22 let json_line = input.is_present("json-lines");
23 let skip_empty = input.is_present("skip-empty");
24 let skip_keys = input
25 .values_of("skip-key")
26 .unwrap_or_default()
27 .map(|s| s.to_string())
28 .collect();
29 JsonSolver {
30 expression,
31 pretty,
32 recursive,
33 json_line,
34 skip_empty,
35 skip_keys,
36 }
37 }
38}
39
40impl JsonSolver {
41 pub fn resolve_value_stream<R>(&self, value: R) -> Result<(), TError>
42 where
43 R: std::io::BufRead,
44 {
45 value
46 .lines()
47 .map(|value| value.map(|v| self.resolve_value_impl(&v)))
48 .flatten()
49 .flatten()
50 .flatten()
51 .map(|s| JsonSolver::value_to_string(self.pretty, &s))
52 .for_each(|s| println!("{}", s));
53 Ok(())
54 }
55
56 pub fn resolve_value(&self, value: &str) -> Result<Vec<String>, TError> {
57 Ok(value
58 .split('\n')
59 .filter(|v| !v.is_empty())
60 .map(|value| self.resolve_value_impl(value))
61 .collect::<Result<Vec<_>, _>>()?
62 .into_iter()
63 .flatten()
64 .map(|s| JsonSolver::value_to_string(self.pretty, &s))
65 .collect::<Vec<String>>())
66 }
67
68 pub fn resolve_line(&self, value: &str) -> Result<Vec<String>, TError> {
69 let result = self.resolve_value_impl(value)?;
70 Ok(result
71 .iter()
72 .map(|v| JsonSolver::value_to_string(self.pretty, v))
73 .collect())
74 }
75
76 fn resolve_value_impl(&self, value: &str) -> Result<Vec<serde_json::Value>, TError> {
77 let root = serde_json::from_str::<serde_json::Value>(value)
78 .map(|s| self.recursively_parse(s).map(|s| self.remove_keys(s)))??;
79 let resolved_value = {
80 let mut result = vec![root];
81 for expr in &self.expression {
82 result =
83 result
84 .into_iter()
85 .map(
86 |reader| -> Box<
87 dyn Iterator<Item = Result<Option<serde_json::Value>, TError>>,
88 > {
89 match reader {
90 serde_json::Value::Array(v) => {
91 let next = v.into_iter().map(|values| {
92 let result = values.get(expr.as_str()).cloned();
93 if let Some(v) = result {
94 Ok(Some(v))
95 } else if self.skip_empty {
96 Ok(None)
97 } else {
98 Err(TError::KeyNotExist(expr.clone()))
99 }
100 });
101 Box::new(next)
102 }
103 o => {
104 let next = std::iter::once({
105 let result = o.get(expr.as_str()).cloned();
106 if let Some(v) = result {
107 Ok(Some(v))
108 } else if self.skip_empty {
109 Ok(None)
110 } else {
111 Err(TError::KeyNotExist(expr.clone()))
112 }
113 });
114 Box::new(next)
115 }
116 }
117 },
118 )
119 .flatten()
120 .collect::<Result<Vec<_>, _>>()?
121 .into_iter()
122 .flatten()
123 .collect::<Vec<_>>();
124 }
125 result
126 };
127 Ok(resolved_value)
128 }
129
130 fn recursively_parse(&self, value: serde_json::Value) -> Result<serde_json::Value, TError> {
131 if self.recursive {
132 match value {
133 serde_json::Value::Array(v) => {
134 let result = v
135 .into_iter()
136 .map(|s| self.recursively_parse(s))
137 .collect::<Result<Vec<_>, _>>()?;
138 Ok(serde_json::Value::Array(result))
139 }
140 serde_json::Value::String(s) => {
141 Ok(serde_json::from_str(&s).unwrap_or(serde_json::Value::String(s)))
142 }
143 serde_json::Value::Object(map) => {
144 let result = map
145 .into_iter()
146 .map(|(key, value)| {
147 self.recursively_parse(value)
148 .map(|parsed_value| (key, parsed_value))
149 })
150 .collect::<Result<serde_json::Map<_, _>, _>>()?;
151 Ok(serde_json::Value::Object(result))
152 }
153 v => Ok(v),
154 }
155 } else {
156 Ok(value)
157 }
158 }
159
160 fn remove_keys(&self, value: serde_json::Value) -> serde_json::Value {
161 match value {
162 serde_json::Value::Object(map) => {
163 let result = map
164 .into_iter()
165 .filter(|s| !self.skip_keys.contains(&s.0))
166 .collect::<serde_json::Map<_, _>>();
167 serde_json::Value::Object(result)
168 }
169 v => v,
170 }
171 }
172
173 fn value_to_string(pretty: bool, value: &serde_json::Value) -> String {
174 if pretty {
175 serde_json::to_string_pretty(value).unwrap()
176 } else {
177 serde_json::to_string(value).unwrap()
178 }
179 }
180}
181
182pub fn clap_app() -> clap::App<'static, 'static> {
183 clap::App::new("json")
184 .about("Perform queries on JSON files")
185 .arg(
186 clap::Arg::with_name("expression")
187 .long("expression")
188 .help("Expression to evaluate the input with")
189 .takes_value(true),
190 )
191 .arg(
192 clap::Arg::with_name("pretty")
193 .long("pretty")
194 .help("Pretty prints the output")
195 .takes_value(false),
196 )
197 .arg(
198 clap::Arg::with_name("recursive")
199 .long("recursive")
200 .help(
201 "Recursively parses every string values as JSON. \
202 Fallback to string if it fails",
203 )
204 .takes_value(false),
205 )
206 .arg(
207 clap::Arg::with_name("json-lines")
208 .long("json-lines")
209 .help("Enable JSON-lines mode")
210 .takes_value(false),
211 )
212 .arg(
213 clap::Arg::with_name("skip-empty")
214 .long("skip-empty")
215 .help("If expression fails to resolve, skip the value")
216 .takes_value(false),
217 )
218 .arg(
219 clap::Arg::with_name("skip-key")
220 .long("skip-key")
221 .help(
222 "Keys to be removed from the final output. \
223 Currently only supports removing root keys.",
224 )
225 .takes_value(true)
226 .multiple(true),
227 )
228 .author(clap::crate_authors!())
229}