substrait_explain/
lib.rs

1#![doc = include_str!("../API.md")]
2
3pub mod extensions;
4pub mod fixtures;
5pub mod grammar;
6pub mod parser;
7pub mod textify;
8
9#[cfg(feature = "cli")]
10pub mod cli;
11#[cfg(feature = "cli")]
12pub mod json;
13
14// Re-export commonly used types for easier access
15pub use parser::ParseError;
16use substrait::proto::Plan;
17use textify::foundation::ErrorQueue;
18pub use textify::foundation::{FormatError, OutputOptions, Visibility};
19use textify::plan::PlanWriter;
20
21/// Parse a Substrait plan from text format.
22///
23/// This is the main entry point for parsing well-formed plans.
24/// Returns a clear error if parsing fails.
25///
26/// The input should be in the Substrait text format, which consists of:
27/// - An optional extensions section starting with "=== Extensions"
28/// - A plan section starting with "=== Plan"
29/// - Indented relation definitions
30///
31/// # Example
32/// ```rust
33/// use substrait_explain::parse;
34///
35/// let plan_text = r#"
36/// === Plan
37/// Root[c, d]
38///   Project[$1, 42]
39///     Read[schema.table => a:i64, b:string?]
40/// "#;
41///
42/// // Parse the plan. Builds a complete Substrait plan.
43/// let plan = parse(plan_text).unwrap();
44/// ```
45///
46/// # Errors
47///
48/// Returns a `ParseError` if the input cannot be parsed as a valid Substrait plan.
49/// The error includes details about what went wrong and where in the input.
50///
51/// ```rust
52/// use substrait_explain::parse;
53///
54/// let invalid_plan = r#"
55/// === Plan
56/// InvalidRelation[invalid syntax]
57/// "#;
58///
59/// match parse(invalid_plan) {
60///     Ok(_) => println!("Valid plan"),
61///     Err(e) => println!("Parse error: {}", e),
62/// }
63/// ```
64pub fn parse(input: &str) -> Result<Plan, ParseError> {
65    parser::Parser::parse(input)
66}
67
68/// Format a Substrait plan as human-readable text.
69///
70/// This is the main entry point for formatting plans. It uses default
71/// formatting options that produce concise, readable output.
72///
73/// Returns a tuple of `(formatted_text, errors)`. The text is always generated,
74/// even if there are formatting errors. Errors are collected and returned for
75/// inspection.
76///
77/// # Example
78/// ```rust
79/// use substrait_explain::{parse, format};
80/// use substrait::proto::Plan;
81///
82/// let plan: Plan = parse(r#"
83/// === Plan
84/// Root[result]
85///   Project[$0, $1]
86///     Read[data => a:i64, b:string]
87/// "#).unwrap();
88///
89/// let (text, errors) = format(&plan);
90/// println!("{}", text);
91///
92/// if !errors.is_empty() {
93///     println!("Formatting warnings: {:?}", errors);
94/// }
95/// ```
96///
97/// # Output Format
98///
99/// The output follows the Substrait text format specification, with relations
100/// displayed in a hierarchical structure using indentation.
101pub fn format(plan: &Plan) -> (String, Vec<FormatError>) {
102    let options = OutputOptions::default();
103    format_with_options(plan, &options)
104}
105
106/// Format a Substrait plan with custom options.
107///
108/// This function allows you to customize the formatting behavior, such as
109/// showing more or less detail, changing indentation, or controlling
110/// type visibility.
111///
112/// # Example
113/// ```rust
114/// use substrait_explain::{parse, format_with_options, OutputOptions, Visibility};
115///
116/// let plan = parse(r#"
117/// === Plan
118/// Root[result]
119///   Project[$0, 42]
120///     Read[data => a:i64]
121/// "#).unwrap();
122///
123/// // Use verbose formatting
124/// let verbose_options = OutputOptions::verbose();
125/// let (text, _errors) = format_with_options(&plan, &verbose_options);
126/// println!("Verbose output:\n{}", text);
127///
128/// // Custom options
129/// let custom_options = OutputOptions {
130///     literal_types: Visibility::Always,
131///     indent: "    ".to_string(),
132///     ..OutputOptions::default()
133/// };
134/// let (text, _errors) = format_with_options(&plan, &custom_options);
135/// println!("Custom output:\n{}", text);
136/// ```
137///
138/// # Options
139///
140/// See [`OutputOptions`] for all available configuration options.
141pub fn format_with_options(plan: &Plan, options: &OutputOptions) -> (String, Vec<FormatError>) {
142    let default_registry = extensions::ExtensionRegistry::default();
143    format_with_registry(plan, options, &default_registry)
144}
145
146/// Format a Substrait plan with custom options and an extension registry.
147///
148/// This function allows you to provide a custom extension registry for handling
149/// ExtensionLeaf, ExtensionSingle, and ExtensionMulti relations.
150///
151/// # Example
152/// ```rust,ignore
153/// use substrait_explain::{parse, format_with_registry, OutputOptions, ExtensionRegistry};
154///
155/// let mut registry = ExtensionRegistry::new();
156/// // Register custom extensions...
157///
158/// let plan = parse("...").unwrap();
159/// let (text, errors) = format_with_registry(&plan, &OutputOptions::default(), &registry);
160/// ```
161pub fn format_with_registry(
162    plan: &Plan,
163    options: &OutputOptions,
164    registry: &extensions::ExtensionRegistry,
165) -> (String, Vec<FormatError>) {
166    let (writer, error_queue) = PlanWriter::<ErrorQueue>::new(options, plan, registry);
167    let output = format!("{writer}");
168    let errors = error_queue.into_iter().collect();
169    (output, errors)
170}