1use 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::{Error, ErrorKind, Result, invalid_data};
36use crate::spec::datatypes::{PrimitiveType, Type};
37
38#[derive(Clone, Debug, PartialEq, Eq, Hash)]
40pub enum Literal {
41 Primitive(PrimitiveLiteral),
43 Struct(Struct),
47 List(Vec<Option<Literal>>),
51 Map(Map),
55}
56
57impl Literal {
58 pub fn bool<T: Into<bool>>(t: T) -> Self {
68 Self::Primitive(PrimitiveLiteral::Boolean(t.into()))
69 }
70
71 pub fn bool_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
82 let v = s
83 .as_ref()
84 .parse::<bool>()
85 .map_err(|e| invalid_data!("Can't parse string to bool.").with_source(e))?;
86 Ok(Self::Primitive(PrimitiveLiteral::Boolean(v)))
87 }
88
89 pub fn int<T: Into<i32>>(t: T) -> Self {
99 Self::Primitive(PrimitiveLiteral::Int(t.into()))
100 }
101
102 pub fn long<T: Into<i64>>(t: T) -> Self {
112 Self::Primitive(PrimitiveLiteral::Long(t.into()))
113 }
114
115 pub fn float<T: Into<f32>>(t: T) -> Self {
129 Self::Primitive(PrimitiveLiteral::Float(OrderedFloat(t.into())))
130 }
131
132 pub fn double<T: Into<f64>>(t: T) -> Self {
146 Self::Primitive(PrimitiveLiteral::Double(OrderedFloat(t.into())))
147 }
148
149 pub fn date(days: i32) -> Self {
151 Self::Primitive(PrimitiveLiteral::Int(days))
152 }
153
154 pub fn date_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
166 let t = s.as_ref().parse::<NaiveDate>().map_err(|e| {
167 invalid_data!("Can't parse date from string: {}", s.as_ref()).with_source(e)
168 })?;
169
170 Ok(Self::date(date::date_from_naive_date(t)))
171 }
172
173 pub fn date_from_ymd(year: i32, month: u32, day: u32) -> Result<Self> {
186 let t = NaiveDate::from_ymd_opt(year, month, day).ok_or_else(|| {
187 invalid_data!("Can't create date from year: {year}, month: {month}, day: {day}")
188 })?;
189
190 Ok(Self::date(date::date_from_naive_date(t)))
191 }
192
193 pub fn time(value: i64) -> Self {
195 Self::Primitive(PrimitiveLiteral::Long(value))
196 }
197
198 fn time_from_naive_time(t: NaiveTime) -> Self {
200 let duration = t - date::unix_epoch().time();
201 let micro_secs = duration.num_microseconds().unwrap();
203
204 Literal::time(micro_secs)
205 }
206
207 pub fn time_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
225 let t = s.as_ref().parse::<NaiveTime>().map_err(|e| {
226 invalid_data!("Can't parse time from string: {}", s.as_ref()).with_source(e)
227 })?;
228
229 Ok(Self::time_from_naive_time(t))
230 }
231
232 pub fn time_from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> Result<Self> {
244 let t = NaiveTime::from_hms_micro_opt(hour, min, sec, micro)
245 .ok_or_else(|| invalid_data!("Can't create time from hour: {hour}, min: {min}, second: {sec}, microsecond: {micro}"))?;
246 Ok(Self::time_from_naive_time(t))
247 }
248
249 pub fn timestamp(value: i64) -> Self {
251 Self::Primitive(PrimitiveLiteral::Long(value))
252 }
253
254 pub fn timestamptz(value: i64) -> Self {
256 Self::Primitive(PrimitiveLiteral::Long(value))
257 }
258
259 pub(crate) fn timestamp_nano(value: i64) -> Self {
261 Self::Primitive(PrimitiveLiteral::Long(value))
262 }
263
264 pub(crate) fn timestamptz_nano(value: i64) -> Self {
266 Self::Primitive(PrimitiveLiteral::Long(value))
267 }
268
269 pub fn timestamp_from_datetime<T: TimeZone>(dt: DateTime<T>) -> Self {
271 Self::timestamp(dt.with_timezone(&Utc).timestamp_micros())
272 }
273
274 pub fn timestamptz_from_datetime<T: TimeZone>(dt: DateTime<T>) -> Self {
276 Self::timestamptz(dt.with_timezone(&Utc).timestamp_micros())
277 }
278
279 pub fn timestamp_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
303 let dt = DateTime::<Utc>::from_str(s.as_ref())
304 .map_err(|e| invalid_data!("Can't parse datetime.").with_source(e))?;
305
306 Ok(Self::timestamp_from_datetime(dt))
307 }
308
309 pub fn timestamptz_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
311 let dt = DateTime::<Utc>::from_str(s.as_ref())
312 .map_err(|e| invalid_data!("Can't parse datetime.").with_source(e))?;
313
314 Ok(Self::timestamptz_from_datetime(dt))
315 }
316
317 pub fn string<S: ToString>(s: S) -> Self {
319 Self::Primitive(PrimitiveLiteral::String(s.to_string()))
320 }
321
322 pub fn uuid(uuid: Uuid) -> Self {
324 Self::Primitive(PrimitiveLiteral::UInt128(uuid.as_u128()))
325 }
326
327 pub fn uuid_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
340 let uuid = Uuid::parse_str(s.as_ref()).map_err(|e| {
341 invalid_data!("Can't parse uuid from string: {}", s.as_ref()).with_source(e)
342 })?;
343 Ok(Self::uuid(uuid))
344 }
345
346 pub fn fixed<I: IntoIterator<Item = u8>>(input: I) -> Self {
358 Literal::Primitive(PrimitiveLiteral::Binary(input.into_iter().collect()))
359 }
360
361 pub fn binary<I: IntoIterator<Item = u8>>(input: I) -> Self {
373 Literal::Primitive(PrimitiveLiteral::Binary(input.into_iter().collect()))
374 }
375
376 pub fn decimal(decimal: i128) -> Self {
378 Self::Primitive(PrimitiveLiteral::Int128(decimal))
379 }
380
381 pub fn decimal_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
393 let decimal = decimal_from_str_exact(s.as_ref())?;
394 Ok(Self::decimal(decimal_mantissa(&decimal)))
395 }
396
397 pub fn as_primitive_literal(&self) -> Option<PrimitiveLiteral> {
399 match self {
400 Literal::Primitive(primitive) => Some(primitive.clone()),
401 _ => None,
402 }
403 }
404
405 pub fn try_from_json(value: JsonValue, data_type: &Type) -> Result<Option<Self>> {
409 match data_type {
410 Type::Primitive(primitive) => match (primitive, value) {
411 (PrimitiveType::Boolean, JsonValue::Bool(bool)) => {
412 Ok(Some(Literal::Primitive(PrimitiveLiteral::Boolean(bool))))
413 }
414 (PrimitiveType::Int, JsonValue::Number(number)) => {
415 Ok(Some(Literal::Primitive(PrimitiveLiteral::Int(
416 number
417 .as_i64()
418 .ok_or(invalid_data!("Failed to convert json number to int"))?
419 .try_into()?,
420 ))))
421 }
422 (PrimitiveType::Long, JsonValue::Number(number)) => {
423 Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(
424 number
425 .as_i64()
426 .ok_or(invalid_data!("Failed to convert json number to long"))?,
427 ))))
428 }
429 (PrimitiveType::Float, JsonValue::Number(number)) => Ok(Some(Literal::Primitive(
430 PrimitiveLiteral::Float(OrderedFloat(
431 number
432 .as_f64()
433 .ok_or(invalid_data!("Failed to convert json number to float"))?
434 as f32,
435 )),
436 ))),
437 (PrimitiveType::Double, JsonValue::Number(number)) => Ok(Some(Literal::Primitive(
438 PrimitiveLiteral::Double(OrderedFloat(
439 number
440 .as_f64()
441 .ok_or(invalid_data!("Failed to convert json number to double"))?,
442 )),
443 ))),
444 (PrimitiveType::Date, JsonValue::String(s)) => {
445 Ok(Some(Literal::Primitive(PrimitiveLiteral::Int(
446 date::date_to_days(&NaiveDate::parse_from_str(&s, "%Y-%m-%d")?),
447 ))))
448 }
449 (PrimitiveType::Date, JsonValue::Number(number)) => {
450 Ok(Some(Literal::Primitive(PrimitiveLiteral::Int(
451 number
452 .as_i64()
453 .ok_or(invalid_data!(
454 "Failed to convert json number to date (days since epoch)"
455 ))?
456 .try_into()?,
457 ))))
458 }
459 (PrimitiveType::Time, JsonValue::String(s)) => {
460 Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(
461 time::time_to_microseconds(&NaiveTime::parse_from_str(&s, "%H:%M:%S%.f")?),
462 ))))
463 }
464 (PrimitiveType::Timestamp, JsonValue::String(s)) => Ok(Some(Literal::Primitive(
465 PrimitiveLiteral::Long(timestamp::datetime_to_microseconds(
466 &NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S%.f")?,
467 )),
468 ))),
469 (PrimitiveType::Timestamptz, JsonValue::String(s)) => {
470 Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(
471 timestamptz::datetimetz_to_microseconds(&Utc.from_utc_datetime(
472 &NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S%.f+00:00")?,
473 )),
474 ))))
475 }
476 (PrimitiveType::TimestampNs, JsonValue::String(s)) => {
477 let ndt = NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S%.f")?;
478 let nanos = timestamp::datetime_to_nanoseconds(&ndt).ok_or_else(|| {
479 invalid_data!(
480 "Timestamp is outside the representable nanosecond range: {ndt}"
481 )
482 })?;
483 Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(nanos))))
484 }
485 (PrimitiveType::TimestamptzNs, JsonValue::String(s)) => {
486 let dt = Utc.from_utc_datetime(&NaiveDateTime::parse_from_str(
487 &s,
488 "%Y-%m-%dT%H:%M:%S%.f+00:00",
489 )?);
490 let nanos = timestamptz::datetimetz_to_nanoseconds(&dt).ok_or_else(|| {
491 invalid_data!(
492 "Timestamptz is outside the representable nanosecond range: {dt}"
493 )
494 })?;
495 Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(nanos))))
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(size), JsonValue::String(s)) => {
504 let bytes = decode_hex_bytes(&s)?;
505 validate_fixed_size(bytes.len(), *size)?;
506 Ok(Some(Literal::Primitive(PrimitiveLiteral::Binary(bytes))))
507 }
508 (PrimitiveType::Binary, JsonValue::String(s)) => Ok(Some(Literal::Primitive(
509 PrimitiveLiteral::Binary(decode_hex_bytes(&s)?),
510 ))),
511 (
512 PrimitiveType::Geometry(_) | PrimitiveType::Geography(_),
513 JsonValue::String(_),
514 ) => Err(Error::new(
515 ErrorKind::FeatureUnsupported,
516 "WKT deserialization for geospatial types is not yet supported",
517 )),
518 (
519 PrimitiveType::Decimal {
520 precision: _,
521 scale,
522 },
523 JsonValue::String(s),
524 ) => {
525 let decimal = decimal_from_str_exact(&s)?;
526 let rescaled = decimal_rescale(decimal, *scale);
527 Ok(Some(Literal::Primitive(PrimitiveLiteral::Int128(
528 decimal_mantissa(&rescaled),
529 ))))
530 }
531 (PrimitiveType::Unknown, value) if !value.is_null() => Err(invalid_data!(
532 "Unknown type only supports null default values"
533 )),
534 (_, JsonValue::Null) => Ok(None),
535 (i, j) => Err(invalid_data!(
536 "The json value {j} doesn't fit to the iceberg type {i}."
537 )),
538 },
539 Type::Struct(schema) => {
540 if let JsonValue::Object(mut object) = value {
541 let values = schema
542 .fields()
543 .iter()
544 .map(|field| match object.remove(&field.id.to_string()) {
545 Some(value) => Literal::try_from_json(value, &field.field_type),
546 None => Ok(None),
547 })
548 .collect::<Result<Vec<_>>>()?;
549 Ok(Some(Literal::Struct(Struct::from_iter(values))))
550 } else {
551 Err(invalid_data!(
552 "The json value for a struct type must be an object."
553 ))
554 }
555 }
556 Type::List(list) => {
557 if let JsonValue::Array(array) = value {
558 Ok(Some(Literal::List(
559 array
560 .into_iter()
561 .map(|value| {
562 Literal::try_from_json(value, &list.element_field.field_type)
563 })
564 .collect::<Result<Vec<_>>>()?,
565 )))
566 } else {
567 Err(invalid_data!(
568 "The json value for a list type must be an array."
569 ))
570 }
571 }
572 Type::Map(map) => {
573 if let JsonValue::Object(mut object) = value {
574 if let (Some(JsonValue::Array(keys)), Some(JsonValue::Array(values))) =
575 (object.remove("keys"), object.remove("values"))
576 {
577 if keys.len() != values.len() {
578 return Err(invalid_data!(
579 "Map keys and values must have the same length, got {} keys and {} values",
580 keys.len(),
581 values.len()
582 ));
583 }
584
585 Ok(Some(Literal::Map(Map::from_iter(
586 keys.into_iter()
587 .zip(values)
588 .map(|(key, value)| {
589 Ok((
590 Literal::try_from_json(key, &map.key_field.field_type)
591 .and_then(|value| {
592 value.ok_or(invalid_data!(
593 "Key of map cannot be null"
594 ))
595 })?,
596 Literal::try_from_json(value, &map.value_field.field_type)?,
597 ))
598 })
599 .collect::<Result<Vec<_>>>()?,
600 ))))
601 } else {
602 Err(invalid_data!(
603 "The json value for a list type must be an array."
604 ))
605 }
606 } else {
607 Err(invalid_data!(
608 "The json value for a list type must be an array."
609 ))
610 }
611 }
612 Type::Variant(_) => Err(invalid_data!(
613 "Variant type is not supported for single-value JSON serialization"
614 )),
615 }
616 }
617
618 pub fn try_into_json(self, r#type: &Type) -> Result<JsonValue> {
622 match (self, r#type) {
623 (Literal::Primitive(prim), Type::Primitive(prim_type)) => match (prim_type, prim) {
624 (PrimitiveType::Boolean, PrimitiveLiteral::Boolean(val)) => {
625 Ok(JsonValue::Bool(val))
626 }
627 (PrimitiveType::Int, PrimitiveLiteral::Int(val)) => {
628 Ok(JsonValue::Number((val).into()))
629 }
630 (PrimitiveType::Long, PrimitiveLiteral::Long(val)) => {
631 Ok(JsonValue::Number((val).into()))
632 }
633 (PrimitiveType::Float, PrimitiveLiteral::Float(val)) => {
634 match Number::from_f64(val.0 as f64) {
635 Some(number) => Ok(JsonValue::Number(number)),
636 None => Ok(JsonValue::Null),
637 }
638 }
639 (PrimitiveType::Double, PrimitiveLiteral::Double(val)) => {
640 match Number::from_f64(val.0) {
641 Some(number) => Ok(JsonValue::Number(number)),
642 None => Ok(JsonValue::Null),
643 }
644 }
645 (PrimitiveType::Date, PrimitiveLiteral::Int(val)) => {
646 Ok(JsonValue::String(date::days_to_date(val).to_string()))
647 }
648 (PrimitiveType::Time, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
649 time::microseconds_to_time(val).to_string(),
650 )),
651 (PrimitiveType::Timestamp, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
652 timestamp::microseconds_to_datetime(val)
653 .format("%Y-%m-%dT%H:%M:%S%.f")
654 .to_string(),
655 )),
656 (PrimitiveType::Timestamptz, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
657 timestamptz::microseconds_to_datetimetz(val)
658 .format("%Y-%m-%dT%H:%M:%S%.f+00:00")
659 .to_string(),
660 )),
661 (PrimitiveType::TimestampNs, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
662 timestamp::nanoseconds_to_datetime(val)
663 .format("%Y-%m-%dT%H:%M:%S%.f")
664 .to_string(),
665 )),
666 (PrimitiveType::TimestamptzNs, PrimitiveLiteral::Long(val)) => {
667 Ok(JsonValue::String(
668 timestamptz::nanoseconds_to_datetimetz(val)
669 .format("%Y-%m-%dT%H:%M:%S%.f+00:00")
670 .to_string(),
671 ))
672 }
673 (PrimitiveType::String, PrimitiveLiteral::String(val)) => {
674 Ok(JsonValue::String(val.clone()))
675 }
676 (_, PrimitiveLiteral::UInt128(val)) => {
677 Ok(JsonValue::String(Uuid::from_u128(val).to_string()))
678 }
679 (PrimitiveType::Fixed(size), PrimitiveLiteral::Binary(val)) => {
680 validate_fixed_size(val.len(), *size)?;
681 Ok(JsonValue::String(encode_hex_bytes(&val)))
682 }
683 (PrimitiveType::Binary, PrimitiveLiteral::Binary(val)) => {
684 Ok(JsonValue::String(encode_hex_bytes(&val)))
685 }
686 (
687 PrimitiveType::Geometry(_) | PrimitiveType::Geography(_),
688 PrimitiveLiteral::Binary(_),
689 ) => Err(Error::new(
690 ErrorKind::FeatureUnsupported,
691 "WKT serialization for geospatial types is not yet supported",
692 )),
693 (_, PrimitiveLiteral::Int128(val)) => match r#type {
694 Type::Primitive(PrimitiveType::Decimal {
695 precision: _precision,
696 scale,
697 }) => {
698 let decimal = try_decimal_from_i128_with_scale(val, *scale)?;
699 Ok(JsonValue::String(decimal.to_string()))
700 }
701 _ => Err(invalid_data!(
702 "The iceberg type for decimal literal must be decimal."
703 ))?,
704 },
705 _ => Err(invalid_data!(
706 "The iceberg value doesn't fit to the iceberg type."
707 )),
708 },
709 (Literal::Struct(s), Type::Struct(struct_type)) => {
710 let mut id_and_value = Vec::with_capacity(struct_type.fields().len());
711 for (value, field) in s.into_iter().zip(struct_type.fields()) {
712 let json = match value {
713 Some(val) => val.try_into_json(&field.field_type)?,
714 None => JsonValue::Null,
715 };
716 id_and_value.push((field.id.to_string(), json));
717 }
718 Ok(JsonValue::Object(JsonMap::from_iter(id_and_value)))
719 }
720 (Literal::List(list), Type::List(list_type)) => Ok(JsonValue::Array(
721 list.into_iter()
722 .map(|opt| match opt {
723 Some(literal) => literal.try_into_json(&list_type.element_field.field_type),
724 None => Ok(JsonValue::Null),
725 })
726 .collect::<Result<Vec<JsonValue>>>()?,
727 )),
728 (Literal::Map(map), Type::Map(map_type)) => {
729 let mut object = JsonMap::with_capacity(2);
730 let mut json_keys = Vec::with_capacity(map.len());
731 let mut json_values = Vec::with_capacity(map.len());
732 for (key, value) in map.into_iter() {
733 json_keys.push(key.try_into_json(&map_type.key_field.field_type)?);
734 json_values.push(match value {
735 Some(literal) => literal.try_into_json(&map_type.value_field.field_type)?,
736 None => JsonValue::Null,
737 });
738 }
739 object.insert("keys".to_string(), JsonValue::Array(json_keys));
740 object.insert("values".to_string(), JsonValue::Array(json_values));
741 Ok(JsonValue::Object(object))
742 }
743 (value, r#type) => Err(invalid_data!(
744 "The iceberg value {value:?} doesn't fit to the iceberg type {type}."
745 )),
746 }
747 }
748
749 pub fn into_any(self) -> Box<dyn Any> {
751 match self {
752 Literal::Primitive(prim) => match prim {
753 PrimitiveLiteral::Boolean(any) => Box::new(any),
754 PrimitiveLiteral::Int(any) => Box::new(any),
755 PrimitiveLiteral::Long(any) => Box::new(any),
756 PrimitiveLiteral::Float(any) => Box::new(any),
757 PrimitiveLiteral::Double(any) => Box::new(any),
758 PrimitiveLiteral::Binary(any) => Box::new(any),
759 PrimitiveLiteral::String(any) => Box::new(any),
760 PrimitiveLiteral::UInt128(any) => Box::new(any),
761 PrimitiveLiteral::Int128(any) => Box::new(any),
762 PrimitiveLiteral::AboveMax | PrimitiveLiteral::BelowMin => unimplemented!(),
763 },
764 _ => unimplemented!(),
765 }
766 }
767}
768
769fn decode_hex_bytes(value: &str) -> Result<Vec<u8>> {
770 if !value.len().is_multiple_of(2) {
771 return Err(invalid_data!(
772 "Hex string must have an even number of characters: {value:?}"
773 ));
774 }
775
776 value
777 .as_bytes()
778 .chunks_exact(2)
779 .map(|chunk| {
780 let high = decode_hex_digit(chunk[0], value)?;
781 let low = decode_hex_digit(chunk[1], value)?;
782 Ok((high << 4) | low)
783 })
784 .collect()
785}
786
787fn decode_hex_digit(digit: u8, value: &str) -> Result<u8> {
788 match digit {
789 b'0'..=b'9' => Ok(digit - b'0'),
790 b'a'..=b'f' => Ok(digit - b'a' + 10),
791 b'A'..=b'F' => Ok(digit - b'A' + 10),
792 _ => Err(invalid_data!(
793 "Hex string contains invalid character: {value:?}"
794 )),
795 }
796}
797
798fn encode_hex_bytes(bytes: &[u8]) -> String {
799 const HEX_DIGITS: &[u8; 16] = b"0123456789abcdef";
800
801 let mut output = String::with_capacity(bytes.len() * 2);
802 for byte in bytes {
803 output.push(HEX_DIGITS[(byte >> 4) as usize] as char);
804 output.push(HEX_DIGITS[(byte & 0x0f) as usize] as char);
805 }
806 output
807}
808
809fn validate_fixed_size(actual: usize, expected: u64) -> Result<()> {
810 if actual as u64 == expected {
811 Ok(())
812 } else {
813 Err(invalid_data!(
814 "Fixed type must be exactly {expected} bytes, got {actual}"
815 ))
816 }
817}