spacetimedb_sql_parser/ast/
mod.rs1use std::fmt::{Display, Formatter};
2
3use sqlparser::ast::Ident;
4
5pub mod sql;
6pub mod sub;
7
8#[derive(Debug)]
10pub enum SqlFrom {
11 Expr(SqlIdent, SqlIdent),
12 Join(SqlIdent, SqlIdent, Vec<SqlJoin>),
13}
14
15impl SqlFrom {
16 pub fn has_unqualified_vars(&self) -> bool {
17 match self {
18 Self::Join(_, _, joins) => joins.iter().any(|join| join.has_unqualified_vars()),
19 _ => false,
20 }
21 }
22}
23
24#[derive(Debug)]
26pub struct SqlJoin {
27 pub var: SqlIdent,
28 pub alias: SqlIdent,
29 pub on: Option<SqlExpr>,
30}
31
32impl SqlJoin {
33 pub fn has_unqualified_vars(&self) -> bool {
34 self.on.as_ref().is_some_and(|expr| expr.has_unqualified_vars())
35 }
36}
37
38#[derive(Debug)]
40pub struct ProjectElem(pub ProjectExpr, pub SqlIdent);
41
42impl ProjectElem {
43 pub fn qualify_vars(self, with: SqlIdent) -> Self {
44 let Self(expr, alias) = self;
45 Self(expr.qualify_vars(with), alias)
46 }
47}
48
49#[derive(Debug)]
51pub enum ProjectExpr {
52 Var(SqlIdent),
53 Field(SqlIdent, SqlIdent),
54}
55
56impl From<ProjectExpr> for SqlExpr {
57 fn from(value: ProjectExpr) -> Self {
58 match value {
59 ProjectExpr::Var(name) => Self::Var(name),
60 ProjectExpr::Field(table, field) => Self::Field(table, field),
61 }
62 }
63}
64
65impl ProjectExpr {
66 pub fn qualify_vars(self, with: SqlIdent) -> Self {
67 match self {
68 Self::Var(name) => Self::Field(with, name),
69 Self::Field(_, _) => self,
70 }
71 }
72}
73
74#[derive(Debug)]
76pub enum Project {
77 Star(Option<SqlIdent>),
80 Exprs(Vec<ProjectElem>),
82 Count(SqlIdent),
84}
85
86impl Project {
87 pub fn qualify_vars(self, with: SqlIdent) -> Self {
88 match self {
89 Self::Star(..) | Self::Count(..) => self,
90 Self::Exprs(elems) => Self::Exprs(elems.into_iter().map(|elem| elem.qualify_vars(with.clone())).collect()),
91 }
92 }
93
94 pub fn has_unqualified_vars(&self) -> bool {
95 match self {
96 Self::Exprs(exprs) => exprs
97 .iter()
98 .any(|ProjectElem(expr, _)| matches!(expr, ProjectExpr::Var(_))),
99 _ => false,
100 }
101 }
102}
103
104#[derive(Debug)]
106pub enum SqlExpr {
107 Lit(SqlLiteral),
109 Var(SqlIdent),
111 Field(SqlIdent, SqlIdent),
113 Bin(Box<SqlExpr>, Box<SqlExpr>, BinOp),
115 Log(Box<SqlExpr>, Box<SqlExpr>, LogOp),
117}
118
119impl SqlExpr {
120 pub fn qualify_vars(self, with: SqlIdent) -> Self {
121 match self {
122 Self::Var(name) => Self::Field(with, name),
123 Self::Lit(..) | Self::Field(..) => self,
124 Self::Bin(a, b, op) => Self::Bin(
125 Box::new(a.qualify_vars(with.clone())),
126 Box::new(b.qualify_vars(with)),
127 op,
128 ),
129 Self::Log(a, b, op) => Self::Log(
130 Box::new(a.qualify_vars(with.clone())),
131 Box::new(b.qualify_vars(with)),
132 op,
133 ),
134 }
135 }
136
137 pub fn has_unqualified_vars(&self) -> bool {
138 match self {
139 Self::Var(_) => true,
140 Self::Bin(a, b, _) | Self::Log(a, b, _) => a.has_unqualified_vars() || b.has_unqualified_vars(),
141 _ => false,
142 }
143 }
144}
145
146#[derive(Debug, Clone)]
149pub struct SqlIdent(pub Box<str>);
150
151impl From<Ident> for SqlIdent {
153 fn from(Ident { value, .. }: Ident) -> Self {
154 SqlIdent(value.into_boxed_str())
155 }
156}
157
158#[derive(Debug)]
160pub enum SqlLiteral {
161 Bool(bool),
163 Hex(Box<str>),
165 Num(Box<str>),
167 Str(Box<str>),
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub enum BinOp {
174 Eq,
175 Ne,
176 Lt,
177 Gt,
178 Lte,
179 Gte,
180}
181
182impl Display for BinOp {
183 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
184 match self {
185 Self::Eq => write!(f, "="),
186 Self::Ne => write!(f, "<>"),
187 Self::Lt => write!(f, "<"),
188 Self::Gt => write!(f, ">"),
189 Self::Lte => write!(f, "<="),
190 Self::Gte => write!(f, ">="),
191 }
192 }
193}
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq)]
196pub enum LogOp {
197 And,
198 Or,
199}
200
201impl Display for LogOp {
202 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
203 match self {
204 Self::And => write!(f, "AND"),
205 Self::Or => write!(f, "OR"),
206 }
207 }
208}