use super::Graph;
use crate::utils::{escape_string, PropertyValue};
use crate::{Result, Value};
impl Graph {
pub fn has_node(&self, node_id: &str) -> Result<bool> {
let result = self
.connection()
.cypher_builder("MATCH (n {id: $id}) RETURN count(n) AS cnt")
.param("id", node_id)
.run()?;
if result.is_empty() {
return Ok(false);
}
let cnt: i64 = result[0].get("cnt").unwrap_or(0);
Ok(cnt > 0)
}
pub fn get_node(&self, node_id: &str) -> Result<Option<Value>> {
let result = self
.connection()
.cypher_builder("MATCH (n {id: $id}) RETURN n")
.param("id", node_id)
.run()?;
if result.is_empty() {
return Ok(None);
}
Ok(result[0].get_value("n").cloned())
}
pub fn upsert_node<I, K, V>(&self, node_id: &str, props: I, label: &str) -> Result<()>
where
I: IntoIterator<Item = (K, V)>,
K: AsRef<str>,
V: Into<PropertyValue>,
{
let props: Vec<(String, PropertyValue)> = props
.into_iter()
.map(|(k, v)| (k.as_ref().to_string(), v.into()))
.collect();
if self.has_node(node_id)? {
for (k, v) in props {
let query = format!(
"MATCH (n {{id: $id}}) SET n.{} = {} RETURN n",
k,
v.to_cypher()
);
self.connection()
.cypher_builder(&query)
.param("id", node_id)
.run()?;
}
} else {
let mut prop_parts = vec![format!("id: '{}'", escape_string(node_id))];
for (k, v) in props {
prop_parts.push(format!("{}: {}", k, v.to_cypher()));
}
let prop_str = prop_parts.join(", ");
let query = format!("CREATE (n:{} {{{}}})", label, prop_str);
self.connection().cypher(&query)?;
}
Ok(())
}
pub fn delete_node(&self, node_id: &str) -> Result<()> {
self.connection()
.cypher_builder("MATCH (n {id: $id}) DETACH DELETE n")
.param("id", node_id)
.run()?;
Ok(())
}
pub fn get_all_nodes(&self, label: Option<&str>) -> Result<Vec<Value>> {
let query = match label {
Some(l) => format!("MATCH (n:{}) RETURN n", l),
None => "MATCH (n) RETURN n".to_string(),
};
let result = self.connection().cypher(&query)?;
let mut nodes = Vec::new();
for row in result.iter() {
if let Some(n) = row.get_value("n") {
nodes.push(n.clone());
}
}
Ok(nodes)
}
}