1use std::fmt;
2use std::ops::Bound;
3use std::str::FromStr as _;
4
5use common::decimal::DecimalExt;
6use geo::Point;
7use rust_decimal::Decimal;
8use surrealdb_cnf::GENERATION_ALLOCATION_LIMIT;
9use surrealdb_types::ToSql;
10
11use super::coerce::ElementPosition;
12use crate::expr::Kind;
13use crate::expr::kind::{GeometryKind, HasKind, KindLiteral};
14use crate::syn;
15use crate::val::range::IntegerRangeExt;
16use crate::val::{
17 Array, Bytes, Closure, Datetime, Duration, File, Geometry, Null, Number, Object, Range,
18 RecordId, Regex, Set, SqlNone, TableName, Uuid, Value,
19};
20
21#[derive(Clone, Debug)]
22pub enum CastError {
23 InvalidKind {
25 from: Value,
26 into: String,
27 },
28 InvalidLength {
29 len: usize,
30 into: String,
31 },
32 ElementOf {
34 inner: Box<CastError>,
35 into: String,
36 position: Option<ElementPosition>,
37 },
38 RangeSizeLimit {
43 value: Box<Range>,
44 },
45}
46impl std::error::Error for CastError {}
47impl fmt::Display for CastError {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self {
50 CastError::InvalidKind {
51 from,
52 into,
53 } => {
54 write!(f, "Could not cast into `{into}` using input `{from}`", from = from.to_sql())
55 }
56 CastError::ElementOf {
57 inner,
58 into,
59 position,
60 } => {
61 inner.fmt(f)?;
62 match position {
63 Some(ElementPosition::Index(i)) => {
64 write!(f, " when casting element at index {i} of `{into}`")
65 }
66 Some(ElementPosition::Key(k)) => {
67 write!(f, " when casting value for key '{k}' of `{into}`")
68 }
69 None => write!(f, " when casting an element of `{into}`"),
70 }
71 }
72 CastError::InvalidLength {
73 len,
74 into,
75 } => {
76 write!(f, "Expected `{into}` but found a collection of length `{len}`")
77 }
78 CastError::RangeSizeLimit {
79 value,
80 } => {
81 write!(
82 f,
83 "Casting range `{value}` to an array would create an array larger then the max allocation limit.",
84 value = value.to_sql()
85 )
86 }
87 }
88 }
89}
90
91pub trait CastErrorExt {
92 fn with_element_of_at_index<F>(self, index: usize, f: F) -> Self
93 where
94 F: Fn() -> String;
95}
96
97impl<T> CastErrorExt for Result<T, CastError> {
98 fn with_element_of_at_index<F>(self, index: usize, f: F) -> Self
99 where
100 F: Fn() -> String,
101 {
102 match self {
103 Ok(x) => Ok(x),
104 Err(e) => Err(CastError::ElementOf {
105 inner: Box::new(e),
106 into: f(),
107 position: Some(ElementPosition::Index(index)),
108 }),
109 }
110 }
111}
112
113pub trait Cast: Sized {
119 fn can_cast(v: &Value) -> bool;
124
125 fn cast(v: Value) -> Result<Self, CastError>;
127}
128
129impl Cast for Value {
130 fn can_cast(_: &Value) -> bool {
131 true
132 }
133
134 fn cast(v: Value) -> Result<Self, CastError> {
135 Ok(v)
136 }
137}
138
139impl Cast for SqlNone {
140 fn can_cast(v: &Value) -> bool {
141 matches!(v, Value::None)
142 }
143
144 fn cast(v: Value) -> Result<Self, CastError> {
145 match v {
146 Value::None => Ok(SqlNone),
147 x => Err(CastError::InvalidKind {
148 from: x,
149 into: "none".to_string(),
150 }),
151 }
152 }
153}
154
155impl Cast for Null {
156 fn can_cast(v: &Value) -> bool {
157 matches!(v, Value::Null)
158 }
159
160 fn cast(v: Value) -> Result<Self, CastError> {
161 match v {
162 Value::Null => Ok(Null),
163 x => Err(CastError::InvalidKind {
164 from: x,
165 into: "null".to_string(),
166 }),
167 }
168 }
169}
170
171impl Cast for bool {
172 fn can_cast(v: &Value) -> bool {
173 match v {
174 Value::Bool(_) => true,
175 Value::String(x) => matches!(x.as_str(), "true" | "false"),
176 _ => false,
177 }
178 }
179
180 fn cast(v: Value) -> Result<Self, CastError> {
181 match v {
182 Value::Bool(b) => Ok(b),
183 Value::String(x) => match x.as_str() {
184 "true" => Ok(true),
185 "false" => Ok(false),
186 _ => Err(CastError::InvalidKind {
187 from: Value::String(x),
188 into: "bool".to_string(),
189 }),
190 },
191 x => Err(CastError::InvalidKind {
192 from: x,
193 into: "bool".to_string(),
194 }),
195 }
196 }
197}
198
199impl Cast for i64 {
200 fn can_cast(v: &Value) -> bool {
203 match v {
204 Value::Number(n) => n.as_int_lossless().is_some(),
205 Value::String(v) => v.parse::<i64>().is_ok(),
206 _ => false,
207 }
208 }
209
210 fn cast(v: Value) -> Result<Self, CastError> {
211 match v {
212 Value::Number(Number::Int(x)) => Ok(x),
214 Value::Number(n) => n.as_int_lossless().ok_or_else(|| CastError::InvalidKind {
218 from: v,
219 into: "int".into(),
220 }),
221 Value::String(ref s) => match s.parse::<i64>() {
223 Ok(v) => Ok(v),
224 _ => Err(CastError::InvalidKind {
225 from: v,
226 into: "int".into(),
227 }),
228 },
229 _ => Err(CastError::InvalidKind {
230 from: v,
231 into: "int".into(),
232 }),
233 }
234 }
235}
236
237impl Cast for f64 {
238 fn can_cast(v: &Value) -> bool {
239 match v {
240 Value::Number(Number::Int(_) | Number::Float(_)) => true,
241 Value::Number(Number::Decimal(v)) => v.is_integer() || i64::try_from(*v).is_ok(),
242 Value::String(v) => v.parse::<f64>().is_ok(),
243 _ => false,
244 }
245 }
246
247 fn cast(v: Value) -> Result<Self, CastError> {
248 match v {
249 Value::Number(Number::Float(i)) => Ok(i),
250 Value::Number(Number::Int(f)) => Ok(f as f64),
251 Value::Number(Number::Decimal(d)) => match d.try_into() {
252 Ok(v) => Ok(v),
254 _ => Err(CastError::InvalidKind {
256 from: v,
257 into: "float".into(),
258 }),
259 },
260 Value::String(ref s) => match s.parse::<f64>() {
262 Ok(v) => Ok(v),
264 _ => Err(CastError::InvalidKind {
266 from: v,
267 into: "float".into(),
268 }),
269 },
270 _ => Err(CastError::InvalidKind {
272 from: v,
273 into: "float".into(),
274 }),
275 }
276 }
277}
278
279impl Cast for Decimal {
280 fn can_cast(v: &Value) -> bool {
281 match v {
282 Value::Number(_) => true,
283 Value::String(v) => v.parse::<f64>().is_ok(),
284 _ => false,
285 }
286 }
287
288 fn cast(v: Value) -> Result<Self, CastError> {
289 match v {
290 Value::Number(Number::Decimal(d)) => Ok(d),
291 Value::Number(Number::Int(ref i)) => Ok(Decimal::from(*i)),
293 Value::Number(Number::Float(ref f)) => match Decimal::try_from(*f) {
295 Ok(d) => Ok(d),
297 _ => Err(CastError::InvalidKind {
299 from: v,
300 into: "decimal".into(),
301 }),
302 },
303 Value::String(ref s) => match Decimal::from_str_normalized(s) {
305 Ok(v) => Ok(v),
307 _ => Err(CastError::InvalidKind {
309 from: v,
310 into: "decimal".into(),
311 }),
312 },
313 _ => Err(CastError::InvalidKind {
315 from: v,
316 into: "decimal".into(),
317 }),
318 }
319 }
320}
321
322impl Cast for Number {
323 fn can_cast(v: &Value) -> bool {
324 match v {
325 Value::Number(_) => true,
326 Value::String(s) => Number::from_str(s).is_ok(),
327 _ => false,
328 }
329 }
330
331 fn cast(v: Value) -> Result<Self, CastError> {
332 match v {
333 Value::Number(v) => Ok(v),
334 Value::String(ref s) => Number::from_str(s).map_err(|_| CastError::InvalidKind {
335 from: v,
336 into: "number".into(),
337 }),
338 _ => Err(CastError::InvalidKind {
340 from: v,
341 into: "number".into(),
342 }),
343 }
344 }
345}
346
347impl Cast for String {
348 fn can_cast(v: &Value) -> bool {
349 match v {
350 Value::None | Value::Null => false,
351 Value::Bytes(b) => std::str::from_utf8(b).is_ok(),
352 _ => true,
353 }
354 }
355
356 fn cast(v: Value) -> Result<Self, CastError> {
357 match v {
358 Value::Bytes(b) => match String::from_utf8(b.0.to_vec()) {
359 Ok(x) => Ok(x),
360 Err(e) => Err(CastError::InvalidKind {
361 from: Value::Bytes(Bytes::from(e.into_bytes())),
362 into: "string".to_owned(),
363 }),
364 },
365
366 Value::Null => Ok("NULL".into()),
367 Value::None => Ok("NONE".into()),
368 Value::String(x) => Ok(x.into_string()),
369 Value::Uuid(x) => Ok(x.to_string()),
370 Value::Datetime(x) => Ok(x.to_string()),
371 Value::Number(Number::Decimal(x)) => Ok(x.to_string()),
372 x => Ok(x.to_sql()),
373 }
374 }
375}
376
377impl Cast for Uuid {
378 fn can_cast(v: &Value) -> bool {
379 match v {
380 Value::Uuid(_) => true,
381 Value::String(s) => Uuid::from_str(s).is_ok(),
382 _ => false,
383 }
384 }
385
386 fn cast(v: Value) -> Result<Self, CastError> {
387 match v {
388 Value::Uuid(u) => Ok(u),
389 Value::String(ref s) => Uuid::from_str(s).map_err(|_| CastError::InvalidKind {
390 from: v,
391 into: "uuid".into(),
392 }),
393 _ => Err(CastError::InvalidKind {
394 from: v,
395 into: "uuid".into(),
396 }),
397 }
398 }
399}
400
401impl Cast for Datetime {
402 fn can_cast(v: &Value) -> bool {
403 match v {
404 Value::Datetime(_) => true,
405 Value::String(s) => Datetime::from_str(s).is_ok(),
406 _ => false,
407 }
408 }
409
410 fn cast(v: Value) -> Result<Self, CastError> {
411 match v {
412 Value::Datetime(v) => Ok(v),
414 Value::String(ref s) => Datetime::from_str(s).map_err(|_| CastError::InvalidKind {
416 from: v,
417 into: "datetime".into(),
418 }),
419 _ => Err(CastError::InvalidKind {
421 from: v,
422 into: "datetime".into(),
423 }),
424 }
425 }
426}
427
428impl Cast for Duration {
429 fn can_cast(v: &Value) -> bool {
430 match v {
431 Value::Duration(_) => true,
432 Value::String(s) => Duration::from_str(s).is_ok(),
433 _ => false,
434 }
435 }
436
437 fn cast(v: Value) -> Result<Self, CastError> {
438 match v {
439 Value::Duration(v) => Ok(v),
441 Value::String(ref s) => Duration::from_str(s).map_err(|_| CastError::InvalidKind {
443 from: v,
444 into: "duration".into(),
445 }),
446 _ => Err(CastError::InvalidKind {
448 from: v,
449 into: "duration".into(),
450 }),
451 }
452 }
453}
454
455impl Cast for Bytes {
456 fn can_cast(v: &Value) -> bool {
457 match v {
458 Value::Bytes(_) | Value::String(_) => true,
459 Value::Array(x) => x.iter().all(|v| value_to_byte(v).is_some()),
460 _ => false,
461 }
462 }
463
464 fn cast(v: Value) -> Result<Self, CastError> {
465 match v {
466 Value::Bytes(b) => Ok(b),
467 Value::String(s) => Ok(Bytes::from(s.into_string().into_bytes())),
468 Value::Array(x) => match x.0.iter().map(value_to_byte).collect::<Option<Vec<u8>>>() {
469 Some(bytes) => Ok(Bytes::from(bytes)),
470 None => Err(CastError::InvalidKind {
471 from: Value::Array(x),
472 into: "bytes".to_owned(),
473 }),
474 },
475 _ => Err(CastError::InvalidKind {
476 from: v,
477 into: "bytes".into(),
478 }),
479 }
480 }
481}
482
483fn value_to_byte(v: &Value) -> Option<u8> {
487 match v {
488 Value::Number(Number::Int(x)) => u8::try_from(*x).ok(),
489 Value::Number(Number::Float(f)) if f.fract() == 0.0 => u8::try_from(*f as i64).ok(),
490 Value::Number(Number::Decimal(d)) if d.is_integer() => {
491 u8::try_from(i64::try_from(*d).ok()?).ok()
492 }
493 Value::String(s) => s.parse::<u8>().ok(),
494 _ => None,
495 }
496}
497
498impl Cast for Array {
499 fn can_cast(v: &Value) -> bool {
500 match v {
501 Value::Array(_) | Value::Bytes(_) | Value::Set(_) => true,
502 Value::Range(r) => r.can_coerce_to_typed::<i64>(),
503 _ => false,
504 }
505 }
506
507 fn cast(v: Value) -> Result<Self, CastError> {
508 match v {
509 Value::Array(x) => Ok(x),
510 Value::Set(s) => Ok(s.into_iter().collect()),
511 Value::Range(range) => {
512 if !range.can_coerce_to_typed::<i64>() {
513 return Err(CastError::InvalidKind {
514 from: Value::Range(range),
515 into: "array".to_string(),
516 });
517 }
518 let range = range.coerce_to_typed::<i64>().expect("range type checked above");
520 if range.len().is_none_or(|n| n > *GENERATION_ALLOCATION_LIMIT) {
521 return Err(CastError::RangeSizeLimit {
522 value: Box::new(Range::from(range)),
523 });
524 }
525
526 Ok(range.cast_to_array())
527 }
528
529 Value::Bytes(x) => Ok(Array(x.0.into_iter().map(|x| Value::from(x as i64)).collect())),
530 _ => Err(CastError::InvalidKind {
531 from: v,
532 into: "array".into(),
533 }),
534 }
535 }
536}
537
538impl Cast for Set {
539 fn can_cast(v: &Value) -> bool {
540 matches!(v, Value::Set(_) | Value::Array(_))
541 }
542
543 fn cast(v: Value) -> Result<Self, CastError> {
544 match v {
545 Value::Set(x) => Ok(x),
546 Value::Array(x) => {
547 Ok(Set::from(x.0))
549 }
550 _ => Err(CastError::InvalidKind {
551 from: v,
552 into: "set".into(),
553 }),
554 }
555 }
556}
557
558impl Cast for Regex {
559 fn can_cast(v: &Value) -> bool {
560 match v {
561 Value::Regex(_) => true,
562 Value::String(x) => Regex::from_str(x).is_ok(),
563 _ => false,
564 }
565 }
566
567 fn cast(v: Value) -> Result<Self, CastError> {
568 match v {
569 Value::Regex(x) => Ok(x),
570 Value::String(x) => match Regex::from_str(&x) {
571 Ok(x) => Ok(x),
572 Err(_) => Err(CastError::InvalidKind {
573 from: Value::String(x),
574 into: "regex".to_string(),
575 }),
576 },
577 x => Err(CastError::InvalidKind {
578 from: x,
579 into: "regex".to_string(),
580 }),
581 }
582 }
583}
584
585impl Cast for Box<Range> {
586 fn can_cast(v: &Value) -> bool {
587 match v {
588 Value::Range(_) => true,
589 Value::Array(x) => x.len() == 2,
590 _ => false,
591 }
592 }
593
594 fn cast(v: Value) -> Result<Self, CastError> {
595 match v {
596 Value::Range(x) => Ok(x),
597 Value::Array(x) => {
598 if x.len() != 2 {
599 return Err(CastError::InvalidKind {
600 from: Value::Array(x),
601 into: "range".to_string(),
602 });
603 }
604
605 let mut iter = x.into_iter();
606 let beg = iter.next().expect("array length checked above");
608 let end = iter.next().expect("array length checked above");
610
611 Ok(Box::new(Range {
612 start: Bound::Included(beg),
613 end: Bound::Excluded(end),
614 }))
615 }
616 _ => Err(CastError::InvalidKind {
617 from: v,
618 into: "range".into(),
619 }),
620 }
621 }
622}
623
624impl Cast for Point<f64> {
625 fn can_cast(v: &Value) -> bool {
626 match v {
627 Value::Geometry(Geometry::Point(_)) => true,
628 Value::Array(x) => x.len() == 2,
629 _ => false,
630 }
631 }
632
633 fn cast(v: Value) -> Result<Self, CastError> {
634 match v {
635 Value::Geometry(Geometry::Point(v)) => Ok(v),
636 Value::Array(x) => {
637 if x.len() != 2 {
638 return Err(CastError::InvalidKind {
639 from: Value::Array(x),
640 into: "point".to_string(),
641 });
642 }
643
644 if !x[0].can_coerce_to::<f64>() || !x[1].can_coerce_to::<f64>() {
645 return Err(CastError::InvalidKind {
646 from: Value::Array(x),
647 into: "point".to_string(),
648 });
649 }
650
651 let mut iter = x.into_iter();
652 let x = iter
654 .next()
655 .expect("array length checked above")
656 .cast_to::<f64>()
657 .expect("value type checked above");
658 let y = iter
660 .next()
661 .expect("array length checked above")
662 .cast_to::<f64>()
663 .expect("value type checked above");
664
665 Ok(Point::new(x, y))
666 }
667 _ => Err(CastError::InvalidKind {
668 from: v,
669 into: "point".into(),
670 }),
671 }
672 }
673}
674
675impl Cast for RecordId {
676 fn can_cast(v: &Value) -> bool {
677 match v {
678 Value::RecordId(_) => true,
679 Value::String(x) => syn::record_id(x).is_ok(),
680 _ => false,
681 }
682 }
683
684 fn cast(v: Value) -> Result<Self, CastError> {
685 match v {
686 Value::RecordId(x) => Ok(x),
687 Value::String(x) => match syn::record_id(&x) {
688 Ok(x) => Ok(x.into()),
689 Err(_) => Err(CastError::InvalidKind {
690 from: Value::String(x),
691 into: "record".to_string(),
692 }),
693 },
694 from => Err(CastError::InvalidKind {
695 from,
696 into: "record".to_string(),
697 }),
698 }
699 }
700}
701
702impl Cast for surrealdb_strand::TableName {
703 fn can_cast(v: &Value) -> bool {
704 matches!(v, Value::Table(_) | Value::String(_))
705 }
706
707 fn cast(v: Value) -> Result<Self, CastError> {
708 match v {
709 Value::Table(x) => Ok(x),
710 Value::String(x) => Ok(surrealdb_strand::TableName::new(x)),
711 from => Err(CastError::InvalidKind {
712 from,
713 into: "table".to_string(),
714 }),
715 }
716 }
717}
718
719impl<T: Cast> Cast for Option<T> {
720 fn can_cast(v: &Value) -> bool {
721 if let Value::None = v {
722 return true;
723 }
724 T::can_cast(v)
725 }
726
727 fn cast(v: Value) -> Result<Self, CastError> {
728 match v {
729 Value::None => Ok(None),
730 x => T::cast(x).map(Some),
731 }
732 }
733}
734
735macro_rules! impl_direct {
736 ($($name:ident => $inner:ty $(= $kind:ident)?),*$(,)?) => {
737 $(
738 impl Cast for $inner {
739 fn can_cast(v: &Value) -> bool{
740 matches!(v, Value::$name(_))
741 }
742
743 fn cast(v: Value) -> Result<Self, CastError> {
744 if let Value::$name(x) = v {
745 return Ok(x);
746 } else {
747 return Err(CastError::InvalidKind{
748 from: v,
749 into: impl_direct!(@kindof $inner $(= $kind)?),
750 });
751 }
752 }
753 }
754 )*
755 };
756
757 (@kindof $inner:ty = $kind:ident) => {
758 <$kind as HasKind>::kind().to_sql()
759 };
760
761 (@kindof $inner:ty) => {
762 <$inner as HasKind>::kind().to_sql()
763 };
764}
765
766impl_direct! {
768 Closure => Box<Closure> = Closure,
769 Object => Object,
770 Geometry => Geometry,
771 File => File,
772}
773
774impl Value {
775 pub fn can_cast_to<T: Cast>(&self) -> bool {
776 T::can_cast(self)
777 }
778
779 pub fn can_cast_to_kind(&self, kind: &Kind) -> bool {
780 match kind {
781 Kind::Any => true,
782 Kind::None => self.can_cast_to::<SqlNone>(),
783 Kind::Null => self.can_cast_to::<Null>(),
784 Kind::Bool => self.can_cast_to::<bool>(),
785 Kind::Int => self.can_cast_to::<i64>(),
786 Kind::Float => self.can_cast_to::<f64>(),
787 Kind::Decimal => self.can_cast_to::<Decimal>(),
788 Kind::Number => self.can_cast_to::<Number>(),
789 Kind::String => self.can_cast_to::<String>(),
790 Kind::Datetime => self.can_cast_to::<Datetime>(),
791 Kind::Duration => self.can_cast_to::<Duration>(),
792 Kind::Object => self.can_cast_to::<crate::val::Object>(),
793 Kind::Bytes => self.can_cast_to::<Bytes>(),
794 Kind::Uuid => self.can_cast_to::<Uuid>(),
795 Kind::Regex => self.can_cast_to::<Regex>(),
796 Kind::Range => self.can_cast_to::<Box<Range>>(),
797 Kind::Function(_, _) => self.can_cast_to::<Box<Closure>>(),
798 Kind::Set(t, l) => match l {
799 Some(l) => self.can_cast_to_set_len(t, *l),
800 None => self.can_cast_to_set(t),
801 },
802 Kind::Array(t, l) => match l {
803 Some(l) => self.can_cast_to_array_len(t, *l),
804 None => self.can_cast_to_array(t),
805 },
806 Kind::Table(t) => {
807 if t.is_empty() {
808 self.can_cast_to::<String>()
809 } else {
810 self.can_cast_to_table(t)
811 }
812 }
813 Kind::Record(t) => {
814 if t.is_empty() {
815 self.can_cast_to::<RecordId>()
816 } else {
817 self.can_cast_to_record(t)
818 }
819 }
820 Kind::Geometry(t) => {
821 if t.is_empty() {
822 self.can_cast_to::<Geometry>()
823 } else {
824 self.can_cast_to_geometry(t)
825 }
826 }
827 Kind::Either(k) => k.iter().any(|x| self.can_cast_to_kind(x)),
828 Kind::Literal(lit) => self.can_cast_to_literal(lit),
829 Kind::File(buckets) => {
830 if buckets.is_empty() {
831 self.can_cast_to::<File>()
832 } else {
833 self.can_cast_to_file_buckets(buckets)
834 }
835 }
836 }
837 }
838
839 fn can_cast_to_array_len(&self, kind: &Kind, len: u64) -> bool {
840 match self {
841 Value::Array(a) => a.len() as u64 == len && a.iter().all(|x| x.can_cast_to_kind(kind)),
842 _ => false,
843 }
844 }
845
846 fn can_cast_to_array(&self, kind: &Kind) -> bool {
847 match self {
848 Value::Array(a) => a.iter().all(|x| x.can_cast_to_kind(kind)),
849 _ => false,
850 }
851 }
852
853 fn can_cast_to_set_len(&self, kind: &Kind, len: u64) -> bool {
854 match self {
855 Value::Set(s) => s.len() as u64 == len && s.iter().all(|x| x.can_cast_to_kind(kind)),
856 _ => false,
857 }
858 }
859
860 fn can_cast_to_set(&self, kind: &Kind) -> bool {
861 match self {
862 Value::Set(s) => s.iter().all(|x| x.can_cast_to_kind(kind)),
863 _ => false,
864 }
865 }
866
867 fn can_cast_to_table(&self, val: &[TableName]) -> bool {
868 match self {
869 Value::Table(t) => t.is_table_type(val),
870 Value::String(_) => true, _ => false,
872 }
873 }
874
875 fn can_cast_to_record(&self, val: &[TableName]) -> bool {
876 match self {
877 Value::RecordId(t) => t.is_table_type(val),
878 _ => false,
879 }
880 }
881
882 fn can_cast_to_geometry(&self, val: &[GeometryKind]) -> bool {
883 self.is_geometry_type(val)
884 }
885
886 fn can_cast_to_literal(&self, val: &KindLiteral) -> bool {
887 val.validate_value(self)
888 }
889
890 fn can_cast_to_file_buckets(&self, buckets: &[String]) -> bool {
891 matches!(self, Value::File(f) if f.is_bucket_type(buckets))
892 }
893
894 pub fn cast_to<T: Cast>(self) -> Result<T, CastError> {
895 T::cast(self)
896 }
897
898 pub fn cast_to_kind(self, kind: &Kind) -> Result<Value, CastError> {
900 match kind {
902 Kind::Any => Ok(self),
903 Kind::None => self.cast_to::<SqlNone>().map(|_| Value::None),
904 Kind::Null => self.cast_to::<Null>().map(|_| Value::Null),
905 Kind::Bool => self.cast_to::<bool>().map(Value::from),
906 Kind::Int => self.cast_to::<i64>().map(Value::from),
907 Kind::Float => self.cast_to::<f64>().map(Value::from),
908 Kind::Decimal => self.cast_to::<Decimal>().map(Value::from),
909 Kind::Number => self.cast_to::<Number>().map(Value::from),
910 Kind::String => self.cast_to::<String>().map(Value::from),
911 Kind::Datetime => self.cast_to::<Datetime>().map(Value::from),
912 Kind::Duration => self.cast_to::<Duration>().map(Value::from),
913 Kind::Object => self.cast_to::<crate::val::Object>().map(Value::from),
914 Kind::Bytes => self.cast_to::<Bytes>().map(Value::from),
915 Kind::Uuid => self.cast_to::<Uuid>().map(Value::from),
916 Kind::Regex => self.cast_to::<Regex>().map(Value::from),
917 Kind::Range => self.cast_to::<Box<Range>>().map(Value::from),
918 Kind::Function(_, _) => self.cast_to::<Box<Closure>>().map(Value::from),
919 Kind::Set(t, l) => match l {
920 Some(l) => self.cast_to_set_type_len(t, *l).map(Value::from),
921 None => self.cast_to_set_type(t).map(Value::from),
922 },
923 Kind::Array(t, l) => match l {
924 Some(l) => self.cast_to_array_len(t, *l).map(Value::from),
925 None => self.cast_to_array(t).map(Value::from),
926 },
927 Kind::Table(t) => match t.is_empty() {
928 true => self
929 .cast_to::<String>()
930 .map(|s| Value::Table(surrealdb_strand::TableName::new(s))),
931 false => self.cast_to_table(t).map(Value::from),
932 },
933 Kind::Record(t) => match t.is_empty() {
934 true => self.cast_to::<RecordId>().map(Value::from),
935 false => self.cast_to_record(t).map(Value::from),
936 },
937 Kind::Geometry(t) => match t.is_empty() {
938 true => self.cast_to::<Geometry>().map(Value::from),
939 false => self.cast_to_geometry(t).map(Value::from),
940 },
941 Kind::Either(k) => {
942 let Some(k) = k.iter().find(|x| self.can_cast_to_kind(x)) else {
943 return Err(CastError::InvalidKind {
944 from: self,
945 into: kind.to_sql(),
946 });
947 };
948
949 Ok(self.cast_to_kind(k).expect(
950 "If can_coerce_to_kind returns true then coerce_to_kind must not error",
951 ))
952 }
953 Kind::Literal(lit) => self.cast_to_literal(lit),
954 Kind::File(buckets) => {
955 if buckets.is_empty() {
956 self.cast_to::<File>().map(Value::from)
957 } else {
958 self.cast_to_file_buckets(buckets).map(Value::from)
959 }
960 }
961 }
962 }
963
964 pub fn cast_to_literal(self, literal: &KindLiteral) -> Result<Value, CastError> {
967 if literal.validate_value(&self) {
968 Ok(self)
969 } else {
970 Err(CastError::InvalidKind {
971 from: self,
972 into: literal.to_sql(),
973 })
974 }
975 }
976
977 fn cast_to_table(self, val: &[TableName]) -> Result<surrealdb_strand::TableName, CastError> {
979 match self {
980 Value::Table(v) if v.is_table_type(val) => Ok(v),
981 Value::String(v) => {
982 let table = surrealdb_strand::TableName::new(v.clone());
984 if table.is_table_type(val) {
985 Ok(table)
986 } else {
987 let mut kind = "table<".to_string();
988 for (idx, t) in val.iter().enumerate() {
989 if idx != 0 {
990 kind.push('|');
991 }
992 kind.push_str(t.as_str())
993 }
994 kind.push('>');
995
996 Err(CastError::InvalidKind {
997 from: Value::String(v),
998 into: kind,
999 })
1000 }
1001 }
1002 x => {
1003 let mut kind = "table<".to_string();
1004 for (idx, t) in val.iter().enumerate() {
1005 if idx != 0 {
1006 kind.push('|');
1007 }
1008 kind.push_str(t.as_str())
1009 }
1010 kind.push('>');
1011
1012 Err(CastError::InvalidKind {
1013 from: x,
1014 into: kind,
1015 })
1016 }
1017 }
1018 }
1019
1020 fn cast_to_record(self, val: &[TableName]) -> Result<RecordId, CastError> {
1022 let expected_kind = || -> String {
1023 let mut kind = "record<".to_string();
1024 for (idx, t) in val.iter().enumerate() {
1025 if idx != 0 {
1026 kind.push('|');
1027 }
1028 kind.push_str(t.as_str())
1029 }
1030 kind.push('>');
1031 kind
1032 };
1033
1034 match self {
1035 Value::RecordId(v) if v.is_table_type(val) => Ok(v),
1036 Value::String(v) => {
1037 let record_id = match syn::record_id(v.as_str()) {
1038 Ok(x) => RecordId::from(x),
1039 Err(_) => {
1040 return Err(CastError::InvalidKind {
1041 from: Value::String(v),
1042 into: expected_kind(),
1043 });
1044 }
1045 };
1046
1047 if !record_id.is_table_type(val) {
1048 return Err(CastError::InvalidKind {
1049 from: Value::String(v),
1050 into: expected_kind(),
1051 });
1052 }
1053
1054 Ok(record_id)
1055 }
1056 x => Err(CastError::InvalidKind {
1057 from: x,
1058 into: expected_kind(),
1059 }),
1060 }
1061 }
1062
1063 fn cast_to_geometry(self, val: &[GeometryKind]) -> Result<Geometry, CastError> {
1065 match self {
1066 Value::Geometry(v) if self.is_geometry_type(val) => Ok(v),
1068 Value::Array(_) => {
1069 if val.contains(&GeometryKind::Point)
1071 && let Some(p) = Geometry::array_to_point(&self)
1072 {
1073 Ok(Geometry::Point(p))
1074 } else {
1075 Err(CastError::InvalidKind {
1076 from: self,
1077 into: "geometry".into(),
1078 })
1079 }
1080 }
1081 _ => Err(CastError::InvalidKind {
1083 from: self,
1084 into: "geometry".into(),
1085 }),
1086 }
1087 }
1088
1089 fn cast_to_array(self, kind: &Kind) -> Result<Array, CastError> {
1091 self.cast_to::<Array>()?
1092 .into_iter()
1093 .enumerate()
1094 .map(|(i, value)| {
1095 value
1096 .cast_to_kind(kind)
1097 .with_element_of_at_index(i, || format!("array<{}>", kind.to_sql()))
1098 })
1099 .collect::<Result<Array, CastError>>()
1100 }
1101
1102 fn cast_to_array_len(self, kind: &Kind, len: u64) -> Result<Array, CastError> {
1104 let array = self.cast_to::<Array>()?;
1105
1106 if (array.len() as u64) != len {
1107 return Err(CastError::InvalidLength {
1108 len: array.len(),
1109 into: format!("array<{},{}>", kind.to_sql(), len),
1110 });
1111 }
1112
1113 array
1114 .into_iter()
1115 .enumerate()
1116 .map(|(i, value)| {
1117 value
1118 .cast_to_kind(kind)
1119 .with_element_of_at_index(i, || format!("array<{}>", kind.to_sql()))
1120 })
1121 .collect::<Result<Array, CastError>>()
1122 }
1123
1124 pub fn cast_to_set_type(self, kind: &Kind) -> Result<Set, CastError> {
1126 self.cast_to::<Array>()?
1127 .into_iter()
1128 .enumerate()
1129 .map(|(i, value)| {
1130 value
1131 .cast_to_kind(kind)
1132 .with_element_of_at_index(i, || format!("set<{}>", kind.to_sql()))
1133 })
1134 .collect::<Result<Set, CastError>>()
1135 }
1136
1137 pub fn cast_to_set_type_len(self, kind: &Kind, len: u64) -> Result<Set, CastError> {
1139 let set = self
1140 .cast_to::<Array>()?
1141 .into_iter()
1142 .enumerate()
1143 .map(|(i, value)| {
1144 value
1145 .cast_to_kind(kind)
1146 .with_element_of_at_index(i, || format!("set<{}>", kind.to_sql()))
1147 })
1148 .collect::<Result<Set, CastError>>()?;
1149
1150 if (set.len() as u64) != len {
1151 return Err(CastError::InvalidLength {
1152 len: set.len(),
1153 into: format!("set<{},{}>", kind.to_sql(), len),
1154 });
1155 }
1156
1157 Ok(set)
1158 }
1159
1160 pub fn cast_to_file_buckets(self, buckets: &[String]) -> Result<File, CastError> {
1161 let v = self.cast_to::<File>()?;
1162
1163 if v.is_bucket_type(buckets) {
1164 return Ok(v);
1165 }
1166
1167 let mut kind = "file<".to_owned();
1168 for (idx, t) in buckets.iter().enumerate() {
1169 if idx != 0 {
1170 kind.push('|');
1171 }
1172 kind.push_str(t.as_str())
1173 }
1174 kind.push('>');
1175 Err(CastError::InvalidKind {
1176 from: v.into(),
1177 into: kind,
1178 })
1179 }
1180}
1181
1182#[cfg(test)]
1183mod tests {
1184 use surrealdb_strand::Strand;
1185
1186 use super::*;
1187
1188 #[test]
1189 fn test_cast_to_table_generic() {
1190 let value = Value::String(Strand::new_static("users"));
1192 let kind = Kind::Table(vec![]);
1193 let result = value.cast_to_kind(&kind);
1194 assert!(result.is_ok());
1195 if let Ok(Value::Table(table)) = result {
1196 assert_eq!(table.as_str(), "users");
1197 } else {
1198 panic!("Expected Value::Table");
1199 }
1200 }
1201
1202 #[test]
1203 fn test_cast_to_table_specific() {
1204 let value = Value::String(Strand::new_static("users"));
1206 let kind = Kind::Table(vec!["users".into()]);
1207 let result = value.cast_to_kind(&kind);
1208 assert!(result.is_ok());
1209 if let Ok(Value::Table(table)) = result {
1210 assert_eq!(table.as_str(), "users");
1211 }
1212
1213 let value = Value::String(Strand::new_static("posts"));
1215 let kind = Kind::Table(vec!["users".into()]);
1216 let result = value.cast_to_kind(&kind);
1217 assert!(result.is_err());
1218 }
1219
1220 #[test]
1221 fn test_cast_to_table_union() {
1222 let value = Value::String(Strand::new_static("posts"));
1224 let kind = Kind::Table(vec!["users".into(), "posts".into()]);
1225 let result = value.cast_to_kind(&kind);
1226 assert!(result.is_ok());
1227 if let Ok(Value::Table(table)) = result {
1228 assert_eq!(table.as_str(), "posts");
1229 }
1230
1231 let value = Value::String(Strand::new_static("comments"));
1233 let kind = Kind::Table(vec!["users".into(), "posts".into()]);
1234 let result = value.cast_to_kind(&kind);
1235 assert!(result.is_err());
1236 }
1237
1238 #[test]
1239 fn test_cast_table_to_table() {
1240 let value = Value::Table(surrealdb_strand::TableName::new("users".to_string()));
1242 let kind = Kind::Table(vec!["users".into()]);
1243 let result = value.cast_to_kind(&kind);
1244 assert!(result.is_ok());
1245 }
1246
1247 #[test]
1248 fn test_can_cast_to_table() {
1249 let value = Value::String(Strand::new_static("users"));
1251 let kind = Kind::Table(vec![]);
1252 assert!(value.can_cast_to_kind(&kind));
1253
1254 let value = Value::Table(surrealdb_strand::TableName::new("users".to_string()));
1256 let kind = Kind::Table(vec!["users".into()]);
1257 assert!(value.can_cast_to_kind(&kind));
1258
1259 let value = Value::Table(surrealdb_strand::TableName::new("posts".to_string()));
1261 let kind = Kind::Table(vec!["users".into()]);
1262 assert!(!value.can_cast_to_kind(&kind));
1263 }
1264
1265 fn float(f: f64) -> Value {
1266 Value::Number(Number::Float(f))
1267 }
1268
1269 fn decimal(mantissa: i128, scale: u32) -> Value {
1270 Value::Number(Number::Decimal(Decimal::from_i128_with_scale(mantissa, scale)))
1271 }
1272
1273 #[test]
1274 fn test_cast_float_to_int_accepts_whole_floats_in_range() {
1275 assert_eq!(float(5.0).cast_to::<i64>().unwrap(), 5);
1276 assert_eq!(float(-5.0).cast_to::<i64>().unwrap(), -5);
1277 assert_eq!(float(-0.0).cast_to::<i64>().unwrap(), 0);
1279 assert_eq!(float(9_007_199_254_740_992.0).cast_to::<i64>().unwrap(), 9_007_199_254_740_992);
1281 assert_eq!(float(i64::MIN as f64).cast_to::<i64>().unwrap(), i64::MIN);
1283 assert_eq!(float(2f64.powi(63) - 1024.0).cast_to::<i64>().unwrap(), i64::MAX - 1023);
1285 }
1286
1287 #[test]
1288 fn test_cast_float_to_int_refuses_what_is_not_one_i64() {
1289 for f in [
1290 2f64.powi(63),
1292 i64::MAX as f64,
1293 -2f64.powi(63) - 2048.0,
1295 1e30,
1296 -1e30,
1297 f64::MAX,
1298 f64::MIN,
1299 f64::NAN,
1300 f64::INFINITY,
1301 f64::NEG_INFINITY,
1302 0.5,
1303 -0.5,
1304 ] {
1305 let err = float(f).cast_to::<i64>().unwrap_err();
1306 assert!(
1307 matches!(&err, CastError::InvalidKind { into, .. } if into == "int"),
1308 "{f} should be refused as an int, got: {err}"
1309 );
1310 assert!(!float(f).can_cast_to::<i64>(), "{f} must not report as castable to int");
1311 }
1312 }
1313
1314 fn cast_battery() -> Vec<Value> {
1318 let mut out = vec![
1319 Value::Number(Number::Int(0)),
1320 Value::Number(Number::Int(i64::MIN)),
1321 Value::Number(Number::Int(i64::MAX)),
1322 decimal(0, 0),
1323 decimal(15, 1),
1324 decimal(-15, 1),
1325 decimal(50, 1),
1327 decimal(i64::MAX as i128, 0),
1328 decimal(i64::MAX as i128 + 1, 0),
1329 decimal(i64::MIN as i128, 0),
1330 decimal(i64::MIN as i128 - 1, 0),
1331 decimal(10_000_000_000_000_000_000, 0),
1332 Value::Number(Number::Decimal(Decimal::MAX)),
1333 Value::Number(Number::Decimal(Decimal::MIN)),
1334 Value::String(Strand::new_static("5")),
1335 Value::String(Strand::new_static("1.5")),
1336 Value::String(Strand::new_static("9223372036854775808")),
1337 Value::String(Strand::new_static("abc")),
1338 ];
1339 for f in [
1340 0.0,
1341 -0.0,
1342 5.0,
1343 0.5,
1344 1e30,
1345 -1e30,
1346 i64::MAX as f64,
1347 i64::MIN as f64,
1348 f64::MAX,
1349 f64::NAN,
1350 f64::INFINITY,
1351 f64::NEG_INFINITY,
1352 ] {
1353 out.push(float(f));
1354 }
1355 out
1356 }
1357
1358 #[test]
1359 fn test_can_cast_agrees_with_cast_to_int() {
1360 for value in cast_battery() {
1364 assert_eq!(
1365 value.can_cast_to_kind(&Kind::Int),
1366 value.clone().cast_to_kind(&Kind::Int).is_ok(),
1367 "can_cast and cast disagree for {value:?} into int"
1368 );
1369 }
1370 }
1371
1372 #[test]
1373 fn test_cast_union_with_int_never_claims_a_value_it_cannot_cast() {
1374 let fractional = decimal(15, 1);
1375 let huge = float(1e30);
1376 let either = Kind::Either(vec![Kind::Int, Kind::Float]);
1377 assert!(matches!(
1379 fractional.cast_to_kind(&either).unwrap(),
1380 Value::Number(Number::Float(f)) if f == 1.5
1381 ));
1382 assert!(matches!(
1383 huge.cast_to_kind(&either).unwrap(),
1384 Value::Number(Number::Float(f)) if f == 1e30
1385 ));
1386 assert!(matches!(float(5.0).cast_to_kind(&either).unwrap(), Value::Number(Number::Int(5))));
1388 let none = Kind::Either(vec![Kind::Int, Kind::Bool]);
1390 assert!(decimal(15, 1).cast_to_kind(&none).is_err());
1391 assert!(float(1e30).cast_to_kind(&none).is_err());
1392 }
1393}