use anyhow::{Result, bail};
use reblessive::tree::Stk;
use crate::catalog::providers::DatabaseProvider;
use crate::catalog::{Error as CatalogError, Permission};
use crate::ctx::FrozenContext;
use crate::dbs::Options;
use crate::doc::CursorDoc;
use crate::exe::FlowResultExt as _;
use crate::exec::Error as ExecError;
use crate::expr::param::Param;
use crate::iam::Action;
use crate::val::Value;
#[instrument(level = "trace", name = "Param::compute", skip_all)]
pub(crate) async fn param_compute(
this: &Param,
stk: &mut Stk,
ctx: &FrozenContext,
opt: &Options,
doc: Option<&CursorDoc>,
) -> Result<Value> {
match this.as_str() {
"this" | "self" => match doc {
Some(v) => Ok(v.doc.as_ref().clone()),
None => Ok(Value::None),
},
v => match ctx.value(v) {
Some(v) => Ok(v.clone()),
None => {
opt.valid_for_db()?;
let Some((ns, db)) = ctx.try_ns_db_ids(opt).await? else {
return Ok(Value::None);
};
let val = ctx.tx().get_db_param(ns, db, v, opt.version).await;
let val = match val {
Ok(x) => x,
Err(e) => {
if matches!(e.downcast_ref(), Some(CatalogError::PaNotFound { .. })) {
return Ok(Value::None);
} else {
return Err(e);
}
}
};
if ctx.check_perms(opt, Action::View)? {
match &val.permissions {
Permission::Full => (),
Permission::None => {
bail!(ExecError::ParamPermissions {
name: v.to_owned(),
})
}
Permission::Specific(e) => {
let opt = &opt.new_for_permission_predicate();
if !stk
.run(|stk| crate::legacy::expr_compute(e, stk, ctx, opt, doc))
.await
.catch_return()?
.is_truthy()
{
bail!(ExecError::ParamPermissions {
name: v.to_owned(),
});
}
}
}
}
Ok(val.value.clone())
}
},
}
}