taitan_orm_parser/template_parser/structs/
atomic.rs1use crate::template::MaybeValue;
2use crate::template_parser::structs::bool_value::Bool;
3use crate::template_parser::structs::connect_op::ConnectOp;
4use crate::template_parser::structs::number::Number;
5use crate::template_parser::structs::operators::Operator;
6use crate::template_parser::structs::placeholder::Placeholder;
7use crate::template_parser::structs::sign::Sign;
8use crate::template_parser::structs::template_part::TemplatePart;
9use crate::template_parser::structs::text::Text;
10use crate::template_parser::structs::values::GenericValue;
11use crate::template_parser::structs::variable::VariableChain;
12use crate::template_parser::to_sql::SqlSegment::Simple;
13use crate::template_parser::to_sql::{SqlSegment, ToSqlSegment};
14use nom::branch::alt;
15use nom::bytes::complete::tag_no_case;
16use nom::character::complete::multispace0;
17use nom::combinator::{map, not};
18use nom::sequence::preceded;
19use nom::IResult;
20use std::fmt::{Display, Formatter};
21use taitan_orm_tracing::debug;
22use crate::template_parser::structs::keyword::PostgresKeyword;
23
24
25
26
27#[derive(Debug, Clone, PartialEq)]
28pub enum Atomic {
29 Number(Number),
30 Text(Text),
31 Bool(Bool),
32 Operator(Operator), Maybe(MaybeValue), Sign(Sign), }
36
37impl Atomic {
38 pub fn parse(input: &str) -> IResult<&str, Atomic> {
39 debug!("Atomic parse({})", &input);
40 let (remaining, parsed) = alt((
41 map(Number::parse, Atomic::Number),
42 map(Text::parse, Atomic::Text),
43 map(Bool::parse, Atomic::Bool),
44 map(Sign::parse, Atomic::Sign), map(Operator::parse, Atomic::Operator),
46 map(MaybeValue::parse, Atomic::Maybe),
47 ))(input)?;
48 debug!("Atomic parse -> {:?}", &parsed);
49 Ok((remaining, parsed))
50 }
51
52 pub fn is_binary_op(&self) -> bool {
53 match self {
54 Atomic::Operator(_) => true,
55 _ => false,
56 }
57 }
58 pub fn is_operand(&self) -> bool {
59 match self {
60 Atomic::Operator(_) | Atomic::Sign(_) => false,
61 _ => true,
62 }
63 }
64
65 pub fn extract_binary_op(&self) -> Option<Operator> {
66 if let Atomic::Operator(o) = self {
67 return Some(o.clone());
68 }
69 None
70 }
71
72 pub fn extract_left_bracket(&self) -> Option<Sign> {
73 if let Atomic::Sign(Sign::Bracket(c)) = self {
74 if c == &'(' {
75 return Some(Sign::Bracket('('));
76 }
77 }
78 None
79 }
80 pub fn extract_right_bracket(&self) -> Option<Sign> {
81 if let Atomic::Sign(Sign::Bracket(c)) = self {
82 if c == &')' {
83 return Some(Sign::Bracket(')'));
84 }
85 }
86 None
87 }
88}
89
90impl ToSqlSegment for Atomic {
91 fn gen_sql_segment(&self) -> SqlSegment {
92 match self {
93 Atomic::Sign(s) => SqlSegment::Simple(s.to_string()),
94 Atomic::Maybe(m) => SqlSegment::Simple(m.gen_sql_segment().to_sql(false).to_string()),
95 Atomic::Operator(b) => SqlSegment::Simple(b.to_string()),
96 Atomic::Bool(b) => SqlSegment::Simple(b.to_string()),
97 Atomic::Text(t) => SqlSegment::Simple(t.to_string()),
98 Atomic::Number(n) => SqlSegment::Simple(n.to_string()),
99 }
100 }
101}
102
103#[derive(Debug, Clone, PartialEq)]
104pub struct AtomicStream {
105 pub atomics: Vec<Atomic>,
106}
107
108impl AtomicStream {
109 pub fn parse(input: &str) -> Result<Self, String> {
110 debug!("SqlTemplate::parse({})", input);
111 let mut atomics = Vec::new();
112 let mut remainder = input;
113 loop {
114 let parse_result = preceded(multispace0, Atomic::parse)(remainder);
115 match parse_result {
116 Ok((remaining, parsed)) => {
117 debug!("SqlTemplate::parse({})->{:?}", remaining, parsed);
118 atomics.push(parsed);
119 remainder = remaining;
120 }
121 Err(err_msg) => {
122 debug!("SqlTemplate::parse error: {}", err_msg);
123 let err_msg = format!("failed to parse atomic: {}", input);
124 return Err(err_msg);
125 }
126 }
127
128 if remainder.is_empty() {
129 break;
130 }
131 }
132 Ok(AtomicStream { atomics })
133 }
134}
135
136#[cfg(test)]
137mod atomic_tests {
138 use super::*;
139 use crate::template_parser::structs::template_part::{EndBlock, StartBlock};
140 use crate::template_parser::structs::values::MaybeValue;
141 use crate::template_parser::structs::variable::Variable;
142 #[test]
143 fn atomic_parser_spec_001() {
144 let template = "#{hello.`test`}";
145 let (_, parsed) = Atomic::parse(template).unwrap();
146 let variable_chain = vec![
147 Variable::Simple("hello".to_string()),
148 Variable::Backquote("test".to_string()),
149 ];
150 assert_eq!(
151 parsed,
152 Atomic::Maybe(MaybeValue::Placeholder(Placeholder::Hash(
153 VariableChain::new(variable_chain.clone())
154 )))
155 );
156
157 let template = "'hello.`test`'";
158 let (_, parsed) = Atomic::parse(template).unwrap();
159 assert_eq!(
160 parsed,
161 Atomic::Text(Text::SingleQuote("'hello.`test`'".to_string()))
162 );
163
164 let template = "\"hello\"";
165 let (_, parsed) = Atomic::parse(template).unwrap();
166 let variable_chain = vec![Variable::DoubleQuote("hello".to_string())];
167 assert_eq!(
168 parsed,
169 Atomic::Maybe(MaybeValue::VariableChain(VariableChain::new(
170 variable_chain.clone()
171 )))
172 );
173
174 let template = r#"
175 {% for item in items %}
176 Item: {{ item | upper }}
177 {% endfor %}"#;
178 let (remaining, parsed) = Atomic::parse(template).unwrap();
179 let expected = TemplatePart::ControlBlock {
180 start_block: StartBlock {
181 name: "for".to_string(),
182 start_modifier: None,
183 end_modifier: None,
184 expr: "item in items".to_string(),
185 },
186 content: "Item: {{ item | upper }}".to_string(),
187 end_block: EndBlock {
188 name: "endfor".to_string(),
189 start_modifier: None,
190 end_modifier: None,
191 },
192 };
193 assert_eq!(parsed, Atomic::Maybe(MaybeValue::TemplatePart(expected)));
194 }
195
196 #[test]
197 fn atomic_parser_spec_002() {
198 let template = "¥";
199 let (_, parsed) = Atomic::parse(template).unwrap();
200 assert_eq!(parsed, Atomic::Sign(Sign::Unknown('¥')));
201 }
202
203 #[test]
204 fn atomic_parser_spec_003() {
205 let template = "1234";
206 let (_, parsed) = Atomic::parse(template).unwrap();
207 assert_eq!(
208 parsed,
209 Atomic::Number(Number {
210 value: "1234".to_string(),
211 unary_op: None
212 })
213 );
214 }
215}