use crate::binder::BoundStatement;
use crate::parser::ast::stmt::Stmt;
use crate::planning::plan::core::nodes::{ProjectNode, StartNode};
use crate::planning::plan::{PlanNodeEnum, SubPlan};
use crate::planning::planner::{Planner, PlannerError, ValidatedStatement};
use crate::planning::statements::plan_combiner::{logical_start_root, wrap_logical_project};
use crate::QueryContext;
use linkrs_core::YieldColumn;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct AssignVariablePlanner;
impl AssignVariablePlanner {
pub fn new() -> Self {
Self
}
}
impl Planner for AssignVariablePlanner {
fn transform(
&mut self,
validated: &ValidatedStatement,
_qctx: Arc<QueryContext>,
) -> Result<SubPlan, PlannerError> {
let assign = match validated.stmt() {
Stmt::AssignVariable(assign) => assign,
_ => {
return Err(PlannerError::PlanGenerationFailed(
"statement does not contain a LET assignment".to_string(),
));
}
};
let start_node = StartNode::new();
let current_node = PlanNodeEnum::Start(start_node.clone());
let yield_column = YieldColumn {
expression: assign.expression.clone(),
alias: assign.name.clone(),
};
let project_node = ProjectNode::new(current_node.clone(), vec![yield_column.clone()])
.map_err(|e| {
PlannerError::PlanGenerationFailed(format!("Failed to create ProjectNode: {}", e))
})?;
let current_node = PlanNodeEnum::Project(project_node);
let logical_root = wrap_logical_project(
logical_start_root(),
vec![yield_column],
current_node.col_names().to_vec(),
);
let sub_plan = SubPlan {
root: Some(current_node),
tail: Some(PlanNodeEnum::Start(start_node)),
logical_root: Some(logical_root),
};
Ok(sub_plan)
}
fn plan_bound(
&mut self,
ctx: &crate::planning::context::PlanContext<'_>,
) -> Result<SubPlan, PlannerError> {
let bound = ctx.bound;
let qctx = ctx.qctx.clone();
let metadata = ctx.metadata;
let validated = ctx.validated;
let _ = (&bound, &qctx, &metadata, &validated);
let assign = match bound {
BoundStatement::AssignVariable(a) => a,
_ => {
return Err(PlannerError::PlanGenerationFailed(
"statement does not contain a LET assignment".to_string(),
));
}
};
let expr_ctx = Arc::new(
linkrs_core::types::expr::expression_context::ExpressionAnalysisContext::new(),
);
let ctx_expr =
crate::binder::expr_converter::bound_expr_to_contextual(&assign.expression, &expr_ctx)
.map_err(PlannerError::PlanGenerationFailed)?;
let start_node = StartNode::new();
let current_node = PlanNodeEnum::Start(start_node.clone());
let yield_column = YieldColumn {
expression: ctx_expr,
alias: assign.name.clone(),
};
let project_node = ProjectNode::new(current_node.clone(), vec![yield_column.clone()])
.map_err(|e| {
PlannerError::PlanGenerationFailed(format!("Failed to create ProjectNode: {}", e))
})?;
let current_node = PlanNodeEnum::Project(project_node);
let logical_root = wrap_logical_project(
logical_start_root(),
vec![yield_column],
current_node.col_names().to_vec(),
);
let sub_plan = SubPlan {
root: Some(current_node),
tail: Some(PlanNodeEnum::Start(start_node)),
logical_root: Some(logical_root),
};
Ok(sub_plan)
}
fn match_planner(&self, stmt: &Stmt) -> bool {
matches!(stmt, Stmt::AssignVariable(_))
}
}
impl Default for AssignVariablePlanner {
fn default() -> Self {
Self::new()
}
}