1use super::{
2 Entry, EntryPath, Type, TypeUnion, ValueObject, ValueRecord, sparse_record::SparseRecord,
3};
4use std::cmp::Ordering;
5
6#[derive(Debug, Default, Clone, PartialEq)]
36pub enum Value {
37 Bool(bool),
39
40 I8(i8),
42
43 I16(i16),
45
46 I32(i32),
48
49 I64(i64),
51
52 U8(u8),
54
55 U16(u16),
57
58 U32(u32),
60
61 U64(u64),
63
64 F32(f32),
66
67 F64(f64),
69
70 SparseRecord(SparseRecord),
72
73 #[default]
75 Null,
76
77 Record(ValueRecord),
79
80 Object(ValueObject),
84
85 List(Vec<Value>),
87
88 String(String),
90
91 Bytes(Vec<u8>),
93
94 Uuid(uuid::Uuid),
96
97 #[cfg(feature = "rust_decimal")]
100 Decimal(rust_decimal::Decimal),
101
102 #[cfg(feature = "bigdecimal")]
105 BigDecimal(bigdecimal::BigDecimal),
106
107 #[cfg(feature = "jiff")]
110 Timestamp(jiff::Timestamp),
111
112 #[cfg(feature = "jiff")]
115 Zoned(jiff::Zoned),
116
117 #[cfg(feature = "jiff")]
120 Date(jiff::civil::Date),
121
122 #[cfg(feature = "jiff")]
125 Time(jiff::civil::Time),
126
127 #[cfg(feature = "jiff")]
130 DateTime(jiff::civil::DateTime),
131
132 #[cfg(feature = "net")]
134 Cidr(cidr::IpCidr),
135
136 #[cfg(feature = "net")]
138 Inet(cidr::IpInet),
139
140 #[cfg(feature = "net")]
142 MacAddr(macaddr::MacAddr6),
143
144 #[cfg(feature = "net")]
146 MacAddr8(macaddr::MacAddr8),
147}
148
149impl Value {
150 pub const fn null() -> Self {
160 Self::Null
161 }
162
163 pub fn checked_add(&self, other: &Self) -> Option<Self> {
167 match (self, other) {
168 (Self::I8(a), Self::I8(b)) => a.checked_add(*b).map(Self::I8),
169 (Self::I16(a), Self::I16(b)) => a.checked_add(*b).map(Self::I16),
170 (Self::I32(a), Self::I32(b)) => a.checked_add(*b).map(Self::I32),
171 (Self::I64(a), Self::I64(b)) => a.checked_add(*b).map(Self::I64),
172 (Self::U8(a), Self::U8(b)) => a.checked_add(*b).map(Self::U8),
173 (Self::U16(a), Self::U16(b)) => a.checked_add(*b).map(Self::U16),
174 (Self::U32(a), Self::U32(b)) => a.checked_add(*b).map(Self::U32),
175 (Self::U64(a), Self::U64(b)) => a.checked_add(*b).map(Self::U64),
176 (Self::F32(a), Self::F32(b)) => Some(Self::F32(a + b)),
177 (Self::F64(a), Self::F64(b)) => Some(Self::F64(a + b)),
178 _ => None,
179 }
180 }
181
182 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
187 match (self, other) {
188 (Self::I8(a), Self::I8(b)) => a.checked_sub(*b).map(Self::I8),
189 (Self::I16(a), Self::I16(b)) => a.checked_sub(*b).map(Self::I16),
190 (Self::I32(a), Self::I32(b)) => a.checked_sub(*b).map(Self::I32),
191 (Self::I64(a), Self::I64(b)) => a.checked_sub(*b).map(Self::I64),
192 (Self::U8(a), Self::U8(b)) => a.checked_sub(*b).map(Self::U8),
193 (Self::U16(a), Self::U16(b)) => a.checked_sub(*b).map(Self::U16),
194 (Self::U32(a), Self::U32(b)) => a.checked_sub(*b).map(Self::U32),
195 (Self::U64(a), Self::U64(b)) => a.checked_sub(*b).map(Self::U64),
196 (Self::F32(a), Self::F32(b)) => Some(Self::F32(a - b)),
197 (Self::F64(a), Self::F64(b)) => Some(Self::F64(a - b)),
198 _ => None,
199 }
200 }
201
202 pub const fn is_null(&self) -> bool {
212 matches!(self, Self::Null)
213 }
214
215 pub const fn is_record(&self) -> bool {
217 matches!(self, Self::Record(_))
218 }
219
220 pub fn record_from_vec(fields: Vec<Self>) -> Self {
230 ValueRecord::from_vec(fields).into()
231 }
232
233 pub const fn from_bool(src: bool) -> Self {
243 Self::Bool(src)
244 }
245
246 pub fn as_str(&self) -> Option<&str> {
249 match self {
250 Self::String(v) => Some(&**v),
251 _ => None,
252 }
253 }
254
255 pub fn as_string_unwrap(&self) -> &str {
262 match self {
263 Self::String(v) => v,
264 _ => todo!(),
265 }
266 }
267
268 pub fn as_record(&self) -> Option<&ValueRecord> {
271 match self {
272 Self::Record(record) => Some(record),
273 _ => None,
274 }
275 }
276
277 pub fn as_record_unwrap(&self) -> &ValueRecord {
284 match self {
285 Self::Record(record) => record,
286 _ => panic!("{self:#?}"),
287 }
288 }
289
290 pub fn as_record_mut_unwrap(&mut self) -> &mut ValueRecord {
297 match self {
298 Self::Record(record) => record,
299 _ => panic!(),
300 }
301 }
302
303 pub fn into_record(self) -> ValueRecord {
310 match self {
311 Self::Record(record) => record,
312 _ => panic!(),
313 }
314 }
315
316 pub fn is_a(&self, resolve: &impl super::Resolve, ty: &Type) -> bool {
325 if let Type::Union(types) = ty {
326 return types.iter().any(|t| self.is_a(resolve, t));
327 }
328 match self {
329 Self::Null => true,
330 Self::Bool(_) => ty.is_bool(),
331 Self::I8(_) => ty.is_i8(),
332 Self::I16(_) => ty.is_i16(),
333 Self::I32(_) => ty.is_i32(),
334 Self::I64(_) => ty.is_i64(),
335 Self::U8(_) => ty.is_u8(),
336 Self::U16(_) => ty.is_u16(),
337 Self::U32(_) => ty.is_u32(),
338 Self::U64(_) => ty.is_u64(),
339 Self::F32(_) => ty.is_f32(),
340 Self::F64(_) => ty.is_f64(),
341 Self::List(value) => match ty {
342 Type::List(ty) => {
343 if value.is_empty() {
344 true
345 } else {
346 value[0].is_a(resolve, ty)
347 }
348 }
349 _ => false,
350 },
351 Self::Record(value) => match ty {
352 Type::Record(field_tys) if value.len() == field_tys.len() => {
353 Self::fields_match(resolve, &value.fields, field_tys.iter())
354 }
355 Type::Model(id) => match resolve.model(*id) {
360 Some(model) => {
361 let fields = model.fields();
362 value.len() == fields.len()
363 && Self::fields_match(
364 resolve,
365 &value.fields,
366 fields.iter().map(|field| field.expr_ty()),
367 )
368 }
369 None => true,
370 },
371 _ => false,
372 },
373 Self::Object(object) => match ty {
381 Type::Object => true,
382 Type::Model(id) => match resolve.model(*id) {
383 Some(model) => model.fields().iter().all(|field| {
384 let name = field.name().app_unwrap();
385 object
386 .iter()
387 .find(|(key, _)| key == name)
388 .is_none_or(|(_, v)| v.is_a(resolve, field.expr_ty()))
389 }),
390 None => true,
391 },
392 _ => false,
393 },
394 Self::SparseRecord(value) => match ty {
395 Type::SparseRecord(fields) => value.fields == *fields,
396 _ => false,
397 },
398 Self::String(_) => ty.is_string(),
399 Self::Bytes(_) => ty.is_bytes(),
400 Self::Uuid(_) => ty.is_uuid(),
401 #[cfg(feature = "rust_decimal")]
402 Value::Decimal(_) => *ty == Type::Decimal,
403 #[cfg(feature = "bigdecimal")]
404 Value::BigDecimal(_) => *ty == Type::BigDecimal,
405 #[cfg(feature = "jiff")]
406 Value::Timestamp(_) => *ty == Type::Timestamp,
407 #[cfg(feature = "jiff")]
408 Value::Zoned(_) => *ty == Type::Zoned,
409 #[cfg(feature = "jiff")]
410 Value::Date(_) => *ty == Type::Date,
411 #[cfg(feature = "jiff")]
412 Value::Time(_) => *ty == Type::Time,
413 #[cfg(feature = "jiff")]
414 Value::DateTime(_) => *ty == Type::DateTime,
415 #[cfg(feature = "net")]
416 Value::Cidr(_) => *ty == Type::Cidr,
417 #[cfg(feature = "net")]
418 Value::Inet(_) => *ty == Type::Inet,
419 #[cfg(feature = "net")]
420 Value::MacAddr(_) => *ty == Type::MacAddr,
421 #[cfg(feature = "net")]
422 Value::MacAddr8(_) => *ty == Type::MacAddr8,
423 }
424 }
425
426 fn fields_match<'a>(
429 resolve: &impl super::Resolve,
430 values: &[Value],
431 tys: impl Iterator<Item = &'a Type>,
432 ) -> bool {
433 values
434 .iter()
435 .zip(tys)
436 .all(|(value, ty)| value.is_a(resolve, ty))
437 }
438
439 pub fn infer_ty(&self) -> Type {
450 match self {
451 Value::Bool(_) => Type::Bool,
452 Value::I8(_) => Type::I8,
453 Value::I16(_) => Type::I16,
454 Value::I32(_) => Type::I32,
455 Value::I64(_) => Type::I64,
456 Value::SparseRecord(v) => Type::SparseRecord(v.fields.clone()),
457 Value::Null => Type::Null,
458 Value::Record(v) => Type::Record(v.fields.iter().map(Self::infer_ty).collect()),
459 Value::Object(v) => Type::Record(
462 v.entries
463 .iter()
464 .map(|(_, value)| value.infer_ty())
465 .collect(),
466 ),
467 Value::String(_) => Type::String,
468 Value::List(items) if items.is_empty() => Type::list(Type::Null),
469 Value::List(items) => {
470 let mut union = TypeUnion::new();
471 for item in items {
472 union.insert(item.infer_ty());
473 }
474 Type::list(union.simplify())
475 }
476 Value::U8(_) => Type::U8,
477 Value::U16(_) => Type::U16,
478 Value::U32(_) => Type::U32,
479 Value::U64(_) => Type::U64,
480 Value::F32(_) => Type::F32,
481 Value::F64(_) => Type::F64,
482 Value::Bytes(_) => Type::Bytes,
483 Value::Uuid(_) => Type::Uuid,
484 #[cfg(feature = "rust_decimal")]
485 Value::Decimal(_) => Type::Decimal,
486 #[cfg(feature = "bigdecimal")]
487 Value::BigDecimal(_) => Type::BigDecimal,
488 #[cfg(feature = "jiff")]
489 Value::Timestamp(_) => Type::Timestamp,
490 #[cfg(feature = "jiff")]
491 Value::Zoned(_) => Type::Zoned,
492 #[cfg(feature = "jiff")]
493 Value::Date(_) => Type::Date,
494 #[cfg(feature = "jiff")]
495 Value::Time(_) => Type::Time,
496 #[cfg(feature = "jiff")]
497 Value::DateTime(_) => Type::DateTime,
498 #[cfg(feature = "net")]
499 Value::Cidr(_) => Type::Cidr,
500 #[cfg(feature = "net")]
501 Value::Inet(_) => Type::Inet,
502 #[cfg(feature = "net")]
503 Value::MacAddr(_) => Type::MacAddr,
504 #[cfg(feature = "net")]
505 Value::MacAddr8(_) => Type::MacAddr8,
506 }
507 }
508
509 pub fn infer_db_ty(
547 &self,
548 storage: &crate::driver::StorageTypes,
549 ) -> crate::Result<crate::schema::db::Type> {
550 use crate::schema::db::Type as DbType;
551
552 let cannot_infer = || {
553 crate::Error::unsupported_feature(format!(
554 "cannot infer a database storage type for {:?}",
555 self.infer_ty()
556 ))
557 };
558
559 Ok(match self {
560 Value::Bool(_) => DbType::Boolean,
561 Value::I8(_) => DbType::Integer(1),
562 Value::I16(_) => DbType::Integer(2),
563 Value::I32(_) => DbType::Integer(4),
564 Value::I64(_) => DbType::Integer(8),
565 Value::U8(_) => DbType::UnsignedInteger(1),
566 Value::U16(_) => DbType::UnsignedInteger(2),
567 Value::U32(_) => DbType::UnsignedInteger(4),
568 Value::U64(_) => DbType::UnsignedInteger(8),
569 Value::F32(_) => DbType::Float(4),
570 Value::F64(_) => DbType::Float(8),
571 Value::String(_) => storage.default_string_type.clone(),
572 Value::Uuid(_) => storage.default_uuid_type.clone(),
573 Value::Bytes(_) => storage.default_bytes_type.clone(),
574 #[cfg(feature = "rust_decimal")]
575 Value::Decimal(_) => storage.default_decimal_type.clone(),
576 #[cfg(feature = "bigdecimal")]
577 Value::BigDecimal(_) => storage.default_bigdecimal_type.clone(),
578 #[cfg(feature = "jiff")]
579 Value::Timestamp(_) => storage.default_timestamp_type.clone(),
580 #[cfg(feature = "jiff")]
581 Value::Zoned(_) => storage.default_zoned_type.clone(),
582 #[cfg(feature = "jiff")]
583 Value::Date(_) => storage.default_date_type.clone(),
584 #[cfg(feature = "jiff")]
585 Value::Time(_) => storage.default_time_type.clone(),
586 #[cfg(feature = "jiff")]
587 Value::DateTime(_) => storage.default_datetime_type.clone(),
588 #[cfg(feature = "net")]
589 Value::Cidr(_) => storage.default_cidr_type.clone(),
590 #[cfg(feature = "net")]
591 Value::Inet(_) => storage.default_inet_type.clone(),
592 #[cfg(feature = "net")]
593 Value::MacAddr(_) => storage.default_macaddr_type.clone(),
594 #[cfg(feature = "net")]
595 Value::MacAddr8(_) => storage.default_macaddr8_type.clone(),
596 Value::List(_) => DbType::from_app(&self.infer_ty(), None, storage)
605 .map_err(|err| err.context(cannot_infer()))?,
606 Value::Null | Value::Record(_) | Value::Object(_) | Value::SparseRecord(_) => {
607 return Err(cannot_infer());
608 }
609 })
610 }
611
612 #[track_caller]
622 pub fn entry(&self, path: impl EntryPath) -> Entry<'_> {
623 let mut value = self;
624
625 for step in path.step_iter() {
626 value = match value {
627 Self::Record(record) => &record[step],
628 Self::List(items) => &items[step],
629 Self::Null => return Entry::Value(value),
633 _ => todo!("base={self:#?}; step={step:#?}"),
634 };
635 }
636
637 Entry::Value(value)
638 }
639
640 pub fn take(&mut self) -> Self {
652 std::mem::take(self)
653 }
654}
655
656impl AsRef<Self> for Value {
657 fn as_ref(&self) -> &Self {
658 self
659 }
660}
661
662impl PartialOrd for Value {
663 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
671 match (self, other) {
672 (Value::Null, _) | (_, Value::Null) => None,
674
675 (Value::Bool(a), Value::Bool(b)) => a.partial_cmp(b),
677
678 (Value::I8(a), Value::I8(b)) => a.partial_cmp(b),
680 (Value::I16(a), Value::I16(b)) => a.partial_cmp(b),
681 (Value::I32(a), Value::I32(b)) => a.partial_cmp(b),
682 (Value::I64(a), Value::I64(b)) => a.partial_cmp(b),
683
684 (Value::U8(a), Value::U8(b)) => a.partial_cmp(b),
686 (Value::U16(a), Value::U16(b)) => a.partial_cmp(b),
687 (Value::U32(a), Value::U32(b)) => a.partial_cmp(b),
688 (Value::U64(a), Value::U64(b)) => a.partial_cmp(b),
689
690 (Value::F32(a), Value::F32(b)) => a.partial_cmp(b),
692 (Value::F64(a), Value::F64(b)) => a.partial_cmp(b),
693
694 (Value::String(a), Value::String(b)) => a.partial_cmp(b),
696
697 (Value::Bytes(a), Value::Bytes(b)) => a.partial_cmp(b),
699
700 (Value::Uuid(a), Value::Uuid(b)) => a.partial_cmp(b),
702
703 #[cfg(feature = "rust_decimal")]
705 (Value::Decimal(a), Value::Decimal(b)) => a.partial_cmp(b),
706
707 #[cfg(feature = "bigdecimal")]
709 (Value::BigDecimal(a), Value::BigDecimal(b)) => a.partial_cmp(b),
710
711 #[cfg(feature = "jiff")]
713 (Value::Timestamp(a), Value::Timestamp(b)) => a.partial_cmp(b),
714 #[cfg(feature = "jiff")]
715 (Value::Zoned(a), Value::Zoned(b)) => a.partial_cmp(b),
716 #[cfg(feature = "jiff")]
717 (Value::Date(a), Value::Date(b)) => a.partial_cmp(b),
718 #[cfg(feature = "jiff")]
719 (Value::Time(a), Value::Time(b)) => a.partial_cmp(b),
720 #[cfg(feature = "jiff")]
721 (Value::DateTime(a), Value::DateTime(b)) => a.partial_cmp(b),
722
723 #[cfg(feature = "net")]
725 (Value::Cidr(a), Value::Cidr(b)) => a.partial_cmp(b),
726 #[cfg(feature = "net")]
727 (Value::Inet(a), Value::Inet(b)) => a.partial_cmp(b),
728 #[cfg(feature = "net")]
729 (Value::MacAddr(a), Value::MacAddr(b)) => a.partial_cmp(b),
730 #[cfg(feature = "net")]
731 (Value::MacAddr8(a), Value::MacAddr8(b)) => a.partial_cmp(b),
732
733 _ => None,
735 }
736 }
737}
738
739impl From<bool> for Value {
740 fn from(src: bool) -> Self {
741 Self::Bool(src)
742 }
743}
744
745impl TryFrom<Value> for bool {
746 type Error = crate::Error;
747
748 fn try_from(value: Value) -> Result<Self, Self::Error> {
749 match value {
750 Value::Bool(v) => Ok(v),
751 _ => Err(crate::Error::type_conversion(value, "bool")),
752 }
753 }
754}
755
756impl From<String> for Value {
757 fn from(src: String) -> Self {
758 Self::String(src)
759 }
760}
761
762impl From<&String> for Value {
763 fn from(src: &String) -> Self {
764 Self::String(src.clone())
765 }
766}
767
768impl From<&str> for Value {
769 fn from(src: &str) -> Self {
770 Self::String(src.to_string())
771 }
772}
773
774impl From<ValueRecord> for Value {
775 fn from(value: ValueRecord) -> Self {
776 Self::Record(value)
777 }
778}
779
780impl<T> From<Option<T>> for Value
781where
782 Self: From<T>,
783{
784 fn from(value: Option<T>) -> Self {
785 match value {
786 Some(value) => Self::from(value),
787 None => Self::Null,
788 }
789 }
790}
791
792impl TryFrom<Value> for String {
793 type Error = crate::Error;
794
795 fn try_from(value: Value) -> Result<Self, Self::Error> {
796 match value {
797 Value::String(v) => Ok(v),
798 _ => Err(crate::Error::type_conversion(value, "String")),
799 }
800 }
801}
802
803impl From<Vec<u8>> for Value {
804 fn from(value: Vec<u8>) -> Self {
805 Self::Bytes(value)
806 }
807}
808
809impl TryFrom<Value> for Vec<u8> {
810 type Error = crate::Error;
811
812 fn try_from(value: Value) -> Result<Self, Self::Error> {
813 match value {
814 Value::Bytes(v) => Ok(v),
815 _ => Err(crate::Error::type_conversion(value, "Bytes")),
816 }
817 }
818}
819
820impl From<uuid::Uuid> for Value {
821 fn from(value: uuid::Uuid) -> Self {
822 Self::Uuid(value)
823 }
824}
825
826impl TryFrom<Value> for uuid::Uuid {
827 type Error = crate::Error;
828
829 fn try_from(value: Value) -> Result<Self, Self::Error> {
830 match value {
831 Value::Uuid(v) => Ok(v),
832 _ => Err(crate::Error::type_conversion(value, "uuid::Uuid")),
833 }
834 }
835}
836
837#[cfg(feature = "rust_decimal")]
838impl From<rust_decimal::Decimal> for Value {
839 fn from(value: rust_decimal::Decimal) -> Self {
840 Self::Decimal(value)
841 }
842}
843
844#[cfg(feature = "rust_decimal")]
845impl TryFrom<Value> for rust_decimal::Decimal {
846 type Error = crate::Error;
847
848 fn try_from(value: Value) -> Result<Self, Self::Error> {
849 match value {
850 Value::Decimal(v) => Ok(v),
851 _ => Err(crate::Error::type_conversion(
852 value,
853 "rust_decimal::Decimal",
854 )),
855 }
856 }
857}
858
859#[cfg(feature = "bigdecimal")]
860impl From<bigdecimal::BigDecimal> for Value {
861 fn from(value: bigdecimal::BigDecimal) -> Self {
862 Self::BigDecimal(value)
863 }
864}
865
866#[cfg(feature = "bigdecimal")]
867impl TryFrom<Value> for bigdecimal::BigDecimal {
868 type Error = crate::Error;
869
870 fn try_from(value: Value) -> Result<Self, Self::Error> {
871 match value {
872 Value::BigDecimal(v) => Ok(v),
873 _ => Err(crate::Error::type_conversion(
874 value,
875 "bigdecimal::BigDecimal",
876 )),
877 }
878 }
879}