1use 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#[derive(Clone, Debug, PartialEq, Eq, Hash)]
39pub enum Literal {
40 Primitive(PrimitiveLiteral),
42 Struct(Struct),
46 List(Vec<Option<Literal>>),
50 Map(Map),
54}
55
56impl Literal {
57 pub fn bool<T: Into<bool>>(t: T) -> Self {
67 Self::Primitive(PrimitiveLiteral::Boolean(t.into()))
68 }
69
70 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 pub fn int<T: Into<i32>>(t: T) -> Self {
97 Self::Primitive(PrimitiveLiteral::Int(t.into()))
98 }
99
100 pub fn long<T: Into<i64>>(t: T) -> Self {
110 Self::Primitive(PrimitiveLiteral::Long(t.into()))
111 }
112
113 pub fn float<T: Into<f32>>(t: T) -> Self {
127 Self::Primitive(PrimitiveLiteral::Float(OrderedFloat(t.into())))
128 }
129
130 pub fn double<T: Into<f64>>(t: T) -> Self {
144 Self::Primitive(PrimitiveLiteral::Double(OrderedFloat(t.into())))
145 }
146
147 pub fn date(days: i32) -> Self {
149 Self::Primitive(PrimitiveLiteral::Int(days))
150 }
151
152 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 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 pub fn time(value: i64) -> Self {
200 Self::Primitive(PrimitiveLiteral::Long(value))
201 }
202
203 fn time_from_naive_time(t: NaiveTime) -> Self {
205 let duration = t - date::unix_epoch().time();
206 let micro_secs = duration.num_microseconds().unwrap();
208
209 Literal::time(micro_secs)
210 }
211
212 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 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 pub fn timestamp(value: i64) -> Self {
263 Self::Primitive(PrimitiveLiteral::Long(value))
264 }
265
266 pub fn timestamptz(value: i64) -> Self {
268 Self::Primitive(PrimitiveLiteral::Long(value))
269 }
270
271 pub(crate) fn timestamp_nano(value: i64) -> Self {
273 Self::Primitive(PrimitiveLiteral::Long(value))
274 }
275
276 pub(crate) fn timestamptz_nano(value: i64) -> Self {
278 Self::Primitive(PrimitiveLiteral::Long(value))
279 }
280
281 pub fn timestamp_from_datetime<T: TimeZone>(dt: DateTime<T>) -> Self {
283 Self::timestamp(dt.with_timezone(&Utc).timestamp_micros())
284 }
285
286 pub fn timestamptz_from_datetime<T: TimeZone>(dt: DateTime<T>) -> Self {
288 Self::timestamptz(dt.with_timezone(&Utc).timestamp_micros())
289 }
290
291 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 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 pub fn string<S: ToString>(s: S) -> Self {
333 Self::Primitive(PrimitiveLiteral::String(s.to_string()))
334 }
335
336 pub fn uuid(uuid: Uuid) -> Self {
338 Self::Primitive(PrimitiveLiteral::UInt128(uuid.as_u128()))
339 }
340
341 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 pub fn fixed<I: IntoIterator<Item = u8>>(input: I) -> Self {
376 Literal::Primitive(PrimitiveLiteral::Binary(input.into_iter().collect()))
377 }
378
379 pub fn binary<I: IntoIterator<Item = u8>>(input: I) -> Self {
391 Literal::Primitive(PrimitiveLiteral::Binary(input.into_iter().collect()))
392 }
393
394 pub fn decimal(decimal: i128) -> Self {
396 Self::Primitive(PrimitiveLiteral::Int128(decimal))
397 }
398
399 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 pub fn as_primitive_literal(&self) -> Option<PrimitiveLiteral> {
420 match self {
421 Literal::Primitive(primitive) => Some(primitive.clone()),
422 _ => None,
423 }
424 }
425
426 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 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 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}