surrealdb-sql 1.1.0

Full type definitions for the SurrealQL query language
Documentation
use crate::ctx::Context;
use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::fnc;
use crate::operator::Operator;
use crate::value::Value;
use revision::revisioned;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::str;

pub(crate) const TOKEN: &str = "$surrealdb::private::crate::Expression";

/// Binary expressions.
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
#[serde(rename = "$surrealdb::private::crate::Expression")]
#[revisioned(revision = 1)]
pub enum Expression {
	Unary {
		o: Operator,
		v: Value,
	},
	Binary {
		l: Value,
		o: Operator,
		r: Value,
	},
}

impl Default for Expression {
	fn default() -> Expression {
		Expression::Binary {
			l: Value::Null,
			o: Operator::default(),
			r: Value::Null,
		}
	}
}

impl Expression {
	/// Create a new binary expression
	#[doc(hidden)]
	pub fn new(l: Value, o: Operator, r: Value) -> Self {
		Self::Binary {
			l,
			o,
			r,
		}
	}
	/// Augment an existing expression
	pub(crate) fn augment(mut self, l: Value, o: Operator) -> Self {
		match &mut self {
			Self::Binary {
				l: left,
				o: op,
				..
			} if o.precedence() >= op.precedence() => match left {
				Value::Expression(x) => {
					*x.as_mut() = std::mem::take(x).augment(l, o);
					self
				}
				_ => {
					*left = Self::new(l, o, std::mem::take(left)).into();
					self
				}
			},
			e => {
				let r = Value::from(std::mem::take(e));
				Self::new(l, o, r)
			}
		}
	}
}

impl Expression {
	pub(crate) fn writeable(&self) -> bool {
		match self {
			Self::Unary {
				v,
				..
			} => v.writeable(),
			Self::Binary {
				l,
				r,
				..
			} => l.writeable() || r.writeable(),
		}
	}

	pub(crate) fn is_static(&self) -> bool {
		match self {
			Self::Unary {
				v,
				..
			} => v.is_static(),
			Self::Binary {
				l,
				r,
				..
			} => l.is_static() && r.is_static(),
		}
	}

	/// Returns the operator
	pub(crate) fn operator(&self) -> &Operator {
		match self {
			Expression::Unary {
				o,
				..
			} => o,
			Expression::Binary {
				o,
				..
			} => o,
		}
	}

	/// Process this type returning a computed simple Value
	pub(crate) async fn compute(
		&self,
		ctx: &Context<'_>,
		opt: &Options,
		txn: &Transaction,
		doc: Option<&CursorDoc<'_>>,
	) -> Result<Value, Error> {
		let (l, o, r) = match self {
			Self::Unary {
				o,
				v,
			} => {
				let operand = v.compute(ctx, opt, txn, doc).await?;
				return match o {
					Operator::Neg => fnc::operate::neg(operand),
					Operator::Not => fnc::operate::not(operand),
					op => unreachable!("{op:?} is not a unary op"),
				};
			}
			Self::Binary {
				l,
				o,
				r,
			} => (l, o, r),
		};

		let l = l.compute(ctx, opt, txn, doc).await?;
		match o {
			Operator::Or => {
				if let true = l.is_truthy() {
					return Ok(l);
				}
			}
			Operator::And => {
				if let false = l.is_truthy() {
					return Ok(l);
				}
			}
			Operator::Tco => {
				if let true = l.is_truthy() {
					return Ok(l);
				}
			}
			Operator::Nco => {
				if let true = l.is_some() {
					return Ok(l);
				}
			}
			_ => {} // Continue
		}
		let r = r.compute(ctx, opt, txn, doc).await?;
		match o {
			Operator::Or => fnc::operate::or(l, r),
			Operator::And => fnc::operate::and(l, r),
			Operator::Tco => fnc::operate::tco(l, r),
			Operator::Nco => fnc::operate::nco(l, r),
			Operator::Add => fnc::operate::add(l, r),
			Operator::Sub => fnc::operate::sub(l, r),
			Operator::Mul => fnc::operate::mul(l, r),
			Operator::Div => fnc::operate::div(l, r),
			Operator::Pow => fnc::operate::pow(l, r),
			Operator::Equal => fnc::operate::equal(&l, &r),
			Operator::Exact => fnc::operate::exact(&l, &r),
			Operator::NotEqual => fnc::operate::not_equal(&l, &r),
			Operator::AllEqual => fnc::operate::all_equal(&l, &r),
			Operator::AnyEqual => fnc::operate::any_equal(&l, &r),
			Operator::Like => fnc::operate::like(&l, &r),
			Operator::NotLike => fnc::operate::not_like(&l, &r),
			Operator::AllLike => fnc::operate::all_like(&l, &r),
			Operator::AnyLike => fnc::operate::any_like(&l, &r),
			Operator::LessThan => fnc::operate::less_than(&l, &r),
			Operator::LessThanOrEqual => fnc::operate::less_than_or_equal(&l, &r),
			Operator::MoreThan => fnc::operate::more_than(&l, &r),
			Operator::MoreThanOrEqual => fnc::operate::more_than_or_equal(&l, &r),
			Operator::Contain => fnc::operate::contain(&l, &r),
			Operator::NotContain => fnc::operate::not_contain(&l, &r),
			Operator::ContainAll => fnc::operate::contain_all(&l, &r),
			Operator::ContainAny => fnc::operate::contain_any(&l, &r),
			Operator::ContainNone => fnc::operate::contain_none(&l, &r),
			Operator::Inside => fnc::operate::inside(&l, &r),
			Operator::NotInside => fnc::operate::not_inside(&l, &r),
			Operator::AllInside => fnc::operate::inside_all(&l, &r),
			Operator::AnyInside => fnc::operate::inside_any(&l, &r),
			Operator::NoneInside => fnc::operate::inside_none(&l, &r),
			Operator::Outside => fnc::operate::outside(&l, &r),
			Operator::Intersects => fnc::operate::intersects(&l, &r),
			Operator::Matches(_) => fnc::operate::matches(ctx, txn, doc, self).await,
			Operator::Knn(_) => fnc::operate::knn(ctx, txn, doc, self).await,
			_ => unreachable!(),
		}
	}
}

impl fmt::Display for Expression {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self {
			Self::Unary {
				o,
				v,
			} => write!(f, "{o}{v}"),
			Self::Binary {
				l,
				o,
				r,
			} => write!(f, "{l} {o} {r}"),
		}
	}
}