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