taitan_orm_parser/template_parser/structs/
placeholder.rs1use std::str::FromStr;
2use crate::template_parser::structs::variable::VariableChain;
3use crate::template_parser::to_sql::{SqlSegment, ToSqlSegment};
4use nom::branch::alt;
5use nom::bytes::complete::tag;
6use nom::character::complete::{digit1, multispace0};
7use nom::combinator::map;
8use nom::sequence::{delimited, preceded, tuple};
9use nom::IResult;
10
11#[derive(Debug, PartialEq, Eq, Clone)]
12pub enum RawPlaceholder {
13 QuestionMark,
14 Indexed(usize),
15 Named(String),
16}
17
18impl RawPlaceholder {
19 pub fn parse(input: &str) -> IResult<&str, RawPlaceholder> {
20 alt((
21 map(tag("?"), |_| RawPlaceholder::QuestionMark),
22 map(preceded(tag("$"), digit1), |d| {
23 RawPlaceholder::Indexed(usize::from_str(d).unwrap())
24 }),
25 map(
26 preceded(tag(":"), preceded(multispace0, VariableChain::parse)),
27 |v| RawPlaceholder::Named(v.to_string()),
28 ),
29 ))(input)
30 }
31}
32
33impl ToSqlSegment for RawPlaceholder {
34 fn gen_sql_segment(&self) -> SqlSegment {
35 match self {
36 RawPlaceholder::QuestionMark => SqlSegment::Simple("?".to_string()),
37 RawPlaceholder::Indexed(i) => SqlSegment::Simple(format!("${}", i)),
38 RawPlaceholder::Named(i) => SqlSegment::Simple(i.to_string()),
39 }
40 }
41}
42
43#[derive(Debug, PartialEq, Eq, Clone)]
44pub enum Placeholder {
45 Raw(RawPlaceholder),
46 Dollar(VariableChain),
47 Hash(VariableChain),
48 At(VariableChain),
49}
50impl Placeholder {
51 pub fn parse(input: &str) -> IResult<&str, Placeholder> {
52 alt((
53 map(RawPlaceholder::parse, Placeholder::Raw),
54 delimited(
55 preceded(tag("$"), preceded(multispace0, tag("{"))),
56 preceded(multispace0, map(VariableChain::parse, Placeholder::Dollar)),
57 preceded(multispace0, tag("}")),
58 ),
59 delimited(
60 preceded(tag("#"), preceded(multispace0, tag("{"))),
61 preceded(multispace0, map(VariableChain::parse, Placeholder::Hash)),
62 preceded(multispace0, tag("}")),
63 ),
64 delimited(
65 preceded(tag("@"), preceded(multispace0, tag("{"))),
66 preceded(multispace0, map(VariableChain::parse, Placeholder::At)),
67 preceded(multispace0, tag("}")),
68 ),
69 ))(input)
70 }
71}
72
73impl ToSqlSegment for Placeholder {
74 fn gen_sql_segment(&self) -> SqlSegment {
75 match self {
76 Placeholder::Dollar(p) => SqlSegment::Dollar(p.to_string()),
77 Placeholder::Hash(p) => SqlSegment::Hash(p.to_string()),
78 Placeholder::At(p) => SqlSegment::At(p.to_string()),
79 Placeholder::Raw(p)=>p.gen_sql_segment(),
80 }
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use crate::template_parser::structs::variable::Variable;
88 #[test]
89 fn placeholder_parser_spec_001() {
90 let template = "@{ hello. name. attr1 }";
91 let (_, placeholder) = Placeholder::parse(template).unwrap();
92 let variable_chain = vec![
93 Variable::Simple("hello".to_string()),
94 Variable::Simple("name".to_string()),
95 Variable::Simple("attr1".to_string()),
96 ];
97 assert_eq!(
98 placeholder,
99 Placeholder::At(VariableChain::new(variable_chain))
100 );
101
102 let template = "#{ [ hello ]. \" name \". ` attr1 ` }";
103 let (_, placeholder) = Placeholder::parse(template).unwrap();
104 let variable_chain = vec![
105 Variable::Brackets("hello".to_string()),
106 Variable::DoubleQuote("name".to_string()),
107 Variable::Backquote("attr1".to_string()),
108 ];
109 assert_eq!(
110 placeholder,
111 Placeholder::Hash(VariableChain::new(variable_chain))
112 );
113
114 let template = "${ [ hello ]. name . ` attr1 ` }";
115 let (_, placeholder) = Placeholder::parse(template).unwrap();
116 let variable_chain = vec![
117 Variable::Brackets("hello".to_string()),
118 Variable::Simple("name".to_string()),
119 Variable::Backquote("attr1".to_string()),
120 ];
121 assert_eq!(
122 placeholder,
123 Placeholder::Dollar(VariableChain::new(variable_chain))
124 );
125 }
126
127 #[test]
128 fn placeholder_parser_spec_002() {
129 let template = "@{ hello. name. attr1. }";
130 let parse_result = Placeholder::parse(template);
131 assert!(parse_result.is_err());
132 if let Err(nom::Err::Error(error)) = parse_result {
133 assert_eq!(error.to_string(), "error Tag at: . }");
134 }
135 }
136}