use crate::syn::token::Span;
#[derive(Clone, Debug, PartialEq)]
pub struct GqlQuery {
pub program: LinearQuery,
}
#[derive(Clone, Debug, PartialEq)]
pub struct LinearQuery {
pub steps: Vec<GqlStep>,
pub ret: Option<ReturnClause>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub enum GqlStep {
Read(MatchItem),
Mutate(MutationStatement),
}
#[derive(Clone, Debug, PartialEq)]
pub enum MutationStatement {
Insert(InsertStatement),
Set(SetStatement),
Remove(RemoveStatement),
Delete(DeleteStatement),
}
#[derive(Clone, Debug, PartialEq)]
pub struct SetStatement {
pub items: Vec<SetItem>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub enum SetItem {
Property {
var: Ident,
prop: Ident,
value: GqlExpr,
span: Span,
},
AllProperties {
var: Ident,
props: Vec<(Ident, GqlExpr)>,
span: Span,
},
Label {
var: Ident,
label: Ident,
span: Span,
},
}
#[derive(Clone, Debug, PartialEq)]
pub struct RemoveStatement {
pub items: Vec<RemoveItem>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub enum RemoveItem {
Property {
var: Ident,
prop: Ident,
span: Span,
},
Label {
var: Ident,
label: Ident,
span: Span,
},
}
#[derive(Clone, Debug, PartialEq)]
pub struct DeleteStatement {
pub detach: DetachMode,
pub items: Vec<GqlExpr>,
pub span: Span,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum DetachMode {
Detach,
NoDetach,
}
#[derive(Clone, Debug, PartialEq)]
pub struct InsertStatement {
pub paths: Vec<InsertPath>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub struct InsertPath {
pub start: InsertNode,
pub steps: Vec<(InsertEdge, InsertNode)>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub struct InsertNode {
pub var: Option<Ident>,
pub label: Option<Ident>,
pub props: Vec<(Ident, GqlExpr)>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub struct InsertEdge {
pub var: Option<Ident>,
pub label: Option<Ident>,
pub direction: InsertEdgeDir,
pub props: Vec<(Ident, GqlExpr)>,
pub span: Span,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum InsertEdgeDir {
Left,
Right,
}
#[derive(Clone, Debug, PartialEq)]
pub enum MatchItem {
Match(MatchClause),
Optional(OptionalBlock),
}
#[derive(Clone, Debug, PartialEq)]
pub struct OptionalBlock {
pub items: Vec<MatchItem>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub struct MatchClause {
pub patterns: Vec<PathPattern>,
pub where_clause: Option<GqlExpr>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PathPattern {
pub path_var: Option<Ident>,
pub prefix: Option<PathPatternPrefix>,
pub start: NodePattern,
pub steps: Vec<PathStep>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PathPatternPrefix {
pub kind: PathSearchKind,
pub mode: Option<PathMode>,
pub span: Span,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum PathSearchKind {
All,
Any {
count: Option<u32>,
},
AllShortest,
AnyShortest,
ShortestCounted {
count: u32,
},
ShortestGroups {
count: Option<u32>,
},
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum PathMode {
Walk,
Trail,
Simple,
Acyclic,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PathStep {
pub edge: EdgePattern,
pub node: NodePattern,
}
#[derive(Clone, Debug, PartialEq)]
pub struct NodePattern {
pub var: Option<Ident>,
pub label: Option<LabelExpr>,
pub predicate: Option<ElementPredicate>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub enum ElementPredicate {
Where(GqlExpr),
Props(Vec<(Ident, GqlExpr)>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct EdgePattern {
pub var: Option<Ident>,
pub label: Option<LabelExpr>,
pub direction: EdgeDirection,
pub predicate: Option<ElementPredicate>,
pub quantifier: Option<Quantifier>,
pub span: Span,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum EdgeDirection {
Left,
Undirected,
Right,
LeftOrUndirected,
UndirectedOrRight,
LeftOrRight,
Any,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Quantifier {
pub kind: QuantifierKind,
pub span: Span,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum QuantifierKind {
Star,
Plus,
Question,
Fixed(u32),
Range(Option<u32>, Option<u32>),
}
#[derive(Clone, Debug, PartialEq)]
pub enum LabelExpr {
Name(Ident),
Wildcard(Span),
Negation(Box<LabelExpr>, Span),
Conjunction(Box<LabelExpr>, Box<LabelExpr>, Span),
Disjunction(Box<LabelExpr>, Box<LabelExpr>, Span),
}
impl LabelExpr {
pub fn span(&self) -> Span {
match self {
LabelExpr::Name(ident) => ident.span,
LabelExpr::Wildcard(span) => *span,
LabelExpr::Negation(_, span)
| LabelExpr::Conjunction(_, _, span)
| LabelExpr::Disjunction(_, _, span) => *span,
}
}
fn has_children(&self) -> bool {
matches!(
self,
LabelExpr::Negation(..) | LabelExpr::Conjunction(..) | LabelExpr::Disjunction(..)
)
}
fn take_children(&mut self, stack: &mut Vec<LabelExpr>) {
fn take(child: &mut Box<LabelExpr>, stack: &mut Vec<LabelExpr>) {
let child = std::mem::replace(&mut **child, LabelExpr::Wildcard(Span::empty()));
if child.has_children() {
stack.push(child);
}
}
match self {
LabelExpr::Name(_) | LabelExpr::Wildcard(_) => {}
LabelExpr::Negation(child, _) => take(child, stack),
LabelExpr::Conjunction(left, right, _) | LabelExpr::Disjunction(left, right, _) => {
take(left, stack);
take(right, stack);
}
}
}
}
impl Drop for LabelExpr {
fn drop(&mut self) {
if !self.has_children() {
return;
}
let mut stack = Vec::new();
self.take_children(&mut stack);
while let Some(mut expr) = stack.pop() {
expr.take_children(&mut stack);
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ReturnClause {
pub quantifier: Option<SetQuantifier>,
pub items: ReturnItems,
pub group_by: Vec<GqlGroupItem>,
pub order_by: Vec<OrderItem>,
pub skip: Option<GqlExpr>,
pub limit: Option<GqlExpr>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub struct GqlGroupItem {
pub expr: GqlExpr,
pub span: Span,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum SetQuantifier {
Distinct,
All,
}
#[derive(Clone, Debug, PartialEq)]
pub enum ReturnItems {
Star,
Items(Vec<ReturnItem>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct ReturnItem {
pub expr: GqlExpr,
pub alias: Option<Ident>,
pub text: String,
}
#[derive(Clone, Debug, PartialEq)]
pub struct OrderItem {
pub expr: GqlExpr,
pub ascending: Option<bool>,
pub nulls_first: Option<bool>,
pub span: Span,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Ident {
pub name: String,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub enum GqlExpr {
Literal(GqlLiteral, Span),
Param {
name: String,
span: Span,
},
Variable(Ident),
Property(Box<GqlExpr>, Ident, Span),
Unary {
op: UnaryOp,
expr: Box<GqlExpr>,
span: Span,
},
Binary {
left: Box<GqlExpr>,
op: BinaryOp,
right: Box<GqlExpr>,
span: Span,
},
IsBool {
expr: Box<GqlExpr>,
value: TruthValue,
negated: bool,
span: Span,
},
IsNull {
expr: Box<GqlExpr>,
negated: bool,
span: Span,
},
FunctionCall {
name: Ident,
quantifier: Option<SetQuantifier>,
star: Option<Span>,
args: Vec<GqlExpr>,
span: Span,
},
List(Vec<GqlExpr>, Span),
Map(Vec<(Ident, GqlExpr)>, Span),
}
impl GqlExpr {
pub fn span(&self) -> Span {
match self {
GqlExpr::Literal(_, span) => *span,
GqlExpr::Param {
span,
..
} => *span,
GqlExpr::Variable(ident) => ident.span,
GqlExpr::Property(_, _, span) => *span,
GqlExpr::Unary {
span,
..
} => *span,
GqlExpr::Binary {
span,
..
} => *span,
GqlExpr::IsBool {
span,
..
} => *span,
GqlExpr::IsNull {
span,
..
} => *span,
GqlExpr::FunctionCall {
span,
..
} => *span,
GqlExpr::List(_, span) => *span,
GqlExpr::Map(_, span) => *span,
}
}
fn has_children(&self) -> bool {
match self {
GqlExpr::Literal(..)
| GqlExpr::Param {
..
}
| GqlExpr::Variable(_) => false,
GqlExpr::Property(..)
| GqlExpr::Unary {
..
}
| GqlExpr::Binary {
..
}
| GqlExpr::IsBool {
..
}
| GqlExpr::IsNull {
..
} => true,
GqlExpr::FunctionCall {
args,
..
} => !args.is_empty(),
GqlExpr::List(items, _) => !items.is_empty(),
GqlExpr::Map(fields, _) => !fields.is_empty(),
}
}
fn take_children(&mut self, stack: &mut Vec<GqlExpr>) {
fn take(child: &mut Box<GqlExpr>, stack: &mut Vec<GqlExpr>) {
let child =
std::mem::replace(&mut **child, GqlExpr::Literal(GqlLiteral::Null, Span::empty()));
if child.has_children() {
stack.push(child);
}
}
match self {
GqlExpr::Literal(..)
| GqlExpr::Param {
..
}
| GqlExpr::Variable(_) => {}
GqlExpr::Property(base, _, _) => take(base, stack),
GqlExpr::Unary {
expr,
..
}
| GqlExpr::IsBool {
expr,
..
}
| GqlExpr::IsNull {
expr,
..
} => take(expr, stack),
GqlExpr::Binary {
left,
right,
..
} => {
take(left, stack);
take(right, stack);
}
GqlExpr::FunctionCall {
args,
..
} => stack.extend(args.drain(..).filter(GqlExpr::has_children)),
GqlExpr::List(items, _) => stack.extend(items.drain(..).filter(GqlExpr::has_children)),
GqlExpr::Map(fields, _) => {
stack.extend(fields.drain(..).map(|(_, value)| value).filter(GqlExpr::has_children))
}
}
}
}
impl Drop for GqlExpr {
fn drop(&mut self) {
if !self.has_children() {
return;
}
let mut stack = Vec::new();
self.take_children(&mut stack);
while let Some(mut expr) = stack.pop() {
expr.take_children(&mut stack);
}
}
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum UnaryOp {
Not,
Neg,
Plus,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum BinaryOp {
Or,
Xor,
And,
Eq,
Neq,
Lt,
Lte,
Gt,
Gte,
Concat,
Add,
Sub,
Mul,
Div,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum TruthValue {
True,
False,
Unknown,
}
#[derive(Clone, Debug, PartialEq)]
pub enum GqlLiteral {
Null,
Bool(bool),
Integer(i64),
Float(f64),
String(String),
}