use serde_json::Value;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub enum GqlStatement {
LinearQuery(LinearQuery),
GraphQuery {
graph_name: String,
query: LinearQuery,
},
}
#[derive(Debug, Clone)]
pub struct LinearQuery {
pub clauses: Vec<QueryClause>,
}
#[derive(Debug, Clone)]
pub enum QueryClause {
Match(MatchClause),
Filter(FilterClause),
Return(ReturnClause),
With(WithClause),
OrderBy(OrderByClause),
Limit(LimitClause),
Offset(OffsetClause),
Insert(InsertClause),
Update(UpdateClause),
Delete(DeleteClause),
Set(SetClause),
Remove(RemoveClause),
}
#[derive(Debug, Clone)]
pub struct MatchClause {
pub optional: bool,
pub patterns: Vec<GraphPattern>,
}
#[derive(Debug, Clone)]
pub enum GraphPattern {
Node(NodePattern),
Path(PathPattern),
Relationship(RelationshipPattern),
}
#[derive(Debug, Clone)]
pub struct NodePattern {
pub variable: Option<String>,
pub labels: Vec<String>,
pub properties: Option<PropertyPattern>,
pub where_clause: Option<Box<Expression>>,
}
#[derive(Debug, Clone)]
pub struct RelationshipPattern {
pub variable: Option<String>,
pub rel_type: Option<String>,
pub properties: Option<PropertyPattern>,
pub direction: RelationshipDirection,
pub length: Option<PathLength>,
}
#[derive(Debug, Clone)]
pub struct PathPattern {
pub start: Box<NodePattern>,
pub relationships: Vec<(RelationshipPattern, Box<NodePattern>)>,
}
#[derive(Debug, Clone)]
pub struct PropertyPattern {
pub properties: HashMap<String, Expression>,
}
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum RelationshipDirection {
Outgoing,
Incoming,
Undirected,
}
#[derive(Debug, Clone)]
pub enum PathLength {
Exact(usize),
Range(Option<usize>, Option<usize>),
Variable,
}
#[derive(Debug, Clone)]
pub struct FilterClause {
pub condition: Expression,
}
#[derive(Debug, Clone)]
pub struct ReturnClause {
pub distinct: bool,
pub items: Vec<ReturnItem>,
}
#[derive(Debug, Clone)]
pub struct ReturnItem {
pub expression: Expression,
pub alias: Option<String>,
}
#[derive(Debug, Clone)]
pub struct WithClause {
pub items: Vec<ReturnItem>,
}
#[derive(Debug, Clone)]
pub struct OrderByClause {
pub items: Vec<OrderByItem>,
}
#[derive(Debug, Clone)]
pub struct OrderByItem {
pub expression: Expression,
pub direction: SortDirection,
}
#[derive(Debug, Clone)]
pub enum SortDirection {
Asc,
Desc,
}
#[derive(Debug, Clone)]
pub struct LimitClause {
pub count: Expression,
}
#[derive(Debug, Clone)]
pub struct OffsetClause {
pub count: Expression,
}
#[derive(Debug, Clone)]
pub struct InsertClause {
pub patterns: Vec<GraphPattern>,
}
#[derive(Debug, Clone)]
pub struct UpdateClause {
pub pattern: GraphPattern,
pub set_items: Vec<SetItem>,
}
#[derive(Debug, Clone)]
pub struct DeleteClause {
pub detach: bool,
pub expressions: Vec<Expression>,
}
#[derive(Debug, Clone)]
pub struct SetClause {
pub items: Vec<SetItem>,
}
#[derive(Debug, Clone)]
pub struct SetItem {
pub target: Expression,
pub value: Expression,
}
#[derive(Debug, Clone)]
pub struct RemoveClause {
pub items: Vec<RemoveItem>,
}
#[derive(Debug, Clone)]
pub enum RemoveItem {
Property(Expression),
Label(Expression, String),
}
#[derive(Debug, Clone)]
pub enum Expression {
Literal(Value),
Parameter(String),
Variable(String),
Property {
object: Box<Expression>,
property: String,
},
Binary {
left: Box<Expression>,
operator: BinaryOperator,
right: Box<Expression>,
},
Unary {
operator: UnaryOperator,
operand: Box<Expression>,
},
FunctionCall {
name: String,
args: Vec<Expression>,
},
List(Vec<Expression>),
ListAccess {
list: Box<Expression>,
index: Box<Expression>,
},
ListSlice {
list: Box<Expression>,
start: Option<Box<Expression>>,
end: Option<Box<Expression>>,
},
PathExpression(Box<PathPattern>),
Case {
when_clauses: Vec<(Expression, Expression)>,
else_clause: Option<Box<Expression>>,
},
Aggregate {
function: AggregateFunction,
expression: Option<Box<Expression>>,
distinct: bool,
},
}
#[derive(Debug, Clone)]
pub enum BinaryOperator {
Add,
Subtract,
Multiply,
Divide,
Modulo,
Equal,
NotEqual,
LessThan,
LessEqual,
GreaterThan,
GreaterEqual,
And,
Or,
Contains,
StartsWith,
EndsWith,
In,
}
#[derive(Debug, Clone)]
pub enum UnaryOperator {
Not,
Minus,
Plus,
}
#[derive(Debug, Clone)]
pub enum AggregateFunction {
Count,
Sum,
Avg,
Min,
Max,
Collect,
}
impl LinearQuery {
pub fn new() -> Self {
Self {
clauses: Vec::new(),
}
}
pub fn add_clause(&mut self, clause: QueryClause) {
self.clauses.push(clause);
}
pub fn match_clauses(&self) -> Vec<&MatchClause> {
self.clauses
.iter()
.filter_map(|c| {
if let QueryClause::Match(m) = c {
Some(m)
} else {
None
}
})
.collect()
}
pub fn return_clause(&self) -> Option<&ReturnClause> {
self.clauses.iter().find_map(|c| {
if let QueryClause::Return(r) = c {
Some(r)
} else {
None
}
})
}
pub fn filter_clauses(&self) -> Vec<&FilterClause> {
self.clauses
.iter()
.filter_map(|c| {
if let QueryClause::Filter(f) = c {
Some(f)
} else {
None
}
})
.collect()
}
}
impl NodePattern {
pub fn new(variable: Option<String>) -> Self {
Self {
variable,
labels: Vec::new(),
properties: None,
where_clause: None,
}
}
pub fn with_label(mut self, label: String) -> Self {
self.labels.push(label);
self
}
pub fn with_properties(mut self, properties: PropertyPattern) -> Self {
self.properties = Some(properties);
self
}
}
impl RelationshipPattern {
pub fn new(direction: RelationshipDirection) -> Self {
Self {
variable: None,
rel_type: None,
properties: None,
direction,
length: None,
}
}
pub fn with_type(mut self, rel_type: String) -> Self {
self.rel_type = Some(rel_type);
self
}
pub fn with_variable(mut self, variable: String) -> Self {
self.variable = Some(variable);
self
}
}
impl Expression {
pub fn literal(value: Value) -> Self {
Expression::Literal(value)
}
pub fn variable(name: String) -> Self {
Expression::Variable(name)
}
pub fn property(object: Expression, property: String) -> Self {
Expression::Property {
object: Box::new(object),
property,
}
}
pub fn binary(left: Expression, operator: BinaryOperator, right: Expression) -> Self {
Expression::Binary {
left: Box::new(left),
operator,
right: Box::new(right),
}
}
}
impl Default for LinearQuery {
fn default() -> Self {
Self::new()
}
}