Skip to main content

lance_graph/
lance_native_planner.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4//! Lance Native physical planner (placeholder)
5//!
6//! This planner is intended to compile logical graph plans into a physical
7//! execution plan that leverages Lance's native scan and filter engine.
8//!
9//! For now, this is a placeholder implementation that conforms to the
10//! `GraphPhysicalPlanner` trait and returns an empty DataFusion logical plan
11//! until the native pipeline is wired up.
12
13use crate::config::GraphConfig;
14use crate::datafusion_planner::GraphPhysicalPlanner;
15use crate::error::Result;
16use crate::logical_plan::LogicalOperator;
17use datafusion::common::DFSchema;
18use datafusion::logical_expr::{EmptyRelation, LogicalPlan};
19use std::sync::Arc;
20
21/// Placeholder Lance-native planner
22pub struct LanceNativePlanner {
23    #[allow(dead_code)]
24    config: GraphConfig,
25}
26
27impl LanceNativePlanner {
28    pub fn new(config: GraphConfig) -> Self {
29        Self { config }
30    }
31}
32
33impl GraphPhysicalPlanner for LanceNativePlanner {
34    fn plan(&self, _logical_plan: &LogicalOperator) -> Result<LogicalPlan> {
35        // Placeholder: return an empty relation. A future implementation will
36        // produce a runnable pipeline using Lance's native execution engine.
37        let schema = Arc::new(DFSchema::empty());
38        Ok(LogicalPlan::EmptyRelation(EmptyRelation {
39            produce_one_row: false,
40            schema,
41        }))
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    #[test]
50    fn test_lance_native_planner_placeholder() {
51        let cfg = GraphConfig::builder()
52            .with_node_label("Person", "id")
53            .build()
54            .unwrap();
55        let planner = LanceNativePlanner::new(cfg);
56        // Minimal logical plan to feed into placeholder
57        let lp = LogicalOperator::Distinct {
58            input: Box::new(LogicalOperator::Limit {
59                input: Box::new(LogicalOperator::Project {
60                    input: Box::new(LogicalOperator::ScanByLabel {
61                        variable: "n".to_string(),
62                        label: "Person".to_string(),
63                        properties: Default::default(),
64                    }),
65                    projections: vec![],
66                }),
67                count: 1,
68            }),
69        };
70        let df_plan = planner.plan(&lp).unwrap();
71        // Empty relation is acceptable as a placeholder
72        match df_plan {
73            LogicalPlan::EmptyRelation(_) => {}
74            _ => panic!("expected empty relation placeholder"),
75        }
76    }
77}