iceberg/spec/values/
literal.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Literal values in Iceberg
19
20use std::any::Any;
21use std::str::FromStr;
22
23use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
24use ordered_float::OrderedFloat;
25use serde_json::{Map as JsonMap, Number, Value as JsonValue};
26use uuid::Uuid;
27
28use super::Map;
29use super::decimal_utils::{
30    decimal_from_str_exact, decimal_mantissa, decimal_rescale, try_decimal_from_i128_with_scale,
31};
32use super::primitive::PrimitiveLiteral;
33use super::struct_value::Struct;
34use super::temporal::{date, time, timestamp, timestamptz};
35use crate::error::Result;
36use crate::spec::datatypes::{PrimitiveType, Type};
37use crate::{Error, ErrorKind};
38
39/// Values present in iceberg type
40#[derive(Clone, Debug, PartialEq, Eq, Hash)]
41pub enum Literal {
42    /// A primitive value
43    Primitive(PrimitiveLiteral),
44    /// A struct is a tuple of typed values. Each field in the tuple is named and has an integer id that is unique in the table schema.
45    /// Each field can be either optional or required, meaning that values can (or cannot) be null. Fields may be any type.
46    /// Fields may have an optional comment or doc string. Fields can have default values.
47    Struct(Struct),
48    /// A list is a collection of values with some element type.
49    /// The element field has an integer id that is unique in the table schema.
50    /// Elements can be either optional or required. Element types may be any type.
51    List(Vec<Option<Literal>>),
52    /// A map is a collection of key-value pairs with a key type and a value type.
53    /// Both the key field and value field each have an integer id that is unique in the table schema.
54    /// Map keys are required and map values can be either optional or required. Both map keys and map values may be any type, including nested types.
55    Map(Map),
56}
57
58impl Literal {
59    /// Creates a boolean value.
60    ///
61    /// Example:
62    /// ```rust
63    /// use iceberg::spec::{Literal, PrimitiveLiteral};
64    /// let t = Literal::bool(true);
65    ///
66    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Boolean(true)), t);
67    /// ```
68    pub fn bool<T: Into<bool>>(t: T) -> Self {
69        Self::Primitive(PrimitiveLiteral::Boolean(t.into()))
70    }
71
72    /// Creates a boolean value from string.
73    /// See [Parse bool from str](https://doc.rust-lang.org/stable/std/primitive.bool.html#impl-FromStr-for-bool) for reference.
74    ///
75    /// Example:
76    /// ```rust
77    /// use iceberg::spec::{Literal, PrimitiveLiteral};
78    /// let t = Literal::bool_from_str("false").unwrap();
79    ///
80    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Boolean(false)), t);
81    /// ```
82    pub fn bool_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
83        let v = s.as_ref().parse::<bool>().map_err(|e| {
84            Error::new(ErrorKind::DataInvalid, "Can't parse string to bool.").with_source(e)
85        })?;
86        Ok(Self::Primitive(PrimitiveLiteral::Boolean(v)))
87    }
88
89    /// Creates an 32bit integer.
90    ///
91    /// Example:
92    /// ```rust
93    /// use iceberg::spec::{Literal, PrimitiveLiteral};
94    /// let t = Literal::int(23i8);
95    ///
96    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Int(23)), t);
97    /// ```
98    pub fn int<T: Into<i32>>(t: T) -> Self {
99        Self::Primitive(PrimitiveLiteral::Int(t.into()))
100    }
101
102    /// Creates an 64bit integer.
103    ///
104    /// Example:
105    /// ```rust
106    /// use iceberg::spec::{Literal, PrimitiveLiteral};
107    /// let t = Literal::long(24i8);
108    ///
109    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Long(24)), t);
110    /// ```
111    pub fn long<T: Into<i64>>(t: T) -> Self {
112        Self::Primitive(PrimitiveLiteral::Long(t.into()))
113    }
114
115    /// Creates an 32bit floating point number.
116    ///
117    /// Example:
118    /// ```rust
119    /// use iceberg::spec::{Literal, PrimitiveLiteral};
120    /// use ordered_float::OrderedFloat;
121    /// let t = Literal::float(32.1f32);
122    ///
123    /// assert_eq!(
124    ///     Literal::Primitive(PrimitiveLiteral::Float(OrderedFloat(32.1))),
125    ///     t
126    /// );
127    /// ```
128    pub fn float<T: Into<f32>>(t: T) -> Self {
129        Self::Primitive(PrimitiveLiteral::Float(OrderedFloat(t.into())))
130    }
131
132    /// Creates an 32bit floating point number.
133    ///
134    /// Example:
135    /// ```rust
136    /// use iceberg::spec::{Literal, PrimitiveLiteral};
137    /// use ordered_float::OrderedFloat;
138    /// let t = Literal::double(32.1f64);
139    ///
140    /// assert_eq!(
141    ///     Literal::Primitive(PrimitiveLiteral::Double(OrderedFloat(32.1))),
142    ///     t
143    /// );
144    /// ```
145    pub fn double<T: Into<f64>>(t: T) -> Self {
146        Self::Primitive(PrimitiveLiteral::Double(OrderedFloat(t.into())))
147    }
148
149    /// Creates date literal from number of days from unix epoch directly.
150    pub fn date(days: i32) -> Self {
151        Self::Primitive(PrimitiveLiteral::Int(days))
152    }
153
154    /// Creates a date in `%Y-%m-%d` format, assume in utc timezone.
155    ///
156    /// See [`NaiveDate::from_str`].
157    ///
158    /// Example
159    /// ```rust
160    /// use iceberg::spec::Literal;
161    /// let t = Literal::date_from_str("1970-01-03").unwrap();
162    ///
163    /// assert_eq!(Literal::date(2), t);
164    /// ```
165    pub fn date_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
166        let t = s.as_ref().parse::<NaiveDate>().map_err(|e| {
167            Error::new(
168                ErrorKind::DataInvalid,
169                format!("Can't parse date from string: {}", s.as_ref()),
170            )
171            .with_source(e)
172        })?;
173
174        Ok(Self::date(date::date_from_naive_date(t)))
175    }
176
177    /// Create a date from calendar date (year, month and day).
178    ///
179    /// See [`NaiveDate::from_ymd_opt`].
180    ///
181    /// Example:
182    ///
183    ///```rust
184    /// use iceberg::spec::Literal;
185    /// let t = Literal::date_from_ymd(1970, 1, 5).unwrap();
186    ///
187    /// assert_eq!(Literal::date(4), t);
188    /// ```
189    pub fn date_from_ymd(year: i32, month: u32, day: u32) -> Result<Self> {
190        let t = NaiveDate::from_ymd_opt(year, month, day).ok_or_else(|| {
191            Error::new(
192                ErrorKind::DataInvalid,
193                format!("Can't create date from year: {year}, month: {month}, day: {day}"),
194            )
195        })?;
196
197        Ok(Self::date(date::date_from_naive_date(t)))
198    }
199
200    /// Creates time in microseconds directly
201    pub fn time(value: i64) -> Self {
202        Self::Primitive(PrimitiveLiteral::Long(value))
203    }
204
205    /// Creates time literal from [`chrono::NaiveTime`].
206    fn time_from_naive_time(t: NaiveTime) -> Self {
207        let duration = t - date::unix_epoch().time();
208        // It's safe to unwrap here since less than 24 hours will never overflow.
209        let micro_secs = duration.num_microseconds().unwrap();
210
211        Literal::time(micro_secs)
212    }
213
214    /// Creates time in microseconds in `%H:%M:%S:.f` format.
215    ///
216    /// See [`NaiveTime::from_str`] for details.
217    ///
218    /// Example:
219    /// ```rust
220    /// use iceberg::spec::Literal;
221    /// let t = Literal::time_from_str("01:02:01.888999777").unwrap();
222    ///
223    /// let micro_secs = {
224    ///     1 * 3600 * 1_000_000 + // 1 hour
225    ///     2 * 60 * 1_000_000 +   // 2 minutes
226    ///     1 * 1_000_000 + // 1 second
227    ///     888999 // microseconds
228    /// };
229    /// assert_eq!(Literal::time(micro_secs), t);
230    /// ```
231    pub fn time_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
232        let t = s.as_ref().parse::<NaiveTime>().map_err(|e| {
233            Error::new(
234                ErrorKind::DataInvalid,
235                format!("Can't parse time from string: {}", s.as_ref()),
236            )
237            .with_source(e)
238        })?;
239
240        Ok(Self::time_from_naive_time(t))
241    }
242
243    /// Creates time literal from hour, minute, second, and microseconds.
244    ///
245    /// See [`NaiveTime::from_hms_micro_opt`].
246    ///
247    /// Example:
248    /// ```rust
249    /// use iceberg::spec::Literal;
250    /// let t = Literal::time_from_hms_micro(22, 15, 33, 111).unwrap();
251    ///
252    /// assert_eq!(Literal::time_from_str("22:15:33.000111").unwrap(), t);
253    /// ```
254    pub fn time_from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> Result<Self> {
255        let t = NaiveTime::from_hms_micro_opt(hour, min, sec, micro)
256            .ok_or_else(|| Error::new(
257                ErrorKind::DataInvalid,
258                format!("Can't create time from hour: {hour}, min: {min}, second: {sec}, microsecond: {micro}"),
259            ))?;
260        Ok(Self::time_from_naive_time(t))
261    }
262
263    /// Creates a timestamp from unix epoch in microseconds.
264    pub fn timestamp(value: i64) -> Self {
265        Self::Primitive(PrimitiveLiteral::Long(value))
266    }
267
268    /// Creates a timestamp with timezone from unix epoch in microseconds.
269    pub fn timestamptz(value: i64) -> Self {
270        Self::Primitive(PrimitiveLiteral::Long(value))
271    }
272
273    /// Creates a timestamp from unix epoch in nanoseconds.
274    pub(crate) fn timestamp_nano(value: i64) -> Self {
275        Self::Primitive(PrimitiveLiteral::Long(value))
276    }
277
278    /// Creates a timestamp with timezone from unix epoch in nanoseconds.
279    pub(crate) fn timestamptz_nano(value: i64) -> Self {
280        Self::Primitive(PrimitiveLiteral::Long(value))
281    }
282
283    /// Creates a timestamp from [`DateTime`].
284    pub fn timestamp_from_datetime<T: TimeZone>(dt: DateTime<T>) -> Self {
285        Self::timestamp(dt.with_timezone(&Utc).timestamp_micros())
286    }
287
288    /// Creates a timestamp with timezone from [`DateTime`].
289    pub fn timestamptz_from_datetime<T: TimeZone>(dt: DateTime<T>) -> Self {
290        Self::timestamptz(dt.with_timezone(&Utc).timestamp_micros())
291    }
292
293    /// Parse a timestamp in RFC3339 format.
294    ///
295    /// See [`DateTime<Utc>::from_str`].
296    ///
297    /// Example:
298    ///
299    /// ```rust
300    /// use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime};
301    /// use iceberg::spec::Literal;
302    /// let t = Literal::timestamp_from_str("2012-12-12 12:12:12.8899-04:00").unwrap();
303    ///
304    /// let t2 = {
305    ///     let date = NaiveDate::from_ymd_opt(2012, 12, 12).unwrap();
306    ///     let time = NaiveTime::from_hms_micro_opt(12, 12, 12, 889900).unwrap();
307    ///     let dt = NaiveDateTime::new(date, time);
308    ///     Literal::timestamp_from_datetime(DateTime::<FixedOffset>::from_local(
309    ///         dt,
310    ///         FixedOffset::west_opt(4 * 3600).unwrap(),
311    ///     ))
312    /// };
313    ///
314    /// assert_eq!(t, t2);
315    /// ```
316    pub fn timestamp_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
317        let dt = DateTime::<Utc>::from_str(s.as_ref()).map_err(|e| {
318            Error::new(ErrorKind::DataInvalid, "Can't parse datetime.").with_source(e)
319        })?;
320
321        Ok(Self::timestamp_from_datetime(dt))
322    }
323
324    /// Similar to [`Literal::timestamp_from_str`], but return timestamp with timezone literal.
325    pub fn timestamptz_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
326        let dt = DateTime::<Utc>::from_str(s.as_ref()).map_err(|e| {
327            Error::new(ErrorKind::DataInvalid, "Can't parse datetime.").with_source(e)
328        })?;
329
330        Ok(Self::timestamptz_from_datetime(dt))
331    }
332
333    /// Creates a string literal.
334    pub fn string<S: ToString>(s: S) -> Self {
335        Self::Primitive(PrimitiveLiteral::String(s.to_string()))
336    }
337
338    /// Creates uuid literal.
339    pub fn uuid(uuid: Uuid) -> Self {
340        Self::Primitive(PrimitiveLiteral::UInt128(uuid.as_u128()))
341    }
342
343    /// Creates uuid from str. See [`Uuid::parse_str`].
344    ///
345    /// Example:
346    ///
347    /// ```rust
348    /// use iceberg::spec::Literal;
349    /// use uuid::Uuid;
350    /// let t1 = Literal::uuid_from_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
351    /// let t2 = Literal::uuid(Uuid::from_u128_le(0xd8d7d6d5d4d3d2d1c2c1b2b1a4a3a2a1));
352    ///
353    /// assert_eq!(t1, t2);
354    /// ```
355    pub fn uuid_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
356        let uuid = Uuid::parse_str(s.as_ref()).map_err(|e| {
357            Error::new(
358                ErrorKind::DataInvalid,
359                format!("Can't parse uuid from string: {}", s.as_ref()),
360            )
361            .with_source(e)
362        })?;
363        Ok(Self::uuid(uuid))
364    }
365
366    /// Creates a fixed literal from bytes.
367    ///
368    /// Example:
369    ///
370    /// ```rust
371    /// use iceberg::spec::{Literal, PrimitiveLiteral};
372    /// let t1 = Literal::fixed(vec![1u8, 2u8]);
373    /// let t2 = Literal::Primitive(PrimitiveLiteral::Binary(vec![1u8, 2u8]));
374    ///
375    /// assert_eq!(t1, t2);
376    /// ```
377    pub fn fixed<I: IntoIterator<Item = u8>>(input: I) -> Self {
378        Literal::Primitive(PrimitiveLiteral::Binary(input.into_iter().collect()))
379    }
380
381    /// Creates a binary literal from bytes.
382    ///
383    /// Example:
384    ///
385    /// ```rust
386    /// use iceberg::spec::{Literal, PrimitiveLiteral};
387    /// let t1 = Literal::binary(vec![1u8, 2u8]);
388    /// let t2 = Literal::Primitive(PrimitiveLiteral::Binary(vec![1u8, 2u8]));
389    ///
390    /// assert_eq!(t1, t2);
391    /// ```
392    pub fn binary<I: IntoIterator<Item = u8>>(input: I) -> Self {
393        Literal::Primitive(PrimitiveLiteral::Binary(input.into_iter().collect()))
394    }
395
396    /// Creates a decimal literal.
397    pub fn decimal(decimal: i128) -> Self {
398        Self::Primitive(PrimitiveLiteral::Int128(decimal))
399    }
400
401    /// Creates decimal literal from string.
402    ///
403    /// Example:
404    ///
405    /// ```rust
406    /// use iceberg::spec::Literal;
407    /// let t1 = Literal::decimal(12345);
408    /// let t2 = Literal::decimal_from_str("123.45").unwrap();
409    ///
410    /// assert_eq!(t1, t2);
411    /// ```
412    pub fn decimal_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
413        let decimal = decimal_from_str_exact(s.as_ref())?;
414        Ok(Self::decimal(decimal_mantissa(&decimal)))
415    }
416
417    /// Attempts to convert the Literal to a PrimitiveLiteral
418    pub fn as_primitive_literal(&self) -> Option<PrimitiveLiteral> {
419        match self {
420            Literal::Primitive(primitive) => Some(primitive.clone()),
421            _ => None,
422        }
423    }
424
425    /// Create iceberg value from a json value
426    ///
427    /// See [this spec](https://iceberg.apache.org/spec/#json-single-value-serialization) for reference.
428    pub fn try_from_json(value: JsonValue, data_type: &Type) -> Result<Option<Self>> {
429        match data_type {
430            Type::Primitive(primitive) => match (primitive, value) {
431                (PrimitiveType::Boolean, JsonValue::Bool(bool)) => {
432                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Boolean(bool))))
433                }
434                (PrimitiveType::Int, JsonValue::Number(number)) => {
435                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Int(
436                        number
437                            .as_i64()
438                            .ok_or(Error::new(
439                                crate::ErrorKind::DataInvalid,
440                                "Failed to convert json number to int",
441                            ))?
442                            .try_into()?,
443                    ))))
444                }
445                (PrimitiveType::Long, JsonValue::Number(number)) => Ok(Some(Literal::Primitive(
446                    PrimitiveLiteral::Long(number.as_i64().ok_or(Error::new(
447                        crate::ErrorKind::DataInvalid,
448                        "Failed to convert json number to long",
449                    ))?),
450                ))),
451                (PrimitiveType::Float, JsonValue::Number(number)) => Ok(Some(Literal::Primitive(
452                    PrimitiveLiteral::Float(OrderedFloat(number.as_f64().ok_or(Error::new(
453                        crate::ErrorKind::DataInvalid,
454                        "Failed to convert json number to float",
455                    ))? as f32)),
456                ))),
457                (PrimitiveType::Double, JsonValue::Number(number)) => Ok(Some(Literal::Primitive(
458                    PrimitiveLiteral::Double(OrderedFloat(number.as_f64().ok_or(Error::new(
459                        crate::ErrorKind::DataInvalid,
460                        "Failed to convert json number to double",
461                    ))?)),
462                ))),
463                (PrimitiveType::Date, JsonValue::String(s)) => {
464                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Int(
465                        date::date_to_days(&NaiveDate::parse_from_str(&s, "%Y-%m-%d")?),
466                    ))))
467                }
468                (PrimitiveType::Date, JsonValue::Number(number)) => {
469                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Int(
470                        number
471                            .as_i64()
472                            .ok_or(Error::new(
473                                crate::ErrorKind::DataInvalid,
474                                "Failed to convert json number to date (days since epoch)",
475                            ))?
476                            .try_into()?,
477                    ))))
478                }
479                (PrimitiveType::Time, JsonValue::String(s)) => {
480                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(
481                        time::time_to_microseconds(&NaiveTime::parse_from_str(&s, "%H:%M:%S%.f")?),
482                    ))))
483                }
484                (PrimitiveType::Timestamp, JsonValue::String(s)) => Ok(Some(Literal::Primitive(
485                    PrimitiveLiteral::Long(timestamp::datetime_to_microseconds(
486                        &NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S%.f")?,
487                    )),
488                ))),
489                (PrimitiveType::Timestamptz, JsonValue::String(s)) => {
490                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(
491                        timestamptz::datetimetz_to_microseconds(&Utc.from_utc_datetime(
492                            &NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S%.f+00:00")?,
493                        )),
494                    ))))
495                }
496                (PrimitiveType::String, JsonValue::String(s)) => {
497                    Ok(Some(Literal::Primitive(PrimitiveLiteral::String(s))))
498                }
499                (PrimitiveType::Uuid, JsonValue::String(s)) => Ok(Some(Literal::Primitive(
500                    PrimitiveLiteral::UInt128(Uuid::parse_str(&s)?.as_u128()),
501                ))),
502                (PrimitiveType::Fixed(_), JsonValue::String(_)) => todo!(),
503                (PrimitiveType::Binary, JsonValue::String(_)) => todo!(),
504                (
505                    PrimitiveType::Decimal {
506                        precision: _,
507                        scale,
508                    },
509                    JsonValue::String(s),
510                ) => {
511                    let decimal = decimal_from_str_exact(&s)?;
512                    let rescaled = decimal_rescale(decimal, *scale);
513                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Int128(
514                        decimal_mantissa(&rescaled),
515                    ))))
516                }
517                (_, JsonValue::Null) => Ok(None),
518                (i, j) => Err(Error::new(
519                    crate::ErrorKind::DataInvalid,
520                    format!("The json value {j} doesn't fit to the iceberg type {i}."),
521                )),
522            },
523            Type::Struct(schema) => {
524                if let JsonValue::Object(mut object) = value {
525                    Ok(Some(Literal::Struct(Struct::from_iter(
526                        schema.fields().iter().map(|field| {
527                            object.remove(&field.id.to_string()).and_then(|value| {
528                                Literal::try_from_json(value, &field.field_type)
529                                    .and_then(|value| {
530                                        value.ok_or(Error::new(
531                                            ErrorKind::DataInvalid,
532                                            "Key of map cannot be null",
533                                        ))
534                                    })
535                                    .ok()
536                            })
537                        }),
538                    ))))
539                } else {
540                    Err(Error::new(
541                        crate::ErrorKind::DataInvalid,
542                        "The json value for a struct type must be an object.",
543                    ))
544                }
545            }
546            Type::List(list) => {
547                if let JsonValue::Array(array) = value {
548                    Ok(Some(Literal::List(
549                        array
550                            .into_iter()
551                            .map(|value| {
552                                Literal::try_from_json(value, &list.element_field.field_type)
553                            })
554                            .collect::<Result<Vec<_>>>()?,
555                    )))
556                } else {
557                    Err(Error::new(
558                        crate::ErrorKind::DataInvalid,
559                        "The json value for a list type must be an array.",
560                    ))
561                }
562            }
563            Type::Map(map) => {
564                if let JsonValue::Object(mut object) = value {
565                    if let (Some(JsonValue::Array(keys)), Some(JsonValue::Array(values))) =
566                        (object.remove("keys"), object.remove("values"))
567                    {
568                        Ok(Some(Literal::Map(Map::from_iter(
569                            keys.into_iter()
570                                .zip(values.into_iter())
571                                .map(|(key, value)| {
572                                    Ok((
573                                        Literal::try_from_json(key, &map.key_field.field_type)
574                                            .and_then(|value| {
575                                                value.ok_or(Error::new(
576                                                    ErrorKind::DataInvalid,
577                                                    "Key of map cannot be null",
578                                                ))
579                                            })?,
580                                        Literal::try_from_json(value, &map.value_field.field_type)?,
581                                    ))
582                                })
583                                .collect::<Result<Vec<_>>>()?,
584                        ))))
585                    } else {
586                        Err(Error::new(
587                            crate::ErrorKind::DataInvalid,
588                            "The json value for a list type must be an array.",
589                        ))
590                    }
591                } else {
592                    Err(Error::new(
593                        crate::ErrorKind::DataInvalid,
594                        "The json value for a list type must be an array.",
595                    ))
596                }
597            }
598        }
599    }
600
601    /// Converting iceberg value to json value.
602    ///
603    /// See [this spec](https://iceberg.apache.org/spec/#json-single-value-serialization) for reference.
604    pub fn try_into_json(self, r#type: &Type) -> Result<JsonValue> {
605        match (self, r#type) {
606            (Literal::Primitive(prim), Type::Primitive(prim_type)) => match (prim_type, prim) {
607                (PrimitiveType::Boolean, PrimitiveLiteral::Boolean(val)) => {
608                    Ok(JsonValue::Bool(val))
609                }
610                (PrimitiveType::Int, PrimitiveLiteral::Int(val)) => {
611                    Ok(JsonValue::Number((val).into()))
612                }
613                (PrimitiveType::Long, PrimitiveLiteral::Long(val)) => {
614                    Ok(JsonValue::Number((val).into()))
615                }
616                (PrimitiveType::Float, PrimitiveLiteral::Float(val)) => {
617                    match Number::from_f64(val.0 as f64) {
618                        Some(number) => Ok(JsonValue::Number(number)),
619                        None => Ok(JsonValue::Null),
620                    }
621                }
622                (PrimitiveType::Double, PrimitiveLiteral::Double(val)) => {
623                    match Number::from_f64(val.0) {
624                        Some(number) => Ok(JsonValue::Number(number)),
625                        None => Ok(JsonValue::Null),
626                    }
627                }
628                (PrimitiveType::Date, PrimitiveLiteral::Int(val)) => {
629                    Ok(JsonValue::String(date::days_to_date(val).to_string()))
630                }
631                (PrimitiveType::Time, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
632                    time::microseconds_to_time(val).to_string(),
633                )),
634                (PrimitiveType::Timestamp, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
635                    timestamp::microseconds_to_datetime(val)
636                        .format("%Y-%m-%dT%H:%M:%S%.f")
637                        .to_string(),
638                )),
639                (PrimitiveType::Timestamptz, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
640                    timestamptz::microseconds_to_datetimetz(val)
641                        .format("%Y-%m-%dT%H:%M:%S%.f+00:00")
642                        .to_string(),
643                )),
644                (PrimitiveType::TimestampNs, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
645                    timestamp::nanoseconds_to_datetime(val)
646                        .format("%Y-%m-%dT%H:%M:%S%.f")
647                        .to_string(),
648                )),
649                (PrimitiveType::TimestamptzNs, PrimitiveLiteral::Long(val)) => {
650                    Ok(JsonValue::String(
651                        timestamptz::nanoseconds_to_datetimetz(val)
652                            .format("%Y-%m-%dT%H:%M:%S%.f+00:00")
653                            .to_string(),
654                    ))
655                }
656                (PrimitiveType::String, PrimitiveLiteral::String(val)) => {
657                    Ok(JsonValue::String(val.clone()))
658                }
659                (_, PrimitiveLiteral::UInt128(val)) => {
660                    Ok(JsonValue::String(Uuid::from_u128(val).to_string()))
661                }
662                (_, PrimitiveLiteral::Binary(val)) => Ok(JsonValue::String(val.iter().fold(
663                    String::new(),
664                    |mut acc, x| {
665                        acc.push_str(&format!("{x:x}"));
666                        acc
667                    },
668                ))),
669                (_, PrimitiveLiteral::Int128(val)) => match r#type {
670                    Type::Primitive(PrimitiveType::Decimal {
671                        precision: _precision,
672                        scale,
673                    }) => {
674                        let decimal = try_decimal_from_i128_with_scale(val, *scale)?;
675                        Ok(JsonValue::String(decimal.to_string()))
676                    }
677                    _ => Err(Error::new(
678                        ErrorKind::DataInvalid,
679                        "The iceberg type for decimal literal must be decimal.",
680                    ))?,
681                },
682                _ => Err(Error::new(
683                    ErrorKind::DataInvalid,
684                    "The iceberg value doesn't fit to the iceberg type.",
685                )),
686            },
687            (Literal::Struct(s), Type::Struct(struct_type)) => {
688                let mut id_and_value = Vec::with_capacity(struct_type.fields().len());
689                for (value, field) in s.into_iter().zip(struct_type.fields()) {
690                    let json = match value {
691                        Some(val) => val.try_into_json(&field.field_type)?,
692                        None => JsonValue::Null,
693                    };
694                    id_and_value.push((field.id.to_string(), json));
695                }
696                Ok(JsonValue::Object(JsonMap::from_iter(id_and_value)))
697            }
698            (Literal::List(list), Type::List(list_type)) => Ok(JsonValue::Array(
699                list.into_iter()
700                    .map(|opt| match opt {
701                        Some(literal) => literal.try_into_json(&list_type.element_field.field_type),
702                        None => Ok(JsonValue::Null),
703                    })
704                    .collect::<Result<Vec<JsonValue>>>()?,
705            )),
706            (Literal::Map(map), Type::Map(map_type)) => {
707                let mut object = JsonMap::with_capacity(2);
708                let mut json_keys = Vec::with_capacity(map.len());
709                let mut json_values = Vec::with_capacity(map.len());
710                for (key, value) in map.into_iter() {
711                    json_keys.push(key.try_into_json(&map_type.key_field.field_type)?);
712                    json_values.push(match value {
713                        Some(literal) => literal.try_into_json(&map_type.value_field.field_type)?,
714                        None => JsonValue::Null,
715                    });
716                }
717                object.insert("keys".to_string(), JsonValue::Array(json_keys));
718                object.insert("values".to_string(), JsonValue::Array(json_values));
719                Ok(JsonValue::Object(object))
720            }
721            (value, r#type) => Err(Error::new(
722                ErrorKind::DataInvalid,
723                format!("The iceberg value {value:?} doesn't fit to the iceberg type {type}."),
724            )),
725        }
726    }
727
728    /// Convert Value to the any type
729    pub fn into_any(self) -> Box<dyn Any> {
730        match self {
731            Literal::Primitive(prim) => match prim {
732                PrimitiveLiteral::Boolean(any) => Box::new(any),
733                PrimitiveLiteral::Int(any) => Box::new(any),
734                PrimitiveLiteral::Long(any) => Box::new(any),
735                PrimitiveLiteral::Float(any) => Box::new(any),
736                PrimitiveLiteral::Double(any) => Box::new(any),
737                PrimitiveLiteral::Binary(any) => Box::new(any),
738                PrimitiveLiteral::String(any) => Box::new(any),
739                PrimitiveLiteral::UInt128(any) => Box::new(any),
740                PrimitiveLiteral::Int128(any) => Box::new(any),
741                PrimitiveLiteral::AboveMax | PrimitiveLiteral::BelowMin => unimplemented!(),
742            },
743            _ => unimplemented!(),
744        }
745    }
746}