use std::sync::Arc;
use crate::binder::BoundStatement;
use crate::parser::ast::Stmt;
use crate::planning::context::PlanContext;
use crate::planning::plan::SubPlan;
use crate::QueryContext;
pub use crate::binder::validation::ValidatedStatement;
use crate::planning::fulltext_planner::FulltextSearchPlanner;
use crate::planning::statements::ddl::maintain_planner::MaintainPlanner;
use crate::planning::statements::ddl::use_planner::UsePlanner;
use crate::planning::statements::ddl::user_management_planner::UserManagementPlanner;
use crate::planning::statements::dml::assignment_planner::AssignmentPlanner;
use crate::planning::statements::dml::copy_planner::CopyPlanner;
use crate::planning::statements::dml::delete_planner::DeletePlanner;
use crate::planning::statements::dml::insert_planner::InsertPlanner;
use crate::planning::statements::dml::merge_planner::MergePlanner;
use crate::planning::statements::dml::remove_planner::RemovePlanner;
use crate::planning::statements::dml::set_planner::SetPlanner;
use crate::planning::statements::dml::update_planner::UpdatePlanner;
use crate::planning::statements::dql::assign_variable_planner::AssignVariablePlanner;
use crate::planning::statements::dql::collect_planner::CollectPlanner;
use crate::planning::statements::dql::explain_planner::ExplainPlanner;
use crate::planning::statements::dql::fetch_edges_planner::FetchEdgesPlanner;
use crate::planning::statements::dql::fetch_vertices_planner::FetchVerticesPlanner;
use crate::planning::statements::dql::filter_planner::FilterPlanner;
use crate::planning::statements::dql::go_planner::GoPlanner;
use crate::planning::statements::dql::group_by_planner::GroupByPlanner;
use crate::planning::statements::dql::lookup_planner::LookupPlanner;
use crate::planning::statements::dql::path_planner::PathPlanner;
use crate::planning::statements::dql::pipe_planner::PipePlanner;
use crate::planning::statements::dql::return_planner::ReturnPlanner;
use crate::planning::statements::dql::set_operation_planner::SetOperationPlanner;
use crate::planning::statements::dql::subgraph_planner::SubgraphPlanner;
use crate::planning::statements::dql::unwind_planner::UnwindPlanner;
use crate::planning::statements::dql::with_planner::WithPlanner;
use crate::planning::statements::dql::yield_planner::YieldPlanner;
use crate::planning::statements::match_statement_planner::MatchStatementPlanner;
#[cfg(feature = "vector")]
use crate::planning::vector_planner::VectorSearchPlanner;
#[derive(Debug, Clone)]
pub struct PlannerConfig {
pub max_plan_depth: usize,
pub enable_parallel_planning: bool,
pub enable_rewrite: bool,
}
impl Default for PlannerConfig {
fn default() -> Self {
Self {
max_plan_depth: 100,
enable_parallel_planning: false,
enable_rewrite: true,
}
}
}
pub type MatchFunc = fn(&Stmt) -> bool;
pub trait Planner: std::fmt::Debug {
fn transform(
&mut self,
validated: &ValidatedStatement,
qctx: Arc<QueryContext>,
) -> Result<SubPlan, PlannerError>;
fn match_planner(&self, stmt: &Stmt) -> bool;
fn plan_bound(&mut self, _ctx: &PlanContext<'_>) -> Result<SubPlan, PlannerError> {
Err(PlannerError::UnsupportedOperation(
"plan_bound not yet implemented for this planner".to_string(),
))
}
fn name(&self) -> &'static str {
std::any::type_name::<Self>()
}
}
#[derive(Debug, Clone)]
pub enum PlannerEnum {
Match(Box<MatchStatementPlanner>),
Go(GoPlanner),
Lookup(LookupPlanner),
Path(PathPlanner),
Subgraph(SubgraphPlanner),
FetchVertices(FetchVerticesPlanner),
FetchEdges(FetchEdgesPlanner),
Maintain(MaintainPlanner),
UserManagement(UserManagementPlanner),
Assignment(AssignmentPlanner),
Insert(InsertPlanner),
Copy(CopyPlanner),
Delete(DeletePlanner),
Update(UpdatePlanner),
Remove(RemovePlanner),
Set(SetPlanner),
Merge(MergePlanner),
GroupBy(GroupByPlanner),
Filter(FilterPlanner),
Collect(CollectPlanner),
SetOperation(SetOperationPlanner),
Use(UsePlanner),
Unwind(UnwindPlanner),
With(WithPlanner),
Return(ReturnPlanner),
AssignVariable(AssignVariablePlanner),
Yield(YieldPlanner),
Pipe(PipePlanner),
Explain(ExplainPlanner),
FulltextSearch(FulltextSearchPlanner),
#[cfg(feature = "vector")]
VectorSearch(VectorSearchPlanner),
}
impl PlannerEnum {
pub fn from_stmt(stmt: &Arc<Stmt>) -> Option<Self> {
Self::from_stmt_ref(stmt.as_ref())
}
pub fn from_stmt_ref(stmt: &Stmt) -> Option<Self> {
match stmt {
Stmt::Match(_) => Some(PlannerEnum::Match(Box::default())),
Stmt::Go(_) => Some(PlannerEnum::Go(GoPlanner::new())),
Stmt::Lookup(_) => Some(PlannerEnum::Lookup(LookupPlanner::new())),
Stmt::FindPath(_) => Some(PlannerEnum::Path(PathPlanner::new())),
Stmt::Subgraph(_) => Some(PlannerEnum::Subgraph(SubgraphPlanner::new())),
Stmt::Fetch(fetch_stmt) => match &fetch_stmt.target {
crate::parser::ast::FetchTarget::Vertices { .. } => {
Some(PlannerEnum::FetchVertices(FetchVerticesPlanner::new()))
}
crate::parser::ast::FetchTarget::Edges { .. } => {
Some(PlannerEnum::FetchEdges(FetchEdgesPlanner::new()))
}
},
Stmt::Insert(_) => Some(PlannerEnum::Insert(InsertPlanner::new())),
Stmt::Copy(_) => Some(PlannerEnum::Copy(CopyPlanner::new())),
Stmt::Delete(_) => Some(PlannerEnum::Delete(DeletePlanner::new())),
Stmt::Update(_) => Some(PlannerEnum::Update(UpdatePlanner::new())),
Stmt::Remove(_) => Some(PlannerEnum::Remove(RemovePlanner::new())),
Stmt::Set(_) => Some(PlannerEnum::Set(SetPlanner::new())),
Stmt::Merge(_) => Some(PlannerEnum::Merge(MergePlanner::new())),
Stmt::Assignment(_) => Some(PlannerEnum::Assignment(AssignmentPlanner::new())),
Stmt::GroupBy(_) => Some(PlannerEnum::GroupBy(GroupByPlanner::new())),
Stmt::Filter(_) => Some(PlannerEnum::Filter(FilterPlanner::new())),
Stmt::Collect(_) => Some(PlannerEnum::Collect(CollectPlanner::new())),
Stmt::SetOperation(_) => Some(PlannerEnum::SetOperation(SetOperationPlanner::new())),
Stmt::Use(_) => Some(PlannerEnum::Use(UsePlanner::new())),
Stmt::Unwind(_) => Some(PlannerEnum::Unwind(UnwindPlanner::new())),
Stmt::With(_) => Some(PlannerEnum::With(WithPlanner::new())),
Stmt::Return(_) => Some(PlannerEnum::Return(ReturnPlanner::new())),
Stmt::AssignVariable(_) => {
Some(PlannerEnum::AssignVariable(AssignVariablePlanner::new()))
}
Stmt::Yield(_) => Some(PlannerEnum::Yield(YieldPlanner::new())),
Stmt::Pipe(_) => Some(PlannerEnum::Pipe(PipePlanner::new())),
Stmt::Explain(_) => Some(PlannerEnum::Explain(ExplainPlanner::new())),
Stmt::Profile(_) => Some(PlannerEnum::Explain(ExplainPlanner::new_profile())),
Stmt::CreateFulltextIndex(_)
| Stmt::DropFulltextIndex(_)
| Stmt::AlterFulltextIndex(_)
| Stmt::ShowFulltextIndex(_)
| Stmt::DescribeFulltextIndex(_)
| Stmt::Search(_)
| Stmt::LookupFulltext(_)
| Stmt::MatchFulltext(_) => {
Some(PlannerEnum::FulltextSearch(FulltextSearchPlanner::new()))
}
#[cfg(feature = "vector")]
Stmt::CreateVectorIndex(_)
| Stmt::DropVectorIndex(_)
| Stmt::SearchVector(_)
| Stmt::LookupVector(_)
| Stmt::MatchVector(_) => Some(PlannerEnum::VectorSearch(VectorSearchPlanner::new())),
Stmt::CreateUser(_)
| Stmt::DropUser(_)
| Stmt::AlterUser(_)
| Stmt::ChangePassword(_)
| Stmt::Grant(_)
| Stmt::Revoke(_)
| Stmt::DescribeUser(_)
| Stmt::ShowUsers(_)
| Stmt::ShowRoles(_) => Some(PlannerEnum::UserManagement(UserManagementPlanner::new())),
Stmt::Create(_)
| Stmt::Drop(_)
| Stmt::Show(_)
| Stmt::Desc(_)
| Stmt::Alter(_)
| Stmt::ShowCreate(_)
| Stmt::ShowSessions(_)
| Stmt::ShowQueries(_)
| Stmt::KillQuery(_)
| Stmt::ShowConfigs(_)
| Stmt::UpdateConfigs(_)
| Stmt::ClearSpace(_)
| Stmt::BeginTransaction(_)
| Stmt::CommitTransaction(_)
| Stmt::RollbackTransaction(_)
| Stmt::Savepoint(_)
| Stmt::ReleaseSavepoint(_)
| Stmt::Checkpoint(_)
| Stmt::PurgeExpired(_)
| Stmt::ExportDatabase(_)
| Stmt::ImportDatabase(_)
| Stmt::AttachDatabase(_)
| Stmt::DetachDatabase(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
Stmt::LoadFrom(_) | Stmt::InQueryCall(_) => {
Some(PlannerEnum::Maintain(MaintainPlanner::new()))
}
Stmt::CreateMacro(_) | Stmt::DropMacro(_) | Stmt::CreateType(_) | Stmt::DropType(_) => {
Some(PlannerEnum::Maintain(MaintainPlanner::new()))
}
_ => None,
}
}
pub fn from_ast(ast: &Arc<crate::parser::ast::stmt::Ast>) -> Option<Self> {
Self::from_stmt_ref(&ast.stmt)
}
pub fn transform(
&mut self,
validated: &ValidatedStatement,
qctx: Arc<QueryContext>,
) -> Result<SubPlan, PlannerError> {
match self {
PlannerEnum::Match(planner) => planner.transform(validated, qctx),
PlannerEnum::Go(planner) => planner.transform(validated, qctx),
PlannerEnum::Lookup(planner) => planner.transform(validated, qctx),
PlannerEnum::Path(planner) => planner.transform(validated, qctx),
PlannerEnum::Subgraph(planner) => planner.transform(validated, qctx),
PlannerEnum::FetchVertices(planner) => planner.transform(validated, qctx),
PlannerEnum::FetchEdges(planner) => planner.transform(validated, qctx),
PlannerEnum::Maintain(planner) => planner.transform(validated, qctx),
PlannerEnum::UserManagement(planner) => planner.transform(validated, qctx),
PlannerEnum::Assignment(planner) => planner.transform(validated, qctx),
PlannerEnum::Insert(planner) => planner.transform(validated, qctx),
PlannerEnum::Copy(planner) => planner.transform(validated, qctx),
PlannerEnum::Delete(planner) => planner.transform(validated, qctx),
PlannerEnum::Update(planner) => planner.transform(validated, qctx),
PlannerEnum::Remove(planner) => planner.transform(validated, qctx),
PlannerEnum::Set(planner) => planner.transform(validated, qctx),
PlannerEnum::Merge(planner) => planner.transform(validated, qctx),
PlannerEnum::GroupBy(planner) => planner.transform(validated, qctx),
PlannerEnum::Filter(planner) => planner.transform(validated, qctx),
PlannerEnum::Collect(planner) => planner.transform(validated, qctx),
PlannerEnum::SetOperation(planner) => planner.transform(validated, qctx),
PlannerEnum::Use(planner) => planner.transform(validated, qctx),
PlannerEnum::Unwind(planner) => planner.transform(validated, qctx),
PlannerEnum::With(planner) => planner.transform(validated, qctx),
PlannerEnum::Return(planner) => planner.transform(validated, qctx),
PlannerEnum::AssignVariable(planner) => planner.transform(validated, qctx),
PlannerEnum::Yield(planner) => planner.transform(validated, qctx),
PlannerEnum::Pipe(planner) => planner.transform(validated, qctx),
PlannerEnum::Explain(planner) => planner.transform(validated, qctx),
PlannerEnum::FulltextSearch(planner) => planner.transform(validated, qctx),
#[cfg(feature = "vector")]
PlannerEnum::VectorSearch(planner) => planner.transform(validated, qctx),
}
}
pub fn from_bound_statement(bound: &BoundStatement) -> Option<Self> {
match bound {
BoundStatement::Match(_) => Some(PlannerEnum::Match(Box::default())),
BoundStatement::Go(_) => Some(PlannerEnum::Go(GoPlanner::new())),
BoundStatement::Lookup(_) => Some(PlannerEnum::Lookup(LookupPlanner::new())),
BoundStatement::FetchVertices(_) => {
Some(PlannerEnum::FetchVertices(FetchVerticesPlanner::new()))
}
BoundStatement::FetchEdges(_) => {
Some(PlannerEnum::FetchEdges(FetchEdgesPlanner::new()))
}
BoundStatement::FindPath(_) => Some(PlannerEnum::Path(PathPlanner::new())),
BoundStatement::Subgraph(_) => Some(PlannerEnum::Subgraph(SubgraphPlanner::new())),
BoundStatement::Return(_) => Some(PlannerEnum::Return(ReturnPlanner::new())),
BoundStatement::With(_) => Some(PlannerEnum::With(WithPlanner::new())),
BoundStatement::Use(_) => Some(PlannerEnum::Use(UsePlanner::new())),
BoundStatement::Unwind(_) => Some(PlannerEnum::Unwind(UnwindPlanner::new())),
BoundStatement::Pipe(_) => Some(PlannerEnum::Pipe(PipePlanner::new())),
BoundStatement::SetOperation(_) => {
Some(PlannerEnum::SetOperation(SetOperationPlanner::new()))
}
BoundStatement::GroupBy(_) => Some(PlannerEnum::GroupBy(GroupByPlanner::new())),
BoundStatement::Filter(_) => Some(PlannerEnum::Filter(FilterPlanner::new())),
BoundStatement::Yield(_) => Some(PlannerEnum::Yield(YieldPlanner::new())),
BoundStatement::Collect(_) => Some(PlannerEnum::Collect(CollectPlanner::new())),
BoundStatement::AssignVariable(_) => {
Some(PlannerEnum::AssignVariable(AssignVariablePlanner::new()))
}
BoundStatement::Insert(_) => Some(PlannerEnum::Insert(InsertPlanner::new())),
BoundStatement::Update(_) => Some(PlannerEnum::Update(UpdatePlanner::new())),
BoundStatement::Delete(_) => Some(PlannerEnum::Delete(DeletePlanner::new())),
BoundStatement::Merge(_) => Some(PlannerEnum::Merge(MergePlanner::new())),
BoundStatement::Set(_) => Some(PlannerEnum::Set(SetPlanner::new())),
BoundStatement::Remove(_) => Some(PlannerEnum::Remove(RemovePlanner::new())),
BoundStatement::Copy(_) => Some(PlannerEnum::Copy(CopyPlanner::new())),
BoundStatement::Drop(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
BoundStatement::Alter(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
BoundStatement::Show(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
BoundStatement::ShowCreate(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
BoundStatement::Desc(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
BoundStatement::ClearSpace(_) => Some(PlannerEnum::Maintain(MaintainPlanner::new())),
BoundStatement::CreateUser(_)
| BoundStatement::DropUser(_)
| BoundStatement::AlterUser(_) => {
Some(PlannerEnum::UserManagement(UserManagementPlanner::new()))
}
BoundStatement::CreateFulltextIndex(_) => {
Some(PlannerEnum::FulltextSearch(FulltextSearchPlanner::new()))
}
BoundStatement::CreateVectorIndex(_) => {
#[cfg(feature = "vector")]
{
Some(PlannerEnum::VectorSearch(VectorSearchPlanner::new()))
}
#[cfg(not(feature = "vector"))]
{
None
}
}
BoundStatement::Explain(_) => Some(PlannerEnum::Explain(ExplainPlanner::new())),
BoundStatement::Profile(_) => Some(PlannerEnum::Explain(ExplainPlanner::new_profile())),
BoundStatement::BeginTransaction(_)
| BoundStatement::Commit(_)
| BoundStatement::Rollback(_)
| BoundStatement::Savepoint(_)
| BoundStatement::ReleaseSavepoint(_) => {
Some(PlannerEnum::Maintain(MaintainPlanner::new()))
}
BoundStatement::Assignment(_) => {
Some(PlannerEnum::Assignment(AssignmentPlanner::new()))
}
BoundStatement::Other(stmt) => Self::from_stmt_ref(stmt.as_ref()),
}
}
pub fn name(&self) -> &'static str {
match self {
PlannerEnum::Match(_) => "MatchPlanner",
PlannerEnum::Go(_) => "GoPlanner",
PlannerEnum::Lookup(_) => "LookupPlanner",
PlannerEnum::Path(_) => "PathPlanner",
PlannerEnum::Subgraph(_) => "SubgraphPlanner",
PlannerEnum::FetchVertices(_) => "FetchVerticesPlanner",
PlannerEnum::FetchEdges(_) => "FetchEdgesPlanner",
PlannerEnum::Maintain(_) => "MaintainPlanner",
PlannerEnum::UserManagement(_) => "UserManagementPlanner",
PlannerEnum::Assignment(_) => "AssignmentPlanner",
PlannerEnum::Insert(_) => "InsertPlanner",
PlannerEnum::Copy(_) => "CopyPlanner",
PlannerEnum::Delete(_) => "DeletePlanner",
PlannerEnum::Update(_) => "UpdatePlanner",
PlannerEnum::Remove(_) => "RemovePlanner",
PlannerEnum::Set(_) => "SetPlanner",
PlannerEnum::Merge(_) => "MergePlanner",
PlannerEnum::GroupBy(_) => "GroupByPlanner",
PlannerEnum::Filter(_) => "FilterPlanner",
PlannerEnum::Collect(_) => "CollectPlanner",
PlannerEnum::SetOperation(_) => "SetOperationPlanner",
PlannerEnum::Use(_) => "UsePlanner",
PlannerEnum::Unwind(_) => "UnwindPlanner",
PlannerEnum::With(_) => "WithPlanner",
PlannerEnum::Return(_) => "ReturnPlanner",
PlannerEnum::AssignVariable(_) => "AssignVariablePlanner",
PlannerEnum::Yield(_) => "YieldPlanner",
PlannerEnum::Pipe(_) => "PipePlanner",
PlannerEnum::Explain(_) => "ExplainPlanner",
PlannerEnum::FulltextSearch(_) => "FulltextSearchPlanner",
#[cfg(feature = "vector")]
PlannerEnum::VectorSearch(_) => "VectorSearchPlanner",
}
}
pub fn matches(&self, stmt: &Stmt) -> bool {
match self {
PlannerEnum::Match(planner) => planner.match_planner(stmt),
PlannerEnum::Go(planner) => planner.match_planner(stmt),
PlannerEnum::Lookup(planner) => planner.match_planner(stmt),
PlannerEnum::Path(planner) => planner.match_planner(stmt),
PlannerEnum::Subgraph(planner) => planner.match_planner(stmt),
PlannerEnum::FetchVertices(planner) => planner.match_planner(stmt),
PlannerEnum::FetchEdges(planner) => planner.match_planner(stmt),
PlannerEnum::Maintain(planner) => planner.match_planner(stmt),
PlannerEnum::UserManagement(planner) => planner.match_planner(stmt),
PlannerEnum::Assignment(planner) => planner.match_planner(stmt),
PlannerEnum::Insert(planner) => planner.match_planner(stmt),
PlannerEnum::Copy(planner) => planner.match_planner(stmt),
PlannerEnum::Delete(planner) => planner.match_planner(stmt),
PlannerEnum::Update(planner) => planner.match_planner(stmt),
PlannerEnum::Remove(planner) => planner.match_planner(stmt),
PlannerEnum::Set(planner) => planner.match_planner(stmt),
PlannerEnum::Merge(planner) => planner.match_planner(stmt),
PlannerEnum::GroupBy(planner) => planner.match_planner(stmt),
PlannerEnum::Filter(planner) => planner.match_planner(stmt),
PlannerEnum::Collect(planner) => planner.match_planner(stmt),
PlannerEnum::SetOperation(planner) => planner.match_planner(stmt),
PlannerEnum::Use(planner) => planner.match_planner(stmt),
PlannerEnum::Unwind(planner) => planner.match_planner(stmt),
PlannerEnum::With(planner) => planner.match_planner(stmt),
PlannerEnum::Return(planner) => planner.match_planner(stmt),
PlannerEnum::AssignVariable(planner) => planner.match_planner(stmt),
PlannerEnum::Yield(planner) => planner.match_planner(stmt),
PlannerEnum::Pipe(planner) => planner.match_planner(stmt),
PlannerEnum::Explain(planner) => planner.match_planner(stmt),
PlannerEnum::FulltextSearch(planner) => planner.match_planner(stmt),
#[cfg(feature = "vector")]
PlannerEnum::VectorSearch(planner) => planner.match_planner(stmt),
}
}
pub fn plan_bound(
&mut self,
ctx: &crate::planning::context::PlanContext<'_>,
) -> Result<SubPlan, PlannerError> {
match self {
PlannerEnum::Match(planner) => planner.plan_bound(ctx),
PlannerEnum::Go(planner) => planner.plan_bound(ctx),
PlannerEnum::Lookup(planner) => planner.plan_bound(ctx),
PlannerEnum::Path(planner) => planner.plan_bound(ctx),
PlannerEnum::Subgraph(planner) => planner.plan_bound(ctx),
PlannerEnum::FetchVertices(planner) => planner.plan_bound(ctx),
PlannerEnum::FetchEdges(planner) => planner.plan_bound(ctx),
PlannerEnum::Maintain(planner) => planner.plan_bound(ctx),
PlannerEnum::UserManagement(planner) => planner.plan_bound(ctx),
PlannerEnum::Assignment(planner) => planner.plan_bound(ctx),
PlannerEnum::Insert(planner) => planner.plan_bound(ctx),
PlannerEnum::Copy(planner) => planner.plan_bound(ctx),
PlannerEnum::Delete(planner) => planner.plan_bound(ctx),
PlannerEnum::Update(planner) => planner.plan_bound(ctx),
PlannerEnum::Remove(planner) => planner.plan_bound(ctx),
PlannerEnum::Set(planner) => planner.plan_bound(ctx),
PlannerEnum::Merge(planner) => planner.plan_bound(ctx),
PlannerEnum::GroupBy(planner) => planner.plan_bound(ctx),
PlannerEnum::Filter(planner) => planner.plan_bound(ctx),
PlannerEnum::Collect(planner) => planner.plan_bound(ctx),
PlannerEnum::SetOperation(planner) => planner.plan_bound(ctx),
PlannerEnum::Use(planner) => planner.plan_bound(ctx),
PlannerEnum::Unwind(planner) => planner.plan_bound(ctx),
PlannerEnum::With(planner) => planner.plan_bound(ctx),
PlannerEnum::Return(planner) => planner.plan_bound(ctx),
PlannerEnum::AssignVariable(planner) => planner.plan_bound(ctx),
PlannerEnum::Yield(planner) => planner.plan_bound(ctx),
PlannerEnum::Pipe(planner) => planner.plan_bound(ctx),
PlannerEnum::Explain(planner) => planner.plan_bound(ctx),
PlannerEnum::FulltextSearch(planner) => planner.plan_bound(ctx),
#[cfg(feature = "vector")]
PlannerEnum::VectorSearch(planner) => planner.plan_bound(ctx),
}
}
}
#[macro_export]
macro_rules! ng_return_if_error {
($expr:expr) => {
match $expr {
Ok(val) => val,
Err(e) => return Err(e.into()),
}
};
}
#[macro_export]
macro_rules! ng_ok_or_err {
($expr:expr, $msg:expr) => {
match $expr {
Ok(val) => val,
Err(_) => return Err(PlannerError::PlanGenerationFailed($msg.to_string())),
}
};
}
#[derive(Debug, thiserror::Error)]
pub enum PlannerError {
#[error("No suitable planner found: {0}")]
NoSuitablePlanner(String),
#[error("Unsupported operation: {0}")]
UnsupportedOperation(String),
#[error("Plan generation failed: {0}")]
PlanGenerationFailed(String),
#[error("Join operation failed: {0}")]
JoinFailed(String),
#[error("Invalid AST context: {0}")]
InvalidAstContext(String),
#[error("Missing input: {0}")]
MissingInput(String),
#[error("Missing variable: {0}")]
MissingVariable(String),
#[error("Invalid operation: {0}")]
InvalidOperation(String),
#[error("Index not found: {0}")]
IndexNotFound(String),
#[error("Unsupported vector filter: {0}")]
UnsupportedVectorFilter(String),
#[error("Tag not found: {0}")]
TagNotFound(String),
#[error("Edge type not found: {0}")]
EdgeTypeNotFound(String),
#[error("Metadata version mismatch: expected {expected}, got {actual}")]
MetadataVersionMismatch { expected: u64, actual: u64 },
#[error("Invalid metadata: {0}")]
InvalidMetadata(String),
}
impl From<linkrs_core::error::DBError> for PlannerError {
fn from(err: linkrs_core::error::DBError) -> Self {
PlannerError::PlanGenerationFailed(err.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_planner_enum_from_stmt() {
let match_stmt = Stmt::Match(crate::parser::ast::MatchStmt {
span: linkrs_core::types::Span::default(),
patterns: vec![],
where_clause: None,
return_clause: None,
order_by: None,
limit: None,
skip: None,
join_hint: None,
optional: false,
delete_clause: None,
});
let planner = PlannerEnum::from_stmt(&Arc::new(match_stmt));
assert!(planner.is_some());
assert_eq!(
planner.expect("Planner should exist").name(),
"MatchPlanner"
);
}
#[test]
fn test_planner_enum_matches() {
let match_stmt = Stmt::Match(crate::parser::ast::MatchStmt {
span: linkrs_core::types::Span::default(),
patterns: vec![],
where_clause: None,
return_clause: None,
order_by: None,
limit: None,
skip: None,
join_hint: None,
optional: false,
delete_clause: None,
});
let planner = PlannerEnum::Match(Box::default());
assert!(planner.matches(&match_stmt));
}
}