hl7_parser/query/
parser.rs

1use super::LocationQuery;
2use crate::parser::Span;
3use nom::{
4    bytes::complete::{tag, take_while1},
5    character::complete::one_of,
6    combinator::opt,
7    sequence::{delimited, preceded},
8    IResult,
9};
10use thiserror::Error;
11
12/// An error that can occur when parsing a query
13#[derive(Debug, Error)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub enum QueryParseError {
16    /// The parsing failed for some reason
17    #[error("Query parsing failed at position {position}: `{fragment}`")]
18    FailedToParse { position: usize, fragment: String },
19
20    /// The input was incomplete
21    #[error("Query parsing failed because of incomplete input.{}", .0.map(|s| format!(" Need at least {s} more characters to continue.")).unwrap_or_default())]
22    IncompleteInput(Option<usize>),
23}
24
25impl<'s> From<nom::Err<nom::error::Error<Span<'s>>>> for QueryParseError {
26    fn from(e: nom::Err<nom::error::Error<Span<'s>>>) -> Self {
27        match e {
28            nom::Err::Incomplete(nom::Needed::Unknown) => QueryParseError::IncompleteInput(None),
29            nom::Err::Incomplete(nom::Needed::Size(size)) => {
30                QueryParseError::IncompleteInput(Some(size.get()))
31            }
32            nom::Err::Error(e) | nom::Err::Failure(e) => {
33                let position = e.input.offset;
34                QueryParseError::FailedToParse {
35                    position,
36                    fragment: e.input.input.chars().take(7).collect(),
37                }
38            }
39        }
40    }
41}
42
43fn nonzero_integer(s: Span) -> IResult<Span, usize> {
44    let (_s, val) = take_while1(|c: char| c.is_ascii_digit())(s)?;
45    let val = val.input.parse::<usize>().map_err(|_| todo!())?;
46    if val == 0 {
47        return Err(nom::Err::Error(nom::error::Error::new(
48            s,
49            nom::error::ErrorKind::Digit,
50        )));
51    }
52    Ok((_s, val))
53}
54
55fn nonzero_array_access(s: Span) -> IResult<Span, usize> {
56    delimited(tag("["), nonzero_integer, tag("]"))(s)
57}
58
59fn preceeded_nonzero_integer(s: Span) -> IResult<Span, usize> {
60    preceded(one_of(".- "), nonzero_integer)(s)
61}
62
63pub fn parse_query(i: Span) -> IResult<Span, LocationQuery> {
64    let (i, segment) = crate::parser::segment::parse_segment_name(i)?;
65    let (i, segment_index) = opt(nonzero_array_access)(i)?;
66    let (i, field) = opt(preceeded_nonzero_integer)(i)?;
67    let (i, repeat) = if field.is_some() {
68        opt(nonzero_array_access)(i)?
69    } else {
70        (i, None)
71    };
72    let (i, component) = if field.is_some() {
73        opt(preceeded_nonzero_integer)(i)?
74    } else {
75        (i, None)
76    };
77    let (i, subcomponent) = if component.is_some() {
78        opt(preceeded_nonzero_integer)(i)?
79    } else {
80        (i, None)
81    };
82
83    let segment = segment.input.to_string();
84    Ok((
85        i,
86        LocationQuery {
87            segment,
88            segment_index,
89            field,
90            repeat,
91            component,
92            subcomponent,
93        },
94    ))
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use pretty_assertions_sorted::assert_eq;
101
102    #[test]
103    fn can_parse_preceeded_nonzero_integer() {
104        let input = Span::new(".123");
105        let actual = preceeded_nonzero_integer(input).unwrap().1;
106        assert_eq!(actual, 123);
107
108        let input = Span::new(" 123");
109        let actual = preceeded_nonzero_integer(input).unwrap().1;
110        assert_eq!(actual, 123);
111
112        let input = Span::new("-123");
113        let actual = preceeded_nonzero_integer(input).unwrap().1;
114        assert_eq!(actual, 123);
115
116        let input = Span::new("123");
117        assert!(preceeded_nonzero_integer(input).is_err());
118
119        let input = Span::new(".abc");
120        assert!(preceeded_nonzero_integer(input).is_err());
121    }
122
123    #[test]
124    fn can_parse_array_access() {
125        let input = Span::new("[123]");
126        let actual = nonzero_array_access(input).unwrap().1;
127        assert_eq!(actual, 123);
128
129        let input = Span::new("[0]");
130        assert!(nonzero_array_access(input).is_err());
131
132        let input = Span::new("[-10]");
133        assert!(nonzero_array_access(input).is_err());
134
135        let input = Span::new("[abc]");
136        assert!(nonzero_array_access(input).is_err());
137    }
138
139    #[test]
140    fn can_parse_full_query() {
141        let input = Span::new("MSH[1].2[3].4.5");
142        let actual = parse_query(input).unwrap().1;
143        assert_eq!(actual.segment, "MSH");
144        assert_eq!(actual.segment_index, Some(1));
145        assert_eq!(actual.field, Some(2));
146        assert_eq!(actual.repeat, Some(3));
147        assert_eq!(actual.component, Some(4));
148        assert_eq!(actual.subcomponent, Some(5));
149    }
150
151    #[test]
152    fn can_parse_truncated_queries() {
153        let input = Span::new("MSH[1].2[3].4");
154        let actual = parse_query(input).unwrap().1;
155        assert_eq!(actual.segment, "MSH");
156        assert_eq!(actual.segment_index, Some(1));
157        assert_eq!(actual.field, Some(2));
158        assert_eq!(actual.repeat, Some(3));
159        assert_eq!(actual.component, Some(4));
160        assert_eq!(actual.subcomponent, None);
161
162        let input = Span::new("MSH[1].2[3]");
163        let actual = parse_query(input).unwrap().1;
164        assert_eq!(actual.segment, "MSH");
165        assert_eq!(actual.segment_index, Some(1));
166        assert_eq!(actual.field, Some(2));
167        assert_eq!(actual.repeat, Some(3));
168        assert_eq!(actual.component, None);
169        assert_eq!(actual.subcomponent, None);
170
171        let input = Span::new("MSH[1].2");
172        let actual = parse_query(input).unwrap().1;
173        assert_eq!(actual.segment, "MSH");
174        assert_eq!(actual.segment_index, Some(1));
175        assert_eq!(actual.field, Some(2));
176        assert_eq!(actual.repeat, None);
177        assert_eq!(actual.component, None);
178        assert_eq!(actual.subcomponent, None);
179
180        let input = Span::new("MSH[1]");
181        let actual = parse_query(input).unwrap().1;
182        assert_eq!(actual.segment, "MSH");
183        assert_eq!(actual.segment_index, Some(1));
184        assert_eq!(actual.field, None);
185        assert_eq!(actual.repeat, None);
186        assert_eq!(actual.component, None);
187        assert_eq!(actual.subcomponent, None);
188
189        let input = Span::new("MSH");
190        let actual = parse_query(input).unwrap().1;
191        assert_eq!(actual.segment, "MSH");
192        assert_eq!(actual.segment_index, None);
193        assert_eq!(actual.field, None);
194        assert_eq!(actual.repeat, None);
195        assert_eq!(actual.component, None);
196        assert_eq!(actual.subcomponent, None);
197
198        let input = Span::new("PID.3");
199        let actual = parse_query(input).unwrap().1;
200        assert_eq!(actual.segment, "PID");
201        assert_eq!(actual.segment_index, None);
202        assert_eq!(actual.field, Some(3));
203        assert_eq!(actual.repeat, None);
204        assert_eq!(actual.component, None);
205        assert_eq!(actual.subcomponent, None);
206    }
207}