1use linkrs_core::types::expr::analysis_utils::collect_variables_from_contextual;
2use linkrs_core::types::expr::contextual::ContextualExpression;
3use linkrs_core::types::Span;
4
5use super::PatternUtils;
6
7use super::{CreateTarget, DeleteTarget, FetchTarget, UpdateTarget};
8use super::{OrderByClause, ReturnClause, ReturnItem, Stmt, YieldClause};
9use crate::parser::ast::types::{LimitClause, SkipClause};
10
11#[derive(Debug, Clone, PartialEq)]
12pub struct UseStmt {
13 pub span: Span,
14 pub space: String,
15}
16
17#[derive(Debug, Clone, PartialEq)]
18pub struct ShowStmt {
19 pub span: Span,
20 pub target: ShowTarget,
21}
22
23#[derive(Debug, Clone, PartialEq)]
24pub enum ShowTarget {
25 Spaces,
26 Tags,
27 Edges,
28 Indexes,
29 Index(String),
30 Stats,
31 Functions,
32 Graphs,
33 Macros,
34 AttachedDatabases,
35 Extensions,
36}
37
38#[derive(Debug, Clone, PartialEq, Default)]
39pub enum ExplainFormat {
40 #[default]
41 Table,
42 Dot,
43}
44
45#[derive(Debug, Clone)]
46pub struct ExplainStmt {
47 pub span: Span,
48 pub statement: Box<Stmt>,
49 pub format: ExplainFormat,
50 pub analyze: bool,
53}
54
55impl PartialEq for ExplainStmt {
56 fn eq(&self, other: &Self) -> bool {
57 self.span == other.span && self.format == other.format && self.analyze == other.analyze
58 }
59}
60
61#[derive(Debug, Clone)]
62pub struct ProfileStmt {
63 pub span: Span,
64 pub statement: Box<Stmt>,
65 pub format: ExplainFormat,
66}
67
68#[derive(Debug, Clone, PartialEq)]
70pub struct AnalyzeStmt {
71 pub span: Span,
72 pub space: Option<String>,
74}
75
76impl PartialEq for ProfileStmt {
77 fn eq(&self, other: &Self) -> bool {
78 self.span == other.span && self.format == other.format
79 }
80}
81
82#[derive(Debug, Clone, PartialEq)]
83pub enum GroupingType {
84 Standard,
85 Rollup(Vec<ContextualExpression>),
86 Cube(Vec<ContextualExpression>),
87 GroupingSets(Vec<Vec<ContextualExpression>>),
88}
89
90#[derive(Debug, Clone, PartialEq)]
91pub struct GroupByStmt {
92 pub span: Span,
93 pub group_items: Vec<ContextualExpression>,
94 pub grouping_type: GroupingType,
95 pub yield_clause: YieldClause,
96 pub having_clause: Option<ContextualExpression>,
97}
98
99#[derive(Debug, Clone)]
100pub struct PipeStmt {
101 pub span: Span,
102 pub left: Box<Stmt>,
103 pub right: Box<Stmt>,
104}
105
106impl PartialEq for PipeStmt {
107 fn eq(&self, other: &Self) -> bool {
108 self.span == other.span
109 }
110}
111
112#[derive(Debug, Clone, PartialEq)]
113pub struct UnwindStmt {
114 pub span: Span,
115 pub expression: ContextualExpression,
116 pub variable: String,
117 pub return_clause: Option<ReturnClause>,
118 pub order_by: Option<OrderByClause>,
119 pub limit: Option<LimitClause>,
120 pub skip: Option<SkipClause>,
121}
122
123#[derive(Debug, Clone)]
124pub struct WithStmt {
125 pub span: Span,
126 pub items: Vec<ReturnItem>,
127 pub where_clause: Option<ContextualExpression>,
128 pub distinct: bool,
129 pub order_by: Option<OrderByClause>,
130 pub skip: Option<SkipClause>,
131 pub limit: Option<LimitClause>,
132 pub recursive: bool,
133 pub ctes: Vec<CteDef>,
134}
135
136#[derive(Debug, Clone)]
143pub struct CteDef {
144 pub span: Span,
145 pub name: String,
146 pub body: Box<Stmt>,
147}
148
149#[derive(Debug, Clone, PartialEq)]
151pub struct FilterStmt {
152 pub span: Span,
153 pub expression: ContextualExpression,
154}
155
156#[derive(Debug, Clone, PartialEq)]
158pub struct CollectStmt {
159 pub span: Span,
160 pub items: Vec<super::YieldItem>,
161}
162
163#[derive(Debug, Clone, PartialEq)]
164pub struct ShowSessionsStmt {
165 pub span: Span,
166}
167
168#[derive(Debug, Clone, PartialEq)]
169pub struct ShowQueriesStmt {
170 pub span: Span,
171}
172
173#[derive(Debug, Clone, PartialEq)]
174pub struct KillQueryStmt {
175 pub span: Span,
176 pub session_id: i64,
177 pub plan_id: i64,
178}
179
180#[derive(Debug, Clone, PartialEq)]
184pub enum PurgeTarget {
185 Tag(String),
186 Edge(String),
187}
188
189#[derive(Debug, Clone, PartialEq)]
195pub struct PurgeExpiredStmt {
196 pub span: Span,
197 pub space_name: String,
198 pub target: Option<PurgeTarget>,
199}
200
201#[derive(Debug, Clone, PartialEq)]
202pub struct ShowConfigsStmt {
203 pub span: Span,
204 pub module: Option<String>,
205}
206
207#[derive(Debug, Clone, PartialEq)]
208pub struct UpdateConfigsStmt {
209 pub span: Span,
210 pub module: Option<String>,
211 pub config_name: String,
212 pub config_value: ContextualExpression,
213}
214
215#[derive(Debug, Clone)]
216pub struct AssignmentStmt {
217 pub span: Span,
218 pub variable: String,
219 pub statement: Box<Stmt>,
220}
221
222impl PartialEq for AssignmentStmt {
223 fn eq(&self, other: &Self) -> bool {
224 self.span == other.span && self.variable == other.variable
225 }
226}
227
228#[derive(Debug, Clone, PartialEq)]
229pub enum SetOperationType {
230 Union,
231 UnionAll,
232 Intersect,
233 Minus,
234}
235
236#[derive(Debug, Clone)]
237pub struct SetOperationStmt {
238 pub span: Span,
239 pub op_type: SetOperationType,
240 pub left: Box<Stmt>,
241 pub right: Box<Stmt>,
242}
243
244impl PartialEq for SetOperationStmt {
245 fn eq(&self, other: &Self) -> bool {
246 self.span == other.span && self.op_type == other.op_type
247 }
248}
249
250#[derive(Debug, Clone, PartialEq)]
252pub struct ExportDatabaseStmt {
253 pub span: Span,
254 pub path: String,
255 pub options: Vec<ExportOption>,
256}
257
258#[derive(Debug, Clone, PartialEq)]
259pub struct ExportOption {
260 pub key: String,
261 pub value: String,
262}
263
264#[derive(Debug, Clone, PartialEq)]
266pub struct ImportDatabaseStmt {
267 pub span: Span,
268 pub path: String,
269}
270
271#[derive(Debug, Clone, Copy, PartialEq, Eq)]
273pub enum ExtensionAction {
274 Load,
276 Install,
278 Uninstall,
280 Update,
283}
284
285#[derive(Debug, Clone, PartialEq)]
291pub struct AttachDatabaseStmt {
292 pub span: Span,
293 pub path: String,
295 pub alias: String,
297 pub db_type: Option<String>,
299 pub options: Vec<(String, String)>,
301}
302
303#[derive(Debug, Clone, PartialEq)]
308pub struct DetachDatabaseStmt {
309 pub span: Span,
310 pub alias: String,
311}
312
313#[derive(Debug, Clone, PartialEq)]
319pub struct ExtensionStmt {
320 pub span: Span,
321 pub action: ExtensionAction,
322 pub name: String,
324 pub source: Option<String>,
326}
327
328pub struct StmtUtils;
329
330impl StmtUtils {
331 pub fn find_variables(stmt: &Stmt) -> Vec<String> {
332 let mut variables = Vec::new();
333 Self::find_variables_recursive(stmt, &mut variables);
334 variables
335 }
336
337 fn find_variables_recursive(stmt: &Stmt, variables: &mut Vec<String>) {
338 match stmt {
339 Stmt::Match(s) => {
340 for pattern in &s.patterns {
341 variables.extend(PatternUtils::find_variables(pattern));
342 }
343 if let Some(ref where_clause) = s.where_clause {
344 variables.extend(collect_variables_from_contextual(where_clause));
345 }
346 }
347 Stmt::Create(s) => match &s.target {
348 CreateTarget::Node {
349 properties: Some(props),
350 ..
351 } => {
352 variables.extend(collect_variables_from_contextual(props));
353 }
354 CreateTarget::Edge {
355 src,
356 dst,
357 properties: Some(props),
358 ..
359 } => {
360 variables.extend(collect_variables_from_contextual(src));
361 variables.extend(collect_variables_from_contextual(dst));
362 variables.extend(collect_variables_from_contextual(props));
363 }
364 _ => {}
365 },
366 Stmt::Delete(s) => match &s.target {
367 DeleteTarget::Vertices { vids, .. } => {
368 for vertex in vids {
369 variables.extend(collect_variables_from_contextual(vertex));
370 }
371 }
372 DeleteTarget::Edges { edges, .. } => {
373 for (src, dst, rank) in edges {
374 variables.extend(collect_variables_from_contextual(src));
375 variables.extend(collect_variables_from_contextual(dst));
376 if let Some(ref rank) = rank {
377 variables.extend(collect_variables_from_contextual(rank));
378 }
379 }
380 }
381 _ => {}
382 },
383 Stmt::Update(s) => {
384 match &s.target {
385 UpdateTarget::Vertex(vertex) => {
386 variables.extend(collect_variables_from_contextual(vertex));
387 }
388 UpdateTarget::Edge { src, dst, rank, .. } => {
389 variables.extend(collect_variables_from_contextual(src));
390 variables.extend(collect_variables_from_contextual(dst));
391 if let Some(ref rank) = rank {
392 variables.extend(collect_variables_from_contextual(rank));
393 }
394 }
395 _ => {}
396 }
397 for assignment in &s.set_clause.assignments {
398 variables.extend(collect_variables_from_contextual(&assignment.value));
399 }
400 if let Some(ref where_clause) = s.where_clause {
401 variables.extend(collect_variables_from_contextual(where_clause));
402 }
403 }
404 Stmt::Go(s) => {
405 for vertex in &s.from.vertices {
406 variables.extend(collect_variables_from_contextual(vertex));
407 }
408 if let Some(ref where_clause) = s.where_clause {
409 variables.extend(collect_variables_from_contextual(where_clause));
410 }
411 }
412 Stmt::Fetch(s) => match &s.target {
413 FetchTarget::Vertices { ids, .. } => {
414 for id in ids {
415 variables.extend(collect_variables_from_contextual(id));
416 }
417 }
418 FetchTarget::Edges { src, dst, rank, .. } => {
419 variables.extend(collect_variables_from_contextual(src));
420 variables.extend(collect_variables_from_contextual(dst));
421 if let Some(ref rank) = rank {
422 variables.extend(collect_variables_from_contextual(rank));
423 }
424 }
425 },
426 Stmt::Lookup(s) => {
427 if let Some(ref where_clause) = s.where_clause {
428 variables.extend(collect_variables_from_contextual(where_clause));
429 }
430 }
431 Stmt::Subgraph(s) => {
432 for vertex in &s.from.vertices {
433 variables.extend(collect_variables_from_contextual(vertex));
434 }
435 if let Some(ref where_clause) = s.where_clause {
436 variables.extend(collect_variables_from_contextual(where_clause));
437 }
438 }
439 Stmt::FindPath(s) => {
440 for vertex in &s.from.vertices {
441 variables.extend(collect_variables_from_contextual(vertex));
442 }
443 variables.extend(collect_variables_from_contextual(&s.to));
444 if let Some(ref where_clause) = s.where_clause {
445 variables.extend(collect_variables_from_contextual(where_clause));
446 }
447 }
448 _ => {}
449 }
450 }
451}