real-rs 0.1.0

Universal query engine with relational algebra - compile the same query to PostgreSQL, SQLite, MongoDB, and YottaDB
Documentation
//! Core relational algebra operations
//!
//! This is the source of truth. SQL and other query languages compile to this.

use crate::schema::{DataType, Schema, Value};

/// Relational algebra expression tree
#[derive(Debug, Clone)]
pub enum Expr {
    /// Base relation (table, collection, global, etc.)
    Relation { name: String, schema: Schema },

    /// σ (selection) - filter rows
    Select {
        input: Box<Expr>,
        predicate: Predicate,
    },

    /// π (projection) - select columns
    Project {
        input: Box<Expr>,
        columns: Vec<String>,
    },

    /// ⨝ (join)
    Join {
        left: Box<Expr>,
        right: Box<Expr>,
        condition: JoinCondition,
    },

    /// ∪ (union)
    Union { left: Box<Expr>, right: Box<Expr> },

    /// ∩ (intersection)
    Intersect { left: Box<Expr>, right: Box<Expr> },

    /// - (difference)
    Difference { left: Box<Expr>, right: Box<Expr> },

    /// ρ (rename)
    Rename {
        input: Box<Expr>,
        from: String,
        to: String,
    },

    /// γ (grouping/aggregation)
    Aggregate {
        input: Box<Expr>,
        group_by: Vec<String>,
        aggregates: Vec<AggregateFunc>,
    },

    /// Sorting (ORDER BY)
    Sort {
        input: Box<Expr>,
        columns: Vec<(String, SortOrder)>,
    },

    /// Limit results (LIMIT)
    Limit {
        input: Box<Expr>,
        count: usize,
    },

    /// Offset results (OFFSET)
    Offset {
        input: Box<Expr>,
        count: usize,
    },
}

#[derive(Debug, Clone)]
pub enum Predicate {
    /// Column comparison
    Compare {
        left: ColumnRef,
        op: CompareOp,
        right: Operand,
    },

    /// Logical AND
    And(Box<Predicate>, Box<Predicate>),

    /// Logical OR
    Or(Box<Predicate>, Box<Predicate>),

    /// Logical NOT
    Not(Box<Predicate>),

    /// IN predicate (column IN (value1, value2, ...))
    In {
        column: ColumnRef,
        values: Vec<Value>,
    },

    /// LIKE predicate for pattern matching
    Like {
        column: ColumnRef,
        pattern: String,
    },

    /// IS NULL predicate
    IsNull(ColumnRef),

    /// BETWEEN predicate (column BETWEEN low AND high)
    Between {
        column: ColumnRef,
        low: Value,
        high: Value,
    },
}

#[derive(Debug, Clone)]
pub enum Operand {
    Column(ColumnRef),
    Literal(Value),
}

#[derive(Debug, Clone)]
pub struct ColumnRef {
    pub table: Option<String>,
    pub name: String,
}

impl ColumnRef {
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            table: None,
            name: name.into(),
        }
    }

    pub fn qualified(table: impl Into<String>, name: impl Into<String>) -> Self {
        Self {
            table: Some(table.into()),
            name: name.into(),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompareOp {
    Eq,
    NotEq,
    Lt,
    Lte,
    Gt,
    Gte,
}

#[derive(Debug, Clone)]
pub enum JoinCondition {
    On(Predicate),
    Using(Vec<String>),
}

#[derive(Debug, Clone)]
pub struct AggregateFunc {
    pub name: String,
    pub func: AggregateType,
    pub input: String,
}

#[derive(Debug, Clone)]
pub enum AggregateType {
    Count,
    Sum,
    Avg,
    Min,
    Max,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SortOrder {
    Asc,
    Desc,
}

/// Builder for constructing algebra expressions with type safety
impl Expr {
    pub fn relation(name: impl Into<String>, schema: Schema) -> Self {
        Expr::Relation {
            name: name.into(),
            schema,
        }
    }

    pub fn select(self, predicate: Predicate) -> Self {
        Expr::Select {
            input: Box::new(self),
            predicate,
        }
    }

    pub fn project(self, columns: Vec<String>) -> Self {
        Expr::Project {
            input: Box::new(self),
            columns,
        }
    }

    pub fn join(self, right: Expr, condition: JoinCondition) -> Self {
        Expr::Join {
            left: Box::new(self),
            right: Box::new(right),
            condition,
        }
    }

    pub fn rename(self, from: impl Into<String>, to: impl Into<String>) -> Self {
        Expr::Rename {
            input: Box::new(self),
            from: from.into(),
            to: to.into(),
        }
    }

    /// Infer the schema that this expression will produce
    pub fn infer_schema(&self) -> Schema {
        match self {
            Expr::Relation { schema, .. } => schema.clone(),
            Expr::Select { input, .. } => input.infer_schema(),
            Expr::Project { input, columns } => {
                let input_schema = input.infer_schema();
                let mut output_schema = Schema::new(&input_schema.name);
                for col_name in columns {
                    if let Some(col) = input_schema.find_column(col_name) {
                        output_schema.columns.push(col.clone());
                    }
                }
                output_schema
            }
            Expr::Rename { input, from, to } => {
                let mut schema = input.infer_schema();
                if let Some(col) = schema.columns.iter_mut().find(|c| c.name == *from) {
                    col.name = to.clone();
                }
                schema
            }
            _ => Schema::new("unknown"),
        }
    }
}