sql-orm-query 0.2.0-rc.1

Query AST and builder primitives for sql-orm.
Documentation
use sql_orm_core::{Entity, EntityColumn, SqlValue};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TableRef {
    pub schema: &'static str,
    pub table: &'static str,
    pub alias: Option<&'static str>,
}

impl TableRef {
    pub const fn new(schema: &'static str, table: &'static str) -> Self {
        Self {
            schema,
            table,
            alias: None,
        }
    }

    pub const fn with_alias(
        schema: &'static str,
        table: &'static str,
        alias: &'static str,
    ) -> Self {
        Self {
            schema,
            table,
            alias: Some(alias),
        }
    }

    pub fn for_entity<E: Entity>() -> Self {
        let metadata = E::metadata();
        Self::new(metadata.schema, metadata.table)
    }

    pub fn for_entity_as<E: Entity>(alias: &'static str) -> Self {
        let metadata = E::metadata();
        Self::with_alias(metadata.schema, metadata.table, alias)
    }

    pub const fn as_alias(self, alias: &'static str) -> Self {
        Self {
            schema: self.schema,
            table: self.table,
            alias: Some(alias),
        }
    }

    pub const fn without_alias(self) -> Self {
        Self {
            schema: self.schema,
            table: self.table,
            alias: None,
        }
    }

    pub const fn reference_name(&self) -> &'static str {
        match self.alias {
            Some(alias) => alias,
            None => self.table,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ColumnRef {
    pub table: TableRef,
    pub rust_field: &'static str,
    pub column_name: &'static str,
}

impl ColumnRef {
    pub const fn new(table: TableRef, rust_field: &'static str, column_name: &'static str) -> Self {
        Self {
            table,
            rust_field,
            column_name,
        }
    }

    pub fn for_entity_column<E: Entity>(column: EntityColumn<E>) -> Self {
        Self::new(
            TableRef::for_entity::<E>(),
            column.rust_field(),
            column.column_name(),
        )
    }

    pub fn for_entity_column_as<E: Entity>(column: EntityColumn<E>, alias: &'static str) -> Self {
        Self::new(
            TableRef::for_entity_as::<E>(alias),
            column.rust_field(),
            column.column_name(),
        )
    }

    pub const fn with_table_alias(self, alias: &'static str) -> Self {
        Self {
            table: self.table.as_alias(alias),
            rust_field: self.rust_field,
            column_name: self.column_name,
        }
    }
}

impl<E: Entity> From<EntityColumn<E>> for ColumnRef {
    fn from(value: EntityColumn<E>) -> Self {
        Self::for_entity_column(value)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
    Add,
    Subtract,
    Multiply,
    Divide,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
    Negate,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
    Column(ColumnRef),
    Value(SqlValue),
    Binary {
        left: Box<Expr>,
        op: BinaryOp,
        right: Box<Expr>,
    },
    Unary {
        op: UnaryOp,
        expr: Box<Expr>,
    },
    Function {
        name: String,
        args: Vec<Expr>,
    },
}

impl Expr {
    pub fn column<E: Entity>(column: EntityColumn<E>) -> Self {
        Self::Column(column.into())
    }

    pub fn column_as<E: Entity>(column: EntityColumn<E>, alias: &'static str) -> Self {
        Self::Column(ColumnRef::for_entity_column_as(column, alias))
    }

    pub const fn value(value: SqlValue) -> Self {
        Self::Value(value)
    }

    pub fn binary(left: Expr, op: BinaryOp, right: Expr) -> Self {
        Self::Binary {
            left: Box::new(left),
            op,
            right: Box::new(right),
        }
    }

    pub fn unary(op: UnaryOp, expr: Expr) -> Self {
        Self::Unary {
            op,
            expr: Box::new(expr),
        }
    }

    pub fn function(name: impl Into<String>, args: Vec<Expr>) -> Self {
        Self::Function {
            name: name.into(),
            args,
        }
    }
}

impl<E: Entity> From<EntityColumn<E>> for Expr {
    fn from(value: EntityColumn<E>) -> Self {
        Self::column(value)
    }
}

impl From<SqlValue> for Expr {
    fn from(value: SqlValue) -> Self {
        Self::Value(value)
    }
}