use std::sync::Arc;
use surrealdb_types::{SqlFormat, ToSql};
use crate::exec::physical_expr::{EvalContext, PhysicalExpr};
use crate::exec::{AccessMode, BoxFut, CombineAccessModes, ContextLevel};
use crate::expr::FlowResult;
use crate::val::Value;
#[derive(Debug, Clone)]
pub struct OptionalChainPart {
pub tail: Vec<Arc<dyn PhysicalExpr>>,
}
impl PhysicalExpr for OptionalChainPart {
fn name(&self) -> &'static str {
"OptionalChain"
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn required_context(&self) -> ContextLevel {
self.tail.iter().map(|p| p.required_context()).max().unwrap_or(ContextLevel::Root)
}
fn evaluate<'a>(&'a self, ctx: EvalContext<'a>) -> BoxFut<'a, FlowResult<Value>> {
Box::pin(async move {
let value = ctx.current_value.cloned().unwrap_or(Value::None);
if matches!(value, Value::None | Value::Null) {
return Ok(value);
}
let mut current = value;
for part in &self.tail {
current = part.evaluate(ctx.with_value(¤t)).await?;
}
Ok(current)
})
}
fn access_mode(&self) -> AccessMode {
self.tail.iter().map(|p| p.access_mode()).combine_all()
}
}
impl ToSql for OptionalChainPart {
fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
f.push('?');
for part in &self.tail {
part.fmt_sql(f, fmt);
}
}
}