1use super::stmt::*;
4use linkrs_core::types::expr::expression_context::ExpressionAnalysisContext;
5use linkrs_core::types::expr::{ContextualExpression, Expression, ExpressionMeta};
6use linkrs_core::Value;
7use std::sync::Arc;
8
9pub struct ExprFactory;
11
12impl ExprFactory {
13 pub fn constant(value: Value, ctx: Arc<ExpressionAnalysisContext>) -> ContextualExpression {
15 let expr = Expression::Literal(value);
16 let meta = ExpressionMeta::new(expr);
17 let id = ctx.register_expression(meta);
18 ContextualExpression::new(id, ctx)
19 }
20
21 pub fn variable(name: String, ctx: Arc<ExpressionAnalysisContext>) -> ContextualExpression {
23 let expr = Expression::Variable(name);
24 let meta = ExpressionMeta::new(expr);
25 let id = ctx.register_expression(meta);
26 ContextualExpression::new(id, ctx)
27 }
28
29 pub fn binary(
31 left: ContextualExpression,
32 op: linkrs_core::types::operators::BinaryOperator,
33 right: ContextualExpression,
34 ) -> ContextualExpression {
35 let ctx = left.context().clone();
36 let left_expr = left
37 .expression()
38 .expect("Left expression should exist")
39 .expression()
40 .clone();
41 let right_expr = right
42 .expression()
43 .expect("Right expression should exist")
44 .expression()
45 .clone();
46 let expr = Expression::Binary {
47 left: Box::new(left_expr),
48 op,
49 right: Box::new(right_expr),
50 };
51 let meta = ExpressionMeta::new(expr);
52 let id = ctx.register_expression(meta);
53 ContextualExpression::new(id, ctx)
54 }
55
56 pub fn unary(
58 op: linkrs_core::types::operators::UnaryOperator,
59 operand: ContextualExpression,
60 ) -> ContextualExpression {
61 let ctx = operand.context().clone();
62 let operand_expr = operand
63 .expression()
64 .expect("Operand expression should exist")
65 .expression()
66 .clone();
67 let expr = Expression::Unary {
68 op,
69 operand: Box::new(operand_expr),
70 };
71 let meta = ExpressionMeta::new(expr);
72 let id = ctx.register_expression(meta);
73 ContextualExpression::new(id, ctx)
74 }
75
76 pub fn function_call(
78 name: String,
79 args: Vec<ContextualExpression>,
80 _distinct: bool,
81 ) -> ContextualExpression {
82 let ctx = if args.is_empty() {
83 Arc::new(ExpressionAnalysisContext::new())
84 } else {
85 args[0].context().clone()
86 };
87 let arg_exprs: Vec<Expression> = args
88 .iter()
89 .map(|arg| {
90 arg.expression()
91 .expect("Arg expression should exist")
92 .expression()
93 .clone()
94 })
95 .collect();
96 let expr = Expression::function(name, arg_exprs);
97 let meta = ExpressionMeta::new(expr);
98 let id = ctx.register_expression(meta);
99 ContextualExpression::new(id, ctx)
100 }
101
102 pub fn property_access(object: ContextualExpression, property: String) -> ContextualExpression {
104 let ctx = object.context().clone();
105 let object_expr = object
106 .expression()
107 .expect("Object expression should exist")
108 .expression()
109 .clone();
110 let expr = Expression::Property {
111 object: Box::new(object_expr),
112 property,
113 };
114 let meta = ExpressionMeta::new(expr);
115 let id = ctx.register_expression(meta);
116 ContextualExpression::new(id, ctx)
117 }
118
119 pub fn list(elements: Vec<ContextualExpression>) -> ContextualExpression {
121 let ctx = if elements.is_empty() {
122 Arc::new(ExpressionAnalysisContext::new())
123 } else {
124 elements[0].context().clone()
125 };
126 let element_exprs: Vec<Expression> = elements
127 .iter()
128 .map(|elem| {
129 elem.expression()
130 .expect("Element expression should exist")
131 .expression()
132 .clone()
133 })
134 .collect();
135 let expr = Expression::List(element_exprs);
136 let meta = ExpressionMeta::new(expr);
137 let id = ctx.register_expression(meta);
138 ContextualExpression::new(id, ctx)
139 }
140
141 pub fn map(pairs: Vec<(String, ContextualExpression)>) -> ContextualExpression {
143 let ctx = if pairs.is_empty() {
144 Arc::new(ExpressionAnalysisContext::new())
145 } else {
146 pairs[0].1.context().clone()
147 };
148 let value_exprs: Vec<(String, Expression)> = pairs
149 .iter()
150 .map(|(key, value)| {
151 (
152 key.clone(),
153 value
154 .expression()
155 .expect("Value expression should exist")
156 .expression()
157 .clone(),
158 )
159 })
160 .collect();
161 let expr = Expression::Map(value_exprs);
162 let meta = ExpressionMeta::new(expr);
163 let id = ctx.register_expression(meta);
164 ContextualExpression::new(id, ctx)
165 }
166
167 pub fn case(
169 match_expression: Option<ContextualExpression>,
170 when_then_pairs: Vec<(ContextualExpression, ContextualExpression)>,
171 default: Option<ContextualExpression>,
172 ) -> ContextualExpression {
173 let ctx = match_expression
174 .as_ref()
175 .map(|e| e.context().clone())
176 .or_else(|| when_then_pairs.first().map(|(w, _)| w.context().clone()))
177 .or_else(|| default.as_ref().map(|d| d.context().clone()))
178 .unwrap_or_else(|| Arc::new(ExpressionAnalysisContext::new()));
179
180 let test_expr = match_expression.map(|e| {
181 Box::new(
182 e.expression()
183 .expect("Match expression should exist")
184 .expression()
185 .clone(),
186 )
187 });
188 let conditions = when_then_pairs
189 .iter()
190 .map(|(when, then)| {
191 let when_expr = when
192 .expression()
193 .expect("When expression should exist")
194 .expression()
195 .clone();
196 let then_expr = then
197 .expression()
198 .expect("Then expression should exist")
199 .expression()
200 .clone();
201 (when_expr, then_expr)
202 })
203 .collect();
204 let default_expr = default.map(|d| {
205 Box::new(
206 d.expression()
207 .expect("Default expression should exist")
208 .expression()
209 .clone(),
210 )
211 });
212 let expr = Expression::Case {
213 test_expr,
214 conditions,
215 default: default_expr,
216 };
217 let meta = ExpressionMeta::new(expr);
218 let id = ctx.register_expression(meta);
219 ContextualExpression::new(id, ctx)
220 }
221
222 pub fn subscript(
224 collection: ContextualExpression,
225 index: ContextualExpression,
226 ) -> ContextualExpression {
227 let ctx = collection.context().clone();
228 let collection_expr = collection
229 .expression()
230 .expect("Collection expression should exist")
231 .expression()
232 .clone();
233 let index_expr = index
234 .expression()
235 .expect("Index expression should exist")
236 .expression()
237 .clone();
238 let expr = Expression::Subscript {
239 collection: Box::new(collection_expr),
240 index: Box::new(index_expr),
241 };
242 let meta = ExpressionMeta::new(expr);
243 let id = ctx.register_expression(meta);
244 ContextualExpression::new(id, ctx)
245 }
246
247 pub fn compare(
249 left: ContextualExpression,
250 op: linkrs_core::types::operators::BinaryOperator,
251 right: ContextualExpression,
252 ) -> ContextualExpression {
253 Self::binary(left, op, right)
254 }
255
256 pub fn logical(
258 left: ContextualExpression,
259 op: linkrs_core::types::operators::BinaryOperator,
260 right: ContextualExpression,
261 ) -> ContextualExpression {
262 Self::binary(left, op, right)
263 }
264
265 pub fn arithmetic(
267 left: ContextualExpression,
268 op: linkrs_core::types::operators::BinaryOperator,
269 right: ContextualExpression,
270 ) -> ContextualExpression {
271 Self::binary(left, op, right)
272 }
273}
274
275pub struct StmtFactory;
277
278impl StmtFactory {
279 pub fn query(statements: Vec<Stmt>, span: Span) -> Stmt {
281 Stmt::Query(QueryStmt::new(statements, span))
282 }
283
284 pub fn create_node(
286 variable: Option<String>,
287 labels: Vec<String>,
288 properties: Option<ContextualExpression>,
289 span: Span,
290 ) -> Stmt {
291 Stmt::Create(CreateStmt {
292 span,
293 target: CreateTarget::Node {
294 variable,
295 labels,
296 properties,
297 },
298 if_not_exists: false,
299 })
300 }
301
302 pub fn create_edge(
304 variable: Option<String>,
305 edge_type: String,
306 src: ContextualExpression,
307 dst: ContextualExpression,
308 properties: Option<ContextualExpression>,
309 direction: EdgeDirection,
310 span: Span,
311 ) -> Stmt {
312 Stmt::Create(CreateStmt {
313 span,
314 target: CreateTarget::Edge {
315 variable,
316 edge_type,
317 src,
318 dst,
319 properties,
320 direction,
321 },
322 if_not_exists: false,
323 })
324 }
325
326 pub fn match_stmt(
328 patterns: Vec<Pattern>,
329 where_clause: Option<ContextualExpression>,
330 return_clause: Option<ReturnClause>,
331 order_by: Option<OrderByClause>,
332 limit: Option<LimitClause>,
333 skip: Option<SkipClause>,
334 span: Span,
335 ) -> Stmt {
336 Stmt::Match(MatchStmt {
337 span,
338 patterns,
339 join_hint: None,
340 where_clause,
341 return_clause,
342 order_by,
343 limit,
344 skip,
345 optional: false,
346 delete_clause: None,
347 })
348 }
349
350 pub fn delete(target: DeleteTarget, span: Span) -> Stmt {
352 Stmt::Delete(DeleteStmt {
353 span,
354 target,
355 with_edge: false,
356 detach: false,
357 })
358 }
359
360 pub fn delete_with_edge(target: DeleteTarget, span: Span) -> Stmt {
362 Stmt::Delete(DeleteStmt {
363 span,
364 target,
365 with_edge: true,
366 detach: false,
367 })
368 }
369
370 pub fn update(
372 target: UpdateTarget,
373 set_clause: SetClause,
374 where_clause: Option<ContextualExpression>,
375 span: Span,
376 ) -> Stmt {
377 Stmt::Update(UpdateStmt {
378 span,
379 target,
380 set_clause,
381 where_clause,
382 is_upsert: false,
383 yield_clause: None,
384 })
385 }
386
387 pub fn go(
389 steps: Steps,
390 from: FromClause,
391 over: Option<OverClause>,
392 where_clause: Option<ContextualExpression>,
393 yield_clause: Option<YieldClause>,
394 span: Span,
395 ) -> Stmt {
396 Stmt::Go(GoStmt {
397 span,
398 steps,
399 from,
400 over,
401 where_clause,
402 yield_clause,
403 })
404 }
405
406 pub fn fetch(target: FetchTarget, span: Span) -> Stmt {
408 Stmt::Fetch(FetchStmt {
409 span,
410 target,
411 yield_clause: None,
412 })
413 }
414
415 pub fn r#use(space: String, span: Span) -> Stmt {
417 Stmt::Use(UseStmt { span, space })
418 }
419
420 pub fn show(target: ShowTarget, span: Span) -> Stmt {
422 Stmt::Show(ShowStmt { span, target })
423 }
424
425 pub fn explain(statement: Box<Stmt>, span: Span) -> Stmt {
427 Stmt::Explain(ExplainStmt {
428 span,
429 statement,
430 format: ExplainFormat::default(),
431 analyze: false,
432 })
433 }
434
435 pub fn explain_with_format(statement: Box<Stmt>, format: ExplainFormat, span: Span) -> Stmt {
437 Stmt::Explain(ExplainStmt {
438 span,
439 statement,
440 format,
441 analyze: false,
442 })
443 }
444
445 pub fn profile(statement: Box<Stmt>, span: Span) -> Stmt {
447 Stmt::Profile(ProfileStmt {
448 span,
449 statement,
450 format: ExplainFormat::default(),
451 })
452 }
453
454 pub fn profile_with_format(statement: Box<Stmt>, format: ExplainFormat, span: Span) -> Stmt {
456 Stmt::Profile(ProfileStmt {
457 span,
458 statement,
459 format,
460 })
461 }
462
463 pub fn lookup(
465 target: LookupTarget,
466 where_clause: Option<ContextualExpression>,
467 yield_clause: Option<YieldClause>,
468 span: Span,
469 ) -> Stmt {
470 Stmt::Lookup(LookupStmt {
471 span,
472 target,
473 where_clause,
474 yield_clause,
475 })
476 }
477
478 pub fn subgraph(
480 steps: Steps,
481 from: FromClause,
482 over: Option<OverClause>,
483 where_clause: Option<ContextualExpression>,
484 yield_clause: Option<YieldClause>,
485 span: Span,
486 ) -> Stmt {
487 Stmt::Subgraph(SubgraphStmt {
488 span,
489 steps,
490 from,
491 over,
492 where_clause,
493 yield_clause,
494 with_prop: false,
495 })
496 }
497
498 pub fn find_path(
500 from: FromClause,
501 to: ContextualExpression,
502 over: Option<OverClause>,
503 where_clause: Option<ContextualExpression>,
504 shortest: bool,
505 yield_clause: Option<YieldClause>,
506 span: Span,
507 ) -> Stmt {
508 Stmt::FindPath(FindPathStmt {
509 span,
510 from,
511 to,
512 over,
513 where_clause,
514 shortest,
515 max_steps: None,
516 limit: None,
517 skip: None,
518 yield_clause,
519 weight_expression: None,
520 heuristic_expression: None,
521 with_loop: false,
522 with_trail: false,
523 with_walk: false,
524 })
525 }
526}
527
528pub struct PatternFactory;
530
531impl PatternFactory {
532 pub fn node(
534 variable: Option<String>,
535 labels: Vec<String>,
536 properties: Option<ContextualExpression>,
537 predicates: Vec<ContextualExpression>,
538 span: Span,
539 ) -> Pattern {
540 Pattern::Node(NodePattern::new(
541 variable, labels, properties, predicates, span,
542 ))
543 }
544
545 pub fn edge(
547 variable: Option<String>,
548 edge_types: Vec<String>,
549 properties: Option<ContextualExpression>,
550 predicates: Vec<ContextualExpression>,
551 direction: EdgeDirection,
552 range: Option<EdgeRange>,
553 span: Span,
554 ) -> Pattern {
555 Pattern::Edge(EdgePattern::new(
556 variable, edge_types, properties, predicates, direction, range, span,
557 ))
558 }
559
560 pub fn path(elements: Vec<PathElement>, span: Span) -> Pattern {
562 Pattern::Path(PathPattern::new(elements, span))
563 }
564
565 pub fn variable(name: String, span: Span) -> Pattern {
567 Pattern::Variable(VariablePattern::new(name, span))
568 }
569
570 pub fn simple_node(variable: Option<String>, labels: Vec<String>, span: Span) -> Pattern {
572 Self::node(variable, labels, None, vec![], span)
573 }
574
575 pub fn simple_edge(
577 variable: Option<String>,
578 edge_types: Vec<String>,
579 direction: EdgeDirection,
580 span: Span,
581 ) -> Pattern {
582 Self::edge(variable, edge_types, None, vec![], direction, None, span)
583 }
584
585 pub fn directed_edge(
587 variable: Option<String>,
588 edge_type: String,
589 direction: EdgeDirection,
590 span: Span,
591 ) -> Pattern {
592 Self::simple_edge(variable, vec![edge_type], direction, span)
593 }
594
595 pub fn undirected_edge(variable: Option<String>, edge_type: String, span: Span) -> Pattern {
597 Self::simple_edge(variable, vec![edge_type], EdgeDirection::Both, span)
598 }
599}
600
601pub struct AstBuilder {
603 span: Span,
604}
605
606impl AstBuilder {
607 pub fn new(span: Span) -> Self {
608 Self { span }
609 }
610
611 pub fn build_simple_match(
613 &self,
614 pattern: Pattern,
615 return_expression: ContextualExpression,
616 ) -> Stmt {
617 let return_clause = ReturnClause {
618 span: self.span,
619 items: vec![ReturnItem::Expression {
620 expression: return_expression,
621 alias: None,
622 }],
623 distinct: false,
624 order_by: None,
625 limit: None,
626 skip: None,
627 sample: None,
628 having_clause: None,
629 };
630
631 StmtFactory::match_stmt(
632 vec![pattern],
633 None,
634 Some(return_clause),
635 None,
636 None,
637 None,
638 self.span,
639 )
640 }
641
642 pub fn build_create_node(&self, variable: Option<String>, labels: Vec<String>) -> Stmt {
644 StmtFactory::create_node(variable, labels, None, self.span)
645 }
646
647 pub fn build_create_edge(
649 &self,
650 variable: Option<String>,
651 edge_type: String,
652 src: ContextualExpression,
653 dst: ContextualExpression,
654 direction: EdgeDirection,
655 ) -> Stmt {
656 StmtFactory::create_edge(variable, edge_type, src, dst, None, direction, self.span)
657 }
658
659 pub fn build_delete_vertices(&self, tag: String, vertices: Vec<ContextualExpression>) -> Stmt {
661 StmtFactory::delete(
662 DeleteTarget::Vertices {
663 tag,
664 vids: vertices,
665 },
666 self.span,
667 )
668 }
669
670 pub fn build_update_vertex(
672 &self,
673 vertex: ContextualExpression,
674 assignments: Vec<Assignment>,
675 ) -> Stmt {
676 let set_clause = SetClause {
677 span: self.span,
678 assignments,
679 };
680
681 StmtFactory::update(UpdateTarget::Vertex(vertex), set_clause, None, self.span)
682 }
683}
684
685#[cfg(test)]
686mod tests {
687 use super::*;
688 use linkrs_core::Value;
689 use std::sync::Arc;
690
691 #[test]
692 fn test_expr_factory() {
693 let ctx = Arc::new(ExpressionAnalysisContext::new());
694
695 let const_expression = ExprFactory::constant(Value::Int(42), ctx.clone());
697 assert!(const_expression.expression().is_some());
698
699 let var_expression = ExprFactory::variable("x".into(), ctx.clone());
701 assert!(var_expression.expression().is_some());
702
703 let left = ExprFactory::constant(Value::Int(5), ctx.clone());
705 let right = ExprFactory::constant(Value::Int(3), ctx.clone());
706 let binary_expression = ExprFactory::binary(
707 left,
708 linkrs_core::types::operators::BinaryOperator::Add,
709 right,
710 );
711 assert!(binary_expression.expression().is_some());
712 }
713}