1use std::sync::Arc;
2
3use spacetimedb_lib::{query::Delta, AlgebraicType, AlgebraicValue};
4use spacetimedb_primitives::TableId;
5use spacetimedb_schema::schema::TableSchema;
6use spacetimedb_sql_parser::ast::{BinOp, LogOp};
7
8#[derive(Debug, PartialEq, Eq)]
23pub enum ProjectName {
24 None(RelExpr),
25 Some(RelExpr, Box<str>),
26}
27
28impl ProjectName {
29 pub fn unwrap(self) -> RelExpr {
31 match self {
32 Self::None(expr) | Self::Some(expr, _) => expr,
33 }
34 }
35
36 pub fn return_name(&self) -> Option<&str> {
39 match self {
40 Self::None(input) => input.return_name(),
41 Self::Some(_, name) => Some(name.as_ref()),
42 }
43 }
44
45 pub fn return_table(&self) -> Option<&TableSchema> {
49 match self {
50 Self::None(input) => input.return_table(),
51 Self::Some(input, alias) => input.find_table_schema(alias),
52 }
53 }
54
55 pub fn return_table_id(&self) -> Option<TableId> {
59 match self {
60 Self::None(input) => input.return_table_id(),
61 Self::Some(input, alias) => input.find_table_id(alias),
62 }
63 }
64
65 pub fn for_each_return_field(&self, mut f: impl FnMut(&str, &AlgebraicType)) {
67 if let Some(schema) = self.return_table() {
68 for schema in schema.columns() {
69 f(&schema.col_name, &schema.col_type);
70 }
71 }
72 }
73}
74
75#[derive(Debug)]
137pub enum ProjectList {
138 Name(Vec<ProjectName>),
139 List(Vec<RelExpr>, Vec<(Box<str>, FieldProject)>),
140 Limit(Box<ProjectList>, u64),
141 Agg(Vec<RelExpr>, AggType, Box<str>, AlgebraicType),
142}
143
144#[derive(Debug)]
145pub enum AggType {
146 Count,
147}
148
149impl ProjectList {
150 pub fn return_table(&self) -> Option<&TableSchema> {
154 match self {
155 Self::Name(project) => project.first().and_then(|expr| expr.return_table()),
156 Self::Limit(input, _) => input.return_table(),
157 Self::List(..) | Self::Agg(..) => None,
158 }
159 }
160
161 pub fn return_table_id(&self) -> Option<TableId> {
165 match self {
166 Self::Name(project) => project.first().and_then(|expr| expr.return_table_id()),
167 Self::Limit(input, _) => input.return_table_id(),
168 Self::List(..) | Self::Agg(..) => None,
169 }
170 }
171
172 pub fn for_each_return_field(&self, mut f: impl FnMut(&str, &AlgebraicType)) {
174 match self {
175 Self::Name(input) => {
176 input.first().inspect(|expr| expr.for_each_return_field(f));
177 }
178 Self::Limit(input, _) => {
179 input.for_each_return_field(f);
180 }
181 Self::List(_, fields) => {
182 for (name, FieldProject { ty, .. }) in fields {
183 f(name, ty);
184 }
185 }
186 Self::Agg(_, _, name, ty) => f(name, ty),
187 }
188 }
189}
190
191#[derive(Debug, Clone, PartialEq, Eq)]
193pub enum RelExpr {
194 RelVar(Relvar),
196 Select(Box<RelExpr>, Expr),
198 LeftDeepJoin(LeftDeepJoin),
200 EqJoin(LeftDeepJoin, FieldProject, FieldProject),
202}
203
204#[derive(Debug, Clone, PartialEq, Eq)]
206pub struct Relvar {
207 pub schema: Arc<TableSchema>,
209 pub alias: Box<str>,
211 pub delta: Option<Delta>,
213}
214
215impl RelExpr {
216 pub fn visit(&self, f: &mut impl FnMut(&Self)) {
218 f(self);
219 match self {
220 Self::Select(lhs, _)
221 | Self::LeftDeepJoin(LeftDeepJoin { lhs, .. })
222 | Self::EqJoin(LeftDeepJoin { lhs, .. }, ..) => {
223 lhs.visit(f);
224 }
225 Self::RelVar(..) => {}
226 }
227 }
228
229 pub fn visit_mut(&mut self, f: &mut impl FnMut(&mut Self)) {
231 f(self);
232 match self {
233 Self::Select(lhs, _)
234 | Self::LeftDeepJoin(LeftDeepJoin { lhs, .. })
235 | Self::EqJoin(LeftDeepJoin { lhs, .. }, ..) => {
236 lhs.visit_mut(f);
237 }
238 Self::RelVar(..) => {}
239 }
240 }
241
242 pub fn nfields(&self) -> usize {
244 match self {
245 Self::RelVar(..) => 1,
246 Self::LeftDeepJoin(join) | Self::EqJoin(join, ..) => join.lhs.nfields() + 1,
247 Self::Select(input, _) => input.nfields(),
248 }
249 }
250
251 pub fn has_field(&self, field: &str) -> bool {
253 match self {
254 Self::RelVar(Relvar { alias, .. }) => alias.as_ref() == field,
255 Self::LeftDeepJoin(join) | Self::EqJoin(join, ..) => {
256 join.rhs.alias.as_ref() == field || join.lhs.has_field(field)
257 }
258 Self::Select(input, _) => input.has_field(field),
259 }
260 }
261
262 pub fn find_table_schema(&self, alias: &str) -> Option<&TableSchema> {
264 match self {
265 Self::RelVar(relvar) if relvar.alias.as_ref() == alias => Some(&relvar.schema),
266 Self::Select(input, _) => input.find_table_schema(alias),
267 Self::EqJoin(LeftDeepJoin { rhs, .. }, ..) if rhs.alias.as_ref() == alias => Some(&rhs.schema),
268 Self::EqJoin(LeftDeepJoin { lhs, .. }, ..) => lhs.find_table_schema(alias),
269 Self::LeftDeepJoin(LeftDeepJoin { rhs, .. }) if rhs.alias.as_ref() == alias => Some(&rhs.schema),
270 Self::LeftDeepJoin(LeftDeepJoin { lhs, .. }) => lhs.find_table_schema(alias),
271 _ => None,
272 }
273 }
274
275 pub fn find_table_id(&self, alias: &str) -> Option<TableId> {
277 self.find_table_schema(alias).map(|schema| schema.table_id)
278 }
279
280 pub fn return_table(&self) -> Option<&TableSchema> {
283 match self {
284 Self::RelVar(Relvar { schema, .. }) => Some(schema),
285 Self::Select(input, _) => input.return_table(),
286 _ => None,
287 }
288 }
289
290 pub fn return_table_id(&self) -> Option<TableId> {
293 self.return_table().map(|schema| schema.table_id)
294 }
295
296 pub fn return_name(&self) -> Option<&str> {
299 match self {
300 Self::RelVar(Relvar { alias, .. }) => Some(alias.as_ref()),
301 Self::Select(input, _) => input.return_name(),
302 _ => None,
303 }
304 }
305}
306
307#[derive(Debug, Clone, PartialEq, Eq)]
309pub struct LeftDeepJoin {
310 pub lhs: Box<RelExpr>,
312 pub rhs: Relvar,
314}
315
316#[derive(Debug, Clone, PartialEq, Eq)]
318pub enum Expr {
319 BinOp(BinOp, Box<Expr>, Box<Expr>),
321 LogOp(LogOp, Box<Expr>, Box<Expr>),
323 Value(AlgebraicValue, AlgebraicType),
325 Field(FieldProject),
327}
328
329impl Expr {
330 pub fn visit(&self, f: &impl Fn(&Self)) {
332 f(self);
333 match self {
334 Self::BinOp(_, a, b) | Self::LogOp(_, a, b) => {
335 a.visit(f);
336 b.visit(f);
337 }
338 Self::Value(..) | Self::Field(..) => {}
339 }
340 }
341
342 pub fn visit_mut(&mut self, f: &mut impl FnMut(&mut Self)) {
344 f(self);
345 match self {
346 Self::BinOp(_, a, b) | Self::LogOp(_, a, b) => {
347 a.visit_mut(f);
348 b.visit_mut(f);
349 }
350 Self::Value(..) | Self::Field(..) => {}
351 }
352 }
353
354 pub const fn bool(v: bool) -> Self {
356 Self::Value(AlgebraicValue::Bool(v), AlgebraicType::Bool)
357 }
358
359 pub const fn str(v: Box<str>) -> Self {
361 Self::Value(AlgebraicValue::String(v), AlgebraicType::String)
362 }
363
364 pub fn ty(&self) -> &AlgebraicType {
366 match self {
367 Self::BinOp(..) | Self::LogOp(..) => &AlgebraicType::Bool,
368 Self::Value(_, ty) | Self::Field(FieldProject { ty, .. }) => ty,
369 }
370 }
371}
372
373#[derive(Debug, Clone, PartialEq, Eq)]
375pub struct FieldProject {
376 pub table: Box<str>,
377 pub field: usize,
378 pub ty: AlgebraicType,
379}