1use super::{DiffTool, Json, KeyPatternType, QueryType};
2use itertools::Itertools;
3use jsonpath_rust::JsonPath;
4use serde::ser::Error;
5use serde::{Serialize, Serializer};
6use serde_json::Value;
7use std::collections::BTreeMap;
8use std::ops::Deref;
9use std::sync::Arc;
10use std::{env, fs};
11
12impl Json {
13 pub fn search_paths(&self, query: Option<&str>, query_type: Option<QueryType>) -> crate::Result<Vec<Jsonpath>> {
14 let json = Arc::<Value>::try_from(self)?;
15 let query = query.map(|it| it.trim()).filter(|it| it.len() > 0).unwrap_or("");
16 let (kp, qt) = Self::parse_query_type(query, query_type)?;
17 match (kp, qt, query, query.is_empty()) {
18 (_, _, _, true) => {
19 Ok(vec![])
20 }
21 (Some(key_pattern), _, _, false) => {
22 Ok(Self::search_key_actual(&json, &key_pattern, None))
23 }
24 (None, Some(QueryType::JsonPath), query, false) => {
25 let (prefix, keyword) = if let Some((prefix, keyword)) = query.rsplit_once(".") {
26 (prefix, Some(keyword))
27 } else {
28 (query, None)
29 };
30 match (prefix, keyword, keyword.unwrap_or("").is_empty()){
31 (prefix, Some(keyword), false) => {
32 Ok(Self::search_key_actual(&json, &KeyPattern::Prefix(keyword.to_lowercase()), Some(prefix)))
33 }
34 (prefix,_,_) => {
35 Ok(json.query(prefix)?.iter().flat_map(|it| match it {
36 Value::Object(map) => map.keys().map(|k| k.to_string()).collect_vec(),
37 Value::Array(_) => vec!["*".to_string()],
38 _ => vec![],
39 }).unique().map(|it| Jsonpath(it)).collect_vec())
40 }
41 }
42 }
43 _ => {
44 unreachable!()
45 }
46 }
47 }
48
49 pub fn query(&self, query: Option<&str>, query_type: Option<QueryType>, beauty: bool) -> crate::Result<String> {
50 let json = Arc::<Value>::try_from(self)?;
51 let query_vals = Self::query_actual(&json, query, query_type)?;
52 if beauty {
53 Ok(serde_json::to_string_pretty(&query_vals)?)
54 } else {
55 Ok(serde_json::to_string(&query_vals)?)
56 }
57 }
58
59 pub fn diff(
60 &self,
61 other: &Self,
62 query: Option<&str>,
63 query_type: Option<QueryType>,
64 diff_tool: Option<DiffTool>,
65 ) -> crate::Result<()> {
66 let tmp_dir = env::temp_dir()
67 .join("jsondiff")
68 .join(chrono::Local::now().format("%Y%m%d%H%M%S%f").to_string());
69 if tmp_dir.exists() {
70 fs::remove_dir_all(&tmp_dir)?;
71 }
72 let left = self;
73 let right = other;
74 let _ = fs::create_dir_all(&tmp_dir)?;
75 let left = left.diff_prepare(query.as_deref(), query_type)?;
76 let left_path = tmp_dir.join("left.json");
77 fs::write(&left_path, left)?;
78 println!("write left to file {}", left_path.display());
79 let right = right.diff_prepare(query.as_deref(), query_type)?;
80 let right_path = tmp_dir.join("right.json");
81 fs::write(&right_path, right)?;
82 println!("write right to file {}", right_path.display());
83 let diff_tool = diff_tool.unwrap_or_default();
84 if diff_tool.is_available() {
85 println!("diff with {}", diff_tool);
86 diff_tool.diff(&left_path, &right_path)?;
87 } else {
88 eprintln!("diff tool {} is not installed", diff_tool);
89 println!(
90 r#"
91install {} command-line interface, see:
92{}"#,
93 diff_tool,
94 diff_tool.how_to_install()
95 )
96 }
97 Ok(())
98 }
99}
100
101#[derive(Debug, Clone)]
102enum QueryVals {
103 Origin(Value),
104 JsonPath(Vec<Value>),
105 KeyPattern(BTreeMap<Jsonpath, Vec<Value>>),
106}
107
108impl serde::Serialize for QueryVals {
109 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
110 where
111 S: Serializer,
112 {
113 match self {
114 QueryVals::Origin(vals) => {
115 vals.serialize(serializer)
116 }
117 QueryVals::JsonPath(vals) => {
118 match serde_json::to_value(vals) {
119 Ok(v) => v.serialize(serializer),
120 Err(err) => Err(S::Error::custom(format!("{}", err)))
121 }
122 }
123 QueryVals::KeyPattern(vals) => {
124 match serde_json::to_value(vals) {
125 Ok(v) => v.serialize(serializer),
126 Err(err) => Err(S::Error::custom(format!("{}", err)))
127 }
128 }
129 }
130 }
131}
132
133#[derive(Debug, Clone)]
134enum KeyPattern {
135 Prefix(String),
136 Suffix(String),
137 Contains(String),
138 Regex(regex::Regex),
139}
140
141impl From<&KeyPattern> for KeyPatternType {
142 fn from(value: &KeyPattern) -> Self {
143 match value {
144 KeyPattern::Prefix(_) => KeyPatternType::Prefix,
145 KeyPattern::Suffix(_) => KeyPatternType::Suffix,
146 KeyPattern::Contains(_) => KeyPatternType::Contains,
147 KeyPattern::Regex(_) => KeyPatternType::Regex,
148 }
149 }
150}
151
152impl KeyPattern {
153 fn new(key_pattern: &str, pattern_type: KeyPatternType) -> crate::Result<Self> {
154 match pattern_type {
155 KeyPatternType::Prefix => Ok(Self::Prefix(key_pattern.to_lowercase())),
156 KeyPatternType::Suffix => Ok(Self::Suffix(key_pattern.to_lowercase())),
157 KeyPatternType::Contains => Ok(Self::Contains(key_pattern.to_lowercase())),
158 KeyPatternType::Regex => Ok(Self::Regex(
159 regex::RegexBuilder::new(key_pattern).case_insensitive(true).build()?
160 )),
161 }
162 }
163
164 fn guess(key_pattern: &str) -> crate::Result<Self> {
165 match regex::RegexBuilder::new(key_pattern).case_insensitive(true).build() {
166 Ok(regex) => {
167 Ok(Self::Regex(regex))
168 }
169 Err(_) => {
170 Self::new(key_pattern, KeyPatternType::default())
171 }
172 }
173 }
174
175 fn match_key(&self, key: &str) -> bool {
176 match self {
177 KeyPattern::Prefix(prefix) => {
178 let key = key.to_lowercase();
179 key.starts_with(prefix)
180 }
181 KeyPattern::Suffix(suffix) => {
182 let key = key.to_lowercase();
183 key.ends_with(suffix)
184 }
185 KeyPattern::Contains(contains) => {
186 let key = key.to_lowercase();
187 key.contains(contains)
188 }
189 KeyPattern::Regex(regex) => {
190 regex.is_match(key)
191 }
192 }
193 }
194}
195
196impl Json {
197 fn parse_query_type(
198 query: &str,
199 query_type: Option<QueryType>,
200 ) -> crate::Result<(Option<KeyPattern>, Option<QueryType>)> {
201 match (query_type, query.is_empty(), query.starts_with("$")) {
202 (Some(QueryType::JsonPath), _, _) | (None, false, true) => {
203 Ok((None, Some(QueryType::JsonPath)))
204 }
205 (Some(qt @ QueryType::KeyPattern(kpt)), _, _) => {
206 Ok((Some(KeyPattern::new(query, kpt)?), Some(qt)))
207 }
208 (None, true, _) => {
209 Ok((None, None))
210 }
211 (None, false, false) => {
212 let kp = KeyPattern::guess(query).ok();
213 let qt = kp.as_ref().map(|it|
214 KeyPatternType::from(it)
215 ).map(|kpt|
216 QueryType::KeyPattern(kpt)
217 );
218 Ok((kp, qt))
219 }
220 }
221 }
222
223 fn query_actual(
224 json: &Value,
225 query: Option<&str>,
226 query_type: Option<QueryType>,
227 ) -> crate::Result<QueryVals> {
228 let query = query.map(|it| it.trim()).filter(|it| it.len() > 0).unwrap_or("");
229 let (kp, qt) = Self::parse_query_type(query, query_type)?;
230 match (kp, qt, query, query.is_empty()) {
231 (_, _, _, true) => {
232 Ok(QueryVals::Origin(json.to_owned()))
233 }
234 (Some(key_pattern), _, _, false) => {
235 let json_paths = Self::search_key_actual(&json, &key_pattern, None);
236 let mut map = BTreeMap::new();
237 for path in json_paths.into_iter() {
238 let arr = json.query(&path).into_iter().flatten().map(|it| it.to_owned()).collect_vec();
239 let _ = map.insert(path, arr);
240 }
241 Ok(QueryVals::KeyPattern(map))
242 }
243 (None, Some(QueryType::JsonPath), query, false) => {
244 let query = query.trim_end_matches(".");
245 let arr = json.query(&query).into_iter().flatten().map(|it| it.to_owned()).collect_vec();
246 Ok(QueryVals::JsonPath(arr))
247 }
248 _ => {
249 unreachable!()
250 }
251 }
252 }
253
254 fn diff_prepare(&self, query: Option<&str>, query_type: Option<QueryType>) -> crate::Result<String> {
255 let json = Arc::<Value>::try_from(self)?;
256 let array = Self::query_actual(&json, query, query_type)?;
257 let pretty = serde_json::to_string_pretty(&array)?;
258 Ok(pretty)
259 }
260
261 fn search_key_actual(json: &Value, key_pattern: &KeyPattern, prefix: Option<&str>) -> Vec<Jsonpath> {
262 let jsons = match &prefix {
263 Some(prefix) => {
264 match json.query(prefix) {
265 Ok(arr) => arr,
266 Err(_) => vec![json],
267 }
268 }
269 None => vec![json],
270 };
271 Self::search_key_recursive(&jsons, &key_pattern, prefix.unwrap_or("$")).into_iter()
272 .unique().map(|it| Jsonpath(it)).collect_vec()
273 }
274}
275
276#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize)]
277#[serde(transparent)]
278pub struct Jsonpath(String);
279impl Deref for Jsonpath {
280 type Target = str;
281 fn deref(&self) -> &Self::Target {
282 &self.0
283 }
284}
285
286impl From<Jsonpath> for String {
287 fn from(it: Jsonpath) -> Self {
288 it.0
289 }
290}
291
292impl Json {
293 fn search_key_recursive(jsons: &[&Value], key_pattern: &KeyPattern, path: &str) -> Vec<String> {
294 jsons.iter().flat_map(|&json| {
295 match json {
296 Value::Object(map) => {
297 let mut vec = Vec::with_capacity(map.len());
298 for (k, v) in map {
299 let path = format!("{}.{}", path, k);
300 let mut children = Self::search_key_recursive(&vec![v], key_pattern, &path);
301 if key_pattern.match_key(k) {
302 vec.push(path);
303 }
304 let _ = vec.append(&mut children);
305 }
306 vec
307 }
308 Value::Array(array) => {
309 let mut vec = Vec::with_capacity(array.len());
310 let path = format!("{}.*", path);
311 let jsons = array.iter().map(|it| it).collect_vec();
312 let mut children = Self::search_key_recursive(&jsons, key_pattern, &path);
313 if children.len() > 0 {
314 let _ = vec.append(&mut children);
315 }
316 vec
317 }
318 _ => {
319 vec![]
320 }
321 }
322 }).collect_vec()
323 }
324}