Skip to content

Commit

Permalink
Add support for alias in formater
Browse files Browse the repository at this point in the history
  • Loading branch information
0x7fff5238100b committed Feb 19, 2023
1 parent 2c3815c commit 805ada9
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 4 deletions.
86 changes: 84 additions & 2 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ pub struct Path;
#[derive(Debug)]
pub struct PathResult(pub PathOutput);

#[derive(Debug, PartialEq)]
pub enum FormatOp {
FormatString {
format: String,
arguments: Vec<String>,
alias: String,
},
}

#[derive(Debug, PartialEq)]
pub enum PickFilterInner {
None,
Expand All @@ -28,6 +37,7 @@ pub enum Filter {
Child(String),
Descendant(String),
Pick(Vec<PickFilterInner>),
Format(FormatOp),
ArrayIndex(usize),
ArrayFrom(usize),
ArrayTo(usize),
Expand All @@ -53,7 +63,7 @@ trait KeyFormater {
struct FormatImpl<'a> {
format: &'a str,
value: &'a Value,
keys: &'a [&'a str],
keys: &'a Vec<String>,
}

impl<'a> FormatImpl<'a> {
Expand Down Expand Up @@ -265,6 +275,78 @@ impl<'a> Context<'a> {
self.stack.clone(),
)),

(Filter::Format(ref target_format), Some(tail)) => match *current.value {
Value::Object(ref obj) => {
let FormatOp::FormatString {
format: ref fmt,
arguments: ref args,
alias: ref alias,
} = target_format;

let output: Option<String> = FormatImpl {
format: fmt,
value: &current.value,
keys: args,
}
.format();

let mut result = obj.clone();
result.insert(alias.to_string(), Value::String(output.unwrap()));

let tlen = tail.len();
if tlen == 0 {
self.results
.borrow_mut()
.push(Rc::new(Value::Object(result)));
} else {
self.stack.borrow_mut().push(StackItem::new(
Rc::new(Value::Object(result)),
tail,
self.stack.clone(),
));
}
}
Value::Array(ref array) => {
for e in array.iter() {
let FormatOp::FormatString {
format: ref fmt,
arguments: ref args,
alias: ref alias,
} = target_format;

let output: Option<String> = FormatImpl {
format: fmt,
value: &current.value,
keys: args,
}
.format();

let mut result = e.clone();
match result.as_object_mut() {
Some(ref mut handle) => {
handle.insert(
alias.to_string(),
Value::String(output.unwrap()),
);
}
_ => {}
};

let tlen = tail.len();
if tlen == 0 {
self.results.borrow_mut().push(Rc::new(result));
} else {
self.stack.borrow_mut().push(StackItem::new(
Rc::new(result),
tail,
self.stack.clone(),
));
}
}
}
_ => {}
},

(Filter::ArrayIndex(ref index), Some(tail)) => match *current.value {
Value::Array(ref array) => {
if *index < array.len() {
Expand Down Expand Up @@ -649,7 +731,7 @@ mod test {
"alias": "jetro"
});

let keys = vec!["name", "alias"];
let keys = vec!["name".to_string(), "alias".to_string()];

let format_impl: Box<dyn KeyFormater> = Box::new(FormatImpl {
format: "{}_{}",
Expand Down
2 changes: 1 addition & 1 deletion src/grammar.pest
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pick = { "pick" ~ (" ")* ~ "(" ~ (literal_keyed | sub_expression_keyed ) ~ ((","
squash = { "squash" ~ "(" ~ ")" }
squashFn = { slash ~ squash }
pickFn = { slash ~ pick }
formats = { "formats" ~ whitespc ~ lparen ~ literal ~ ((",")* ~ whitespc ~ literal)+ ~ whitespc ~ rparen}
formats = { "formats" ~ whitespc ~ lparen ~ literal ~ ((",")* ~ whitespc ~ literal)+ ~ whitespc ~ rparen ~ whitespc ~ as}
formatsFn = { slash ~ formats }

sub_expression = { path ~ (pickFn | child | any_child | descendant_child | array_index | slice | array_to | array_from)* }
Expand Down
57 changes: 56 additions & 1 deletion src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use pest_derive::Parser as Parse;

use crate::context::{Filter, PickFilterInner};
use crate::context::{Filter, FormatOp, PickFilterInner};
use pest::Parser;

#[derive(Parse)]
Expand All @@ -14,6 +14,45 @@ pub fn parse<'a>(input: &'a str) -> Vec<Filter> {
for token in root.into_inner() {
match token.as_rule() {
Rule::path => actions.push(Filter::Root),
Rule::formatsFn => {
let mut arguments: Vec<String> = vec![];
let mut elem = token.into_inner().nth(1).unwrap().into_inner();
let head = elem.next().unwrap().as_str();
let format: String = {
if head.len() > 2 {
head[1..head.len() - 1].to_string()
} else {
"".to_string()
}
};
let mut alias: String = "unknown".to_string();
for e in elem {
match e.as_rule() {
Rule::literal => {
let name: String = {
let elem = e.as_str();
if elem.len() > 2 {
elem[1..elem.len() - 1].to_string()
} else {
"".to_string()
}
};
arguments.push(name);
}
_ => {
let e = e.as_str();
if e.len() > 2 {
alias = e[4..e.len() - 1].to_string();
}
}
}
}
actions.push(Filter::Format(FormatOp::FormatString {
format,
arguments,
alias,
}));
}
Rule::any_child => actions.push(Filter::AnyChild),
Rule::array_index => {
let elem = token.into_inner().nth(1).unwrap().as_span();
Expand Down Expand Up @@ -241,4 +280,20 @@ mod test {
let actions = parse(">/[1:4]");
assert_eq!(actions, vec![Filter::Root, Filter::Slice(1, 4),]);
}

#[test]
fn test_format() {
let actions = parse(">/formats('{}{}', 'name', 'alias') as 'some_key'");
assert_eq!(
actions,
vec![
Filter::Root,
Filter::Format(FormatOp::FormatString {
format: "{}{}".to_string(),
arguments: vec!["name".to_string(), "alias".to_string()],
alias: "some_key".to_string(),
})
]
);
}
}

0 comments on commit 805ada9

Please sign in to comment.