Skip to content

Commit eba6e60

Browse files
committed
Minor: improve documentation for sql unparsing
1 parent 1e9f0e1 commit eba6e60

File tree

4 files changed

+105
-18
lines changed

4 files changed

+105
-18
lines changed

datafusion/sql/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,22 @@
1717
// Make cheap clones clear: https://github.com/apache/datafusion/issues/11143
1818
#![deny(clippy::clone_on_ref_ptr)]
1919

20-
//! This module provides:
20+
//! This crate provides:
2121
//!
2222
//! 1. A SQL parser, [`DFParser`], that translates SQL query text into
2323
//! an abstract syntax tree (AST), [`Statement`].
2424
//!
2525
//! 2. A SQL query planner [`SqlToRel`] that creates [`LogicalPlan`]s
2626
//! from [`Statement`]s.
2727
//!
28+
//! 3. A SQL [`unparser`] that converts [`Expr`]s and [`LogicalPlan`]s
29+
//! into SQL query text.
30+
//!
2831
//! [`DFParser`]: parser::DFParser
2932
//! [`Statement`]: parser::Statement
3033
//! [`SqlToRel`]: planner::SqlToRel
3134
//! [`LogicalPlan`]: datafusion_expr::logical_plan::LogicalPlan
35+
//! [`Expr`]: datafusion_expr::expr::Expr
3236
3337
mod cte;
3438
mod expr;

datafusion/sql/src/unparser/expr.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,21 +72,34 @@ impl Display for Unparsed {
7272
}
7373
}
7474

75-
/// Convert a DataFusion [`Expr`] to `sqlparser::ast::Expr`
75+
/// Convert a DataFusion [`Expr`] to [`ast::Expr`]
7676
///
77-
/// This function is the opposite of `SqlToRel::sql_to_expr` and can
78-
/// be used to, among other things, convert [`Expr`]s to strings.
79-
/// Throws an error if [`Expr`] can not be represented by an `sqlparser::ast::Expr`
77+
/// This function is the opposite of [`SqlToRel::sql_to_expr`] and can be used
78+
/// to, among other things, convert [`Expr`]s to SQL strings. Such strings could
79+
/// be used to pass filters or other expressions to another SQL engine.
80+
///
81+
/// # Errors
82+
///
83+
/// Throws an error if [`Expr`] can not be represented by an [`ast::Expr`]
84+
///
85+
/// # See Also
86+
///
87+
/// * [`Unparser`] for more control over the conversion to SQL
88+
/// * [`plan_to_sql`] for converting a [`LogicalPlan`] to SQL
8089
///
8190
/// # Example
8291
/// ```
8392
/// use datafusion_expr::{col, lit};
8493
/// use datafusion_sql::unparser::expr_to_sql;
85-
/// let expr = col("a").gt(lit(4));
86-
/// let sql = expr_to_sql(&expr).unwrap();
87-
///
88-
/// assert_eq!(format!("{}", sql), "(a > 4)")
94+
/// let expr = col("a").gt(lit(4)); // form an expression `a > 4`
95+
/// let sql = expr_to_sql(&expr).unwrap(); // convert to ast::Expr
96+
/// // use the Display impl to convert to SQL text
97+
/// assert_eq!(sql.to_string(), "(a > 4)")
8998
/// ```
99+
///
100+
/// [`SqlToRel::sql_to_expr`]: crate::planner::SqlToRel::sql_to_expr
101+
/// [`plan_to_sql`]: crate::unparser::plan_to_sql
102+
/// [`LogicalPlan`]: datafusion_expr::logical_plan::LogicalPlan
90103
pub fn expr_to_sql(expr: &Expr) -> Result<ast::Expr> {
91104
let unparser = Unparser::default();
92105
unparser.expr_to_sql(expr)

datafusion/sql/src/unparser/mod.rs

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18+
//! [`Unparser`] for converting `Expr` to SQL text
19+
1820
mod ast;
1921
mod expr;
2022
mod plan;
@@ -27,6 +29,29 @@ pub use plan::plan_to_sql;
2729
use self::dialect::{DefaultDialect, Dialect};
2830
pub mod dialect;
2931

32+
/// Convert a DataFusion [`Expr`] to [`sqlparser::ast::Expr`]
33+
///
34+
/// See [`expr_to_sql`] for background. `Unparser` allows greater control of
35+
/// the conversion, but with a more complicated API.
36+
///
37+
/// To get more human-readable output, see [`Self::with_pretty`]
38+
///
39+
/// # Example
40+
/// ```
41+
/// use datafusion_expr::{col, lit};
42+
/// use datafusion_sql::unparser::Unparser;
43+
/// let expr = col("a").gt(lit(4)); // form an expression `a > 4`
44+
/// let unparser = Unparser::default();
45+
/// let sql = unparser.expr_to_sql(&expr).unwrap();// convert to AST
46+
/// // use the Display impl to convert to SQL text
47+
/// assert_eq!(sql.to_string(), "(a > 4)");
48+
/// // now convert to pretty sql
49+
/// let unparser = unparser.with_pretty(true);
50+
/// let sql = unparser.expr_to_sql(&expr).unwrap();
51+
/// assert_eq!(sql.to_string(), "a > 4"); // note lack of parenthesis
52+
/// ```
53+
///
54+
/// [`Expr`]: datafusion_expr::Expr
3055
pub struct Unparser<'a> {
3156
dialect: &'a dyn Dialect,
3257
pretty: bool,
@@ -40,9 +65,42 @@ impl<'a> Unparser<'a> {
4065
}
4166
}
4267

43-
/// Allow unparser to remove parenthesis according to the precedence rules of DataFusion.
44-
/// This might make it invalid SQL for other SQL query engines with different precedence
45-
/// rules, even if its valid for DataFusion.
68+
/// Create pretty SQL output, better suited for human consumption
69+
///
70+
/// See example on the struct level documentation
71+
///
72+
/// # Pretty Output
73+
///
74+
/// By default, `Unparser` generates SQL text that will parse back to the
75+
/// same parsed [`Expr`], which is useful for creating machine readable
76+
/// expressions to send to other systems. However, the resulting expressions are
77+
/// not always nice to read for humans.
78+
///
79+
/// For example
80+
///
81+
/// ```sql
82+
/// ((a + 4) > 5)
83+
/// ```
84+
///
85+
/// This method removes parenthesis using to the precedence rules of
86+
/// DataFusion. If the output is reparsed, the resulting [`Expr`] produces
87+
/// same value as the original in DataFusion, but with a potentially
88+
/// different order of operations.
89+
///
90+
/// Note that this setting may create invalid SQL for other SQL query
91+
/// engines with different precedence rules
92+
///
93+
/// # Example
94+
/// ```
95+
/// use datafusion_expr::{col, lit};
96+
/// use datafusion_sql::unparser::Unparser;
97+
/// let expr = col("a").gt(lit(4)).and(col("b").lt(lit(5))); // form an expression `a > 4 AND b < 5`
98+
/// let unparser = Unparser::default().with_pretty(true);
99+
/// let sql = unparser.expr_to_sql(&expr).unwrap();
100+
/// assert_eq!(sql.to_string(), "a > 4 AND b < 5"); // note lack of parenthesis
101+
/// ```
102+
///
103+
/// [`Expr`]: datafusion_expr::Expr
46104
pub fn with_pretty(mut self, pretty: bool) -> Self {
47105
self.pretty = pretty;
48106
self

datafusion/sql/src/unparser/plan.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,18 @@ use super::{
3333
Unparser,
3434
};
3535

36-
/// Convert a DataFusion [`LogicalPlan`] to `sqlparser::ast::Statement`
36+
/// Convert a DataFusion [`LogicalPlan`] to [`ast::Statement`]
3737
///
38-
/// This function is the opposite of `SqlToRel::sql_statement_to_plan` and can
39-
/// be used to, among other things, convert `LogicalPlan`s to strings.
38+
/// This function is the opposite of [`SqlToRel::sql_statement_to_plan`] and can
39+
/// be used to, among other things, to convert `LogicalPlan`s to SQL strings.
40+
///
41+
/// # Errors
42+
///
43+
/// This function returns an error if the plan cannot be converted to SQL.
44+
///
45+
/// # See Also
46+
///
47+
/// * [`expr_to_sql`] for converting [`Expr`], a single expression to SQL
4048
///
4149
/// # Example
4250
/// ```
@@ -47,16 +55,20 @@ use super::{
4755
/// Field::new("id", DataType::Utf8, false),
4856
/// Field::new("value", DataType::Utf8, false),
4957
/// ]);
58+
/// // Scan 'table' and select columns 'id' and 'value'
5059
/// let plan = table_scan(Some("table"), &schema, None)
5160
/// .unwrap()
5261
/// .project(vec![col("id"), col("value")])
5362
/// .unwrap()
5463
/// .build()
5564
/// .unwrap();
56-
/// let sql = plan_to_sql(&plan).unwrap();
57-
///
58-
/// assert_eq!(format!("{}", sql), "SELECT \"table\".id, \"table\".\"value\" FROM \"table\"")
65+
/// let sql = plan_to_sql(&plan).unwrap(); // convert to AST
66+
/// // use the Display impl to convert to SQL text
67+
/// assert_eq!(sql.to_string(), "SELECT \"table\".id, \"table\".\"value\" FROM \"table\"")
5968
/// ```
69+
///
70+
/// [`SqlToRel::sql_statement_to_plan`]: crate::planner::SqlToRel::sql_statement_to_plan
71+
/// [`expr_to_sql`]: crate::unparser::expr_to_sql
6072
pub fn plan_to_sql(plan: &LogicalPlan) -> Result<ast::Statement> {
6173
let unparser = Unparser::default();
6274
unparser.plan_to_sql(plan)

0 commit comments

Comments
 (0)