@@ -30,7 +30,7 @@ use crate::logical_plan::Subquery;
3030use crate :: Volatility ;
3131use crate :: { udaf, ExprSchemable , Operator , Signature , WindowFrame , WindowUDF } ;
3232
33- use arrow:: datatypes:: { DataType , FieldRef } ;
33+ use arrow:: datatypes:: { DataType , Field , FieldRef } ;
3434use datafusion_common:: cse:: { HashNode , NormalizeEq , Normalizeable } ;
3535use datafusion_common:: tree_node:: {
3636 Transformed , TransformedResult , TreeNode , TreeNodeContainer , TreeNodeRecursion ,
@@ -284,8 +284,8 @@ pub enum Expr {
284284 Column ( Column ) ,
285285 /// A named reference to a variable in a registry.
286286 ScalarVariable ( DataType , Vec < String > ) ,
287- /// A constant value along with associated metadata
288- Literal ( ScalarValue , Option < BTreeMap < String , String > > ) ,
287+ /// A constant value along with associated [`FieldMetadata`].
288+ Literal ( ScalarValue , Option < FieldMetadata > ) ,
289289 /// A binary expression such as "age > 21"
290290 BinaryExpr ( BinaryExpr ) ,
291291 /// LIKE expression
@@ -413,6 +413,168 @@ impl<'a> TreeNodeContainer<'a, Self> for Expr {
413413 }
414414}
415415
416+ /// Literal metadata
417+ ///
418+ /// Stores metadata associated with a literal expressions
419+ /// and is designed to be fast to `clone`.
420+ ///
421+ /// This structure is used to store metadata associated with a literal expression, and it
422+ /// corresponds to the `metadata` field on [`Field`].
423+ ///
424+ /// # Example: Create [`FieldMetadata`] from a [`Field`]
425+ /// ```
426+ /// # use std::collections::HashMap;
427+ /// # use datafusion_expr::expr::FieldMetadata;
428+ /// # use arrow::datatypes::{Field, DataType};
429+ /// # let field = Field::new("c1", DataType::Int32, true)
430+ /// # .with_metadata(HashMap::from([("foo".to_string(), "bar".to_string())]));
431+ /// // Create a new `FieldMetadata` instance from a `Field`
432+ /// let metadata = FieldMetadata::new_from_field(&field);
433+ /// // There is also a `From` impl:
434+ /// let metadata = FieldMetadata::from(&field);
435+ /// ```
436+ ///
437+ /// # Example: Update a [`Field`] with [`FieldMetadata`]
438+ /// ```
439+ /// # use datafusion_expr::expr::FieldMetadata;
440+ /// # use arrow::datatypes::{Field, DataType};
441+ /// # let field = Field::new("c1", DataType::Int32, true);
442+ /// # let metadata = FieldMetadata::new_from_field(&field);
443+ /// // Add any metadata from `FieldMetadata` to `Field`
444+ /// let updated_field = metadata.add_to_field(field);
445+ /// ```
446+ ///
447+ #[ derive( Clone , PartialEq , Eq , PartialOrd , Hash , Debug ) ]
448+ pub struct FieldMetadata {
449+ /// The inner metadata of a literal expression, which is a map of string
450+ /// keys to string values.
451+ ///
452+ /// Note this is not a `HashMap because `HashMap` does not provide
453+ /// implementations for traits like `Debug` and `Hash`.
454+ inner : Arc < BTreeMap < String , String > > ,
455+ }
456+
457+ impl Default for FieldMetadata {
458+ fn default ( ) -> Self {
459+ Self :: new_empty ( )
460+ }
461+ }
462+
463+ impl FieldMetadata {
464+ /// Create a new empty metadata instance.
465+ pub fn new_empty ( ) -> Self {
466+ Self {
467+ inner : Arc :: new ( BTreeMap :: new ( ) ) ,
468+ }
469+ }
470+
471+ /// Merges two optional `FieldMetadata` instances, overwriting any existing
472+ /// keys in `m` with keys from `n` if present
473+ pub fn merge_options (
474+ m : Option < & FieldMetadata > ,
475+ n : Option < & FieldMetadata > ,
476+ ) -> Option < FieldMetadata > {
477+ match ( m, n) {
478+ ( Some ( m) , Some ( n) ) => {
479+ let mut merged = m. clone ( ) ;
480+ merged. extend ( n. clone ( ) ) ;
481+ Some ( merged)
482+ }
483+ ( Some ( m) , None ) => Some ( m. clone ( ) ) ,
484+ ( None , Some ( n) ) => Some ( n. clone ( ) ) ,
485+ ( None , None ) => None ,
486+ }
487+ }
488+
489+ /// Create a new metadata instance from a `Field`'s metadata.
490+ pub fn new_from_field ( field : & Field ) -> Self {
491+ let inner = field
492+ . metadata ( )
493+ . iter ( )
494+ . map ( |( k, v) | ( k. to_string ( ) , v. to_string ( ) ) )
495+ . collect ( ) ;
496+ Self {
497+ inner : Arc :: new ( inner) ,
498+ }
499+ }
500+
501+ /// Create a new metadata instance from a map of string keys to string values.
502+ pub fn new ( inner : BTreeMap < String , String > ) -> Self {
503+ Self {
504+ inner : Arc :: new ( inner) ,
505+ }
506+ }
507+
508+ /// Get the inner metadata as a reference to a `BTreeMap`.
509+ pub fn inner ( & self ) -> & BTreeMap < String , String > {
510+ & self . inner
511+ }
512+
513+ /// Return the inner metadata
514+ pub fn into_inner ( self ) -> Arc < BTreeMap < String , String > > {
515+ self . inner
516+ }
517+
518+ /// Adds metadata from `other` into `self`, overwriting any existing keys.
519+ pub fn extend ( & mut self , other : Self ) {
520+ let other = Arc :: unwrap_or_clone ( other. into_inner ( ) ) ;
521+ Arc :: make_mut ( & mut self . inner ) . extend ( other) ;
522+ }
523+
524+ /// Returns true if the metadata is empty.
525+ pub fn is_empty ( & self ) -> bool {
526+ self . inner . is_empty ( )
527+ }
528+
529+ /// Returns the number of key-value pairs in the metadata.
530+ pub fn len ( & self ) -> usize {
531+ self . inner . len ( )
532+ }
533+
534+ /// Updates the metadata on the Field with this metadata, if it is not empty.
535+ pub fn add_to_field ( & self , field : Field ) -> Field {
536+ if self . inner . is_empty ( ) {
537+ return field;
538+ }
539+
540+ field. with_metadata (
541+ self . inner
542+ . iter ( )
543+ . map ( |( k, v) | ( k. clone ( ) , v. clone ( ) ) )
544+ . collect ( ) ,
545+ )
546+ }
547+ }
548+
549+ impl From < & Field > for FieldMetadata {
550+ fn from ( field : & Field ) -> Self {
551+ Self :: new_from_field ( field)
552+ }
553+ }
554+
555+ impl From < BTreeMap < String , String > > for FieldMetadata {
556+ fn from ( inner : BTreeMap < String , String > ) -> Self {
557+ Self :: new ( inner)
558+ }
559+ }
560+
561+ impl From < std:: collections:: HashMap < String , String > > for FieldMetadata {
562+ fn from ( map : std:: collections:: HashMap < String , String > ) -> Self {
563+ Self :: new ( map. into_iter ( ) . collect ( ) )
564+ }
565+ }
566+
567+ /// From reference
568+ impl From < & std:: collections:: HashMap < String , String > > for FieldMetadata {
569+ fn from ( map : & std:: collections:: HashMap < String , String > ) -> Self {
570+ let inner = map
571+ . iter ( )
572+ . map ( |( k, v) | ( k. to_string ( ) , v. to_string ( ) ) )
573+ . collect ( ) ;
574+ Self :: new ( inner)
575+ }
576+ }
577+
416578/// UNNEST expression.
417579#[ derive( Clone , PartialEq , Eq , PartialOrd , Hash , Debug ) ]
418580pub struct Unnest {
0 commit comments