1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use crate::types::*;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9#[serde(tag = "op")]
10pub enum LogicalOp {
11 NodeScan {
13 label: Label,
14 as_: String,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 props: Option<Properties>,
17 },
18
19 IndexScan {
21 label: Label,
22 as_: String,
23 index: String,
24 value: Value,
25 },
26
27 Filter {
29 pred: Predicate,
30 input: Box<LogicalOp>,
31 },
32
33 Expand {
35 edge: EdgePattern,
36 to_as: String,
37 from: Box<LogicalOp>,
38 },
39
40 Join {
42 left: Box<LogicalOp>,
43 right: Box<LogicalOp>,
44 on: Vec<String>, },
46
47 Project {
49 cols: Vec<String>,
50 input: Box<LogicalOp>,
51 },
52
53 Group {
55 keys: Vec<String>,
56 aggregations: Vec<Aggregation>,
57 input: Box<LogicalOp>,
58 },
59
60 Sort {
62 keys: Vec<SortKey>,
63 input: Box<LogicalOp>,
64 },
65
66 Limit {
68 count: usize,
69 input: Box<LogicalOp>,
70 },
71
72 Distinct {
74 input: Box<LogicalOp>,
75 },
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct EdgePattern {
81 pub label: Label,
82 pub dir: Direction,
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub props: Option<Properties>,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89pub enum Direction {
90 #[serde(rename = "out")]
91 Out,
92 #[serde(rename = "in")]
93 In,
94 #[serde(rename = "both")]
95 Both,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100#[serde(untagged)]
101pub enum Predicate {
102 Eq { eq: [Expr; 2] },
103 Ne { ne: [Expr; 2] },
104 Lt { lt: [Expr; 2] },
105 Le { le: [Expr; 2] },
106 Gt { gt: [Expr; 2] },
107 Ge { ge: [Expr; 2] },
108 And { and: Vec<Predicate> },
109 Or { or: Vec<Predicate> },
110 Not { not: Box<Predicate> },
111}
112
113impl std::fmt::Display for Predicate {
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 match self {
116 Predicate::Eq { eq } => write!(f, "{} = {}", eq[0], eq[1]),
117 Predicate::Ne { ne } => write!(f, "{} <> {}", ne[0], ne[1]),
118 Predicate::Lt { lt } => write!(f, "{} < {}", lt[0], lt[1]),
119 Predicate::Le { le } => write!(f, "{} <= {}", le[0], le[1]),
120 Predicate::Gt { gt } => write!(f, "{} > {}", gt[0], gt[1]),
121 Predicate::Ge { ge } => write!(f, "{} >= {}", ge[0], ge[1]),
122 Predicate::And { and } => {
123 write!(f, "(")?;
124 for (i, p) in and.iter().enumerate() {
125 if i > 0 {
126 write!(f, " AND ")?;
127 }
128 write!(f, "{}", p)?;
129 }
130 write!(f, ")")
131 }
132 Predicate::Or { or } => {
133 write!(f, "(")?;
134 for (i, p) in or.iter().enumerate() {
135 if i > 0 {
136 write!(f, " OR ")?;
137 }
138 write!(f, "{}", p)?;
139 }
140 write!(f, ")")
141 }
142 Predicate::Not { not } => write!(f, "NOT {}", not),
143 }
144 }
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
149#[serde(untagged)]
150pub enum Expr {
151 Var(String),
152 Const(Value),
153 Fn { fn_: String, args: Vec<Expr> },
154}
155
156impl std::fmt::Display for Expr {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 match self {
159 Expr::Var(v) => write!(f, "{}", v),
160 Expr::Const(val) => write!(f, "{:?}", val),
161 Expr::Fn { fn_, args } => {
162 write!(f, "{}({})", fn_, args.len())
163 }
164 }
165 }
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
170pub struct Aggregation {
171 pub fn_: String,
172 pub args: Vec<String>,
173 pub as_: String,
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct SortKey {
179 pub expr: Expr,
180 pub asc: bool,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct PlanIR {
186 pub plan: LogicalOp,
187 #[serde(skip_serializing_if = "Option::is_none")]
188 pub limit: Option<usize>,
189}
190
191#[derive(Debug, Clone)]
193pub struct Row {
194 pub values: HashMap<String, Value>,
195}
196
197pub type RowStream = Vec<Row>;