kotoba_execution/planner/
logical.rs1use kotoba_core::{types::*, ir::*};
4use kotoba_core::types::Result;
5
6#[derive(Debug)]
8pub struct LogicalPlanner;
9
10impl Default for LogicalPlanner {
11 fn default() -> Self {
12 Self::new()
13 }
14}
15
16impl LogicalPlanner {
17 pub fn new() -> Self {
18 Self
19 }
20
21 pub fn parse_gql(&self, gql: &str) -> Result<PlanIR> {
23 if gql.trim().to_lowercase().starts_with("match") {
27 self.parse_match_query(gql)
28 } else {
29 Err(KotobaError::Parse(format!("Unsupported GQL query: {}", gql)))
30 }
31 }
32
33 fn parse_match_query(&self, _gql: &str) -> Result<PlanIR> {
35 let plan = LogicalOp::NodeScan {
39 label: "Person".to_string(),
40 as_: "n".to_string(),
41 props: None,
42 };
43
44 Ok(PlanIR {
45 plan,
46 limit: Some(100),
47 })
48 }
49
50 pub fn optimize(&self, plan: &PlanIR, _catalog: &Catalog) -> PlanIR {
52 plan.clone()
56 }
57}
58
59#[derive(Debug)]
61pub struct CostEstimator;
62
63impl Default for CostEstimator {
64 fn default() -> Self {
65 Self::new()
66 }
67}
68
69impl CostEstimator {
70 pub fn new() -> Self {
71 Self
72 }
73
74 pub fn estimate_cost(&self, op: &LogicalOp, catalog: &Catalog) -> f64 {
76 match op {
77 LogicalOp::NodeScan { label, .. } => {
78 catalog.get_label(label)
80 .map(|_| 100.0) .unwrap_or(1000.0)
82 }
83 LogicalOp::Expand { .. } => 50.0,
84 LogicalOp::Filter { .. } => 10.0,
85 LogicalOp::Join { .. } => 200.0,
86 LogicalOp::Project { .. } => 5.0,
87 LogicalOp::Sort { .. } => 100.0,
88 LogicalOp::Limit { .. } => 1.0,
89 LogicalOp::Distinct { .. } => 50.0,
90 LogicalOp::IndexScan { .. } => 10.0,
91 LogicalOp::Group { .. } => 150.0,
92 }
93 }
94}