@@ -322,6 +322,20 @@ impl fmt::Display for JsonOperator {
322
322
}
323
323
}
324
324
325
+ /// Options for `CAST` / `TRY_CAST`
326
+ /// BigQuery: <https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#formatting_syntax>
327
+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
328
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
329
+ #[ cfg_attr(
330
+ feature = "visitor" ,
331
+ derive( Visit , VisitMut ) ,
332
+ visit( with = "visit_expr" )
333
+ ) ]
334
+ pub enum CastFormat {
335
+ Value ( Value ) ,
336
+ ValueAtTimeZone ( Value , Value ) ,
337
+ }
338
+
325
339
/// An SQL expression of any type.
326
340
///
327
341
/// The parser does not distinguish between expressions of different types
@@ -437,19 +451,28 @@ pub enum Expr {
437
451
Cast {
438
452
expr : Box < Expr > ,
439
453
data_type : DataType ,
454
+ // Optional CAST(string_expression AS type FORMAT format_string_expression) as used by BigQuery
455
+ // https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#formatting_syntax
456
+ format : Option < CastFormat > ,
440
457
} ,
441
458
/// TRY_CAST an expression to a different data type e.g. `TRY_CAST(foo AS VARCHAR(123))`
442
459
// this differs from CAST in the choice of how to implement invalid conversions
443
460
TryCast {
444
461
expr : Box < Expr > ,
445
462
data_type : DataType ,
463
+ // Optional CAST(string_expression AS type FORMAT format_string_expression) as used by BigQuery
464
+ // https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#formatting_syntax
465
+ format : Option < CastFormat > ,
446
466
} ,
447
467
/// SAFE_CAST an expression to a different data type e.g. `SAFE_CAST(foo AS FLOAT64)`
448
468
// only available for BigQuery: https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#safe_casting
449
469
// this works the same as `TRY_CAST`
450
470
SafeCast {
451
471
expr : Box < Expr > ,
452
472
data_type : DataType ,
473
+ // Optional CAST(string_expression AS type FORMAT format_string_expression) as used by BigQuery
474
+ // https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#formatting_syntax
475
+ format : Option < CastFormat > ,
453
476
} ,
454
477
/// AT a timestamp to a different timezone e.g. `FROM_UNIXTIME(0) AT TIME ZONE 'UTC-06:00'`
455
478
AtTimeZone {
@@ -597,6 +620,15 @@ pub enum Expr {
597
620
} ,
598
621
}
599
622
623
+ impl fmt:: Display for CastFormat {
624
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
625
+ match self {
626
+ CastFormat :: Value ( v) => write ! ( f, "{v}" ) ,
627
+ CastFormat :: ValueAtTimeZone ( v, tz) => write ! ( f, "{v} AT TIME ZONE {tz}" ) ,
628
+ }
629
+ }
630
+ }
631
+
600
632
impl fmt:: Display for Expr {
601
633
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
602
634
match self {
@@ -753,9 +785,39 @@ impl fmt::Display for Expr {
753
785
write ! ( f, "{op}{expr}" )
754
786
}
755
787
}
756
- Expr :: Cast { expr, data_type } => write ! ( f, "CAST({expr} AS {data_type})" ) ,
757
- Expr :: TryCast { expr, data_type } => write ! ( f, "TRY_CAST({expr} AS {data_type})" ) ,
758
- Expr :: SafeCast { expr, data_type } => write ! ( f, "SAFE_CAST({expr} AS {data_type})" ) ,
788
+ Expr :: Cast {
789
+ expr,
790
+ data_type,
791
+ format,
792
+ } => {
793
+ if let Some ( format) = format {
794
+ write ! ( f, "CAST({expr} AS {data_type} FORMAT {format})" )
795
+ } else {
796
+ write ! ( f, "CAST({expr} AS {data_type})" )
797
+ }
798
+ }
799
+ Expr :: TryCast {
800
+ expr,
801
+ data_type,
802
+ format,
803
+ } => {
804
+ if let Some ( format) = format {
805
+ write ! ( f, "TRY_CAST({expr} AS {data_type} FORMAT {format})" )
806
+ } else {
807
+ write ! ( f, "TRY_CAST({expr} AS {data_type})" )
808
+ }
809
+ }
810
+ Expr :: SafeCast {
811
+ expr,
812
+ data_type,
813
+ format,
814
+ } => {
815
+ if let Some ( format) = format {
816
+ write ! ( f, "SAFE_CAST({expr} AS {data_type} FORMAT {format})" )
817
+ } else {
818
+ write ! ( f, "SAFE_CAST({expr} AS {data_type})" )
819
+ }
820
+ }
759
821
Expr :: Extract { field, expr } => write ! ( f, "EXTRACT({field} FROM {expr})" ) ,
760
822
Expr :: Ceil { expr, field } => {
761
823
if field == & DateTimeField :: NoDateTime {
0 commit comments