use std::collections::HashMap;
use std::net::SocketAddr;
use crate::error::BoltError;
use crate::types::{BoltDict, BoltValue};
use super::connection::BoltConnection;
pub struct BoltSession {
conn: BoltConnection,
}
impl BoltSession {
pub async fn connect(addr: SocketAddr) -> Result<Self, BoltError> {
let mut conn = BoltConnection::connect(addr).await?;
let extra = BoltDict::from([(
"user_agent".to_string(),
BoltValue::String("boltr-client/0.1".to_string()),
)]);
conn.hello(extra).await?;
conn.logon("none", None, None).await?;
Ok(Self { conn })
}
pub async fn connect_basic(
addr: SocketAddr,
username: &str,
password: &str,
) -> Result<Self, BoltError> {
let mut conn = BoltConnection::connect(addr).await?;
let extra = BoltDict::from([(
"user_agent".to_string(),
BoltValue::String("boltr-client/0.1".to_string()),
)]);
conn.hello(extra).await?;
conn.logon("basic", Some(username), Some(password)).await?;
Ok(Self { conn })
}
pub fn version(&self) -> (u8, u8) {
self.conn.version()
}
pub async fn run(&mut self, query: &str) -> Result<QueryResult, BoltError> {
self.run_with_params(query, HashMap::new(), BoltDict::new())
.await
}
pub async fn run_with_params(
&mut self,
query: &str,
params: HashMap<String, BoltValue>,
extra: BoltDict,
) -> Result<QueryResult, BoltError> {
let run_meta = self.conn.run(query, params, extra).await?;
let columns: Vec<String> = run_meta
.get("fields")
.and_then(|v| {
if let BoltValue::List(items) = v {
Some(
items
.iter()
.filter_map(|item| item.as_str().map(String::from))
.collect(),
)
} else {
None
}
})
.unwrap_or_default();
let (records, summary) = self.conn.pull_all().await?;
Ok(QueryResult {
columns,
records,
summary,
})
}
pub async fn begin(&mut self) -> Result<(), BoltError> {
self.conn.begin(BoltDict::new()).await
}
pub async fn commit(&mut self) -> Result<BoltDict, BoltError> {
self.conn.commit().await
}
pub async fn rollback(&mut self) -> Result<BoltDict, BoltError> {
self.conn.rollback().await
}
pub async fn discard(&mut self) -> Result<(), BoltError> {
self.conn.discard_all().await
}
pub async fn reset(&mut self) -> Result<(), BoltError> {
self.conn.reset().await
}
pub async fn close(mut self) -> Result<(), BoltError> {
self.conn.goodbye().await
}
pub fn connection(&mut self) -> &mut BoltConnection {
&mut self.conn
}
}
#[derive(Debug)]
pub struct QueryResult {
pub columns: Vec<String>,
pub records: Vec<Vec<BoltValue>>,
pub summary: BoltDict,
}