use serde_json::{Value as Json, json};
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Outcome {
pub ok: bool,
pub lines: Vec<String>,
pub columns: Vec<String>,
pub rows: Vec<Vec<String>>,
pub data: Option<Json>,
}
impl Outcome {
pub fn new(ok: bool) -> Self {
Outcome {
ok,
..Default::default()
}
}
pub fn lines(ok: bool, lines: Vec<String>) -> Self {
Outcome {
ok,
lines,
..Default::default()
}
}
pub fn failed(lines: Vec<String>) -> Self {
Outcome {
ok: false,
lines,
..Default::default()
}
}
pub fn with_first(mut self, line: String) -> Self {
self.lines.insert(0, line);
self
}
pub fn with_data(mut self, data: Json) -> Self {
self.data = Some(data);
self
}
pub fn to_json(&self) -> Json {
let mut envelope = serde_json::Map::new();
envelope.insert("ok".to_string(), json!(self.ok));
envelope.insert("lines".to_string(), json!(self.lines));
envelope.insert("columns".to_string(), json!(self.columns));
envelope.insert("rows".to_string(), json!(self.rows));
if let Some(data) = &self.data {
envelope.insert("data".to_string(), data.clone());
}
Json::Object(envelope)
}
pub fn to_output_json(&self) -> Json {
match &self.data {
Some(data) => data.clone(),
None => self.to_json(),
}
}
pub fn from_json(value: &Json) -> Self {
Outcome {
ok: value.get("ok").and_then(Json::as_bool).unwrap_or(false),
lines: strings(value.get("lines")),
columns: strings(value.get("columns")),
rows: value
.get("rows")
.and_then(Json::as_array)
.map(|rows| rows.iter().map(|row| strings(Some(row))).collect())
.unwrap_or_default(),
data: value.get("data").cloned(),
}
}
pub fn from_stdout(stdout: &str) -> serde_json::Result<Outcome> {
Ok(Outcome::from_json(&serde_json::from_str(stdout)?))
}
}
fn strings(value: Option<&Json>) -> Vec<String> {
value
.and_then(Json::as_array)
.map(|items| {
items
.iter()
.map(|item| match item {
Json::String(text) => text.clone(),
other => other.to_string(),
})
.collect()
})
.unwrap_or_default()
}