use arrow_array::RecordBatch;
use arrow_schema::SchemaRef;
use redis::aio::MultiplexedConnection;
use crate::{
convert::{response_to_batch, response_to_batch_auto},
error::Result,
};
#[derive(Clone)]
pub struct FalkorExecutor {
conn: MultiplexedConnection,
graph: String,
}
impl FalkorExecutor {
pub async fn connect(url: &str, graph: impl Into<String>) -> Result<Self> {
let client = redis::Client::open(url)?;
let conn = client.get_multiplexed_async_connection().await?;
Ok(Self {
conn,
graph: graph.into(),
})
}
pub async fn query(&mut self, cypher: &str, schema: &SchemaRef) -> Result<RecordBatch> {
let raw: redis::Value = redis::cmd("GRAPH.QUERY")
.arg(&self.graph)
.arg(cypher)
.query_async(&mut self.conn)
.await?;
response_to_batch(raw, schema)
}
pub async fn query_auto(&mut self, cypher: &str) -> Result<RecordBatch> {
let raw: redis::Value = redis::cmd("GRAPH.QUERY")
.arg(&self.graph)
.arg(cypher)
.query_async(&mut self.conn)
.await?;
response_to_batch_auto(raw)
}
pub async fn execute(&mut self, cypher: &str) -> Result<u64> {
let raw: redis::Value = redis::cmd("GRAPH.QUERY")
.arg(&self.graph)
.arg(cypher)
.query_async(&mut self.conn)
.await?;
Ok(parse_affected_count(raw))
}
pub fn graph(&self) -> &str {
&self.graph
}
}
fn parse_affected_count(response: redis::Value) -> u64 {
let outer = match response {
redis::Value::Array(v) => v,
_ => return 0,
};
let stats = match outer.last() {
Some(redis::Value::Array(s)) => s,
_ => return 0,
};
let mut total = 0u64;
for stat in stats {
if let redis::Value::BulkString(b) = stat {
let s = String::from_utf8_lossy(b);
if (s.contains("created:") || s.contains("deleted:"))
&& let Some(n) = s
.split(':')
.nth(1)
.and_then(|p| p.trim().parse::<u64>().ok())
{
total += n;
}
}
}
total
}