use crate::{
ctx::Context,
dbs::{Options, Transaction},
doc::CursorDoc,
err::Error,
iam::Action,
sql::{ident::Ident, value::Value, Permission},
};
use revision::revisioned;
use serde::{Deserialize, Serialize};
use std::{fmt, ops::Deref, str};
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Param";
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
#[serde(rename = "$surrealdb::private::sql::Param")]
#[revisioned(revision = 1)]
pub struct Param(pub Ident);
impl From<Ident> for Param {
fn from(v: Ident) -> Self {
Self(v)
}
}
impl From<String> for Param {
fn from(v: String) -> Self {
Self(v.into())
}
}
impl From<&str> for Param {
fn from(v: &str) -> Self {
Self(v.into())
}
}
impl Deref for Param {
type Target = Ident;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Param {
pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
match self.as_str() {
"this" | "self" => match doc {
Some(v) => v.doc.compute(ctx, opt, txn, doc).await,
None => Ok(Value::None),
},
v => match ctx.value(v) {
Some(v) => v.compute(ctx, opt, txn, doc).await,
None => {
let val = {
let mut run = txn.lock().await;
run.get_and_cache_db_param(opt.ns(), opt.db(), v).await
};
match val {
Ok(val) => {
if opt.check_perms(Action::View) {
match &val.permissions {
Permission::Full => (),
Permission::None => {
return Err(Error::ParamPermissions {
name: v.to_owned(),
})
}
Permission::Specific(e) => {
let opt = &opt.new_with_perms(false);
if !e.compute(ctx, opt, txn, doc).await?.is_truthy() {
return Err(Error::ParamPermissions {
name: v.to_owned(),
});
}
}
}
}
Ok(val.value.to_owned())
}
Err(_) => Ok(Value::None),
}
}
},
}
}
}
impl fmt::Display for Param {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "${}", &self.0)
}
}