2022-05-03 20:20:36 +00:00
|
|
|
use super::tx::Transaction;
|
|
|
|
use crate::ctx::Context;
|
|
|
|
use crate::dbs::Attach;
|
|
|
|
use crate::dbs::Executor;
|
2023-06-20 22:50:26 +00:00
|
|
|
use crate::dbs::Notification;
|
2022-05-03 20:20:36 +00:00
|
|
|
use crate::dbs::Options;
|
|
|
|
use crate::dbs::Response;
|
|
|
|
use crate::dbs::Session;
|
|
|
|
use crate::dbs::Variables;
|
|
|
|
use crate::err::Error;
|
|
|
|
use crate::sql;
|
2022-06-20 11:26:27 +00:00
|
|
|
use crate::sql::Query;
|
|
|
|
use crate::sql::Value;
|
2023-06-20 22:50:26 +00:00
|
|
|
use channel::Receiver;
|
2022-05-15 19:38:46 +00:00
|
|
|
use channel::Sender;
|
2022-06-20 11:26:27 +00:00
|
|
|
use futures::lock::Mutex;
|
2023-03-29 18:16:18 +00:00
|
|
|
use std::fmt;
|
2022-06-20 11:26:27 +00:00
|
|
|
use std::sync::Arc;
|
2023-06-12 11:23:30 +00:00
|
|
|
use std::time::Duration;
|
2023-03-29 18:16:18 +00:00
|
|
|
use tracing::instrument;
|
2023-06-20 22:50:26 +00:00
|
|
|
use uuid::Uuid;
|
2022-05-03 20:20:36 +00:00
|
|
|
|
|
|
|
/// The underlying datastore instance which stores the dataset.
|
2022-12-07 19:30:29 +00:00
|
|
|
#[allow(dead_code)]
|
2022-05-03 20:20:36 +00:00
|
|
|
pub struct Datastore {
|
2023-07-05 21:26:13 +00:00
|
|
|
// The inner datastore type
|
|
|
|
inner: Inner,
|
|
|
|
// The unique id of this datastore, used in notifications
|
|
|
|
id: Uuid,
|
|
|
|
// Whether this datastore runs in strict mode by default
|
|
|
|
strict: bool,
|
|
|
|
// The maximum duration timeout for running multiple statements in a query
|
2023-06-12 11:23:30 +00:00
|
|
|
query_timeout: Option<Duration>,
|
2023-07-05 21:26:13 +00:00
|
|
|
// The maximum duration timeout for running multiple statements in a transaction
|
|
|
|
transaction_timeout: Option<Duration>,
|
|
|
|
// Whether this datastore enables live query notifications to subscribers
|
|
|
|
notification_channel: Option<(Sender<Notification>, Receiver<Notification>)>,
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
|
|
|
|
2022-05-06 22:09:49 +00:00
|
|
|
#[allow(clippy::large_enum_variant)]
|
2022-05-03 20:20:36 +00:00
|
|
|
pub(super) enum Inner {
|
2022-08-28 13:35:25 +00:00
|
|
|
#[cfg(feature = "kv-mem")]
|
2022-05-03 20:20:36 +00:00
|
|
|
Mem(super::mem::Datastore),
|
2022-08-28 13:35:25 +00:00
|
|
|
#[cfg(feature = "kv-rocksdb")]
|
|
|
|
RocksDB(super::rocksdb::Datastore),
|
2023-05-31 12:35:41 +00:00
|
|
|
#[cfg(feature = "kv-speedb")]
|
|
|
|
SpeeDB(super::speedb::Datastore),
|
2022-05-03 20:20:36 +00:00
|
|
|
#[cfg(feature = "kv-indxdb")]
|
2022-08-28 13:35:25 +00:00
|
|
|
IndxDB(super::indxdb::Datastore),
|
2022-05-03 20:20:36 +00:00
|
|
|
#[cfg(feature = "kv-tikv")]
|
|
|
|
TiKV(super::tikv::Datastore),
|
2022-08-15 18:35:41 +00:00
|
|
|
#[cfg(feature = "kv-fdb")]
|
2023-06-20 11:48:20 +00:00
|
|
|
FoundationDB(super::fdb::Datastore),
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
|
|
|
|
2023-03-29 18:16:18 +00:00
|
|
|
impl fmt::Display for Datastore {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2023-03-30 10:10:07 +00:00
|
|
|
#![allow(unused_variables)]
|
2023-03-29 18:16:18 +00:00
|
|
|
match &self.inner {
|
|
|
|
#[cfg(feature = "kv-mem")]
|
|
|
|
Inner::Mem(_) => write!(f, "memory"),
|
|
|
|
#[cfg(feature = "kv-rocksdb")]
|
|
|
|
Inner::RocksDB(_) => write!(f, "rocksdb"),
|
2023-05-31 12:35:41 +00:00
|
|
|
#[cfg(feature = "kv-speedb")]
|
|
|
|
Inner::SpeeDB(_) => write!(f, "speedb"),
|
2023-03-29 18:16:18 +00:00
|
|
|
#[cfg(feature = "kv-indxdb")]
|
2023-05-31 12:35:41 +00:00
|
|
|
Inner::IndxDB(_) => write!(f, "indxdb"),
|
2023-03-29 18:16:18 +00:00
|
|
|
#[cfg(feature = "kv-tikv")]
|
|
|
|
Inner::TiKV(_) => write!(f, "tikv"),
|
|
|
|
#[cfg(feature = "kv-fdb")]
|
2023-06-20 11:48:20 +00:00
|
|
|
Inner::FoundationDB(_) => write!(f, "fdb"),
|
2023-03-30 10:10:07 +00:00
|
|
|
#[allow(unreachable_patterns)]
|
|
|
|
_ => unreachable!(),
|
2023-03-29 18:16:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-03 20:20:36 +00:00
|
|
|
impl Datastore {
|
|
|
|
/// Creates a new datastore instance
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2022-12-30 08:23:19 +00:00
|
|
|
/// # use surrealdb::kvs::Datastore;
|
|
|
|
/// # use surrealdb::err::Error;
|
2022-05-04 09:11:51 +00:00
|
|
|
/// # #[tokio::main]
|
|
|
|
/// # async fn main() -> Result<(), Error> {
|
|
|
|
/// let ds = Datastore::new("memory").await?;
|
2022-05-03 20:20:36 +00:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Or to create a file-backed store:
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2022-12-30 08:23:19 +00:00
|
|
|
/// # use surrealdb::kvs::Datastore;
|
|
|
|
/// # use surrealdb::err::Error;
|
2022-05-04 09:11:51 +00:00
|
|
|
/// # #[tokio::main]
|
|
|
|
/// # async fn main() -> Result<(), Error> {
|
|
|
|
/// let ds = Datastore::new("file://temp.db").await?;
|
2022-05-03 20:20:36 +00:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Or to connect to a tikv-backed distributed store:
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2022-12-30 08:23:19 +00:00
|
|
|
/// # use surrealdb::kvs::Datastore;
|
|
|
|
/// # use surrealdb::err::Error;
|
2022-05-04 09:11:51 +00:00
|
|
|
/// # #[tokio::main]
|
|
|
|
/// # async fn main() -> Result<(), Error> {
|
|
|
|
/// let ds = Datastore::new("tikv://127.0.0.1:2379").await?;
|
2022-05-03 20:20:36 +00:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
pub async fn new(path: &str) -> Result<Datastore, Error> {
|
2023-06-12 11:23:30 +00:00
|
|
|
let inner = match path {
|
2022-05-03 20:20:36 +00:00
|
|
|
"memory" => {
|
2023-04-23 11:08:21 +00:00
|
|
|
#[cfg(feature = "kv-mem")]
|
|
|
|
{
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Starting kvs store in {}", path);
|
2023-06-12 11:23:30 +00:00
|
|
|
let v = super::mem::Datastore::new().await.map(Inner::Mem);
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Started kvs store in {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
v
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "kv-mem"))]
|
|
|
|
return Err(Error::Ds("Cannot connect to the `memory` storage engine as it is not enabled in this build of SurrealDB".to_owned()));
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
2022-08-28 13:35:25 +00:00
|
|
|
// Parse and initiate an File database
|
|
|
|
s if s.starts_with("file:") => {
|
2023-04-23 11:08:21 +00:00
|
|
|
#[cfg(feature = "kv-rocksdb")]
|
|
|
|
{
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Starting kvs store at {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
let s = s.trim_start_matches("file://");
|
|
|
|
let s = s.trim_start_matches("file:");
|
2023-06-12 11:23:30 +00:00
|
|
|
let v = super::rocksdb::Datastore::new(s).await.map(Inner::RocksDB);
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Started kvs store at {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
v
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "kv-rocksdb"))]
|
|
|
|
return Err(Error::Ds("Cannot connect to the `rocksdb` storage engine as it is not enabled in this build of SurrealDB".to_owned()));
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
2022-08-28 13:35:25 +00:00
|
|
|
// Parse and initiate an RocksDB database
|
|
|
|
s if s.starts_with("rocksdb:") => {
|
2023-04-23 11:08:21 +00:00
|
|
|
#[cfg(feature = "kv-rocksdb")]
|
|
|
|
{
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Starting kvs store at {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
let s = s.trim_start_matches("rocksdb://");
|
|
|
|
let s = s.trim_start_matches("rocksdb:");
|
2023-06-12 11:23:30 +00:00
|
|
|
let v = super::rocksdb::Datastore::new(s).await.map(Inner::RocksDB);
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Started kvs store at {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
v
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "kv-rocksdb"))]
|
|
|
|
return Err(Error::Ds("Cannot connect to the `rocksdb` storage engine as it is not enabled in this build of SurrealDB".to_owned()));
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
2023-05-31 12:35:41 +00:00
|
|
|
// Parse and initiate an SpeeDB database
|
|
|
|
s if s.starts_with("speedb:") => {
|
|
|
|
#[cfg(feature = "kv-speedb")]
|
|
|
|
{
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Starting kvs store at {}", path);
|
2023-05-31 12:35:41 +00:00
|
|
|
let s = s.trim_start_matches("speedb://");
|
|
|
|
let s = s.trim_start_matches("speedb:");
|
2023-06-12 11:23:30 +00:00
|
|
|
let v = super::speedb::Datastore::new(s).await.map(Inner::SpeeDB);
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Started kvs store at {}", path);
|
2023-05-31 12:35:41 +00:00
|
|
|
v
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "kv-speedb"))]
|
|
|
|
return Err(Error::Ds("Cannot connect to the `speedb` storage engine as it is not enabled in this build of SurrealDB".to_owned()));
|
|
|
|
}
|
2022-08-28 13:35:25 +00:00
|
|
|
// Parse and initiate an IndxDB database
|
|
|
|
s if s.starts_with("indxdb:") => {
|
2023-04-23 11:08:21 +00:00
|
|
|
#[cfg(feature = "kv-indxdb")]
|
|
|
|
{
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Starting kvs store at {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
let s = s.trim_start_matches("indxdb://");
|
|
|
|
let s = s.trim_start_matches("indxdb:");
|
2023-06-12 11:23:30 +00:00
|
|
|
let v = super::indxdb::Datastore::new(s).await.map(Inner::IndxDB);
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Started kvs store at {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
v
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "kv-indxdb"))]
|
|
|
|
return Err(Error::Ds("Cannot connect to the `indxdb` storage engine as it is not enabled in this build of SurrealDB".to_owned()));
|
2022-08-28 13:35:25 +00:00
|
|
|
}
|
|
|
|
// Parse and initiate a TiKV database
|
2022-05-03 20:20:36 +00:00
|
|
|
s if s.starts_with("tikv:") => {
|
2023-04-23 11:08:21 +00:00
|
|
|
#[cfg(feature = "kv-tikv")]
|
|
|
|
{
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Connecting to kvs store at {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
let s = s.trim_start_matches("tikv://");
|
|
|
|
let s = s.trim_start_matches("tikv:");
|
2023-06-12 11:23:30 +00:00
|
|
|
let v = super::tikv::Datastore::new(s).await.map(Inner::TiKV);
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Connected to kvs store at {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
v
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "kv-tikv"))]
|
|
|
|
return Err(Error::Ds("Cannot connect to the `tikv` storage engine as it is not enabled in this build of SurrealDB".to_owned()));
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
2022-08-28 13:35:25 +00:00
|
|
|
// Parse and initiate a FoundationDB database
|
2022-08-15 18:35:41 +00:00
|
|
|
s if s.starts_with("fdb:") => {
|
2023-04-23 11:08:21 +00:00
|
|
|
#[cfg(feature = "kv-fdb")]
|
|
|
|
{
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Connecting to kvs store at {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
let s = s.trim_start_matches("fdb://");
|
|
|
|
let s = s.trim_start_matches("fdb:");
|
2023-06-20 11:48:20 +00:00
|
|
|
let v = super::fdb::Datastore::new(s).await.map(Inner::FoundationDB);
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Connected to kvs store at {}", path);
|
2023-04-23 11:08:21 +00:00
|
|
|
v
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "kv-fdb"))]
|
|
|
|
return Err(Error::Ds("Cannot connect to the `foundationdb` storage engine as it is not enabled in this build of SurrealDB".to_owned()));
|
2022-08-15 18:35:41 +00:00
|
|
|
}
|
2022-05-03 20:20:36 +00:00
|
|
|
// The datastore path is not valid
|
2022-12-07 19:30:29 +00:00
|
|
|
_ => {
|
2023-07-04 21:02:10 +00:00
|
|
|
info!("Unable to load the specified datastore {}", path);
|
2022-12-07 19:30:29 +00:00
|
|
|
Err(Error::Ds("Unable to load the specified datastore".into()))
|
|
|
|
}
|
2023-06-12 11:23:30 +00:00
|
|
|
};
|
2023-07-05 21:26:13 +00:00
|
|
|
// Set the properties on the datastore
|
2023-06-12 11:23:30 +00:00
|
|
|
inner.map(|inner| Self {
|
2023-07-05 21:26:13 +00:00
|
|
|
id: Uuid::default(),
|
2023-06-12 11:23:30 +00:00
|
|
|
inner,
|
2023-07-05 21:26:13 +00:00
|
|
|
strict: false,
|
2023-06-12 11:23:30 +00:00
|
|
|
query_timeout: None,
|
2023-07-05 21:26:13 +00:00
|
|
|
transaction_timeout: None,
|
|
|
|
notification_channel: None,
|
2023-06-12 11:23:30 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-07-05 21:26:13 +00:00
|
|
|
/// Specify whether this Datastore should run in strict mode
|
|
|
|
pub fn with_strict_mode(mut self, strict: bool) -> Self {
|
|
|
|
self.strict = strict;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Specify whether this datastore should enable live query notifications
|
|
|
|
pub fn with_notifications(mut self) -> Self {
|
|
|
|
self.notification_channel = Some(channel::bounded(100));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set a global query timeout for this Datastore
|
|
|
|
pub fn with_query_timeout(mut self, duration: Option<Duration>) -> Self {
|
2023-06-12 11:23:30 +00:00
|
|
|
self.query_timeout = duration;
|
|
|
|
self
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
2022-05-10 07:36:48 +00:00
|
|
|
|
2023-07-05 21:26:13 +00:00
|
|
|
/// Set a global transaction timeout for this Datastore
|
|
|
|
pub fn with_transaction_timeout(mut self, duration: Option<Duration>) -> Self {
|
|
|
|
self.transaction_timeout = duration;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2023-06-20 22:50:26 +00:00
|
|
|
// Adds entries to the KV store indicating membership information
|
|
|
|
pub async fn register_membership(&self) -> Result<(), Error> {
|
|
|
|
let mut tx = self.transaction(true, false).await?;
|
2023-07-05 21:26:13 +00:00
|
|
|
tx.set_cl(self.id).await?;
|
|
|
|
tx.set_hb(self.id).await?;
|
2023-06-20 22:50:26 +00:00
|
|
|
tx.commit().await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Creates a heartbeat entry for the member indicating to the cluster
|
|
|
|
// that the node is alive
|
|
|
|
pub async fn heartbeat(&self) -> Result<(), Error> {
|
|
|
|
let mut tx = self.transaction(true, false).await?;
|
2023-07-05 21:26:13 +00:00
|
|
|
tx.set_hb(self.id).await?;
|
2023-06-20 22:50:26 +00:00
|
|
|
tx.commit().await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-05-03 23:38:16 +00:00
|
|
|
/// Create a new transaction on this datastore
|
2022-08-28 12:18:12 +00:00
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2022-12-30 08:23:19 +00:00
|
|
|
/// use surrealdb::kvs::Datastore;
|
|
|
|
/// use surrealdb::err::Error;
|
2022-08-28 12:18:12 +00:00
|
|
|
///
|
|
|
|
/// #[tokio::main]
|
|
|
|
/// async fn main() -> Result<(), Error> {
|
|
|
|
/// let ds = Datastore::new("file://database.db").await?;
|
|
|
|
/// let mut tx = ds.transaction(true, false).await?;
|
|
|
|
/// tx.cancel().await?;
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// ```
|
2022-05-03 20:20:36 +00:00
|
|
|
pub async fn transaction(&self, write: bool, lock: bool) -> Result<Transaction, Error> {
|
2022-12-07 19:30:29 +00:00
|
|
|
#![allow(unused_variables)]
|
2023-04-14 11:43:25 +00:00
|
|
|
let inner = match &self.inner {
|
2022-08-28 13:35:25 +00:00
|
|
|
#[cfg(feature = "kv-mem")]
|
2022-05-03 20:20:36 +00:00
|
|
|
Inner::Mem(v) => {
|
|
|
|
let tx = v.transaction(write, lock).await?;
|
2023-04-14 11:43:25 +00:00
|
|
|
super::tx::Inner::Mem(tx)
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
2022-08-28 13:35:25 +00:00
|
|
|
#[cfg(feature = "kv-rocksdb")]
|
|
|
|
Inner::RocksDB(v) => {
|
2022-05-03 20:20:36 +00:00
|
|
|
let tx = v.transaction(write, lock).await?;
|
2023-04-14 11:43:25 +00:00
|
|
|
super::tx::Inner::RocksDB(tx)
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
2023-05-31 12:35:41 +00:00
|
|
|
#[cfg(feature = "kv-speedb")]
|
|
|
|
Inner::SpeeDB(v) => {
|
|
|
|
let tx = v.transaction(write, lock).await?;
|
|
|
|
super::tx::Inner::SpeeDB(tx)
|
|
|
|
}
|
2022-08-28 13:35:25 +00:00
|
|
|
#[cfg(feature = "kv-indxdb")]
|
|
|
|
Inner::IndxDB(v) => {
|
2022-05-03 20:20:36 +00:00
|
|
|
let tx = v.transaction(write, lock).await?;
|
2023-04-14 11:43:25 +00:00
|
|
|
super::tx::Inner::IndxDB(tx)
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
|
|
|
#[cfg(feature = "kv-tikv")]
|
|
|
|
Inner::TiKV(v) => {
|
|
|
|
let tx = v.transaction(write, lock).await?;
|
2023-04-14 11:43:25 +00:00
|
|
|
super::tx::Inner::TiKV(tx)
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
2022-08-15 18:35:41 +00:00
|
|
|
#[cfg(feature = "kv-fdb")]
|
2023-06-20 11:48:20 +00:00
|
|
|
Inner::FoundationDB(v) => {
|
2022-08-15 18:35:41 +00:00
|
|
|
let tx = v.transaction(write, lock).await?;
|
2023-06-20 11:48:20 +00:00
|
|
|
super::tx::Inner::FoundationDB(tx)
|
2022-08-15 18:35:41 +00:00
|
|
|
}
|
2022-12-07 19:30:29 +00:00
|
|
|
#[allow(unreachable_patterns)]
|
|
|
|
_ => unreachable!(),
|
2023-04-14 11:43:25 +00:00
|
|
|
};
|
|
|
|
|
2023-04-17 14:39:37 +00:00
|
|
|
#[allow(unreachable_code)]
|
2023-04-14 11:43:25 +00:00
|
|
|
Ok(Transaction {
|
|
|
|
inner,
|
|
|
|
cache: super::cache::Cache::default(),
|
|
|
|
})
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
2022-05-10 07:36:48 +00:00
|
|
|
|
2022-05-03 23:38:16 +00:00
|
|
|
/// Parse and execute an SQL query
|
2022-08-28 12:18:12 +00:00
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2022-12-30 08:23:19 +00:00
|
|
|
/// use surrealdb::kvs::Datastore;
|
|
|
|
/// use surrealdb::err::Error;
|
|
|
|
/// use surrealdb::dbs::Session;
|
2022-08-28 12:18:12 +00:00
|
|
|
///
|
|
|
|
/// #[tokio::main]
|
|
|
|
/// async fn main() -> Result<(), Error> {
|
|
|
|
/// let ds = Datastore::new("memory").await?;
|
|
|
|
/// let ses = Session::for_kv();
|
|
|
|
/// let ast = "USE NS test DB test; SELECT * FROM person;";
|
2023-07-05 21:26:13 +00:00
|
|
|
/// let res = ds.execute(ast, &ses, None).await?;
|
2022-08-28 12:18:12 +00:00
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// ```
|
2023-03-29 18:16:18 +00:00
|
|
|
#[instrument(skip_all)]
|
2022-05-03 20:20:36 +00:00
|
|
|
pub async fn execute(
|
|
|
|
&self,
|
|
|
|
txt: &str,
|
|
|
|
sess: &Session,
|
|
|
|
vars: Variables,
|
|
|
|
) -> Result<Vec<Response>, Error> {
|
|
|
|
// Parse the SQL query text
|
|
|
|
let ast = sql::parse(txt)?;
|
2023-06-19 22:35:08 +00:00
|
|
|
// Process the AST
|
2023-07-05 21:26:13 +00:00
|
|
|
self.process(ast, sess, vars).await
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|
2022-05-10 07:36:48 +00:00
|
|
|
|
2022-05-03 23:38:16 +00:00
|
|
|
/// Execute a pre-parsed SQL query
|
2022-08-28 12:18:12 +00:00
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2022-12-30 08:23:19 +00:00
|
|
|
/// use surrealdb::kvs::Datastore;
|
|
|
|
/// use surrealdb::err::Error;
|
|
|
|
/// use surrealdb::dbs::Session;
|
2022-08-28 12:18:12 +00:00
|
|
|
/// use surrealdb::sql::parse;
|
|
|
|
///
|
|
|
|
/// #[tokio::main]
|
|
|
|
/// async fn main() -> Result<(), Error> {
|
|
|
|
/// let ds = Datastore::new("memory").await?;
|
|
|
|
/// let ses = Session::for_kv();
|
|
|
|
/// let ast = parse("USE NS test DB test; SELECT * FROM person;")?;
|
2023-07-05 21:26:13 +00:00
|
|
|
/// let res = ds.process(ast, &ses, None).await?;
|
2022-08-28 12:18:12 +00:00
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// ```
|
2023-03-29 18:16:18 +00:00
|
|
|
#[instrument(skip_all)]
|
2022-05-03 20:20:36 +00:00
|
|
|
pub async fn process(
|
|
|
|
&self,
|
|
|
|
ast: Query,
|
|
|
|
sess: &Session,
|
|
|
|
vars: Variables,
|
|
|
|
) -> Result<Vec<Response>, Error> {
|
|
|
|
// Create a new query options
|
2023-07-05 21:26:13 +00:00
|
|
|
let opt = Options::default()
|
|
|
|
.with_id(self.id)
|
|
|
|
.with_ns(sess.ns())
|
|
|
|
.with_db(sess.db())
|
|
|
|
.with_live(sess.live())
|
|
|
|
.with_auth(sess.au.clone())
|
|
|
|
.with_strict(self.strict);
|
2022-05-03 20:20:36 +00:00
|
|
|
// Create a new query executor
|
|
|
|
let mut exe = Executor::new(self);
|
|
|
|
// Create a default context
|
2023-06-12 11:23:30 +00:00
|
|
|
let mut ctx = Context::default();
|
|
|
|
// Set the global query timeout
|
|
|
|
if let Some(timeout) = self.query_timeout {
|
|
|
|
ctx.add_timeout(timeout);
|
|
|
|
}
|
2023-07-05 21:26:13 +00:00
|
|
|
// Setup the notification channel
|
|
|
|
if let Some(channel) = &self.notification_channel {
|
|
|
|
ctx.add_notifications(Some(&channel.0));
|
|
|
|
}
|
2022-05-03 20:20:36 +00:00
|
|
|
// Start an execution context
|
|
|
|
let ctx = sess.context(ctx);
|
|
|
|
// Store the query variables
|
2022-11-01 23:55:33 +00:00
|
|
|
let ctx = vars.attach(ctx)?;
|
2022-06-27 16:01:39 +00:00
|
|
|
// Process all statements
|
2022-05-03 20:20:36 +00:00
|
|
|
exe.execute(ctx, opt, ast).await
|
|
|
|
}
|
2022-05-10 07:36:48 +00:00
|
|
|
|
2022-08-28 12:18:12 +00:00
|
|
|
/// Ensure a SQL [`Value`] is fully computed
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2022-12-30 08:23:19 +00:00
|
|
|
/// use surrealdb::kvs::Datastore;
|
|
|
|
/// use surrealdb::err::Error;
|
|
|
|
/// use surrealdb::dbs::Session;
|
2022-10-31 23:12:41 +00:00
|
|
|
/// use surrealdb::sql::Future;
|
2022-08-28 12:18:12 +00:00
|
|
|
/// use surrealdb::sql::Value;
|
|
|
|
///
|
|
|
|
/// #[tokio::main]
|
|
|
|
/// async fn main() -> Result<(), Error> {
|
|
|
|
/// let ds = Datastore::new("memory").await?;
|
|
|
|
/// let ses = Session::for_kv();
|
2023-04-29 15:58:22 +00:00
|
|
|
/// let val = Value::Future(Box::new(Future::from(Value::Bool(true))));
|
2023-07-05 21:26:13 +00:00
|
|
|
/// let res = ds.compute(val, &ses, None).await?;
|
2022-08-28 12:18:12 +00:00
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// ```
|
2023-03-29 18:16:18 +00:00
|
|
|
#[instrument(skip_all)]
|
2022-06-20 11:26:27 +00:00
|
|
|
pub async fn compute(
|
|
|
|
&self,
|
|
|
|
val: Value,
|
|
|
|
sess: &Session,
|
|
|
|
vars: Variables,
|
|
|
|
) -> Result<Value, Error> {
|
2023-07-05 21:26:13 +00:00
|
|
|
// Create a new query options
|
|
|
|
let opt = Options::default()
|
|
|
|
.with_id(self.id)
|
|
|
|
.with_ns(sess.ns())
|
|
|
|
.with_db(sess.db())
|
|
|
|
.with_live(sess.live())
|
|
|
|
.with_auth(sess.au.clone())
|
|
|
|
.with_strict(self.strict);
|
2022-06-20 11:26:27 +00:00
|
|
|
// Start a new transaction
|
|
|
|
let txn = self.transaction(val.writeable(), false).await?;
|
|
|
|
//
|
|
|
|
let txn = Arc::new(Mutex::new(txn));
|
|
|
|
// Create a default context
|
2023-06-12 11:23:30 +00:00
|
|
|
let mut ctx = Context::default();
|
|
|
|
// Set the global query timeout
|
|
|
|
if let Some(timeout) = self.query_timeout {
|
|
|
|
ctx.add_timeout(timeout);
|
|
|
|
}
|
2023-07-05 21:26:13 +00:00
|
|
|
// Setup the notification channel
|
|
|
|
if let Some(channel) = &self.notification_channel {
|
|
|
|
ctx.add_notifications(Some(&channel.0));
|
|
|
|
}
|
2022-06-20 11:26:27 +00:00
|
|
|
// Start an execution context
|
|
|
|
let ctx = sess.context(ctx);
|
|
|
|
// Store the query variables
|
2022-11-01 23:55:33 +00:00
|
|
|
let ctx = vars.attach(ctx)?;
|
2022-06-20 11:26:27 +00:00
|
|
|
// Compute the value
|
2023-07-06 14:57:42 +00:00
|
|
|
let res = val.compute(&ctx, &opt, &txn, None).await?;
|
2022-06-20 11:26:27 +00:00
|
|
|
// Store any data
|
|
|
|
match val.writeable() {
|
|
|
|
true => txn.lock().await.commit().await?,
|
|
|
|
false => txn.lock().await.cancel().await?,
|
|
|
|
};
|
|
|
|
// Return result
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
|
2023-06-20 22:50:26 +00:00
|
|
|
/// Subscribe to live notifications
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// use surrealdb::kvs::Datastore;
|
|
|
|
/// use surrealdb::err::Error;
|
|
|
|
/// use surrealdb::dbs::Session;
|
|
|
|
///
|
|
|
|
/// #[tokio::main]
|
|
|
|
/// async fn main() -> Result<(), Error> {
|
2023-07-05 21:26:13 +00:00
|
|
|
/// let ds = Datastore::new("memory").await?.with_notifications();
|
2023-06-20 22:50:26 +00:00
|
|
|
/// let ses = Session::for_kv();
|
2023-07-05 21:26:13 +00:00
|
|
|
/// if let Some(channel) = ds.notifications() {
|
|
|
|
/// while let Ok(v) = channel.recv().await {
|
|
|
|
/// println!("Received notification: {v}");
|
|
|
|
/// }
|
|
|
|
/// }
|
2023-06-20 22:50:26 +00:00
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
#[instrument(skip_all)]
|
2023-07-05 21:26:13 +00:00
|
|
|
pub fn notifications(&self) -> Option<Receiver<Notification>> {
|
|
|
|
self.notification_channel.as_ref().map(|v| v.1.clone())
|
2023-06-20 22:50:26 +00:00
|
|
|
}
|
|
|
|
|
2022-05-10 07:36:48 +00:00
|
|
|
/// Performs a full database export as SQL
|
2023-03-29 18:16:18 +00:00
|
|
|
#[instrument(skip(self, chn))]
|
2022-05-15 19:38:46 +00:00
|
|
|
pub async fn export(&self, ns: String, db: String, chn: Sender<Vec<u8>>) -> Result<(), Error> {
|
2022-05-10 07:36:48 +00:00
|
|
|
// Start a new transaction
|
|
|
|
let mut txn = self.transaction(false, false).await?;
|
2022-05-15 19:38:46 +00:00
|
|
|
// Process the export
|
|
|
|
txn.export(&ns, &db, chn).await?;
|
2022-08-21 12:13:38 +00:00
|
|
|
// Everything ok
|
2022-05-15 19:38:46 +00:00
|
|
|
Ok(())
|
2022-05-10 07:36:48 +00:00
|
|
|
}
|
2022-05-03 20:20:36 +00:00
|
|
|
}
|