use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use anyhow::Result;
use async_trait::async_trait;
use lazy_static::lazy_static;
use tokio::runtime::Runtime;
use crate::api::IDgraphClient;
use crate::client::lazy::ILazyChannel;
#[cfg(feature = "acl")]
use crate::client::AclClientType as AsyncAclClient;
use crate::client::ILazyClient;
use crate::stub::Stub;
#[cfg(feature = "acl")]
pub use crate::sync::client::acl::{
AclClient, AclClientType, TxnAcl, TxnAclBestEffort, TxnAclMutated, TxnAlcReadOnly,
};
#[cfg(all(feature = "acl", feature = "tls"))]
pub use crate::sync::client::acl::{
AclTlsClient, TxnAclTls, TxnAclTlsBestEffort, TxnAclTlsMutated, TxnAclTlsReadOnly,
};
pub use crate::sync::client::default::{Client, Txn, TxnBestEffort, TxnMutated, TxnReadOnly};
#[cfg(feature = "slash-ql")]
pub use crate::sync::client::slash_ql::{
SlashQl, SlashQlClient, TxnSlashQl, TxnSlashQlBestEffort, TxnSlashQlMutated, TxnSlashQlReadOnly,
};
#[cfg(feature = "tls")]
pub use crate::sync::client::tls::{
TlsClient, TxnTls, TxnTlsBestEffort, TxnTlsMutated, TxnTlsReadOnly,
};
use crate::sync::txn::{TxnBestEffortType, TxnMutatedType, TxnReadOnlyType, TxnType};
use crate::txn::TxnType as AsyncTxn;
use crate::{Operation, Payload, Version};
#[cfg(feature = "acl")]
mod acl;
mod default;
#[cfg(feature = "slash-ql")]
mod slash_ql;
#[cfg(feature = "tls")]
mod tls;
lazy_static! {
static ref RT: Arc<Runtime> = Arc::new(Runtime::new().expect("Tokio runtime"));
}
#[derive(Debug)]
pub struct ClientState {
rt: Arc<Runtime>,
}
impl ClientState {
pub fn new() -> Self {
Self {
rt: Arc::clone(&*RT),
}
}
}
impl Default for ClientState {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
pub trait IClient {
type AsyncClient;
type Client: ILazyClient<Channel = Self::Channel>;
type Channel: ILazyChannel;
fn client(&self) -> Self::Client;
fn clients(self) -> Vec<Self::Client>;
fn async_client_ref(&self) -> &Self::AsyncClient;
fn async_client(self) -> Self::AsyncClient;
fn new_txn(&self) -> AsyncTxn<Self::Client>;
#[cfg(feature = "acl")]
async fn login<T: Into<String> + Send + Sync>(
self,
user_id: T,
password: T,
) -> Result<AsyncAclClient<Self::Channel>>;
#[cfg(all(feature = "acl", feature = "dgraph-21-03"))]
async fn login_into_namespace<T: Into<String> + Send + Sync>(
self,
user_id: T,
password: T,
namespace: u64,
) -> Result<AsyncAclClient<Self::Channel>>;
}
pub struct ClientVariant<S: IClient> {
state: Box<ClientState>,
extra: S,
}
impl<S: IClient> Deref for ClientVariant<S> {
type Target = Box<ClientState>;
fn deref(&self) -> &Self::Target {
&self.state
}
}
impl<S: IClient> DerefMut for ClientVariant<S> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.state
}
}
impl<C: IClient> ClientVariant<C> {
fn any_stub(&self) -> Stub<C::Client> {
Stub::new(self.extra.client())
}
pub fn new_txn(&self) -> TxnType<C::Client> {
let rt = Arc::clone(&self.rt);
let async_txn = self.extra.new_txn();
TxnType::new(rt, async_txn)
}
pub fn new_read_only_txn(&self) -> TxnReadOnlyType<C::Client> {
self.new_txn().read_only()
}
pub fn new_mutated_txn(&self) -> TxnMutatedType<C::Client> {
self.new_txn().mutated()
}
pub fn new_best_effort_txn(&self) -> TxnBestEffortType<C::Client> {
self.new_read_only_txn().best_effort()
}
pub fn alter(&self, op: Operation) -> Result<Payload> {
let mut stub = self.any_stub();
self.rt.block_on(async move { stub.alter(op).await })
}
pub fn set_schema<S: Into<String>>(&self, schema: S) -> Result<Payload> {
let op = Operation {
schema: schema.into(),
..Default::default()
};
self.alter(op)
}
#[cfg(any(feature = "dgraph-1-1", feature = "dgraph-21-03"))]
pub fn set_schema_in_background<S: Into<String>>(&self, schema: S) -> Result<Payload> {
let op = Operation {
schema: schema.into(),
run_in_background: true,
..Default::default()
};
self.alter(op)
}
pub fn drop_all(&self) -> Result<Payload> {
let op = Operation {
drop_all: true,
..Default::default()
};
self.alter(op)
}
pub fn check_version(&self) -> Result<Version> {
let mut stub = self.any_stub();
self.rt.block_on(async move { stub.check_version().await })
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "acl")]
use crate::client::LazyChannel;
use super::*;
#[cfg(not(feature = "acl"))]
fn client() -> Client {
Client::new("http://127.0.0.1:19080").unwrap()
}
#[cfg(feature = "acl")]
fn client() -> AclClientType<LazyChannel> {
let default = Client::new("http://127.0.0.1:19080").unwrap();
default.login("groot", "password").unwrap()
}
#[test]
fn alter() {
let client = client();
let op = Operation {
schema: "name: string @index(exact) .".into(),
..Default::default()
};
let response = client.alter(op);
assert!(response.is_ok());
}
#[test]
fn drop_all() {
let client = client();
let response = client.drop_all();
assert!(response.is_ok());
}
#[test]
fn check_version() {
let client = client();
let response = client.check_version();
assert!(response.is_ok());
}
}