pub mod ast;
mod builder;
pub mod error;
mod planner;
pub mod query;
pub use ast::{
BinaryOp, CaseExpr, Clause, CypherQuery, CypherValue, Expression, NodePattern, PathPattern,
RelDirection, RelPattern, RelationshipLength, ReturnItem, SetItem, SortDirection, SortItem,
UnaryOp, WhereExpr,
};
pub use error::CypherError;
pub use query::{MatchStrategy, Parameters, PetgraphCypher, QueryResult, ResultValue, Row};
use petgraph::Graph;
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq)]
pub struct NodeData {
pub variable: Option<String>,
pub labels: Vec<String>,
pub properties: HashMap<String, CypherValue>,
}
pub trait CypherProperties {
fn get(&self, name: &str) -> Option<&CypherValue>;
fn properties(&self) -> HashMap<String, CypherValue>;
}
pub trait CypherNode: CypherProperties {
fn has_label(&self, label: &str) -> bool;
fn labels(&self) -> Vec<String>;
fn from_cypher(
variable: Option<String>,
labels: Vec<String>,
properties: HashMap<String, CypherValue>,
) -> Self;
}
#[derive(Debug, Clone, PartialEq)]
pub struct EdgeData {
pub variable: Option<String>,
pub rel_type: Option<String>,
pub properties: HashMap<String, CypherValue>,
}
pub trait CypherEdge: CypherProperties {
fn has_rel_type(&self, rel_type: &str) -> bool;
fn rel_type(&self) -> Option<&str>;
fn from_cypher(
variable: Option<String>,
rel_type: Option<String>,
properties: HashMap<String, CypherValue>,
) -> Self;
}
impl CypherProperties for NodeData {
fn get(&self, name: &str) -> Option<&CypherValue> {
self.properties.get(name)
}
fn properties(&self) -> HashMap<String, CypherValue> {
self.properties.clone()
}
}
impl CypherNode for NodeData {
fn has_label(&self, label: &str) -> bool {
self.labels.iter().any(|node_label| node_label == label)
}
fn labels(&self) -> Vec<String> {
self.labels.clone()
}
fn from_cypher(
variable: Option<String>,
labels: Vec<String>,
properties: HashMap<String, CypherValue>,
) -> Self {
Self {
variable,
labels,
properties,
}
}
}
impl CypherProperties for EdgeData {
fn get(&self, name: &str) -> Option<&CypherValue> {
self.properties.get(name)
}
fn properties(&self) -> HashMap<String, CypherValue> {
self.properties.clone()
}
}
impl CypherEdge for EdgeData {
fn has_rel_type(&self, rel_type: &str) -> bool {
self.rel_type.as_deref() == Some(rel_type)
}
fn rel_type(&self) -> Option<&str> {
self.rel_type.as_deref()
}
fn from_cypher(
variable: Option<String>,
rel_type: Option<String>,
properties: HashMap<String, CypherValue>,
) -> Self {
Self {
variable,
rel_type,
properties,
}
}
}
pub fn parse_cypher(query: &str) -> Result<CypherQuery, CypherError> {
planner::plan_query(query)
}
pub fn build_graph_from_cypher_typed<N: CypherNode, E: CypherEdge>(
query: &str,
) -> Result<Graph<N, E>, CypherError> {
let ast = parse_cypher(query)?;
builder::build_graph(ast)
}
pub fn build_graph_from_cypher(query: &str) -> Result<Graph<NodeData, EdgeData>, CypherError> {
build_graph_from_cypher_typed(query)
}