sql_composer/parser/
compose.rs1use std::path::PathBuf;
4
5use winnow::combinator::trace;
6use winnow::error::ParserError;
7use winnow::stream::{AsBStr, AsChar, Compare, Stream, StreamIsPartial};
8use winnow::token::{literal, take_while};
9use winnow::Parser;
10
11use crate::types::ComposeRef;
12
13pub fn compose_path<'i, Input, Error>(input: &mut Input) -> Result<PathBuf, Error>
15where
16 Input: StreamIsPartial + Stream + Compare<&'i str>,
17 <Input as Stream>::Slice: AsBStr,
18 <Input as Stream>::Token: AsChar + Clone,
19 Error: ParserError<Input>,
20{
21 trace("compose_path", move |input: &mut Input| {
22 let path_str = take_while(1.., |c: <Input as Stream>::Token| {
23 let ch = c.as_char();
24 ch != ')' && ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r'
25 })
26 .parse_next(input)?;
27 let path_str = String::from_utf8_lossy(path_str.as_bstr()).to_string();
28 Ok(PathBuf::from(path_str))
29 })
30 .parse_next(input)
31}
32
33pub fn compose<'i, Input, Error>(input: &mut Input) -> Result<ComposeRef, Error>
38where
39 Input: StreamIsPartial + Stream + Compare<&'i str>,
40 <Input as Stream>::Slice: AsBStr,
41 <Input as Stream>::Token: AsChar + Clone,
42 Error: ParserError<Input>,
43{
44 trace("compose", move |input: &mut Input| {
45 let path = compose_path(input)?;
46 literal(")").parse_next(input)?;
47 Ok(ComposeRef { path })
48 })
49 .parse_next(input)
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use winnow::error::ContextError;
56
57 type TestInput<'a> = &'a str;
58
59 #[test]
60 fn test_compose_simple() {
61 let mut input: TestInput = "templates/get_user.tql)";
62 let result = compose::<_, ContextError>.parse_next(&mut input).unwrap();
63 assert_eq!(result.path, PathBuf::from("templates/get_user.tql"));
64 assert_eq!(input, "");
65 }
66
67 #[test]
68 fn test_compose_relative_path() {
69 let mut input: TestInput = "src/tests/simple-template.tql)";
70 let result = compose::<_, ContextError>.parse_next(&mut input).unwrap();
71 assert_eq!(result.path, PathBuf::from("src/tests/simple-template.tql"));
72 }
73
74 #[test]
75 fn test_compose_with_trailing() {
76 let mut input: TestInput = "get_user.tql) AND active";
77 let result = compose::<_, ContextError>.parse_next(&mut input).unwrap();
78 assert_eq!(result.path, PathBuf::from("get_user.tql"));
79 assert_eq!(input, " AND active");
80 }
81}