pg2sqlite_core/ir/
expr.rs1#[derive(Debug, Clone, PartialEq)]
5pub enum Expr {
6 IntegerLiteral(i64),
8 FloatLiteral(f64),
10 StringLiteral(String),
12 BooleanLiteral(bool),
14 Null,
16 ColumnRef(String),
18 FunctionCall { name: String, args: Vec<Expr> },
20 Cast {
22 expr: std::boxed::Box<Expr>,
23 type_name: String,
24 },
25 BinaryOp {
27 left: std::boxed::Box<Expr>,
28 op: String,
29 right: std::boxed::Box<Expr>,
30 },
31 UnaryOp {
33 op: String,
34 expr: std::boxed::Box<Expr>,
35 },
36 IsNull {
38 expr: std::boxed::Box<Expr>,
39 negated: bool,
40 },
41 InList {
43 expr: std::boxed::Box<Expr>,
44 list: Vec<Expr>,
45 negated: bool,
46 },
47 Between {
49 expr: std::boxed::Box<Expr>,
50 low: std::boxed::Box<Expr>,
51 high: std::boxed::Box<Expr>,
52 negated: bool,
53 },
54 Nested(std::boxed::Box<Expr>),
56 NextVal(String),
58 CurrentTimestamp,
60 Raw(String),
62}
63
64impl Expr {
65 pub fn to_sql(&self) -> String {
67 match self {
68 Expr::IntegerLiteral(n) => n.to_string(),
69 Expr::FloatLiteral(n) => n.to_string(),
70 Expr::StringLiteral(s) => format!("'{}'", s.replace('\'', "''")),
71 Expr::BooleanLiteral(b) => {
72 if *b {
73 "1".to_string()
74 } else {
75 "0".to_string()
76 }
77 }
78 Expr::Null => "NULL".to_string(),
79 Expr::ColumnRef(name) => {
80 name.split('.')
82 .map(|part| {
83 let ident = super::Ident::new(part);
84 ident.to_sql()
85 })
86 .collect::<Vec<_>>()
87 .join(".")
88 }
89 Expr::FunctionCall { name, args } => {
90 let args_str: Vec<String> = args.iter().map(|a| a.to_sql()).collect();
91 format!("{name}({})", args_str.join(", "))
92 }
93 Expr::Cast { expr, type_name } => {
94 format!("CAST({} AS {type_name})", expr.to_sql())
95 }
96 Expr::BinaryOp { left, op, right } => {
97 format!("{} {op} {}", left.to_sql(), right.to_sql())
98 }
99 Expr::UnaryOp { op, expr } => {
100 format!("{op} {}", expr.to_sql())
101 }
102 Expr::IsNull { expr, negated } => {
103 if *negated {
104 format!("{} IS NOT NULL", expr.to_sql())
105 } else {
106 format!("{} IS NULL", expr.to_sql())
107 }
108 }
109 Expr::InList {
110 expr,
111 list,
112 negated,
113 } => {
114 let items: Vec<String> = list.iter().map(|e| e.to_sql()).collect();
115 let not = if *negated { "NOT " } else { "" };
116 format!("{} {not}IN ({})", expr.to_sql(), items.join(", "))
117 }
118 Expr::Between {
119 expr,
120 low,
121 high,
122 negated,
123 } => {
124 let not = if *negated { "NOT " } else { "" };
125 format!(
126 "{} {not}BETWEEN {} AND {}",
127 expr.to_sql(),
128 low.to_sql(),
129 high.to_sql()
130 )
131 }
132 Expr::Nested(inner) => format!("({})", inner.to_sql()),
133 Expr::NextVal(seq) => format!("nextval('{seq}')"),
134 Expr::CurrentTimestamp => "CURRENT_TIMESTAMP".to_string(),
135 Expr::Raw(sql) => sql.clone(),
136 }
137 }
138}