Parse singular segment
This commit is contained in:
parent
fb3a67531a
commit
1df5d7e70a
|
|
@ -18,15 +18,42 @@
|
|||
|
||||
use hurl_core::reader::Reader;
|
||||
|
||||
use crate::jsonpath2::ast::query::AbsoluteQuery;
|
||||
use crate::jsonpath2::parser::{primitives::expect_str, segments, ParseResult};
|
||||
use crate::jsonpath2::ast::query::{AbsoluteQuery, Query, RelativeQuery};
|
||||
use crate::jsonpath2::parser::primitives::{expect_str, match_str};
|
||||
use crate::jsonpath2::parser::{segments, ParseError, ParseErrorKind, ParseResult};
|
||||
|
||||
pub fn parse(reader: &mut Reader) -> ParseResult<AbsoluteQuery> {
|
||||
expect_str("$", reader)?;
|
||||
let segments = segments::parse(reader)?;
|
||||
let segments = segments::parse(reader, false)?;
|
||||
Ok(AbsoluteQuery::new(segments))
|
||||
}
|
||||
|
||||
/// Parse a singular query.
|
||||
/// Regardless of the input value, the expression produces a nodelist containing at most one node
|
||||
#[allow(dead_code)]
|
||||
pub fn singular_query(reader: &mut Reader) -> ParseResult<Query> {
|
||||
if match_str("$", reader) {
|
||||
let segments = segments::parse(reader, true)?;
|
||||
Ok(Query::AbsoluteQuery(AbsoluteQuery::new(segments)))
|
||||
} else if match_str("@", reader) {
|
||||
let segments = segments::parse(reader, true)?;
|
||||
Ok(Query::RelativeQuery(RelativeQuery::new(segments)))
|
||||
} else {
|
||||
let pos = reader.cursor().pos;
|
||||
let kind = ParseErrorKind::Expecting("a singular query".to_string());
|
||||
Err(ParseError::new(pos, kind))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_relative_query(reader: &mut Reader) -> ParseResult<Option<RelativeQuery>> {
|
||||
if match_str("@", reader) {
|
||||
let segments = segments::parse(reader, false)?;
|
||||
Ok(Some(RelativeQuery::new(segments)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
|
@ -91,4 +118,16 @@ mod tests {
|
|||
);
|
||||
assert_eq!(reader.cursor().index, CharPos(6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_relative_query() {
|
||||
let mut reader = Reader::new("@['isbn']");
|
||||
assert_eq!(
|
||||
try_relative_query(&mut reader).unwrap().unwrap(),
|
||||
RelativeQuery::new(vec![Segment::Child(ChildSegment::new(vec![
|
||||
Selector::Name(NameSelector::new("isbn".to_string()))
|
||||
]))])
|
||||
);
|
||||
assert_eq!(reader.cursor().index, CharPos(9));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,14 +22,44 @@ use crate::jsonpath2::ast::selector::{NameSelector, Selector, WildcardSelector};
|
|||
use crate::jsonpath2::parser::{selectors, ParseError, ParseErrorKind};
|
||||
use hurl_core::reader::Reader;
|
||||
|
||||
pub fn parse(reader: &mut Reader) -> ParseResult<Vec<Segment>> {
|
||||
/// Parse segments
|
||||
/// Only parse singular segments by setting `only_singular` to true
|
||||
pub fn parse(reader: &mut Reader, only_singular: bool) -> ParseResult<Vec<Segment>> {
|
||||
let mut segments = vec![];
|
||||
let mut current_pos = reader.cursor().pos;
|
||||
|
||||
// Parsing singular segments
|
||||
// In the spec, it is defined as parsing only name and index segments
|
||||
// For reporting error, we will first parse any segment instead, and then check whether the segment is singular
|
||||
while let Some(segment) = try_segment(reader)? {
|
||||
if only_singular && !segment.is_singular() {
|
||||
return Err(ParseError::new(
|
||||
current_pos,
|
||||
ParseErrorKind::Expecting("singular segment".to_string()),
|
||||
));
|
||||
}
|
||||
segments.push(segment);
|
||||
current_pos = reader.cursor().pos;
|
||||
}
|
||||
Ok(segments)
|
||||
}
|
||||
|
||||
impl Segment {
|
||||
fn is_singular(&self) -> bool {
|
||||
if let Segment::Child(child_segment) = self {
|
||||
for selector in child_segment.selectors() {
|
||||
if !matches!(selector, Selector::Name(_)) && !matches!(selector, Selector::Index(_))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_segment(reader: &mut Reader) -> ParseResult<Option<Segment>> {
|
||||
if let Some(segment) = try_segment_shorthand(reader)? {
|
||||
return Ok(Some(segment));
|
||||
|
|
@ -52,7 +82,7 @@ fn try_segment(reader: &mut Reader) -> ParseResult<Option<Segment>> {
|
|||
Ok(Some(segment))
|
||||
}
|
||||
|
||||
// try to parse a shorthand notation
|
||||
/// try to parse a shorthand notation
|
||||
fn try_segment_shorthand(reader: &mut Reader) -> ParseResult<Option<Segment>> {
|
||||
if match_str(".*", reader) {
|
||||
Ok(Some(Segment::Child(ChildSegment::new(vec![
|
||||
|
|
@ -102,7 +132,7 @@ fn alpha(reader: &mut Reader) -> ParseResult<char> {
|
|||
mod tests {
|
||||
|
||||
use crate::jsonpath2::ast::selector::{NameSelector, Selector, WildcardSelector};
|
||||
use hurl_core::reader::{CharPos, Reader};
|
||||
use hurl_core::reader::{CharPos, Pos, Reader};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -111,7 +141,7 @@ mod tests {
|
|||
let mut reader = Reader::new("['isbn']]");
|
||||
|
||||
assert_eq!(
|
||||
parse(&mut reader).unwrap(),
|
||||
parse(&mut reader, false).unwrap(),
|
||||
vec![Segment::Child(ChildSegment::new(vec![Selector::Name(
|
||||
NameSelector::new("isbn".to_string())
|
||||
)]))]
|
||||
|
|
@ -178,4 +208,32 @@ mod tests {
|
|||
);
|
||||
assert_eq!(reader.cursor().index, CharPos(3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_singular_segments() {
|
||||
let mut reader = Reader::new(".*");
|
||||
|
||||
assert_eq!(
|
||||
parse(&mut reader, true).unwrap_err(),
|
||||
ParseError::new(
|
||||
Pos::new(1, 1),
|
||||
ParseErrorKind::Expecting("singular segment".to_string())
|
||||
)
|
||||
);
|
||||
assert_eq!(reader.cursor().index, CharPos(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_is_singular() {
|
||||
assert!(
|
||||
Segment::Child(ChildSegment::new(vec![Selector::Name(NameSelector::new(
|
||||
"name".to_string()
|
||||
))]))
|
||||
.is_singular()
|
||||
);
|
||||
assert!(!Segment::Child(ChildSegment::new(vec![Selector::Wildcard(
|
||||
WildcardSelector
|
||||
)]))
|
||||
.is_singular());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,13 +18,12 @@
|
|||
|
||||
use super::{ParseError, ParseErrorKind};
|
||||
use crate::jsonpath2::ast::expr::LogicalExpr;
|
||||
use crate::jsonpath2::ast::query::RelativeQuery;
|
||||
use crate::jsonpath2::ast::selector::{
|
||||
ArraySliceSelector, FilterSelector, IndexSelector, NameSelector, Selector, WildcardSelector,
|
||||
};
|
||||
use crate::jsonpath2::parser::literal::{try_integer, try_string_literal};
|
||||
use crate::jsonpath2::parser::primitives::{expect_str, match_str};
|
||||
use crate::jsonpath2::parser::segments;
|
||||
use crate::jsonpath2::parser::query::try_relative_query;
|
||||
use hurl_core::reader::Reader;
|
||||
|
||||
use super::ParseResult;
|
||||
|
|
@ -106,7 +105,7 @@ fn try_array_slice_selector(reader: &mut Reader) -> ParseResult<Option<ArraySlic
|
|||
/// Try to parse a filter selector
|
||||
fn try_filter_selector(reader: &mut Reader) -> ParseResult<Option<FilterSelector>> {
|
||||
if match_str("?", reader) {
|
||||
let rel_query = try_rel_query(reader)?.unwrap();
|
||||
let rel_query = try_relative_query(reader)?.unwrap();
|
||||
let expr = LogicalExpr::new(rel_query);
|
||||
Ok(Some(FilterSelector::new(expr)))
|
||||
} else {
|
||||
|
|
@ -114,18 +113,12 @@ fn try_filter_selector(reader: &mut Reader) -> ParseResult<Option<FilterSelector
|
|||
}
|
||||
}
|
||||
|
||||
fn try_rel_query(reader: &mut Reader) -> ParseResult<Option<RelativeQuery>> {
|
||||
if match_str("@", reader) {
|
||||
let segments = segments::parse(reader)?;
|
||||
Ok(Some(RelativeQuery::new(segments)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::jsonpath2::ast::segment::{ChildSegment, Segment};
|
||||
use crate::jsonpath2::ast::{
|
||||
query::RelativeQuery,
|
||||
segment::{ChildSegment, Segment},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use hurl_core::reader::{CharPos, Reader};
|
||||
|
|
@ -242,16 +235,4 @@ mod tests {
|
|||
);
|
||||
assert_eq!(reader.cursor().index, CharPos(10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_rel_query() {
|
||||
let mut reader = Reader::new("@['isbn']");
|
||||
assert_eq!(
|
||||
try_rel_query(&mut reader).unwrap().unwrap(),
|
||||
RelativeQuery::new(vec![Segment::Child(ChildSegment::new(vec![
|
||||
Selector::Name(NameSelector::new("isbn".to_string()))
|
||||
]))])
|
||||
);
|
||||
assert_eq!(reader.cursor().index, CharPos(9));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue