surrealdb-core 3.2.1

A scalable, distributed, collaborative, document-graph database, for the realtime web
Documentation
use revision::revisioned;
use surrealdb_types::ToSql;

mod access;
mod analyzer;
mod api;
pub(crate) mod base;
mod bucket;
mod config;
mod event;
mod field;
mod function;
mod index;
mod ml;
mod module;
mod param;
mod sequence;
mod user;
use std::fmt::{Display, Formatter};

pub use access::*;
pub use analyzer::*;
pub use api::*;
pub use bucket::*;
pub use config::*;
pub use event::*;
pub use field::*;
pub use function::*;
pub use index::*;
pub use ml::*;
pub use module::*;
pub(crate) use param::*;
pub use sequence::*;
pub use user::*;

use crate::expr::Expr;
use crate::expr::statements::info::InfoStructure;
use crate::val::Value;

/// Placeholder substituted for a secret when a catalog definition is serialised
/// through `INFO FOR …`. Credentials (Argon2 hashes, SCRAM verifiers, symmetric
/// and issuer keys) are offline-crackable or directly replayable, so metadata
/// surfaces must never return their real values. Export goes through the
/// `from_definition` paths and is intentionally not redacted.
pub(crate) const REDACTED: &str = "[REDACTED]";

#[revisioned(revision = 1)]
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
pub(crate) enum Permission {
	None,
	#[default]
	Full,
	Specific(Expr),
}

impl Permission {
	pub fn is_none(&self) -> bool {
		matches!(self, Self::None)
	}

	pub fn is_specific(&self) -> bool {
		matches!(self, Self::Specific(_))
	}

	/// Whether this permission clause directly contains a data-modifying
	/// statement, which is not allowed (GHSA-66r2-5gwj-gxm2).
	pub(crate) fn has_direct_write(&self) -> bool {
		match self {
			Permission::None | Permission::Full => false,
			Permission::Specific(e) => e.has_direct_write(),
		}
	}

	fn to_sql_definition(&self) -> crate::sql::Permission {
		match self {
			Permission::None => crate::sql::Permission::None,
			Permission::Full => crate::sql::Permission::Full,
			Permission::Specific(v) => crate::sql::Permission::Specific(v.clone().into()),
		}
	}
}

impl InfoStructure for Permission {
	fn structure(self) -> Value {
		match self {
			Permission::None => Value::Bool(false),
			Permission::Full => Value::Bool(true),
			Permission::Specific(v) => v.to_sql().into(),
		}
	}
}

impl ToSql for Permission {
	fn fmt_sql(&self, f: &mut String, sql_fmt: surrealdb_types::SqlFormat) {
		self.to_sql_definition().fmt_sql(f, sql_fmt);
	}
}

impl ToSql for Permissions {
	fn fmt_sql(&self, f: &mut String, sql_fmt: surrealdb_types::SqlFormat) {
		self.to_sql_definition().fmt_sql(f, sql_fmt);
	}
}

#[revisioned(revision = 1)]
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
pub struct Permissions {
	pub(crate) select: Permission,
	pub(crate) create: Permission,
	pub(crate) update: Permission,
	pub(crate) delete: Permission,
}

impl Permissions {
	pub fn none() -> Self {
		Permissions {
			select: Permission::None,
			create: Permission::None,
			update: Permission::None,
			delete: Permission::None,
		}
	}

	pub(crate) fn to_sql_definition(&self) -> crate::sql::Permissions {
		self.clone().into()
	}

	/// Whether any of the select/create/update/delete clauses directly contains
	/// a data-modifying statement (GHSA-66r2-5gwj-gxm2).
	pub(crate) fn has_direct_write(&self) -> bool {
		self.select.has_direct_write()
			|| self.create.has_direct_write()
			|| self.update.has_direct_write()
			|| self.delete.has_direct_write()
	}
}

impl InfoStructure for Permissions {
	fn structure(self) -> Value {
		Value::from(map! {
			"select" => self.select.structure(),
			"create" => self.create.structure(),
			"update" => self.update.structure(),
			"delete" => self.delete.structure(),
		})
	}
}

#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum PermissionKind {
	Select,
	Create,
	Update,
	Delete,
}

impl PermissionKind {
	fn as_str(&self) -> &str {
		match self {
			PermissionKind::Select => "select",
			PermissionKind::Create => "create",
			PermissionKind::Update => "update",
			PermissionKind::Delete => "delete",
		}
	}
}

impl Display for PermissionKind {
	fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
		f.write_str(self.as_str())
	}
}