linkrs_query/planning/statements/pattern_planner/
node.rs1use std::sync::Arc;
4
5use crate::metadata::MetadataContext;
6use crate::parser::ast::pattern::NodePattern;
7use crate::planning::plan::core::nodes::base::plan_node_traits::PlanNode;
8use crate::planning::plan::core::nodes::operation::filter_node::FilterNode;
9use crate::planning::plan::core::nodes::ScanVerticesNode;
10use crate::planning::plan::SubPlan;
11use crate::planning::planner::PlannerError;
12use crate::planning::statements::{expression_helpers, index_scan_planner};
13use linkrs_core::types::expr::expression_context::ExpressionAnalysisContext;
14use linkrs_core::types::expr::ContextualExpression;
15
16use super::logical_mirror::{logical_filter, logical_scan_vertices};
17
18pub fn plan_pattern_node(
19 node: &NodePattern,
20 space_id: u64,
21 space_name: &str,
22 enable_index_optimization: bool,
23 metadata_context: &Option<MetadataContext>,
24 expr_context: &Option<Arc<ExpressionAnalysisContext>>,
25 where_expression: Option<&ContextualExpression>,
26) -> Result<SubPlan, PlannerError> {
27 let var_name = node.variable.clone().unwrap_or_else(|| "n".to_string());
28
29 if enable_index_optimization {
30 if let Some(index_plan) = index_scan_planner::try_create_index_scan_plan(
31 node,
32 space_id,
33 space_name,
34 &var_name,
35 enable_index_optimization,
36 metadata_context.as_ref(),
37 where_expression,
38 )? {
39 let logical_root = logical_scan_vertices(
42 space_id,
43 space_name,
44 node.labels.first().map(|s| s.as_str()),
45 &var_name,
46 );
47 return Ok(SubPlan {
48 root: index_plan.root,
49 tail: index_plan.tail,
50 logical_root: Some(logical_root),
51 });
52 }
53 }
54
55 let mut scan_node = ScanVerticesNode::new(space_id, space_name);
58 scan_node.set_col_names(vec![var_name.clone()]);
59 scan_node.set_output_var(var_name.clone());
60 if let Some(label) = node.labels.first() {
61 scan_node.set_tag(label);
62 }
63 let scan_root = scan_node.into_enum();
64 let mut logical_root = logical_scan_vertices(
65 space_id,
66 space_name,
67 node.labels.first().map(|s| s.as_str()),
68 &var_name,
69 );
70 let mut plan = SubPlan {
71 root: Some(scan_root.clone()),
72 tail: Some(scan_root),
73 logical_root: Some(logical_root.clone()),
74 };
75
76 if !node.labels.is_empty() {
77 let expr_ctx = expr_context.as_ref().expect("expr_context should be set");
78 let label_filter = expression_helpers::build_label_filter_expression(
79 &node.variable,
80 &node.labels,
81 expr_ctx,
82 );
83 let root_node = plan.root.as_ref().expect("The root of plan should exist");
84 let filter_node = FilterNode::new(root_node.clone(), label_filter.clone())
85 .map_err(|e| PlannerError::PlanGenerationFailed(e.to_string()))?;
86 logical_root = logical_filter(logical_root, label_filter);
87 plan = SubPlan {
88 root: Some(filter_node.into_enum()),
89 tail: plan.tail,
90 logical_root: Some(logical_root.clone()),
91 };
92 }
93
94 if let Some(ref props) = node.properties {
95 let filter_expr = if let Some(ref expr_ctx) = expr_context {
96 expression_helpers::convert_properties_to_filter(&var_name, props, expr_ctx)
97 } else {
98 None
99 };
100
101 let filter_expr = match filter_expr {
102 Some(expr) => expr,
103 None => props.clone(),
104 };
105
106 let filter_node = FilterNode::new(
107 plan.root
108 .as_ref()
109 .expect("The root of plan should exist")
110 .clone(),
111 filter_expr.clone(),
112 )
113 .map_err(|e| PlannerError::PlanGenerationFailed(e.to_string()))?;
114 logical_root = logical_filter(logical_root, filter_expr);
115 plan = SubPlan {
116 root: Some(filter_node.into_enum()),
117 tail: plan.tail,
118 logical_root: Some(logical_root.clone()),
119 };
120 }
121
122 if !node.predicates.is_empty() {
123 for pred in &node.predicates {
124 let filter_node = FilterNode::new(
125 plan.root
126 .as_ref()
127 .expect("The root of plan should exist")
128 .clone(),
129 pred.clone(),
130 )
131 .map_err(|e| PlannerError::PlanGenerationFailed(e.to_string()))?;
132 logical_root = logical_filter(logical_root, pred.clone());
133 plan = SubPlan {
134 root: Some(filter_node.into_enum()),
135 tail: plan.tail,
136 logical_root: Some(logical_root.clone()),
137 };
138 }
139 }
140
141 Ok(plan)
142}
143pub fn plan_node_pattern(space_id: u64, space_name: &str) -> Result<SubPlan, PlannerError> {
144 let scan_node = ScanVerticesNode::new(space_id, space_name);
145 let scan_root = scan_node.into_enum();
146 let logical_root = logical_scan_vertices(space_id, space_name, None, "n");
147 Ok(SubPlan {
148 root: Some(scan_root.clone()),
149 tail: Some(scan_root),
150 logical_root: Some(logical_root),
151 })
152}