tv_cli/
data.rs

1use std::collections::HashMap;
2
3use crate::{
4    table::{cell::Cell, Table},
5    utils::multi_lines,
6};
7use anyhow::{Context, Result};
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Deserialize, Serialize, Clone)]
11#[serde(untagged)]
12enum Json {
13    Object(serde_json::Map<String, serde_json::Value>),
14    Value(serde_json::Value),
15}
16
17#[derive(Debug, Clone)]
18pub struct Data {
19    data: Vec<Json>,
20    sort_key: Option<String>,
21}
22
23impl Data {
24    fn new(data: Vec<Json>) -> Self {
25        Self {
26            data,
27            sort_key: None,
28        }
29    }
30
31    pub fn from(s: &str) -> Result<Self> {
32        serde_json::from_str::<Vec<Json>>(s)
33            .map(Self::new)
34            .context("unsupported format")
35    }
36
37    pub fn set_sort_key(&mut self, s: Option<String>) -> &mut Self {
38        self.sort_key = s;
39        self
40    }
41
42    fn keys(&self) -> Vec<String> {
43        self.data
44            .get(0)
45            .map(|x| match x {
46                Json::Object(obj) => obj.keys().map(|x| x.clone()).collect(),
47                _ => vec![],
48            })
49            .unwrap_or_default()
50    }
51
52    fn sorted_data(&self) -> Vec<Json> {
53        let sort_keys = self
54            .sort_key
55            .clone()
56            .map(|x| x.split(".").map(String::from).collect::<Vec<_>>());
57
58        if let Some(keys) = sort_keys {
59            let mut data = self.data.clone();
60            data.sort_by_cached_key(|x| {
61                let val = keys.iter().fold(x.clone(), |val, key| match val {
62                    Json::Object(obj) => obj
63                        .get(key)
64                        .map(|v| match v {
65                            serde_json::Value::Object(o) => Json::Object(o.clone()),
66                            _ => Json::Value(v.clone()),
67                        })
68                        .unwrap_or(Json::Value(serde_json::Value::default())),
69                    _ => val,
70                });
71
72                match val {
73                    Json::Object(_) => String::new(),
74                    // NOTE: Numbers are sorted by strings, so fill them with 0s.
75                    Json::Value(serde_json::Value::Number(n)) => format!("{: >099}", n),
76                    Json::Value(v) => v.to_string(),
77                }
78            });
79            data
80        } else {
81            self.data.clone()
82        }
83    }
84
85    fn value_strings(&self) -> Vec<Vec<String>> {
86        self.sorted_data()
87            .iter()
88            .map(|x| match x {
89                Json::Object(obj) => self
90                    .keys()
91                    .iter()
92                    .map(|k| obj.get(k.as_str()).map(|x| x.clone()))
93                    .collect::<Vec<_>>(),
94                Json::Value(serde_json::Value::Array(arr)) => {
95                    arr.clone().iter().map(|x| Some(x.clone())).collect()
96                }
97                Json::Value(val) => vec![Some(val.clone())],
98            })
99            .map(|x| {
100                x.iter()
101                    .map(|x| match x {
102                        Some(serde_json::Value::String(s)) => String::from(s),
103                        Some(serde_json::Value::Bool(b)) => b.to_string(),
104                        Some(serde_json::Value::Number(n)) => n.to_string(),
105                        Some(serde_json::Value::Null) => String::from("null"),
106                        None => String::from("undefined"),
107                        _ => String::from("..."),
108                    })
109                    .collect::<Vec<_>>()
110            })
111            .collect::<Vec<_>>()
112    }
113
114    pub fn nested_fields(&self) -> Vec<(String, Self)> {
115        let nested_fields = {
116            let data = self.sorted_data();
117            let filtered_data = data.iter().filter_map(|x| match x {
118                Json::Object(obj) => Some(obj),
119                _ => None,
120            });
121            let nested_fields = filtered_data.map(|x| {
122                x.keys()
123                    .zip(x.values())
124                    .filter(|(_, x)| match x {
125                        serde_json::Value::Object(_) | serde_json::Value::Array(_) => true,
126                        _ => false,
127                    })
128                    .collect::<Vec<_>>()
129            });
130            let mut map: HashMap<String, Vec<serde_json::Value>> = HashMap::new();
131            nested_fields.for_each(|xs| {
132                xs.into_iter().for_each(|(k, v)| {
133                    let mut vec = if let Some(vec) = map.get(k) {
134                        vec.clone()
135                    } else {
136                        Vec::new()
137                    };
138
139                    vec.push(v.clone());
140                    map.insert(k.clone(), vec);
141                });
142            });
143            map
144        };
145
146        nested_fields
147            .iter()
148            .map(|(k, v)| {
149                (
150                    k.clone(),
151                    Self::new(
152                        v.iter()
153                            .map(|x| match x {
154                                serde_json::Value::Object(o) => Json::Object(o.clone()),
155                                _ => Json::Value(x.clone()),
156                            })
157                            .collect(),
158                    ),
159                )
160            })
161            .collect()
162    }
163
164    pub fn pick(&self, key: String) -> Result<Self> {
165        let keys = key.split(".").collect::<Vec<_>>();
166        let data = self
167            .data
168            .iter()
169            .filter_map(|x| match x {
170                Json::Object(obj) => {
171                    let (&head, tail) = keys.split_first()?;
172                    let init = obj.get(head)?;
173                    tail.iter().try_fold(init, |acc, &x| match acc {
174                        serde_json::Value::Object(obj) => obj.get(x),
175                        _ => None,
176                    })
177                }
178                _ => None,
179            })
180            .map(|x| match x {
181                serde_json::Value::Object(obj) => Json::Object(obj.clone()),
182                _ => Json::Value(x.clone()),
183            })
184            .collect::<Vec<_>>();
185
186        if data.is_empty() {
187            return Err(anyhow::Error::msg(format!("{} is not found", key)));
188        }
189
190        Ok(Self::new(data))
191    }
192}
193
194impl Into<Table<String>> for Data {
195    fn into(self) -> Table<String> {
196        let mut table = Table::new();
197        let keys = self.keys();
198        let values = multi_lines(self.value_strings());
199
200        if !keys.is_empty() {
201            let title = keys.into_iter().map(|x| Cell::new(x)).collect::<Vec<_>>();
202            table.set_header(Some(title));
203        }
204        values
205            .into_iter()
206            .map(|xs| xs.into_iter().map(Cell::new).collect::<Vec<_>>())
207            .for_each(|row| table.push_row(row));
208
209        table
210    }
211}