@@ -30,7 +30,7 @@ use crate::logical_plan::Subquery;
30
30
use crate :: Volatility ;
31
31
use crate :: { udaf, ExprSchemable , Operator , Signature , WindowFrame , WindowUDF } ;
32
32
33
- use arrow:: datatypes:: { DataType , FieldRef } ;
33
+ use arrow:: datatypes:: { DataType , Field , FieldRef } ;
34
34
use datafusion_common:: cse:: { HashNode , NormalizeEq , Normalizeable } ;
35
35
use datafusion_common:: tree_node:: {
36
36
Transformed , TransformedResult , TreeNode , TreeNodeContainer , TreeNodeRecursion ,
@@ -284,8 +284,8 @@ pub enum Expr {
284
284
Column ( Column ) ,
285
285
/// A named reference to a variable in a registry.
286
286
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 > ) ,
289
289
/// A binary expression such as "age > 21"
290
290
BinaryExpr ( BinaryExpr ) ,
291
291
/// LIKE expression
@@ -413,6 +413,168 @@ impl<'a> TreeNodeContainer<'a, Self> for Expr {
413
413
}
414
414
}
415
415
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
+
416
578
/// UNNEST expression.
417
579
#[ derive( Clone , PartialEq , Eq , PartialOrd , Hash , Debug ) ]
418
580
pub struct Unnest {
0 commit comments