luna_orm_trait/
parser.rs

1use nom::branch::alt;
2use nom::bytes::complete::escaped;
3use nom::bytes::complete::{tag, take_till, take_until, take_while};
4use nom::character::complete::{
5    alpha0, alphanumeric0, alphanumeric1, char, multispace0, multispace1, one_of,
6};
7use nom::character::is_alphanumeric;
8use nom::combinator::{cut, iterator, map, opt, value};
9use nom::error::{context, ContextError, ParseError, VerboseError};
10use nom::multi::separated_list1;
11use nom::sequence::Tuple;
12use nom::sequence::{delimited, terminated};
13use nom::sequence::{preceded, tuple};
14use nom::Compare;
15use nom::InputLength;
16use nom::InputTake;
17
18use nom::IResult;
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum TemplateValue {
22    SingleQuoteString(String),
23    DoubleQuoteString(String),
24    BackQuoteString(String),
25    Star(String),
26    Segment(String),
27    Variable(String),
28}
29
30impl ToString for TemplateValue {
31    fn to_string(&self) -> String {
32        match self {
33            TemplateValue::SingleQuoteString(v)
34            | TemplateValue::DoubleQuoteString(v)
35            | TemplateValue::BackQuoteString(v)
36            | TemplateValue::Star(v)
37            | TemplateValue::Segment(v)
38            | TemplateValue::Variable(v) => v.to_string(),
39        }
40    }
41}
42
43pub struct ParsedTemplateSql {
44    pub sql: String,
45    pub variables: Vec<String>,
46}
47
48impl ParsedTemplateSql {
49    pub fn build(template_sql: &str) -> Result<Self, nom::Err<nom::error::Error<&str>>> {
50        let (_, parsed) = parse_template_sql(template_sql)?;
51        let parsed_template = ParsedTemplateSql::new(parsed);
52        Ok(parsed_template)
53    }
54
55    pub fn new(values: Vec<TemplateValue>) -> Self {
56        let has_question_mark: bool = values
57            .iter()
58            .any(|e| &TemplateValue::Segment("?".to_string()) == e);
59        if has_question_mark {
60            panic!("sql template should not contains ?");
61        }
62
63        let variables: Vec<String> = values
64            .iter()
65            .filter(|e| matches!(e, TemplateValue::Variable(_)))
66            .map(|e| e.to_string())
67            .collect();
68
69        let result: Vec<TemplateValue> = values
70            .into_iter()
71            .map(|e| {
72                let t: TemplateValue = if let TemplateValue::Variable(_) = e {
73                    TemplateValue::Segment("?".to_string())
74                } else {
75                    e
76                };
77                t
78            })
79            .collect();
80
81        let marked_sql = result
82            .iter()
83            .map(|e| e.to_string())
84            .collect::<Vec<String>>()
85            .join(" ");
86
87        Self {
88            sql: marked_sql,
89            variables,
90        }
91    }
92}
93
94pub fn parse_back_quote_string<'a, E: ParseError<&'a str>>(
95    input: &'a str,
96) -> IResult<&'a str, TemplateValue, E> {
97    let (remaining, parsed) = preceded(
98        preceded(multispace0, char('`')),
99        cut(terminated(take_until("`"), char('`'))),
100    )(input)?;
101    let value = TemplateValue::BackQuoteString(format!("`{}`", parsed));
102    return Ok((remaining, value));
103}
104
105pub fn parse_single_quote_string<'a, E: ParseError<&'a str>>(
106    input: &'a str,
107) -> IResult<&'a str, TemplateValue, E> {
108    let (remaining, parsed) = preceded(
109        preceded(multispace0, char('\'')),
110        cut(terminated(take_until("'"), char('\''))),
111    )(input)?;
112    let value = TemplateValue::SingleQuoteString(format!("'{}'", parsed));
113    return Ok((remaining, value));
114}
115
116pub fn parse_double_quote_string<'a, E: ParseError<&'a str>>(
117    input: &'a str,
118) -> IResult<&'a str, TemplateValue, E> {
119    let (remaining, parsed) = preceded(
120        preceded(multispace0, char('"')),
121        cut(terminated(take_until("\""), char('"'))),
122    )(input)?;
123    let value = TemplateValue::DoubleQuoteString(format!("\"{}\"", parsed));
124    return Ok((remaining, value));
125}
126
127fn parse_string<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
128    input: &'a str,
129) -> IResult<&'a str, TemplateValue, E> {
130    context(
131        "string",
132        alt((
133            parse_single_quote_string,
134            parse_double_quote_string,
135            parse_back_quote_string,
136        )),
137    )(input)
138}
139
140//pub fn parse_string(input: &str) -> IResult<&str, &str> {
141//    alt((parse_single_quote_string, parse_double_quote_string))(input)
142//}
143
144pub fn parse_dot<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, &'a str, E> {
145    delimited(multispace0, tag("."), multispace0)(input)
146}
147pub fn parse_variable_seg<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
148    input: &'a str,
149) -> IResult<&'a str, &'a str, E> {
150    context("variable_seg", preceded(multispace0, alphanumeric1))(input)
151}
152
153/*
154pub fn check_following_dot<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
155    input: &'a str,
156) -> IResult<&'a str, (), E> {
157    if input.starts_with(".") {
158        let error = VerboseError::from_char(input, '.');
159        return Err(nom::Err::Failure(error));
160    }
161    return Ok((input, ()));
162}
163*/
164
165pub fn parse_variable<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
166    input: &'a str,
167) -> IResult<&'a str, TemplateValue, E> {
168    //let (remaining, parsed) = parse_variable_seg(input)?;
169    //let first_seg: &str = parsed;
170
171    let segs_result = delimited(
172        preceded(multispace0, tag("#{")),
173        separated_list1(parse_dot, parse_variable_seg),
174        preceded(multispace0, tag("}")),
175    )(input)?;
176    let (remaining, parsed) = segs_result;
177    let following_segs: Vec<&str> = parsed;
178    let mut segs: Vec<&str> = Vec::new();
179    //segs.push(first_seg);
180    segs.extend(following_segs);
181    let variable = segs.join(".");
182    return Ok((remaining, TemplateValue::Variable(variable.to_string())));
183}
184
185pub fn parse_segment<'a, E: ParseError<&'a str>>(
186    input: &'a str,
187) -> IResult<&'a str, TemplateValue, E> {
188    let (remaining, parsed) = alt((
189        preceded(multispace0, alphanumeric1),
190        preceded(multispace0, tag("*")),
191        preceded(multispace0, tag(",")),
192        preceded(multispace0, tag(";")),
193        preceded(multispace0, tag("=")),
194        preceded(multispace0, tag("?")),
195        preceded(multispace0, tag("<")),
196        preceded(multispace0, tag(">")),
197        preceded(multispace0, tag("%")),
198        preceded(multispace0, tag("(")),
199        preceded(multispace0, tag(")")),
200    ))(input)?;
201    return Ok((remaining, TemplateValue::Segment(parsed.to_string())));
202}
203
204/*
205pub fn parse_variable(input: &str) -> IResult<&str, &str> {
206    delimited(
207        tuple((tag("#{"), multispace0)),
208        parse_dot_variable,
209        tuple((multispace0, tag("}"))),
210    )(input)
211}
212*/
213
214pub fn parese_template_value(input: &str) -> IResult<&str, TemplateValue> {
215    alt((parse_variable, parse_string, parse_segment))(input)
216}
217pub fn parse_template_sql(input: &str) -> IResult<&str, Vec<TemplateValue>> {
218    let mut values: Vec<TemplateValue> = Vec::new();
219    let (mut remaining, mut parsed) = parese_template_value(input)?;
220    values.push(parsed);
221    while !remaining.is_empty() {
222        (remaining, parsed) = parese_template_value(remaining)?;
223        values.push(parsed);
224    }
225    return Ok((remaining, values));
226}
227
228#[cfg(test)]
229mod test {
230
231    use nom::error::ErrorKind;
232
233    use super::TemplateValue;
234    use super::*;
235
236    #[test]
237    pub fn test_string() {
238        let (remaining, parsed) =
239            parse_string::<(&str, ErrorKind)>("'this is single string'").unwrap();
240        assert_eq!(
241            parsed,
242            TemplateValue::SingleQuoteString("'this is single string'".to_string())
243        );
244        let (remaining, parsed) =
245            parse_string::<(&str, ErrorKind)>("\"this is double string\"").unwrap();
246        assert_eq!(
247            parsed,
248            TemplateValue::DoubleQuoteString("\"this is double string\"".to_string())
249        );
250    }
251
252    #[test]
253    pub fn test_variable() {
254        let (remaining, parsed) = parse_variable::<(&str, ErrorKind)>("#{ var1 . var2 }").unwrap();
255        assert_eq!(parsed, TemplateValue::Variable("var1.var2".to_string()));
256    }
257
258    #[test]
259    pub fn test_template() {
260        let (remaining, parsed) =
261            parse_template_sql("SELECT * `test` user #{v1. v2. v3} where id = 23").unwrap();
262        let result_vec = vec![
263            TemplateValue::Segment("SELECT".to_string()),
264            TemplateValue::Segment("*".to_string()),
265            TemplateValue::BackQuoteString("`test`".to_string()),
266            TemplateValue::Segment("user".to_string()),
267            TemplateValue::Variable("v1.v2.v3".to_string()),
268            TemplateValue::Segment("where".to_string()),
269            TemplateValue::Segment("id".to_string()),
270            TemplateValue::Segment("=".to_string()),
271            TemplateValue::Segment("23".to_string()),
272        ];
273        assert_eq!(parsed, result_vec);
274
275        let parsed_sql = ParsedTemplateSql::new(parsed);
276
277        assert_eq!(parsed_sql.sql, "SELECT * `test` user ? where id = 23");
278        let variables = vec!["v1.v2.v3".to_string()];
279        assert_eq!(parsed_sql.variables, variables);
280    }
281}