surrealdb-core 3.3.1

A scalable, distributed, collaborative, document-graph database, for the realtime web
use anyhow::{Result, bail};
use reblessive::tree::Stk;
use surrealdb_types::ToSql;

use crate::exec::Error as ExecError;
use crate::expr::{Error as ExprError, Operation};
use crate::fnc::args::Optional;
use crate::val::{Closure, ClosureEvaluator, Value};

pub async fn chain(
	(stk, ev): (&mut Stk, Option<&dyn ClosureEvaluator>),
	(value, worker): (Value, Box<Closure>),
) -> Result<Value> {
	if let Some(ev) = ev {
		ev.invoke(stk, &worker, vec![value]).await
	} else {
		Ok(Value::None)
	}
}

pub async fn expect(
	(stk, ev): (&mut Stk, Option<&dyn ClosureEvaluator>),
	(value, worker, Optional(message)): (Value, Box<Closure>, Optional<Value>),
) -> Result<Value> {
	if let Some(ev) = ev {
		let got = ev.invoke(stk, &worker, vec![value.clone()]).await?;
		match got {
			Value::Bool(true) => Ok(value),
			Value::Bool(false) => {
				let suffix = match message {
					None | Some(Value::None) => String::new(),
					Some(user_message) => {
						format!(" with message: {}", user_message.to_sql())
					}
				};
				bail!(ExecError::Thrown(format!("value::expect assertion failed{suffix}")))
			}
			other => {
				bail!(ExprError::InvalidFunctionArguments {
					name: "value::expect".to_owned(),
					message: format!(
						"Assertion closure must return a bool, got {}",
						other.kind_of()
					),
				})
			}
		}
	} else {
		Ok(Value::None)
	}
}

pub async fn diff((val1, val2): (Value, Value)) -> Result<Value> {
	Ok(Operation::operations_to_value(val1.diff(&val2)))
}

pub async fn patch((mut val, diff): (Value, Value)) -> Result<Value> {
	val.patch(diff)?;
	Ok(val)
}