cfg_core! {
use crate::EncryptionConfig;
}
use crate::{Database, Result};
use super::DbType;
pub struct Builder<T = ()> {
inner: T,
}
impl Builder<()> {
cfg_core! {
pub fn new_local(path: impl AsRef<std::path::Path>) -> Builder<Local> {
Builder {
inner: Local {
path: path.as_ref().to_path_buf(),
flags: crate::OpenFlags::default(),
encryption_config: None,
},
}
}
}
cfg_replication! {
pub fn new_remote_replica(
path: impl AsRef<std::path::Path>,
url: String,
auth_token: String,
) -> Builder<RemoteReplica> {
Builder {
inner: RemoteReplica {
path: path.as_ref().to_path_buf(),
remote: Remote {
url,
auth_token,
connector: None,
version: None,
},
encryption_config: None,
read_your_writes: true,
sync_interval: None,
http_request_callback: None,
namespace: None
},
}
}
pub fn new_local_replica(path: impl AsRef<std::path::Path>) -> Builder<LocalReplica> {
Builder {
inner: LocalReplica {
path: path.as_ref().to_path_buf(),
flags: crate::OpenFlags::default(),
remote: None,
encryption_config: None,
http_request_callback: None
},
}
}
}
cfg_remote! {
pub fn new_remote(url: String, auth_token: String) -> Builder<Remote> {
Builder {
inner: Remote {
url,
auth_token,
connector: None,
version: None,
},
}
}
}
}
cfg_replication_or_remote! {
pub struct Remote {
url: String,
auth_token: String,
connector: Option<crate::util::ConnectorService>,
version: Option<String>,
}
}
cfg_core! {
pub struct Local {
path: std::path::PathBuf,
flags: crate::OpenFlags,
encryption_config: Option<EncryptionConfig>,
}
impl Builder<Local> {
pub fn flags(mut self, flags: crate::OpenFlags) -> Builder<Local> {
self.inner.flags = flags;
self
}
pub fn encryption_config(
mut self,
encryption_config: EncryptionConfig,
) -> Builder<Local> {
self.inner.encryption_config = Some(encryption_config);
self
}
pub async fn build(self) -> Result<Database> {
let db = if self.inner.path == std::path::Path::new(":memory:") {
let db = crate::local::Database::open(":memory:", crate::OpenFlags::default())?;
Database {
db_type: DbType::Memory { db } ,
}
} else {
let path = self
.inner
.path
.to_str()
.ok_or(crate::Error::InvalidUTF8Path)?
.to_owned();
Database {
db_type: DbType::File {
path,
flags: self.inner.flags,
encryption_config: self.inner.encryption_config,
},
}
};
Ok(db)
}
}
}
cfg_replication! {
pub struct RemoteReplica {
path: std::path::PathBuf,
remote: Remote,
encryption_config: Option<EncryptionConfig>,
read_your_writes: bool,
sync_interval: Option<std::time::Duration>,
http_request_callback: Option<crate::util::HttpRequestCallback>,
namespace: Option<String>,
}
pub struct LocalReplica {
path: std::path::PathBuf,
flags: crate::OpenFlags,
remote: Option<Remote>,
encryption_config: Option<EncryptionConfig>,
http_request_callback: Option<crate::util::HttpRequestCallback>,
}
impl Builder<RemoteReplica> {
pub fn connector<C>(mut self, connector: C) -> Builder<RemoteReplica>
where
C: tower::Service<http::Uri> + Send + Clone + Sync + 'static,
C::Response: crate::util::Socket,
C::Future: Send + 'static,
C::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
{
self.inner.remote = self.inner.remote.connector(connector);
self
}
pub fn encryption_config(
mut self,
encryption_config: EncryptionConfig,
) -> Builder<RemoteReplica> {
self.inner.encryption_config = Some(encryption_config.into());
self
}
pub fn read_your_writes(mut self, read_your_writes: bool) -> Builder<RemoteReplica> {
self.inner.read_your_writes = read_your_writes;
self
}
pub fn sync_interval(mut self, duration: std::time::Duration) -> Builder<RemoteReplica> {
self.inner.sync_interval = Some(duration);
self
}
pub fn http_request_callback<F>(mut self, f: F) -> Builder<RemoteReplica>
where
F: Fn(&mut http::Request<()>) + Send + Sync + 'static
{
self.inner.http_request_callback = Some(std::sync::Arc::new(f));
self
}
pub fn namespace(mut self, namespace: impl Into<String>) -> Builder<RemoteReplica>
{
self.inner.namespace = Some(namespace.into());
self
}
#[doc(hidden)]
pub fn version(mut self, version: String) -> Builder<RemoteReplica> {
self.inner.remote = self.inner.remote.version(version);
self
}
pub async fn build(self) -> Result<Database> {
let RemoteReplica {
path,
remote:
Remote {
url,
auth_token,
connector,
version,
},
encryption_config,
read_your_writes,
sync_interval,
http_request_callback,
namespace
} = self.inner;
let connector = if let Some(connector) = connector {
connector
} else {
let https = super::connector()?;
use tower::ServiceExt;
let svc = https
.map_err(|e| e.into())
.map_response(|s| Box::new(s) as Box<dyn crate::util::Socket>);
crate::util::ConnectorService::new(svc)
};
let path = path.to_str().ok_or(crate::Error::InvalidUTF8Path)?.to_owned();
let db = crate::local::Database::open_http_sync_internal(
connector,
path,
url,
auth_token,
version,
read_your_writes,
encryption_config.clone(),
sync_interval,
http_request_callback,
namespace,
)
.await?;
Ok(Database {
db_type: DbType::Sync { db, encryption_config },
})
}
}
impl Builder<LocalReplica> {
pub fn flags(mut self, flags: crate::OpenFlags) -> Builder<LocalReplica> {
self.inner.flags = flags;
self
}
pub fn http_request_callback<F>(mut self, f: F) -> Builder<LocalReplica>
where
F: Fn(&mut http::Request<()>) + Send + Sync + 'static
{
self.inner.http_request_callback = Some(std::sync::Arc::new(f));
self
}
pub async fn build(self) -> Result<Database> {
let LocalReplica {
path,
flags,
remote,
encryption_config,
http_request_callback
} = self.inner;
let path = path.to_str().ok_or(crate::Error::InvalidUTF8Path)?.to_owned();
let db = if let Some(Remote {
url,
auth_token,
connector,
version,
}) = remote
{
let connector = if let Some(connector) = connector {
connector
} else {
let https = super::connector()?;
use tower::ServiceExt;
let svc = https
.map_err(|e| e.into())
.map_response(|s| Box::new(s) as Box<dyn crate::util::Socket>);
crate::util::ConnectorService::new(svc)
};
crate::local::Database::open_local_sync_remote_writes(
connector,
path,
url,
auth_token,
version,
flags,
encryption_config.clone(),
http_request_callback,
)
.await?
} else {
crate::local::Database::open_local_sync(path, flags, encryption_config.clone()).await?
};
Ok(Database {
db_type: DbType::Sync { db, encryption_config },
})
}
}
}
cfg_remote! {
impl Builder<Remote> {
pub fn connector<C>(mut self, connector: C) -> Builder<Remote>
where
C: tower::Service<http::Uri> + Send + Clone + Sync + 'static,
C::Response: crate::util::Socket,
C::Future: Send + 'static,
C::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
{
self.inner = self.inner.connector(connector);
self
}
#[doc(hidden)]
pub fn version(mut self, version: String) -> Builder<Remote> {
self.inner = self.inner.version(version);
self
}
pub async fn build(self) -> Result<Database> {
let Remote {
url,
auth_token,
connector,
version,
} = self.inner;
let connector = if let Some(connector) = connector {
connector
} else {
let https = super::connector()?;
use tower::ServiceExt;
let svc = https
.map_err(|e| e.into())
.map_response(|s| Box::new(s) as Box<dyn crate::util::Socket>);
crate::util::ConnectorService::new(svc)
};
Ok(Database {
db_type: DbType::Remote {
url,
auth_token,
connector,
version,
},
})
}
}
}
cfg_replication_or_remote! {
impl Remote {
fn connector<C>(mut self, connector: C) -> Remote
where
C: tower::Service<http::Uri> + Send + Clone + Sync + 'static,
C::Response: crate::util::Socket,
C::Future: Send + 'static,
C::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
{
use tower::ServiceExt;
let svc = connector
.map_err(|e| e.into())
.map_response(|s| Box::new(s) as Box<dyn crate::util::Socket>);
let svc = crate::util::ConnectorService::new(svc);
self.connector = Some(svc);
self
}
fn version(mut self, version: String) -> Remote {
self.version = Some(version);
self
}
}
}