use crate::cnf; use crate::dbs::Auth; use crate::dbs::Level; use crate::dbs::Notification; use crate::err::Error; use channel::Sender; use std::sync::Arc; use uuid::Uuid; /// An Options is passed around when processing a set of query /// statements. An Options contains specific information for how /// to process each particular statement, including the record /// version to retrieve, whether futures should be processed, and /// whether field/event/table queries should be processed (useful /// when importing data, where these queries might fail). #[derive(Clone, Debug)] pub struct Options { /// Current Node ID pub id: Arc, /// Currently selected NS pub ns: Option>, /// Currently selected DB pub db: Option>, /// Connection authentication data pub auth: Arc, /// Approximately how large is the current call stack? dive: u8, /// Whether live queries are allowed? pub live: bool, /// Should we force tables/events to re-run? pub force: bool, /// Should we run permissions checks? pub perms: bool, /// Should we error if tables don't exist? pub strict: bool, /// Should we process field queries? pub fields: bool, /// Should we process event queries? pub events: bool, /// Should we process table queries? pub tables: bool, /// Should we process index queries? pub indexes: bool, /// Should we process function futures? pub futures: bool, /// pub sender: Sender, } impl Default for Options { fn default() -> Self { Options::new(Arc::new(Uuid::new_v4()), channel::unbounded().0, Arc::new(Auth::No)) } } impl Options { /// Create a new Options object pub fn new(id: Arc, send: Sender, auth: Arc) -> Options { Options { id, ns: None, db: None, dive: 0, live: false, perms: true, force: false, strict: false, fields: true, events: true, tables: true, indexes: true, futures: false, sender: send, auth, } } /// Get current Node ID pub fn id(&self) -> &Uuid { self.id.as_ref() } /// Get currently selected NS pub fn ns(&self) -> &str { self.ns.as_ref().unwrap() } /// Get currently selected DB pub fn db(&self) -> &str { self.db.as_ref().unwrap() } /// Create a new Options object for a function/subquery/future/etc. /// /// The parameter is the approximate cost of the operation (more concretely, the size of the /// stack frame it uses relative to a simple function call). When in doubt, use a value of 1. pub fn dive(&self, cost: u8) -> Result { let dive = self.dive.saturating_add(cost); if dive <= *cnf::MAX_COMPUTATION_DEPTH { Ok(Options { sender: self.sender.clone(), auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), dive, ..*self }) } else { Err(Error::ComputationDepthExceeded) } } /// Create a new Options object for a subquery pub fn force(&self, v: bool) -> Options { Options { sender: self.sender.clone(), auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), force: v, ..*self } } /// Create a new Options object for a subquery pub fn perms(&self, v: bool) -> Options { Options { sender: self.sender.clone(), auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), perms: v, ..*self } } /// Create a new Options object for a subquery pub fn fields(&self, v: bool) -> Options { Options { sender: self.sender.clone(), auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), fields: v, ..*self } } /// Create a new Options object for a subquery pub fn events(&self, v: bool) -> Options { Options { sender: self.sender.clone(), auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), events: v, ..*self } } /// Create a new Options object for a subquery pub fn tables(&self, v: bool) -> Options { Options { sender: self.sender.clone(), auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), tables: v, ..*self } } /// Create a new Options object for a subquery pub fn indexes(&self, v: bool) -> Options { Options { sender: self.sender.clone(), auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), indexes: v, ..*self } } /// Create a new Options object for a subquery pub fn import(&self, v: bool) -> Options { Options { sender: self.sender.clone(), auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), fields: !v, events: !v, tables: !v, ..*self } } /// Create a new Options object for a subquery pub fn strict(&self, v: bool) -> Options { Options { sender: self.sender.clone(), auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), strict: v, ..*self } } /// Create a new Options object for a subquery pub fn futures(&self, v: bool) -> Options { Options { sender: self.sender.clone(), auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), futures: v, ..*self } } /// Create a new Options object for a subquery pub fn sender(&self, v: Sender) -> Options { Options { auth: self.auth.clone(), id: self.id.clone(), ns: self.ns.clone(), db: self.db.clone(), sender: v, ..*self } } /// Check whether realtime queries are supported pub fn realtime(&self) -> Result<(), Error> { if !self.live { return Err(Error::RealtimeDisabled); } Ok(()) } /// Check whether the authentication permissions are ok pub fn check(&self, level: Level) -> Result<(), Error> { if !self.auth.check(level) { return Err(Error::QueryPermissions); } Ok(()) } /// Check whether the necessary NS / DB options have been set pub fn needs(&self, level: Level) -> Result<(), Error> { if self.ns.is_none() && matches!(level, Level::Ns | Level::Db) { return Err(Error::NsEmpty); } if self.db.is_none() && matches!(level, Level::Db) { return Err(Error::DbEmpty); } Ok(()) } }