use std::sync::Arc;
use crate::errors::{FilterReturnType, TypingError};
use crate::static_assert_size;
use spacetimedb_lib::AlgebraicValue;
use spacetimedb_primitives::TableId;
use spacetimedb_schema::schema::TableSchema;
use spacetimedb_sql_parser::ast::BinOp;
use super::ty::{InvalidTypeId, Symbol, TyCtx, TyId, Type, TypeWithCtx};
#[derive(Debug)]
pub enum RelExpr {
RelVar(Arc<TableSchema>, TyId),
Select(Box<Select>),
Proj(Box<Project>),
Join(Box<[RelExpr]>, TyId),
Union(Box<RelExpr>, Box<RelExpr>),
Minus(Box<RelExpr>, Box<RelExpr>),
Dedup(Box<RelExpr>),
}
static_assert_size!(RelExpr, 24);
impl RelExpr {
pub fn project(input: RelExpr, expr: Let) -> Self {
Self::Proj(Box::new(Project { input, expr }))
}
pub fn select(input: RelExpr, expr: Let) -> Self {
Self::Select(Box::new(Select { input, expr }))
}
pub fn ty_id(&self) -> TyId {
match self {
Self::RelVar(_, id) | Self::Join(_, id) => *id,
Self::Select(op) => op.input.ty_id(),
Self::Proj(op) => op.expr.exprs[0].ty_id(),
Self::Union(input, _) | Self::Minus(input, _) | Self::Dedup(input) => input.ty_id(),
}
}
pub fn ty<'a>(&self, ctx: &'a TyCtx) -> Result<TypeWithCtx<'a>, InvalidTypeId> {
ctx.try_resolve(self.ty_id())
}
pub fn table_id(&self, ctx: &mut TyCtx) -> Result<TableId, TypingError> {
match &*self.ty(ctx)? {
Type::Var(id, _) => Ok(*id),
_ => Err(FilterReturnType.into()),
}
}
}
#[derive(Debug)]
pub struct Select {
pub input: RelExpr,
pub expr: Let,
}
#[derive(Debug)]
pub struct Project {
pub input: RelExpr,
pub expr: Let,
}
#[derive(Debug)]
pub struct Let {
pub vars: Vec<(Symbol, Expr)>,
pub exprs: Vec<Expr>,
}
#[derive(Debug)]
pub enum Expr {
Bin(BinOp, Box<Expr>, Box<Expr>),
Var(Symbol, TyId),
Row(Box<[(Symbol, Expr)]>, TyId),
Lit(AlgebraicValue, TyId),
Field(Box<Expr>, usize, TyId),
Input(TyId),
}
static_assert_size!(Expr, 32);
impl Expr {
pub const fn bool(v: bool) -> Self {
Self::Lit(AlgebraicValue::Bool(v), TyId::BOOL)
}
pub fn str(v: Box<str>) -> Self {
Self::Lit(AlgebraicValue::String(v), TyId::STR)
}
pub fn ty_id(&self) -> TyId {
match self {
Self::Bin(..) => TyId::BOOL,
Self::Lit(_, id) | Self::Var(_, id) | Self::Input(id) | Self::Field(_, _, id) | Self::Row(_, id) => *id,
}
}
pub fn ty<'a>(&self, ctx: &'a TyCtx) -> Result<TypeWithCtx<'a>, InvalidTypeId> {
ctx.try_resolve(self.ty_id())
}
}