Split jsonpath index selector (unique/multiple index)

- specify one index to return one element
- specify two or more index to return a collection of elements
This commit is contained in:
Fabrice Reix 2023-05-05 17:40:31 +02:00 committed by jcamiel
parent a97b172e58
commit 479e9e97cd
No known key found for this signature in database
GPG Key ID: 07FF11CFD55356CC
3 changed files with 33 additions and 34 deletions

View File

@ -28,7 +28,8 @@ pub struct Query {
pub enum Selector {
Wildcard,
NameChild(String),
ArrayIndex(Vec<usize>), // one or more indexes (separated by comma)
ArrayIndex(usize), // one unique index
ArrayIndices(Vec<usize>), // two or more indexes (separated by comma)
ArraySlice(Slice),
ArrayWildcard,
Filter(Predicate),

View File

@ -61,6 +61,9 @@ impl Selector {
Selector::NameChild(field) => root
.get(field)
.map(|result| JsonpathResult::SingleEntry(result.clone())),
Selector::ArrayIndex(index) => root
.get(index)
.map(|result| JsonpathResult::SingleEntry(result.clone())),
// Selectors returning a collection ("indefinite")
Selector::Wildcard | Selector::ArrayWildcard => {
@ -163,22 +166,14 @@ impl Selector {
};
Some(JsonpathResult::Collection(elements))
}
// Selectors returning one or the other
Selector::ArrayIndex(indexes) => {
if indexes.len() == 1 {
let index = indexes[0];
root.get(index)
.map(|result| JsonpathResult::SingleEntry(result.clone()))
} else {
let mut values = vec![];
for index in indexes {
if let Some(value) = root.get(index) {
values.push(value.clone())
}
Selector::ArrayIndices(indexes) => {
let mut values = vec![];
for index in indexes {
if let Some(value) = root.get(index) {
values.push(value.clone())
}
Some(JsonpathResult::Collection(values))
}
Some(JsonpathResult::Collection(values))
}
}
}
@ -322,7 +317,7 @@ mod tests {
selectors: vec![
Selector::NameChild("store".to_string()),
Selector::NameChild("book".to_string()),
Selector::ArrayIndex(vec![0]),
Selector::ArrayIndex(0),
Selector::NameChild("title".to_string()),
],
};
@ -401,11 +396,11 @@ mod tests {
#[test]
pub fn test_selector_array_index() {
assert_eq!(
Selector::ArrayIndex(vec![0]).eval(&json_books()).unwrap(),
Selector::ArrayIndex(0).eval(&json_books()).unwrap(),
JsonpathResult::SingleEntry(json_first_book())
);
assert_eq!(
Selector::ArrayIndex(vec![1, 2])
Selector::ArrayIndices(vec![1, 2])
.eval(&json_books())
.unwrap(),
JsonpathResult::Collection(vec![json_second_book(), json_third_book()])
@ -458,9 +453,13 @@ mod tests {
pub fn test_array_index() {
let value = json!(["first", "second", "third", "forth", "fifth"]);
assert_eq!(
Selector::ArrayIndex(vec![2]).eval(&value).unwrap(),
Selector::ArrayIndex(2).eval(&value).unwrap(),
JsonpathResult::SingleEntry(json!("third"))
);
assert_eq!(
Selector::ArrayIndices(vec![2, 3]).eval(&value).unwrap(),
JsonpathResult::Collection(vec![json!("third"), json!("forth")])
);
}
#[test]

View File

@ -50,7 +50,7 @@ fn selector(reader: &mut Reader) -> ParseResult<Selector> {
selector_wildcard,
selector_recursive_wildcard,
selector_recursive_key,
selector_array_index,
selector_array_index_or_array_indices,
selector_array_wildcard,
selector_array_slice,
selector_object_key_bracket,
@ -60,7 +60,7 @@ fn selector(reader: &mut Reader) -> ParseResult<Selector> {
)
}
fn selector_array_index(reader: &mut Reader) -> Result<Selector, Error> {
fn selector_array_index_or_array_indices(reader: &mut Reader) -> Result<Selector, Error> {
try_left_bracket(reader)?;
let mut indexes = vec![];
let i = match natural(reader) {
@ -94,7 +94,12 @@ fn selector_array_index(reader: &mut Reader) -> Result<Selector, Error> {
}
}
literal("]", reader)?;
Ok(Selector::ArrayIndex(indexes))
let selector = if indexes.len() == 1 {
Selector::ArrayIndex(*indexes.first().unwrap())
} else {
Selector::ArrayIndices(indexes)
};
Ok(selector)
}
fn selector_array_wildcard(reader: &mut Reader) -> Result<Selector, Error> {
@ -312,7 +317,7 @@ mod tests {
#[test]
pub fn test_query() {
let expected_query = Query {
selectors: vec![Selector::ArrayIndex(vec![2])],
selectors: vec![Selector::ArrayIndex(2)],
};
assert_eq!(query(&mut Reader::new("$[2]")).unwrap(), expected_query);
@ -338,7 +343,7 @@ mod tests {
selectors: vec![
Selector::NameChild("store".to_string()),
Selector::NameChild("book".to_string()),
Selector::ArrayIndex(vec![0]),
Selector::ArrayIndex(0),
Selector::NameChild("title".to_string()),
],
};
@ -354,7 +359,7 @@ mod tests {
let expected_query = Query {
selectors: vec![
Selector::RecursiveKey("book".to_string()),
Selector::ArrayIndex(vec![2]),
Selector::ArrayIndex(2),
],
};
assert_eq!(
@ -423,26 +428,20 @@ mod tests {
#[test]
pub fn test_selector_array_index() {
let mut reader = Reader::new("[2]");
assert_eq!(
selector(&mut reader).unwrap(),
Selector::ArrayIndex(vec![2])
);
assert_eq!(selector(&mut reader).unwrap(), Selector::ArrayIndex(2));
assert_eq!(reader.state.cursor, 3);
let mut reader = Reader::new("[0,1]");
assert_eq!(
selector(&mut reader).unwrap(),
Selector::ArrayIndex(vec![0, 1])
Selector::ArrayIndices(vec![0, 1])
);
assert_eq!(reader.state.cursor, 5);
// you don't need to keep the exact string
// this is not part of the AST
let mut reader = Reader::new(".[2]");
assert_eq!(
selector(&mut reader).unwrap(),
Selector::ArrayIndex(vec![2])
);
assert_eq!(selector(&mut reader).unwrap(), Selector::ArrayIndex(2));
assert_eq!(reader.state.cursor, 4);
}