diff --git a/lib/src/dbs/auth.rs b/lib/src/dbs/auth.rs index 51ef1d03..4fcb29fd 100644 --- a/lib/src/dbs/auth.rs +++ b/lib/src/dbs/auth.rs @@ -7,12 +7,18 @@ pub enum Level { Sc, } +/// Specifies the authentication level for the datastore execution context. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd)] pub enum Auth { + /// Specifies that the user is not authenticated No, + /// Specifies that the user is authenticated with full root permissions Kv, + /// Specifies that the user is has full permissions for a particular Namespace Ns(String), + /// Specifies that the user is has full permissions for a particular Namespace and Database Db(String, String), + /// Specifies that the user is has full permissions for a particular Namespace, Database, and Scope Sc(String, String, String), } @@ -23,7 +29,8 @@ impl Default for Auth { } impl Auth { - pub fn perms(&self) -> bool { + /// Checks whether permissions clauses need to be processed + pub(crate) fn perms(&self) -> bool { match self { Auth::No => true, Auth::Sc(_, _, _) => true, @@ -32,7 +39,8 @@ impl Auth { Auth::Kv => false, } } - pub fn check(&self, level: Level) -> bool { + /// Checks whether the current authentication matches the required level + pub(crate) fn check(&self, level: Level) -> bool { match self { Auth::No => matches!(level, Level::No), Auth::Sc(_, _, _) => matches!(level, Level::No | Level::Sc), diff --git a/lib/src/dbs/response.rs b/lib/src/dbs/response.rs index e2d5d193..9f5da003 100644 --- a/lib/src/dbs/response.rs +++ b/lib/src/dbs/response.rs @@ -4,6 +4,7 @@ use serde::ser::SerializeStruct; use serde::Serialize; use std::time::Duration; +/// The return value when running a query set on the database. #[derive(Debug)] pub struct Response { pub sql: Option, @@ -12,11 +13,11 @@ pub struct Response { } impl Response { - // Return the transaction speed + /// Return the transaction duration as a string pub fn speed(&self) -> String { format!("{:?}", self.time) } - // Retrieve the response as a result + /// Retrieve the response as a result by reference pub fn output(&self) -> Result<&Value, &Error> { match &self.result { Ok(v) => Ok(v), diff --git a/lib/src/dbs/session.rs b/lib/src/dbs/session.rs index c5ec28d8..cc15941f 100644 --- a/lib/src/dbs/session.rs +++ b/lib/src/dbs/session.rs @@ -3,29 +3,38 @@ use crate::dbs::Auth; use crate::sql::value::Value; use std::sync::Arc; +/// Specifies the current session information when processing a query. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Session { - pub au: Arc, // Authentication info - pub ip: Option, // Session ip address - pub or: Option, // Session origin - pub id: Option, // Session id - pub ns: Option, // Namespace - pub db: Option, // Database - pub sc: Option, // Scope - pub sd: Option, // Scope auth data + /// The current [`Auth`] information + pub au: Arc, + /// The current connection IP address + pub ip: Option, + /// The current connection origin + pub or: Option, + /// The current connection ID + pub id: Option, + /// THe currently selected namespace + pub ns: Option, + /// THe currently selected database + pub db: Option, + /// The currently selected authentication scope + pub sc: Option, + /// The current scope authentication data + pub sd: Option, } impl Session { // Retrieves the selected namespace - pub fn ns(&self) -> Option> { + pub(crate) fn ns(&self) -> Option> { self.ns.to_owned().map(Arc::new) } // Retrieves the selected database - pub fn db(&self) -> Option> { + pub(crate) fn db(&self) -> Option> { self.db.to_owned().map(Arc::new) } // Convert a session into a runtime - pub fn context(&self, mut ctx: Context) -> Context { + pub(crate) fn context(&self, mut ctx: Context) -> Context { // Add session value let key = String::from("session"); let val: Value = self.into(); diff --git a/lib/src/err/mod.rs b/lib/src/err/mod.rs index bf2a0ff6..d0e5c5f0 100644 --- a/lib/src/err/mod.rs +++ b/lib/src/err/mod.rs @@ -20,35 +20,47 @@ use indxdb::err::Error as IndxDBError; #[cfg(feature = "parallel")] use tokio::sync::mpsc::error::SendError as TokioError; +/// An error originating from the SurrealDB client library. #[derive(Error, Debug)] pub enum Error { + /// This error is used for ignoring a document when processing a query + #[doc(hidden)] #[error("Conditional clause is not truthy")] Ignore, + /// There was an error when connecting to the underlying datastore #[error("Couldn't setup connection to underlying datastore")] Ds, + /// There was an error when starting a new transaction #[error("Couldn't create a database transaction")] Tx, + /// The transaction was already cancelled or committed #[error("Couldn't update a finished transaction")] TxFinished, + /// The current transaction was created as read-only #[error("Couldn't write to a read only transaction")] TxReadonly, + /// The conditional value in the request was not equal #[error("Value being checked was not correct")] TxConditionNotMet, + /// No namespace has been selected #[error("Specify a namespace to use")] NsEmpty, + /// No database has been selected #[error("Specify a database to use")] DbEmpty, + /// No SQL query has been specified #[error("Specify some SQL code to execute")] QueryEmpty, + /// There was an error with the SQL query #[error("Parse error on line {line} at character {char} when parsing '{sql}'")] InvalidQuery { line: usize, @@ -56,125 +68,154 @@ pub enum Error { sql: String, }, + /// There was an error with the provided JSON Patch #[error("The JSON Patch contains invalid operations. {message}")] InvalidPatch { message: String, }, + /// There was an error with the provided JavaScript code #[error("Problem with embedded script function. {message}")] InvalidScript { message: String, }, + /// The wrong number of arguments was given for the specified function #[error("Incorrect arguments for function {name}(). {message}")] InvalidArguments { name: String, message: String, }, + /// The query timedout #[error("Query timeout of {timer:?} exceeded")] QueryTimeout { timer: Duration, }, + /// The query did not execute, because the transaction was cancelled #[error("Query not executed due to cancelled transaction")] QueryCancelled, + /// The query did not execute, because the transaction has failed #[error("Query not executed due to failed transaction")] QueryNotExecuted, + /// The permissions do not allow for performing the specified query #[error("You don't have permission to perform this query type")] QueryPermissions, + /// The permissions do not allow for changing to the specified namespace #[error("You don't have permission to change to the {ns} namespace")] NsNotAllowed { ns: String, }, + /// The permissions do not allow for changing to the specified database #[error("You don't have permission to change to the {db} database")] DbNotAllowed { db: String, }, + /// The requested namespace does not exist #[error("The namespace does not exist")] NsNotFound, + /// The requested namespace token does not exist #[error("The namespace token does not exist")] NtNotFound, + /// The requested namespace login does not exist #[error("The namespace login does not exist")] NlNotFound, + /// The requested database does not exist #[error("The database does not exist")] DbNotFound, + /// The requested database token does not exist #[error("The database token does not exist")] DtNotFound, + /// The requested database login does not exist #[error("The database login does not exist")] DlNotFound, + /// The requested scope does not exist #[error("The scope does not exist")] ScNotFound, + /// The requested scope token does not exist #[error("The scope token does not exist")] StNotFound, + /// The requested table does not exist #[error("The table does not exist")] TbNotFound, - #[error("Too many recursive subqueries have been set")] + /// Too many recursive subqueries have been processed + #[error("Too many recursive subqueries have been processed")] TooManySubqueries { limit: usize, }, + /// Can not execute CREATE query using the specified value #[error("Can not execute CREATE query using value '{value}'")] CreateStatement { value: Value, }, + /// Can not execute UPDATE query using the specified value #[error("Can not execute UPDATE query using value '{value}'")] UpdateStatement { value: Value, }, + /// Can not execute RELATE query using the specified value #[error("Can not execute RELATE query using value '{value}'")] RelateStatement { value: Value, }, + /// Can not execute DELETE query using the specified value #[error("Can not execute DELETE query using value '{value}'")] DeleteStatement { value: Value, }, + /// Can not execute INSERT query using the specified value #[error("Can not execute INSERT query using value '{value}'")] InsertStatement { value: Value, }, + /// The permissions do not allow this query to be run on this table #[error("You don't have permission to run the `{query}` query on the `{table}` table")] TablePermissions { query: String, table: String, }, + /// The specified table can not be written as it is setup as a foreign table view #[error("Unable to write to the `{table}` table while setup as a view")] TableIsView { table: String, }, + /// A database entry for the specified record already exists #[error("Database record `{thing}` already exists")] RecordExists { thing: Thing, }, + /// A database index entry for the specified record already exists #[error("Database index `{index}` already contains `{thing}`")] IndexExists { index: String, thing: Thing, }, + /// The specified field did not conform to the field ASSERT clause #[error("Found '{value}' for field '{field}' but field must conform to: {check}")] FieldValue { value: Value, @@ -182,27 +223,34 @@ pub enum Error { check: Value, }, + /// Represents an underlying error with Serde encoding / decoding #[error("Serde error: {0}")] Serde(#[from] SerdeError), + /// Represents an underlying error from the EchoDB instance #[error("Key encoding error: {0}")] Encode(#[from] EncodeError), + /// Represents an underlying error from the EchoDB instance #[error("Key decoding error: {0}")] Decode(#[from] DecodeError), + /// Represents an underlying error from the EchoDB instance #[cfg(feature = "kv-echodb")] #[error("Datastore error: {0}")] EchoDB(#[from] EchoDBError), + /// Represents an underlying error from the IndxDB instance #[cfg(feature = "kv-indxdb")] #[error("Datastore error: {0}")] IndxDB(#[from] IndxDBError), + /// Represents an underlying error from the TiKV instance #[cfg(feature = "kv-tikv")] #[error("Datastore error: {0}")] TiKV(#[from] TiKVError), + /// Represents an underlying error with Tokio message channels #[cfg(feature = "parallel")] #[error("Tokio Error: {0}")] Tokio(#[from] TokioError<(Option, Value)>), diff --git a/lib/src/kvs/ds.rs b/lib/src/kvs/ds.rs index 1c6c7e8f..50da7dba 100644 --- a/lib/src/kvs/ds.rs +++ b/lib/src/kvs/ds.rs @@ -98,7 +98,7 @@ impl Datastore { _ => unreachable!(), } } - /// Create a new transaction + /// Create a new transaction on this datastore pub async fn transaction(&self, write: bool, lock: bool) -> Result { match &self.inner { #[cfg(feature = "kv-echodb")] @@ -131,7 +131,7 @@ impl Datastore { } } } - /// Execute a query + /// Parse and execute an SQL query pub async fn execute( &self, txt: &str, @@ -158,7 +158,7 @@ impl Datastore { opt.db = sess.db(); exe.execute(ctx, opt, ast).await } - /// Execute a query + /// Execute a pre-parsed SQL query pub async fn process( &self, ast: Query, diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 630ef4a0..2cbb2151 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,3 +1,11 @@ +//! This library provides an easy-to-use client for [SurrealDB](https://surrealdb.com), +//! the ultimate cloud database for tomorrow's applications. SurrealDB is a scalable, +//! distributed, collaborative, document-graph database for the realtime web. +//! +//! This library can be used to start an embedded in-memory datastore, an embedded +//! datastore persisted to disk, or for connecting to a distributed [TiKV](https://tikv.org) +//! key-value store. + #![forbid(unsafe_code)] #[macro_use] @@ -17,12 +25,10 @@ mod kvs; pub mod sql; -pub use err::Error; - pub use dbs::Auth; pub use dbs::Response; pub use dbs::Session; - +pub use err::Error; pub use kvs::Datastore; pub use kvs::Key; pub use kvs::Transaction;