aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGuillaume Pasquet <dev@etenil.net>2022-03-03 23:18:08 +0000
committerGuillaume Pasquet <dev@etenil.net>2022-03-03 23:18:08 +0000
commit57af17cfa6e08a6fe9bf6d73d401af17dccfa3bb (patch)
treecd550ccf0eb78f360e6813ffdfd3c89d817eb21f /src
parentf797f10c2eda28a221759fc26ddf483f41232604 (diff)
Introduce JSONPath and potentially break old stuff.
Diffstat (limited to 'src')
-rw-r--r--src/barbfile.rs76
-rw-r--r--src/executor.rs8
-rw-r--r--src/main.rs3
3 files changed, 70 insertions, 17 deletions
diff --git a/src/barbfile.rs b/src/barbfile.rs
index 91ffd0a..f3cb58f 100644
--- a/src/barbfile.rs
+++ b/src/barbfile.rs
@@ -2,6 +2,11 @@ use regex::Regex;
use std::str::FromStr;
use std::string::ToString;
use std::{error::Error, fmt};
+
+use jsonpath_rust::JsonPathQuery;
+use serde_json::{json, Value};
+
+#[cfg(feature = "jq")]
use jq_rs;
#[derive(Debug)]
@@ -86,16 +91,22 @@ impl Header {
}
}
+enum FilterType {
+ JQ,
+ PATH,
+}
+
pub struct BarbFilter {
name: Option<String>,
filter: String,
+ filter_type: FilterType,
}
impl FromStr for BarbFilter {
type Err = BarbParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
- let re = Regex::new("^#(?P<name>[A-Za-z0-9_]*)\\|(?P<filter>.+)$").unwrap();
+ let re = Regex::new("^#(?P<name>[A-Za-z0-9_]*)(?P<type>[|$])(?P<filter>.+)$").unwrap();
let groups = re.captures(s).ok_or(BarbParseError {})?;
Ok(BarbFilter::new(
@@ -104,20 +115,36 @@ impl FromStr for BarbFilter {
any => Some(String::from(any)),
},
String::from(&groups["filter"]),
+ match &groups["type"] {
+ "|" => FilterType::JQ,
+ _ => FilterType::PATH,
+ },
))
}
}
impl PreambleLine for BarbFilter {
fn is_match(s: String) -> bool {
- let re = Regex::new("^#(?P<name>[A-Za-z0-9_]*)\\|(?P<filter>.+)$").unwrap();
+ let re = Regex::new("^#(?P<name>[A-Za-z0-9_]*)[|$](?P<filter>.+)$").unwrap();
re.is_match(s.as_str())
}
}
impl BarbFilter {
- pub fn new(name: Option<String>, filter: String) -> BarbFilter {
- BarbFilter { name, filter }
+ fn new(name: Option<String>, filter: String, filter_type: FilterType) -> BarbFilter {
+ BarbFilter {
+ name,
+ filter,
+ filter_type,
+ }
+ }
+
+ pub fn from_path(filter: String) -> BarbFilter {
+ BarbFilter {
+ name: None,
+ filter_type: FilterType::PATH,
+ filter,
+ }
}
pub fn name(&self) -> &Option<String> {
@@ -128,11 +155,38 @@ impl BarbFilter {
&self.filter
}
- pub fn apply(&self, body: &String) -> Result<String, String> {
+ #[cfg(feature = "jq")]
+ fn apply_jq(&self, body: &String) -> Result<String, String> {
jq_rs::run(self.filter.as_str(), body.as_str())
.map_err(|x| x.to_string())
.map(|x| String::from(x.trim().trim_matches('"')))
}
+
+ fn apply_path(&self, body: &String) -> Result<String, String> {
+ let json: Value = serde_json::from_str(body.as_str())
+ .map_err(|_| String::from("Failed to decode body"))?;
+ let path = &json.path(self.filter.as_str())?;
+ Ok(match path {
+ Value::Array(val) => match val.len() {
+ 1 => val.first().unwrap(),
+ _ => path,
+ },
+ _ => path,
+ }
+ .to_string()
+ .trim()
+ .trim_matches('"')
+ .to_string())
+ }
+
+ pub fn apply(&self, body: &String) -> Result<String, String> {
+ match self.filter_type {
+ #[cfg(feature = "jq")]
+ FilterType::JQ => self.apply_jq(body),
+ FilterType::PATH => self.apply_path(body),
+ _ => Ok(body.to_string()),
+ }
+ }
}
struct BarbPreamble {
@@ -225,7 +279,7 @@ impl FromStr for BarbFile {
if BarbFilter::is_match(String::from(line)) {
match BarbFilter::from_str(line) {
Ok(filter) => filters.push(filter),
- Err(_) => ()
+ Err(_) => (),
};
}
}
@@ -277,7 +331,10 @@ mod tests {
.unwrap();
assert!(matches!(barbfile.preamble.method, Method::GET));
assert_eq!(barbfile.preamble.url, "https://blah.com/api/blah");
- assert_eq!(barbfile.preamble.filters[0].filter(), &String::from("filtr"));
+ assert_eq!(
+ barbfile.preamble.filters[0].filter(),
+ &String::from("filtr")
+ );
assert_eq!(barbfile.preamble.headers.len(), 1);
assert_eq!(barbfile.preamble.headers[0].name, "Authorization");
assert_eq!(barbfile.preamble.headers[0].value, "BLAH");
@@ -291,7 +348,10 @@ mod tests {
.unwrap();
assert!(matches!(barbfile.preamble.method, Method::POST));
assert_eq!(barbfile.preamble.url, "https://blah.com/api/blah");
- assert_eq!(barbfile.preamble.filters[0].filter(), &String::from("filtr"));
+ assert_eq!(
+ barbfile.preamble.filters[0].filter(),
+ &String::from("filtr")
+ );
assert_eq!(barbfile.preamble.headers.len(), 1);
assert_eq!(barbfile.preamble.headers[0].name, "Authorization");
assert_eq!(barbfile.preamble.headers[0].value, "BLAH");
diff --git a/src/executor.rs b/src/executor.rs
index 15704c2..eccab39 100644
--- a/src/executor.rs
+++ b/src/executor.rs
@@ -89,7 +89,7 @@ impl Executor {
arg_filter: &Option<String>,
) -> Result<String, String> {
if let Some(filter) = arg_filter {
- return Ok(BarbFilter::new(None, filter.to_string()).apply(&body)?);
+ return Ok(BarbFilter::from_path(filter.to_string()).apply(&body)?);
} else if bfile.filters().len() > 0 {
let mut end_body: String = body.clone();
for filter in bfile.filters().iter() {
@@ -144,11 +144,7 @@ impl Executor {
}
output.end_resp_hdr();
- output.body(self.apply_filters(
- &bfile,
- response.into_string().unwrap(),
- filter,
- )?);
+ output.body(self.apply_filters(&bfile, response.into_string().unwrap(), filter)?);
Ok(())
}
diff --git a/src/main.rs b/src/main.rs
index 2973b27..1738391 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -27,8 +27,6 @@ struct Args {
#[clap(short, long)]
filter: Option<String>,
#[clap(short, long)]
- path: Option<String>,
- #[clap(short, long)]
no_color: bool,
files: Vec<String>,
}
@@ -62,7 +60,6 @@ fn main() {
for file in args.files_iter() {
match executor.execute(file, &output, args.jq_filter()) {
- //match run_file(&args, &mut executor, file) {
Ok(()) => (),
Err(err) => println!("{}", err),
}