1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! GraphForge Graph IR → DataFusion relational lowering.
//!
//! # Milestone status
//!
//! - M12 #574 — IR expression lowering to DataFusion `Expr`
//! - M12 #573 — Wire SessionContext
//! - M12 #575 — Lower simple GraphOps (Filter, Project, …)
//! - M12 #576 — Lower NodeScan and Expand
//! - M12 #578 — Graph-native Extension stubs + `explain_logical` ← **this issue**
pub use ;
pub use GraphPlanLowerer;
pub use GfError;
pub use GraphPlan;
use OntologyHandle;
/// A DataFusion [`datafusion::logical_expr::LogicalPlan`] produced by the
/// relational lowering pass.
///
/// Using a type alias means all downstream code (including `graphforge-exec`) works
/// directly with the native DataFusion type without any wrapping overhead.
pub type LogicalPlan = LogicalPlan;
/// Lower a [`GraphPlan`] to a DataFusion [`LogicalPlan`].
///
/// Delegates to [`GraphPlanLowerer`] with `catalog = None` and
/// `ontology = None` (exploratory mode). Scan operators (`NodeScan`,
/// `Expand`) return [`GfError::Plan`] until #576 is complete.
///
/// # Errors
///
/// Returns [`GfError::Plan`] if any operator in the pipeline cannot be
/// lowered (e.g. graph-native scan operators not yet implemented in #576).
/// Lower a [`GraphPlan`] and run DataFusion's analyzer + optimizer over it.
///
/// Uses a transient [`SessionContext`](datafusion::prelude::SessionContext)
/// with no registered catalog — the lowered plan is self-contained (scans use
/// [`LogicalTableSource`](datafusion::logical_expr::logical_plan::LogicalTableSource)
/// with static schemas), so optimisation needs no external state. Lowering
/// runs in exploratory mode (`catalog = None`, `ontology = None`).
///
/// # Errors
///
/// Returns [`GfError::Plan`] if lowering fails or the analyzer/optimizer
/// rejects the plan (e.g. unresolved `$param` placeholders).
/// Render a [`GraphPlan`]'s optimised DataFusion [`LogicalPlan`] as indented
/// text (with per-node schemas) for the `explain` LogicalPlan stage.
///
/// Lowers in exploratory mode (no ontology). Falls back to the
/// pre-optimisation plan when the analyzer/optimizer rejects it — graph-native
/// [`Extension`](datafusion::logical_expr::Extension) stub nodes carry no
/// optimiser semantics yet, and `$param` placeholders cannot be type-coerced
/// until execution time. In both cases the un-optimised plan is still valid,
/// inspectable output.
///
/// # Errors
///
/// Returns [`GfError`] if the plan cannot be lowered at all.
/// Like [`explain_logical`] but lowers with an optional [`OntologyHandle`] so
/// that typed edge scans and variable-length expands can resolve relation-type
/// names. Used by the logical-plan golden suite (which binds against a formal
/// ontology for deterministic type IDs).
///
/// # Errors
///
/// Returns [`GfError`] if the plan cannot be lowered.
/// Like [`explain_logical_with`] but also threads a
/// [`GraphCatalog`](graphforge_storage::GraphCatalog) so property accesses (e.g.
/// `n.name`) resolve to their column names via the catalog's `PropId → name`
/// map instead of falling back to `prop_<id>` placeholders. Used by the engine
/// facade's `explain`, which lowers against the instance's runtime catalog.
///
/// # Errors
///
/// Returns [`GfError`] if the plan cannot be lowered.