use std::fmt::Debug;
use std::sync::Arc;
use anyhow::{Result, bail};
use crate::err::Error;
use crate::exec::Error as ExecError;
use crate::exec::config::ExecConfig;
use crate::expr::Base;
use crate::iam::Auth;
#[derive(Clone, Debug)]
pub struct Options {
pub(crate) ns: Option<Arc<str>>,
pub(crate) db: Option<Arc<str>>,
pub(crate) dive: u32,
pub(crate) auth: Arc<Auth>,
pub(crate) force: Force,
pub(crate) perms: bool,
pub(crate) caller_perms: bool,
pub(crate) no_write: Option<NoWriteFrame>,
pub(crate) import: bool,
pub(crate) version: Option<u64>,
pub(crate) for_update: bool,
async_event_depth: Option<u16>,
}
#[derive(Clone, Debug)]
pub enum Force {
All,
None,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum NoWriteFrame {
PermissionPredicate,
ComputedField,
}
impl Options {
pub(crate) fn new(config: &ExecConfig) -> Self {
Self {
ns: None,
db: None,
dive: config.max_computation_depth,
perms: true,
caller_perms: true,
no_write: None,
force: Force::None,
import: false,
auth: Arc::new(Auth::default()),
version: None,
for_update: false,
async_event_depth: None,
}
}
pub fn set_ns(&mut self, ns: Option<Arc<str>>) {
self.ns = ns
}
pub fn set_db(&mut self, db: Option<Arc<str>>) {
self.db = db
}
pub fn with_max_computation_depth(mut self, depth: u32) -> Self {
self.dive = depth;
self
}
pub(crate) fn with_dive_consumed(&self, depth: u32) -> Self {
Self {
dive: self.dive.saturating_sub(depth),
..self.clone()
}
}
pub fn with_ns(mut self, ns: Option<Arc<str>>) -> Self {
self.ns = ns;
self
}
pub fn with_db(mut self, db: Option<Arc<str>>) -> Self {
self.db = db;
self
}
pub fn with_auth(mut self, auth: Arc<Auth>) -> Self {
self.auth = auth;
self
}
pub fn limited_by(&self, limit: &crate::iam::AuthLimit) -> Options {
self.clone().with_auth(Arc::new(self.auth.new_limited(limit)))
}
pub fn with_perms(mut self, perms: bool) -> Self {
self.perms = perms;
self.caller_perms = perms;
self
}
pub(crate) fn new_for_reference_cascade(&self) -> Self {
Self {
perms: false,
..self.clone()
}
}
pub(crate) fn new_with_caller_perms(&self) -> Self {
Self {
perms: self.caller_perms,
..self.clone()
}
}
pub fn with_force(mut self, force: Force) -> Self {
self.force = force;
self
}
pub fn with_import(mut self, import: bool) -> Self {
self.set_import(import);
self
}
pub fn set_import(&mut self, import: bool) {
self.import = import;
}
pub fn with_version(mut self, version: Option<u64>) -> Self {
self.version = version;
self
}
pub fn with_for_update(mut self, for_update: bool) -> Self {
self.for_update = for_update;
self
}
pub fn with_async_event_depth(mut self, depth: u16) -> Self {
self.async_event_depth = Some(depth);
self
}
pub fn new_with_auth(&self, auth: Arc<Auth>) -> Self {
Self {
auth,
ns: self.ns.clone(),
db: self.db.clone(),
force: self.force.clone(),
perms: self.perms,
..self.clone()
}
}
pub fn new_with_perms(&self, perms: bool) -> Self {
Self {
perms,
caller_perms: perms,
..self.clone()
}
}
pub fn new_for_permission_predicate(&self) -> Self {
Self {
perms: false,
caller_perms: false,
no_write: Some(NoWriteFrame::PermissionPredicate),
..self.clone()
}
}
pub fn new_for_mutable_permission_predicate(&self) -> Self {
Self {
perms: false,
caller_perms: false,
no_write: None,
..self.clone()
}
}
pub fn new_for_computed_field(&self) -> Self {
Self {
no_write: Some(NoWriteFrame::ComputedField),
..self.clone()
}
}
pub fn new_with_force(&self, force: Force) -> Self {
Self {
force,
..self.clone()
}
}
pub fn new_with_import(&self, import: bool) -> Self {
Self {
import,
..self.clone()
}
}
pub(crate) fn selected_base(&self) -> Result<Base, Error> {
match (self.ns.as_ref(), self.db.as_ref()) {
(None, None) => Ok(Base::Root),
(Some(_), None) => Ok(Base::Ns),
(Some(_), Some(_)) => Ok(Base::Db),
(None, Some(_)) => Err(ExecError::NsEmpty.into()),
}
}
pub(crate) fn dive(&self, cost: u8) -> Result<Self, Error> {
if self.dive < cost as u32 {
return Err(ExecError::ComputationDepthExceeded.into());
}
Ok(Self {
dive: self.dive - cost as u32,
..self.clone()
})
}
#[inline(always)]
pub fn ns(&self) -> Result<&str> {
self.ns.as_deref().ok_or_else(|| ExecError::NsEmpty).map_err(anyhow::Error::new)
}
pub(crate) fn arc_ns(&self) -> Result<Arc<str>> {
self.ns.clone().ok_or_else(|| ExecError::NsEmpty).map_err(anyhow::Error::new)
}
#[inline(always)]
pub fn db(&self) -> Result<&str> {
self.db.as_deref().ok_or_else(|| ExecError::DbEmpty).map_err(anyhow::Error::new)
}
pub(crate) fn arc_db(&self) -> Result<Arc<str>> {
self.db.clone().ok_or_else(|| ExecError::DbEmpty).map_err(anyhow::Error::new)
}
#[inline(always)]
pub fn ns_db(&self) -> Result<(&str, &str)> {
Ok((self.ns()?, self.db()?))
}
pub(crate) fn arc_ns_db(&self) -> Result<(Arc<str>, Arc<str>)> {
Ok((self.arc_ns()?, self.arc_db()?))
}
pub fn ns_db_arc(&self) -> Result<(&str, &str)> {
Ok((self.ns()?, self.db()?))
}
#[inline(always)]
pub fn valid_for_ns(&self) -> Result<()> {
if self.ns.is_none() {
bail!(ExecError::NsEmpty);
}
Ok(())
}
#[inline(always)]
pub fn valid_for_db(&self) -> Result<()> {
if self.ns.is_none() {
bail!(ExecError::NsEmpty);
}
if self.db.is_none() {
bail!(ExecError::DbEmpty);
}
Ok(())
}
pub(crate) fn async_event_depth(&self) -> Option<u16> {
self.async_event_depth
}
}
const _: () = assert!(std::mem::size_of::<Options>() <= 128);