use super::{
Arc, ExpressionPredicate, FilterExpression, FilterOperator, GraphStore, HashMap, LogicalType,
NestedLoopJoinOperator, NodeScanOp, Operator, PhysicalJoinType, Result, ScanOperator, Value,
};
impl super::Planner {
pub(super) fn plan_node_scan(
&self,
scan: &NodeScanOp,
) -> Result<(Box<dyn Operator>, Vec<String>)> {
let scan_op = if let Some(label) = &scan.label {
ScanOperator::with_label(Arc::clone(&self.store) as Arc<dyn GraphStore>, label)
} else {
ScanOperator::new(Arc::clone(&self.store) as Arc<dyn GraphStore>)
};
let scan_operator: Box<dyn Operator> =
Box::new(scan_op.with_transaction_context(self.viewing_epoch, self.transaction_id));
if let Some(input) = &scan.input {
let (input_op, mut input_columns) = self.plan_operator(input)?;
if input_columns.contains(&scan.variable) {
if let Some(label) = &scan.label {
let variable_columns: HashMap<String, usize> = input_columns
.iter()
.enumerate()
.map(|(i, name)| (name.clone(), i))
.collect();
let filter_expr = FilterExpression::FunctionCall {
name: "hasLabel".to_string(),
args: vec![
FilterExpression::Variable(scan.variable.clone()),
FilterExpression::Literal(Value::String(label.as_str().into())),
],
};
let predicate = ExpressionPredicate::new(
filter_expr,
variable_columns,
Arc::clone(&self.store) as Arc<dyn GraphStore>,
)
.with_transaction_context(self.viewing_epoch, self.transaction_id);
let filtered = Box::new(FilterOperator::new(input_op, Box::new(predicate)));
return Ok((filtered, input_columns));
}
return Ok((input_op, input_columns));
}
let mut output_schema: Vec<LogicalType> =
input_columns.iter().map(|_| LogicalType::Any).collect();
output_schema.push(LogicalType::Node);
input_columns.push(scan.variable.clone());
let join_op = Box::new(NestedLoopJoinOperator::new(
input_op,
scan_operator,
None, PhysicalJoinType::Cross,
output_schema,
));
Ok((join_op, input_columns))
} else {
let columns = vec![scan.variable.clone()];
Ok((scan_operator, columns))
}
}
}