1use std::sync::Arc;
10
11use crate::binder::BoundStatement;
12use crate::parser::ast::Stmt;
13use crate::planning::context::PlanContext;
14use crate::planning::plan::SubPlan;
15use crate::QueryContext;
16
17pub use crate::binder::validation::ValidatedStatement;
19
20use crate::planning::fulltext_planner::FulltextSearchPlanner;
21use crate::planning::statements::ddl::maintain_planner::MaintainPlanner;
22use crate::planning::statements::ddl::use_planner::UsePlanner;
23use crate::planning::statements::ddl::user_management_planner::UserManagementPlanner;
24use crate::planning::statements::dml::assignment_planner::AssignmentPlanner;
25use crate::planning::statements::dml::copy_planner::CopyPlanner;
26use crate::planning::statements::dml::delete_planner::DeletePlanner;
27use crate::planning::statements::dml::insert_planner::InsertPlanner;
28use crate::planning::statements::dml::merge_planner::MergePlanner;
29use crate::planning::statements::dml::remove_planner::RemovePlanner;
30use crate::planning::statements::dml::set_planner::SetPlanner;
31use crate::planning::statements::dml::update_planner::UpdatePlanner;
32use crate::planning::statements::dql::assign_variable_planner::AssignVariablePlanner;
33use crate::planning::statements::dql::collect_planner::CollectPlanner;
34use crate::planning::statements::dql::explain_planner::ExplainPlanner;
35use crate::planning::statements::dql::fetch_edges_planner::FetchEdgesPlanner;
36use crate::planning::statements::dql::fetch_vertices_planner::FetchVerticesPlanner;
37use crate::planning::statements::dql::filter_planner::FilterPlanner;
38use crate::planning::statements::dql::go_planner::GoPlanner;
39use crate::planning::statements::dql::group_by_planner::GroupByPlanner;
40use crate::planning::statements::dql::lookup_planner::LookupPlanner;
41use crate::planning::statements::dql::path_planner::PathPlanner;
42use crate::planning::statements::dql::pipe_planner::PipePlanner;
43use crate::planning::statements::dql::return_planner::ReturnPlanner;
44use crate::planning::statements::dql::set_operation_planner::SetOperationPlanner;
45use crate::planning::statements::dql::subgraph_planner::SubgraphPlanner;
46use crate::planning::statements::dql::unwind_planner::UnwindPlanner;
47use crate::planning::statements::dql::with_planner::WithPlanner;
48use crate::planning::statements::dql::yield_planner::YieldPlanner;
49use crate::planning::statements::match_statement_planner::MatchStatementPlanner;
50#[cfg(feature = "vector")]
51use crate::planning::vector_planner::VectorSearchPlanner;
52
53#[derive(Debug, Clone)]
55pub struct PlannerConfig {
56 pub max_plan_depth: usize,
57 pub enable_parallel_planning: bool,
58 pub enable_rewrite: bool,
59}
60
61impl Default for PlannerConfig {
62 fn default() -> Self {
63 Self {
64 max_plan_depth: 100,
65 enable_parallel_planning: false,
66 enable_rewrite: true,
67 }
68 }
69}
70
71pub type MatchFunc = fn(&Stmt) -> bool;
73
74pub trait Planner: std::fmt::Debug {
80 fn transform(
86 &mut self,
87 validated: &ValidatedStatement,
88 qctx: Arc<QueryContext>,
89 ) -> Result<SubPlan, PlannerError>;
90
91 fn match_planner(&self, stmt: &Stmt) -> bool;
93
94 fn plan_bound(&mut self, _ctx: &PlanContext<'_>) -> Result<SubPlan, PlannerError> {
102 Err(PlannerError::UnsupportedOperation(
103 "plan_bound not yet implemented for this planner".to_string(),
104 ))
105 }
106
107 fn name(&self) -> &'static str {
108 std::any::type_name::<Self>()
109 }
110}
111
112#[derive(Debug, Clone)]
119pub enum PlannerEnum {
120 Match(Box<MatchStatementPlanner>),
121 Go(GoPlanner),
122 Lookup(LookupPlanner),
123 Path(PathPlanner),
124 Subgraph(SubgraphPlanner),
125 FetchVertices(FetchVerticesPlanner),
126 FetchEdges(FetchEdgesPlanner),
127 Maintain(MaintainPlanner),
128 UserManagement(UserManagementPlanner),
129 Assignment(AssignmentPlanner),
130 Insert(InsertPlanner),
131 Copy(CopyPlanner),
132 Delete(DeletePlanner),
133 Update(UpdatePlanner),
134 Remove(RemovePlanner),
135 Set(SetPlanner),
136 Merge(MergePlanner),
137 GroupBy(GroupByPlanner),
138 Filter(FilterPlanner),
139 Collect(CollectPlanner),
140 SetOperation(SetOperationPlanner),
141 Use(UsePlanner),
142 Unwind(UnwindPlanner),
143 With(WithPlanner),
144 Return(ReturnPlanner),
145 AssignVariable(AssignVariablePlanner),
146 Yield(YieldPlanner),
147 Pipe(PipePlanner),
148 Explain(ExplainPlanner),
149 FulltextSearch(FulltextSearchPlanner),
150 #[cfg(feature = "vector")]
151 VectorSearch(VectorSearchPlanner),
152}
153
154impl PlannerEnum {
155 pub fn from_stmt(stmt: &Arc<Stmt>) -> Option<Self> {
158 Self::from_stmt_ref(stmt.as_ref())
159 }
160
161 pub fn from_stmt_ref(stmt: &Stmt) -> Option<Self> {
164 match stmt {
165 Stmt::Match(_) => Some(PlannerEnum::Match(Box::default())),
166 Stmt::Go(_) => Some(PlannerEnum::Go(GoPlanner::new())),
167 Stmt::Lookup(_) => Some(PlannerEnum::Lookup(LookupPlanner::new())),
168 Stmt::FindPath(_) => Some(PlannerEnum::Path(PathPlanner::new())),
169 Stmt::Subgraph(_) => Some(PlannerEnum::Subgraph(SubgraphPlanner::new())),
170 Stmt::Fetch(fetch_stmt) => match &fetch_stmt.target {
171 crate::parser::ast::FetchTarget::Vertices { .. } => {
172 Some(PlannerEnum::FetchVertices(FetchVerticesPlanner::new()))
173 }
174 crate::parser::ast::FetchTarget::Edges { .. } => {
175 Some(PlannerEnum::FetchEdges(FetchEdgesPlanner::new()))
176 }
177 },
178 Stmt::Insert(_) => Some(PlannerEnum::Insert(InsertPlanner::new())),
179 Stmt::Copy(_) => Some(PlannerEnum::Copy(CopyPlanner::new())),
180 Stmt::Delete(_) => Some(PlannerEnum::Delete(DeletePlanner::new())),
181 Stmt::Update(_) => Some(PlannerEnum::Update(UpdatePlanner::new())),
182 Stmt::Remove(_) => Some(PlannerEnum::Remove(RemovePlanner::new())),
183 Stmt::Set(_) => Some(PlannerEnum::Set(SetPlanner::new())),
184 Stmt::Merge(_) => Some(PlannerEnum::Merge(MergePlanner::new())),
185 Stmt::Assignment(_) => Some(PlannerEnum::Assignment(AssignmentPlanner::new())),
186 Stmt::GroupBy(_) => Some(PlannerEnum::GroupBy(GroupByPlanner::new())),
187 Stmt::Filter(_) => Some(PlannerEnum::Filter(FilterPlanner::new())),
188 Stmt::Collect(_) => Some(PlannerEnum::Collect(CollectPlanner::new())),
189 Stmt::SetOperation(_) => Some(PlannerEnum::SetOperation(SetOperationPlanner::new())),
190 Stmt::Use(_) => Some(PlannerEnum::Use(UsePlanner::new())),
191 Stmt::Unwind(_) => Some(PlannerEnum::Unwind(UnwindPlanner::new())),
192 Stmt::With(_) => Some(PlannerEnum::With(WithPlanner::new())),
193 Stmt::Return(_) => Some(PlannerEnum::Return(ReturnPlanner::new())),
194 Stmt::AssignVariable(_) => {
195 Some(PlannerEnum::AssignVariable(AssignVariablePlanner::new()))
196 }
197 Stmt::Yield(_) => Some(PlannerEnum::Yield(YieldPlanner::new())),
198 Stmt::Pipe(_) => Some(PlannerEnum::Pipe(PipePlanner::new())),
199 Stmt::Explain(_) => Some(PlannerEnum::Explain(ExplainPlanner::new())),
200 Stmt::Profile(_) => Some(PlannerEnum::Explain(ExplainPlanner::new_profile())),
201 Stmt::CreateFulltextIndex(_)
203 | Stmt::DropFulltextIndex(_)
204 | Stmt::AlterFulltextIndex(_)
205 | Stmt::ShowFulltextIndex(_)
206 | Stmt::DescribeFulltextIndex(_)
207 | Stmt::Search(_)
208 | Stmt::LookupFulltext(_)
209 | Stmt::MatchFulltext(_) => {
210 Some(PlannerEnum::FulltextSearch(FulltextSearchPlanner::new()))
211 }
212 #[cfg(feature = "vector")]
213 Stmt::CreateVectorIndex(_)
214 | Stmt::DropVectorIndex(_)
215 | Stmt::SearchVector(_)
216 | Stmt::LookupVector(_)
217 | Stmt::MatchVector(_) => Some(PlannerEnum::VectorSearch(VectorSearchPlanner::new())),
218 Stmt::CreateUser(_)
219 | Stmt::DropUser(_)
220 | Stmt::AlterUser(_)
221 | Stmt::ChangePassword(_)
222 | Stmt::Grant(_)
223 | Stmt::Revoke(_)
224 | Stmt::DescribeUser(_)
225 | Stmt::ShowUsers(_)
226 | Stmt::ShowRoles(_) => Some(PlannerEnum::UserManagement(UserManagementPlanner::new())),
227 Stmt::Create(_)
228 | Stmt::Drop(_)
229 | Stmt::Show(_)
230 | Stmt::Desc(_)
231 | Stmt::Alter(_)
232 | Stmt::ShowCreate(_)
233 | Stmt::ShowSessions(_)
234 | Stmt::ShowQueries(_)
235 | Stmt::KillQuery(_)
236 | Stmt::ShowConfigs(_)
237 | Stmt::UpdateConfigs(_)
238 | Stmt::ClearSpace(_)
239 | Stmt::BeginTransaction(_)
240 | Stmt::CommitTransaction(_)
241 | Stmt::RollbackTransaction(_)
242 | Stmt::Savepoint(_)
243 | Stmt::ReleaseSavepoint(_)
244 | Stmt::Checkpoint(_)
245 | Stmt::PurgeExpired(_)
246 | Stmt::ExportDatabase(_)
247 | Stmt::ImportDatabase(_)
248 | Stmt::AttachDatabase(_)
249 | Stmt::DetachDatabase(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
250 Stmt::LoadFrom(_) | Stmt::InQueryCall(_) => {
254 Some(PlannerEnum::Maintain(MaintainPlanner::new()))
255 }
256 Stmt::CreateMacro(_) | Stmt::DropMacro(_) | Stmt::CreateType(_) | Stmt::DropType(_) => {
259 Some(PlannerEnum::Maintain(MaintainPlanner::new()))
260 }
261 _ => None,
263 }
264 }
265
266 pub fn from_ast(ast: &Arc<crate::parser::ast::stmt::Ast>) -> Option<Self> {
269 Self::from_stmt_ref(&ast.stmt)
270 }
271
272 pub fn transform(
274 &mut self,
275 validated: &ValidatedStatement,
276 qctx: Arc<QueryContext>,
277 ) -> Result<SubPlan, PlannerError> {
278 match self {
279 PlannerEnum::Match(planner) => planner.transform(validated, qctx),
280 PlannerEnum::Go(planner) => planner.transform(validated, qctx),
281 PlannerEnum::Lookup(planner) => planner.transform(validated, qctx),
282 PlannerEnum::Path(planner) => planner.transform(validated, qctx),
283 PlannerEnum::Subgraph(planner) => planner.transform(validated, qctx),
284 PlannerEnum::FetchVertices(planner) => planner.transform(validated, qctx),
285 PlannerEnum::FetchEdges(planner) => planner.transform(validated, qctx),
286 PlannerEnum::Maintain(planner) => planner.transform(validated, qctx),
287 PlannerEnum::UserManagement(planner) => planner.transform(validated, qctx),
288 PlannerEnum::Assignment(planner) => planner.transform(validated, qctx),
289 PlannerEnum::Insert(planner) => planner.transform(validated, qctx),
290 PlannerEnum::Copy(planner) => planner.transform(validated, qctx),
291 PlannerEnum::Delete(planner) => planner.transform(validated, qctx),
292 PlannerEnum::Update(planner) => planner.transform(validated, qctx),
293 PlannerEnum::Remove(planner) => planner.transform(validated, qctx),
294 PlannerEnum::Set(planner) => planner.transform(validated, qctx),
295 PlannerEnum::Merge(planner) => planner.transform(validated, qctx),
296 PlannerEnum::GroupBy(planner) => planner.transform(validated, qctx),
297 PlannerEnum::Filter(planner) => planner.transform(validated, qctx),
298 PlannerEnum::Collect(planner) => planner.transform(validated, qctx),
299 PlannerEnum::SetOperation(planner) => planner.transform(validated, qctx),
300 PlannerEnum::Use(planner) => planner.transform(validated, qctx),
301 PlannerEnum::Unwind(planner) => planner.transform(validated, qctx),
302 PlannerEnum::With(planner) => planner.transform(validated, qctx),
303 PlannerEnum::Return(planner) => planner.transform(validated, qctx),
304 PlannerEnum::AssignVariable(planner) => planner.transform(validated, qctx),
305 PlannerEnum::Yield(planner) => planner.transform(validated, qctx),
306 PlannerEnum::Pipe(planner) => planner.transform(validated, qctx),
307 PlannerEnum::Explain(planner) => planner.transform(validated, qctx),
308 PlannerEnum::FulltextSearch(planner) => planner.transform(validated, qctx),
309 #[cfg(feature = "vector")]
310 PlannerEnum::VectorSearch(planner) => planner.transform(validated, qctx),
311 }
312 }
313
314 pub fn from_bound_statement(bound: &BoundStatement) -> Option<Self> {
316 match bound {
317 BoundStatement::Match(_) => Some(PlannerEnum::Match(Box::default())),
318 BoundStatement::Go(_) => Some(PlannerEnum::Go(GoPlanner::new())),
319 BoundStatement::Lookup(_) => Some(PlannerEnum::Lookup(LookupPlanner::new())),
320 BoundStatement::FetchVertices(_) => {
321 Some(PlannerEnum::FetchVertices(FetchVerticesPlanner::new()))
322 }
323 BoundStatement::FetchEdges(_) => {
324 Some(PlannerEnum::FetchEdges(FetchEdgesPlanner::new()))
325 }
326 BoundStatement::FindPath(_) => Some(PlannerEnum::Path(PathPlanner::new())),
327 BoundStatement::Subgraph(_) => Some(PlannerEnum::Subgraph(SubgraphPlanner::new())),
328 BoundStatement::Return(_) => Some(PlannerEnum::Return(ReturnPlanner::new())),
329 BoundStatement::With(_) => Some(PlannerEnum::With(WithPlanner::new())),
330 BoundStatement::Use(_) => Some(PlannerEnum::Use(UsePlanner::new())),
331 BoundStatement::Unwind(_) => Some(PlannerEnum::Unwind(UnwindPlanner::new())),
332 BoundStatement::Pipe(_) => Some(PlannerEnum::Pipe(PipePlanner::new())),
333 BoundStatement::SetOperation(_) => {
334 Some(PlannerEnum::SetOperation(SetOperationPlanner::new()))
335 }
336 BoundStatement::GroupBy(_) => Some(PlannerEnum::GroupBy(GroupByPlanner::new())),
337 BoundStatement::Filter(_) => Some(PlannerEnum::Filter(FilterPlanner::new())),
338 BoundStatement::Yield(_) => Some(PlannerEnum::Yield(YieldPlanner::new())),
339 BoundStatement::Collect(_) => Some(PlannerEnum::Collect(CollectPlanner::new())),
340 BoundStatement::AssignVariable(_) => {
341 Some(PlannerEnum::AssignVariable(AssignVariablePlanner::new()))
342 }
343 BoundStatement::Insert(_) => Some(PlannerEnum::Insert(InsertPlanner::new())),
344 BoundStatement::Update(_) => Some(PlannerEnum::Update(UpdatePlanner::new())),
345 BoundStatement::Delete(_) => Some(PlannerEnum::Delete(DeletePlanner::new())),
346 BoundStatement::Merge(_) => Some(PlannerEnum::Merge(MergePlanner::new())),
347 BoundStatement::Set(_) => Some(PlannerEnum::Set(SetPlanner::new())),
348 BoundStatement::Remove(_) => Some(PlannerEnum::Remove(RemovePlanner::new())),
349 BoundStatement::Copy(_) => Some(PlannerEnum::Copy(CopyPlanner::new())),
350 BoundStatement::Drop(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
351 BoundStatement::Alter(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
352 BoundStatement::Show(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
353 BoundStatement::ShowCreate(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
354 BoundStatement::Desc(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
355 BoundStatement::ClearSpace(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
356 BoundStatement::CreateUser(_)
357 | BoundStatement::DropUser(_)
358 | BoundStatement::AlterUser(_) => {
359 Some(PlannerEnum::UserManagement(UserManagementPlanner::new()))
360 }
361 BoundStatement::CreateFulltextIndex(_) => {
362 Some(PlannerEnum::FulltextSearch(FulltextSearchPlanner::new()))
363 }
364 BoundStatement::CreateVectorIndex(_) => {
365 #[cfg(feature = "vector")]
366 {
367 Some(PlannerEnum::VectorSearch(VectorSearchPlanner::new()))
368 }
369 #[cfg(not(feature = "vector"))]
370 {
371 None
372 }
373 }
374 BoundStatement::Explain(_) => Some(PlannerEnum::Explain(ExplainPlanner::new())),
375 BoundStatement::Profile(_) => Some(PlannerEnum::Explain(ExplainPlanner::new_profile())),
376 BoundStatement::BeginTransaction(_)
377 | BoundStatement::Commit(_)
378 | BoundStatement::Rollback(_)
379 | BoundStatement::Savepoint(_)
380 | BoundStatement::ReleaseSavepoint(_) => {
381 Some(PlannerEnum::Maintain(MaintainPlanner::new()))
382 }
383 BoundStatement::Assignment(_) => {
384 Some(PlannerEnum::Assignment(AssignmentPlanner::new()))
385 }
386 BoundStatement::Other(stmt) => Self::from_stmt_ref(stmt.as_ref()),
387 }
388 }
389
390 pub fn name(&self) -> &'static str {
392 match self {
393 PlannerEnum::Match(_) => "MatchPlanner",
394 PlannerEnum::Go(_) => "GoPlanner",
395 PlannerEnum::Lookup(_) => "LookupPlanner",
396 PlannerEnum::Path(_) => "PathPlanner",
397 PlannerEnum::Subgraph(_) => "SubgraphPlanner",
398 PlannerEnum::FetchVertices(_) => "FetchVerticesPlanner",
399 PlannerEnum::FetchEdges(_) => "FetchEdgesPlanner",
400 PlannerEnum::Maintain(_) => "MaintainPlanner",
401 PlannerEnum::UserManagement(_) => "UserManagementPlanner",
402 PlannerEnum::Assignment(_) => "AssignmentPlanner",
403 PlannerEnum::Insert(_) => "InsertPlanner",
404 PlannerEnum::Copy(_) => "CopyPlanner",
405 PlannerEnum::Delete(_) => "DeletePlanner",
406 PlannerEnum::Update(_) => "UpdatePlanner",
407 PlannerEnum::Remove(_) => "RemovePlanner",
408 PlannerEnum::Set(_) => "SetPlanner",
409 PlannerEnum::Merge(_) => "MergePlanner",
410 PlannerEnum::GroupBy(_) => "GroupByPlanner",
411 PlannerEnum::Filter(_) => "FilterPlanner",
412 PlannerEnum::Collect(_) => "CollectPlanner",
413 PlannerEnum::SetOperation(_) => "SetOperationPlanner",
414 PlannerEnum::Use(_) => "UsePlanner",
415 PlannerEnum::Unwind(_) => "UnwindPlanner",
416 PlannerEnum::With(_) => "WithPlanner",
417 PlannerEnum::Return(_) => "ReturnPlanner",
418 PlannerEnum::AssignVariable(_) => "AssignVariablePlanner",
419 PlannerEnum::Yield(_) => "YieldPlanner",
420 PlannerEnum::Pipe(_) => "PipePlanner",
421 PlannerEnum::Explain(_) => "ExplainPlanner",
422 PlannerEnum::FulltextSearch(_) => "FulltextSearchPlanner",
423 #[cfg(feature = "vector")]
424 PlannerEnum::VectorSearch(_) => "VectorSearchPlanner",
425 }
426 }
427
428 pub fn matches(&self, stmt: &Stmt) -> bool {
430 match self {
431 PlannerEnum::Match(planner) => planner.match_planner(stmt),
432 PlannerEnum::Go(planner) => planner.match_planner(stmt),
433 PlannerEnum::Lookup(planner) => planner.match_planner(stmt),
434 PlannerEnum::Path(planner) => planner.match_planner(stmt),
435 PlannerEnum::Subgraph(planner) => planner.match_planner(stmt),
436 PlannerEnum::FetchVertices(planner) => planner.match_planner(stmt),
437 PlannerEnum::FetchEdges(planner) => planner.match_planner(stmt),
438 PlannerEnum::Maintain(planner) => planner.match_planner(stmt),
439 PlannerEnum::UserManagement(planner) => planner.match_planner(stmt),
440 PlannerEnum::Assignment(planner) => planner.match_planner(stmt),
441 PlannerEnum::Insert(planner) => planner.match_planner(stmt),
442 PlannerEnum::Copy(planner) => planner.match_planner(stmt),
443 PlannerEnum::Delete(planner) => planner.match_planner(stmt),
444 PlannerEnum::Update(planner) => planner.match_planner(stmt),
445 PlannerEnum::Remove(planner) => planner.match_planner(stmt),
446 PlannerEnum::Set(planner) => planner.match_planner(stmt),
447 PlannerEnum::Merge(planner) => planner.match_planner(stmt),
448 PlannerEnum::GroupBy(planner) => planner.match_planner(stmt),
449 PlannerEnum::Filter(planner) => planner.match_planner(stmt),
450 PlannerEnum::Collect(planner) => planner.match_planner(stmt),
451 PlannerEnum::SetOperation(planner) => planner.match_planner(stmt),
452 PlannerEnum::Use(planner) => planner.match_planner(stmt),
453 PlannerEnum::Unwind(planner) => planner.match_planner(stmt),
454 PlannerEnum::With(planner) => planner.match_planner(stmt),
455 PlannerEnum::Return(planner) => planner.match_planner(stmt),
456 PlannerEnum::AssignVariable(planner) => planner.match_planner(stmt),
457 PlannerEnum::Yield(planner) => planner.match_planner(stmt),
458 PlannerEnum::Pipe(planner) => planner.match_planner(stmt),
459 PlannerEnum::Explain(planner) => planner.match_planner(stmt),
460 PlannerEnum::FulltextSearch(planner) => planner.match_planner(stmt),
461 #[cfg(feature = "vector")]
462 PlannerEnum::VectorSearch(planner) => planner.match_planner(stmt),
463 }
464 }
465
466 pub fn plan_bound(
468 &mut self,
469 ctx: &crate::planning::context::PlanContext<'_>,
470 ) -> Result<SubPlan, PlannerError> {
471 match self {
472 PlannerEnum::Match(planner) => planner.plan_bound(ctx),
473 PlannerEnum::Go(planner) => planner.plan_bound(ctx),
474 PlannerEnum::Lookup(planner) => planner.plan_bound(ctx),
475 PlannerEnum::Path(planner) => planner.plan_bound(ctx),
476 PlannerEnum::Subgraph(planner) => planner.plan_bound(ctx),
477 PlannerEnum::FetchVertices(planner) => planner.plan_bound(ctx),
478 PlannerEnum::FetchEdges(planner) => planner.plan_bound(ctx),
479 PlannerEnum::Maintain(planner) => planner.plan_bound(ctx),
480 PlannerEnum::UserManagement(planner) => planner.plan_bound(ctx),
481 PlannerEnum::Assignment(planner) => planner.plan_bound(ctx),
482 PlannerEnum::Insert(planner) => planner.plan_bound(ctx),
483 PlannerEnum::Copy(planner) => planner.plan_bound(ctx),
484 PlannerEnum::Delete(planner) => planner.plan_bound(ctx),
485 PlannerEnum::Update(planner) => planner.plan_bound(ctx),
486 PlannerEnum::Remove(planner) => planner.plan_bound(ctx),
487 PlannerEnum::Set(planner) => planner.plan_bound(ctx),
488 PlannerEnum::Merge(planner) => planner.plan_bound(ctx),
489 PlannerEnum::GroupBy(planner) => planner.plan_bound(ctx),
490 PlannerEnum::Filter(planner) => planner.plan_bound(ctx),
491 PlannerEnum::Collect(planner) => planner.plan_bound(ctx),
492 PlannerEnum::SetOperation(planner) => planner.plan_bound(ctx),
493 PlannerEnum::Use(planner) => planner.plan_bound(ctx),
494 PlannerEnum::Unwind(planner) => planner.plan_bound(ctx),
495 PlannerEnum::With(planner) => planner.plan_bound(ctx),
496 PlannerEnum::Return(planner) => planner.plan_bound(ctx),
497 PlannerEnum::AssignVariable(planner) => planner.plan_bound(ctx),
498 PlannerEnum::Yield(planner) => planner.plan_bound(ctx),
499 PlannerEnum::Pipe(planner) => planner.plan_bound(ctx),
500 PlannerEnum::Explain(planner) => planner.plan_bound(ctx),
501 PlannerEnum::FulltextSearch(planner) => planner.plan_bound(ctx),
502 #[cfg(feature = "vector")]
503 PlannerEnum::VectorSearch(planner) => planner.plan_bound(ctx),
504 }
505 }
506}
507
508#[macro_export]
510macro_rules! ng_return_if_error {
511 ($expr:expr) => {
512 match $expr {
513 Ok(val) => val,
514 Err(e) => return Err(e.into()),
515 }
516 };
517}
518
519#[macro_export]
521macro_rules! ng_ok_or_err {
522 ($expr:expr, $msg:expr) => {
523 match $expr {
524 Ok(val) => val,
525 Err(_) => return Err(PlannerError::PlanGenerationFailed($msg.to_string())),
526 }
527 };
528}
529
530#[derive(Debug, thiserror::Error)]
532pub enum PlannerError {
533 #[error("No suitable planner found: {0}")]
534 NoSuitablePlanner(String),
535
536 #[error("Unsupported operation: {0}")]
537 UnsupportedOperation(String),
538
539 #[error("Plan generation failed: {0}")]
540 PlanGenerationFailed(String),
541
542 #[error("Join operation failed: {0}")]
543 JoinFailed(String),
544
545 #[error("Invalid AST context: {0}")]
546 InvalidAstContext(String),
547
548 #[error("Missing input: {0}")]
549 MissingInput(String),
550
551 #[error("Missing variable: {0}")]
552 MissingVariable(String),
553
554 #[error("Invalid operation: {0}")]
555 InvalidOperation(String),
556
557 #[error("Index not found: {0}")]
558 IndexNotFound(String),
559
560 #[error("Unsupported vector filter: {0}")]
561 UnsupportedVectorFilter(String),
562
563 #[error("Tag not found: {0}")]
564 TagNotFound(String),
565
566 #[error("Edge type not found: {0}")]
567 EdgeTypeNotFound(String),
568
569 #[error("Metadata version mismatch: expected {expected}, got {actual}")]
570 MetadataVersionMismatch { expected: u64, actual: u64 },
571
572 #[error("Invalid metadata: {0}")]
573 InvalidMetadata(String),
574}
575
576impl From<linkrs_core::error::DBError> for PlannerError {
578 fn from(err: linkrs_core::error::DBError) -> Self {
579 PlannerError::PlanGenerationFailed(err.to_string())
580 }
581}
582
583#[cfg(test)]
584mod tests {
585 use super::*;
586
587 #[test]
588 fn test_planner_enum_from_stmt() {
589 let match_stmt = Stmt::Match(crate::parser::ast::MatchStmt {
591 span: linkrs_core::types::Span::default(),
592 patterns: vec![],
593 where_clause: None,
594 return_clause: None,
595 order_by: None,
596 limit: None,
597 skip: None,
598 join_hint: None,
599 optional: false,
600 delete_clause: None,
601 });
602
603 let planner = PlannerEnum::from_stmt(&Arc::new(match_stmt));
604 assert!(planner.is_some());
605 assert_eq!(
606 planner.expect("Planner should exist").name(),
607 "MatchPlanner"
608 );
609 }
610
611 #[test]
612 fn test_planner_enum_matches() {
613 let match_stmt = Stmt::Match(crate::parser::ast::MatchStmt {
614 span: linkrs_core::types::Span::default(),
615 patterns: vec![],
616 where_clause: None,
617 return_clause: None,
618 order_by: None,
619 limit: None,
620 skip: None,
621 join_hint: None,
622 optional: false,
623 delete_clause: None,
624 });
625
626 let planner = PlannerEnum::Match(Box::default());
627 assert!(planner.matches(&match_stmt));
628 }
629}