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
140pub 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
153pub fn parse_variable<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
166 input: &'a str,
167) -> IResult<&'a str, TemplateValue, E> {
168 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.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
204pub 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}