1515// specific language governing permissions and limitations
1616// under the License.
1717
18+ use std:: fmt:: Display ;
1819use std:: hash:: { Hash , Hasher } ;
1920use std:: sync:: Arc ;
2021
@@ -71,7 +72,7 @@ use itertools::Itertools;
7172/// specifies the output sorted by EITHER `a ASC` or `b DESC`, the sort can be
7273/// avoided.
7374///
74- /// # Example equivalent equivalent expressions
75+ /// # Example equivalent expressions
7576///
7677/// Similarly, consider the table below:
7778///
@@ -92,6 +93,32 @@ use itertools::Itertools;
9293/// `Hash(a)` and output partitioning is `Hash(b)`, then DataFusion avoids
9394/// repartitioning the data as the existing partitioning satisfies the
9495/// requirement.
96+ ///
97+ /// # Code Example
98+ /// ```
99+ /// use std::sync::Arc;
100+ /// use arrow_schema::{Schema, Field, DataType, SchemaRef};
101+ /// use datafusion_physical_expr::{ConstExpr, EquivalenceProperties};
102+ /// use datafusion_physical_expr::expressions::col;
103+ ///
104+ /// let schema: SchemaRef = Arc::new(Schema::new(vec![
105+ /// Field::new("a", DataType::Int32, false),
106+ /// Field::new("b", DataType::Int32, false),
107+ /// Field::new("c", DataType::Int32, false),
108+ /// ]));
109+ ///
110+ /// let col_a = col("a", &schema).unwrap();
111+ /// let col_b = col("b", &schema).unwrap();
112+ /// let col_c = col("c", &schema).unwrap();
113+ ///
114+ /// // This object represents data that is sorted by a ASC, c DESC
115+ /// // with a single constant value of b
116+ /// let mut eq_properties = EquivalenceProperties::new(schema);
117+ /// eq_properties.add_constants(vec![ConstExpr::from(col_b)]);
118+ /// eq_properties.add_new_ordering(vec![col_a.asc(), col_c.desc()]);
119+ ///
120+ /// assert_eq!(eq_properties.to_string(), "ff")
121+ /// ```
95122#[ derive( Debug , Clone ) ]
96123pub struct EquivalenceProperties {
97124 /// Collection of equivalence classes that store expressions with the same
@@ -203,6 +230,11 @@ impl EquivalenceProperties {
203230 self . oeq_class . add_new_orderings ( orderings) ;
204231 }
205232
233+ /// Adds a single ordering to the existing ordering equivalence class.
234+ pub fn add_new_ordering ( & mut self , ordering : LexOrdering ) {
235+ self . add_new_orderings ( [ ordering] ) ;
236+ }
237+
206238 /// Incorporates the given equivalence group to into the existing
207239 /// equivalence group within.
208240 pub fn add_equivalence_group ( & mut self , other_eq_group : EquivalenceGroup ) {
@@ -1059,6 +1091,37 @@ impl EquivalenceProperties {
10591091 }
10601092}
10611093
1094+ /// More readable display version of the `EquivalenceProperties`.
1095+ ///
1096+ /// Format:
1097+ /// ```text
1098+ /// order: [[a ASC, b ASC], [a ASC, c ASC]], eq: [[a = b], [a = c]], const: [a = 1]
1099+ /// ```
1100+ impl Display for EquivalenceProperties {
1101+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
1102+ if self . eq_group . is_empty ( )
1103+ && self . oeq_class . is_empty ( )
1104+ && self . constants . is_empty ( )
1105+ {
1106+ return write ! ( f, "No properties" ) ;
1107+ }
1108+ if !self . oeq_class . is_empty ( ) {
1109+ write ! ( f, "order: {}" , self . oeq_class) ?;
1110+ }
1111+ if !self . eq_group . is_empty ( ) {
1112+ write ! ( f, ", eq: {}" , self . eq_group) ?;
1113+ }
1114+ if !self . constants . is_empty ( ) {
1115+ write ! ( f, ", const: [" ) ?;
1116+ for c in & self . constants {
1117+ write ! ( f, ", {}" , c) ?;
1118+ }
1119+ write ! ( f, "]" ) ?;
1120+ }
1121+ Ok ( ( ) )
1122+ }
1123+ }
1124+
10621125/// Calculates the properties of a given [`ExprPropertiesNode`].
10631126///
10641127/// Order information can be retrieved as:
@@ -3032,21 +3095,31 @@ mod tests {
30323095 // Check whether constants are same
30333096 let lhs_constants = lhs. constants ( ) ;
30343097 let rhs_constants = rhs. constants ( ) ;
3035- assert_eq ! ( lhs_constants. len( ) , rhs_constants. len( ) , "{}" , err_msg) ;
3098+ assert_eq ! (
3099+ lhs_constants. len( ) ,
3100+ rhs_constants. len( ) ,
3101+ "{err_msg}\n lhs: {lhs}\n rhs: {rhs}"
3102+ ) ;
30363103 for rhs_constant in rhs_constants {
30373104 assert ! (
30383105 const_exprs_contains( lhs_constants, rhs_constant. expr( ) ) ,
3039- "{}" ,
3040- err_msg
3106+ "{err_msg}\n lhs: {lhs}\n rhs: {rhs}"
30413107 ) ;
30423108 }
30433109
30443110 // Check whether orderings are same.
30453111 let lhs_orderings = lhs. oeq_class ( ) ;
30463112 let rhs_orderings = & rhs. oeq_class . orderings ;
3047- assert_eq ! ( lhs_orderings. len( ) , rhs_orderings. len( ) , "{}" , err_msg) ;
3113+ assert_eq ! (
3114+ lhs_orderings. len( ) ,
3115+ rhs_orderings. len( ) ,
3116+ "{err_msg}\n lhs: {lhs}\n rhs: {rhs}"
3117+ ) ;
30483118 for rhs_ordering in rhs_orderings {
3049- assert ! ( lhs_orderings. contains( rhs_ordering) , "{}" , err_msg) ;
3119+ assert ! (
3120+ lhs_orderings. contains( rhs_ordering) ,
3121+ "{err_msg}\n lhs: {lhs}\n rhs: {rhs}"
3122+ ) ;
30503123 }
30513124 }
30523125}
0 commit comments