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 {
201 match v {
202 Value::Number(Number::Int(_)) => true,
203 Value::Number(Number::Float(v)) => v.fract() == 0.0,
204 Value::Number(Number::Decimal(v)) => v.is_integer() || i64::try_from(*v).is_ok(),
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(Number::Float(v)) if v.fract() == 0.0 => Ok(v as i64),
216 Value::Number(Number::Decimal(d)) if d.is_integer() => match d.try_into() {
218 Ok(v) => Ok(v),
219 _ => Err(CastError::InvalidKind {
220 from: v,
221 into: "int".into(),
222 }),
223 },
224 Value::String(ref s) => match s.parse::<i64>() {
226 Ok(v) => Ok(v),
227 _ => Err(CastError::InvalidKind {
228 from: v,
229 into: "int".into(),
230 }),
231 },
232 _ => Err(CastError::InvalidKind {
233 from: v,
234 into: "int".into(),
235 }),
236 }
237 }
238}
239
240impl Cast for f64 {
241 fn can_cast(v: &Value) -> bool {
242 match v {
243 Value::Number(Number::Int(_) | Number::Float(_)) => true,
244 Value::Number(Number::Decimal(v)) => v.is_integer() || i64::try_from(*v).is_ok(),
245 Value::String(v) => v.parse::<f64>().is_ok(),
246 _ => false,
247 }
248 }
249
250 fn cast(v: Value) -> Result<Self, CastError> {
251 match v {
252 Value::Number(Number::Float(i)) => Ok(i),
253 Value::Number(Number::Int(f)) => Ok(f as f64),
254 Value::Number(Number::Decimal(d)) => match d.try_into() {
255 Ok(v) => Ok(v),
257 _ => Err(CastError::InvalidKind {
259 from: v,
260 into: "float".into(),
261 }),
262 },
263 Value::String(ref s) => match s.parse::<f64>() {
265 Ok(v) => Ok(v),
267 _ => Err(CastError::InvalidKind {
269 from: v,
270 into: "float".into(),
271 }),
272 },
273 _ => Err(CastError::InvalidKind {
275 from: v,
276 into: "float".into(),
277 }),
278 }
279 }
280}
281
282impl Cast for Decimal {
283 fn can_cast(v: &Value) -> bool {
284 match v {
285 Value::Number(_) => true,
286 Value::String(v) => v.parse::<f64>().is_ok(),
287 _ => false,
288 }
289 }
290
291 fn cast(v: Value) -> Result<Self, CastError> {
292 match v {
293 Value::Number(Number::Decimal(d)) => Ok(d),
294 Value::Number(Number::Int(ref i)) => Ok(Decimal::from(*i)),
296 Value::Number(Number::Float(ref f)) => match Decimal::try_from(*f) {
298 Ok(d) => Ok(d),
300 _ => Err(CastError::InvalidKind {
302 from: v,
303 into: "decimal".into(),
304 }),
305 },
306 Value::String(ref s) => match Decimal::from_str_normalized(s) {
308 Ok(v) => Ok(v),
310 _ => Err(CastError::InvalidKind {
312 from: v,
313 into: "decimal".into(),
314 }),
315 },
316 _ => Err(CastError::InvalidKind {
318 from: v,
319 into: "decimal".into(),
320 }),
321 }
322 }
323}
324
325impl Cast for Number {
326 fn can_cast(v: &Value) -> bool {
327 match v {
328 Value::Number(_) => true,
329 Value::String(s) => Number::from_str(s).is_ok(),
330 _ => false,
331 }
332 }
333
334 fn cast(v: Value) -> Result<Self, CastError> {
335 match v {
336 Value::Number(v) => Ok(v),
337 Value::String(ref s) => Number::from_str(s).map_err(|_| CastError::InvalidKind {
338 from: v,
339 into: "number".into(),
340 }),
341 _ => Err(CastError::InvalidKind {
343 from: v,
344 into: "number".into(),
345 }),
346 }
347 }
348}
349
350impl Cast for String {
351 fn can_cast(v: &Value) -> bool {
352 match v {
353 Value::None | Value::Null => false,
354 Value::Bytes(b) => std::str::from_utf8(b).is_ok(),
355 _ => true,
356 }
357 }
358
359 fn cast(v: Value) -> Result<Self, CastError> {
360 match v {
361 Value::Bytes(b) => match String::from_utf8(b.0.to_vec()) {
362 Ok(x) => Ok(x),
363 Err(e) => Err(CastError::InvalidKind {
364 from: Value::Bytes(Bytes::from(e.into_bytes())),
365 into: "string".to_owned(),
366 }),
367 },
368
369 Value::Null => Ok("NULL".into()),
370 Value::None => Ok("NONE".into()),
371 Value::String(x) => Ok(x.into_string()),
372 Value::Uuid(x) => Ok(x.to_string()),
373 Value::Datetime(x) => Ok(x.to_string()),
374 Value::Number(Number::Decimal(x)) => Ok(x.to_string()),
375 x => Ok(x.to_sql()),
376 }
377 }
378}
379
380impl Cast for Uuid {
381 fn can_cast(v: &Value) -> bool {
382 match v {
383 Value::Uuid(_) => true,
384 Value::String(s) => Uuid::from_str(s).is_ok(),
385 _ => false,
386 }
387 }
388
389 fn cast(v: Value) -> Result<Self, CastError> {
390 match v {
391 Value::Uuid(u) => Ok(u),
392 Value::String(ref s) => Uuid::from_str(s).map_err(|_| CastError::InvalidKind {
393 from: v,
394 into: "uuid".into(),
395 }),
396 _ => Err(CastError::InvalidKind {
397 from: v,
398 into: "uuid".into(),
399 }),
400 }
401 }
402}
403
404impl Cast for Datetime {
405 fn can_cast(v: &Value) -> bool {
406 match v {
407 Value::Datetime(_) => true,
408 Value::String(s) => Datetime::from_str(s).is_ok(),
409 _ => false,
410 }
411 }
412
413 fn cast(v: Value) -> Result<Self, CastError> {
414 match v {
415 Value::Datetime(v) => Ok(v),
417 Value::String(ref s) => Datetime::from_str(s).map_err(|_| CastError::InvalidKind {
419 from: v,
420 into: "datetime".into(),
421 }),
422 _ => Err(CastError::InvalidKind {
424 from: v,
425 into: "datetime".into(),
426 }),
427 }
428 }
429}
430
431impl Cast for Duration {
432 fn can_cast(v: &Value) -> bool {
433 match v {
434 Value::Duration(_) => true,
435 Value::String(s) => Duration::from_str(s).is_ok(),
436 _ => false,
437 }
438 }
439
440 fn cast(v: Value) -> Result<Self, CastError> {
441 match v {
442 Value::Duration(v) => Ok(v),
444 Value::String(ref s) => Duration::from_str(s).map_err(|_| CastError::InvalidKind {
446 from: v,
447 into: "duration".into(),
448 }),
449 _ => Err(CastError::InvalidKind {
451 from: v,
452 into: "duration".into(),
453 }),
454 }
455 }
456}
457
458impl Cast for Bytes {
459 fn can_cast(v: &Value) -> bool {
460 match v {
461 Value::Bytes(_) | Value::String(_) => true,
462 Value::Array(x) => x.iter().all(|v| value_to_byte(v).is_some()),
463 _ => false,
464 }
465 }
466
467 fn cast(v: Value) -> Result<Self, CastError> {
468 match v {
469 Value::Bytes(b) => Ok(b),
470 Value::String(s) => Ok(Bytes::from(s.into_string().into_bytes())),
471 Value::Array(x) => match x.0.iter().map(value_to_byte).collect::<Option<Vec<u8>>>() {
472 Some(bytes) => Ok(Bytes::from(bytes)),
473 None => Err(CastError::InvalidKind {
474 from: Value::Array(x),
475 into: "bytes".to_owned(),
476 }),
477 },
478 _ => Err(CastError::InvalidKind {
479 from: v,
480 into: "bytes".into(),
481 }),
482 }
483 }
484}
485
486fn value_to_byte(v: &Value) -> Option<u8> {
490 match v {
491 Value::Number(Number::Int(x)) => u8::try_from(*x).ok(),
492 Value::Number(Number::Float(f)) if f.fract() == 0.0 => u8::try_from(*f as i64).ok(),
493 Value::Number(Number::Decimal(d)) if d.is_integer() => {
494 u8::try_from(i64::try_from(*d).ok()?).ok()
495 }
496 Value::String(s) => s.parse::<u8>().ok(),
497 _ => None,
498 }
499}
500
501impl Cast for Array {
502 fn can_cast(v: &Value) -> bool {
503 match v {
504 Value::Array(_) | Value::Bytes(_) | Value::Set(_) => true,
505 Value::Range(r) => r.can_coerce_to_typed::<i64>(),
506 _ => false,
507 }
508 }
509
510 fn cast(v: Value) -> Result<Self, CastError> {
511 match v {
512 Value::Array(x) => Ok(x),
513 Value::Set(s) => Ok(s.into_iter().collect()),
514 Value::Range(range) => {
515 if !range.can_coerce_to_typed::<i64>() {
516 return Err(CastError::InvalidKind {
517 from: Value::Range(range),
518 into: "array".to_string(),
519 });
520 }
521 let range = range.coerce_to_typed::<i64>().expect("range type checked above");
523 if range.len().is_none_or(|n| n > *GENERATION_ALLOCATION_LIMIT) {
524 return Err(CastError::RangeSizeLimit {
525 value: Box::new(Range::from(range)),
526 });
527 }
528
529 Ok(range.cast_to_array())
530 }
531
532 Value::Bytes(x) => Ok(Array(x.0.into_iter().map(|x| Value::from(x as i64)).collect())),
533 _ => Err(CastError::InvalidKind {
534 from: v,
535 into: "array".into(),
536 }),
537 }
538 }
539}
540
541impl Cast for Set {
542 fn can_cast(v: &Value) -> bool {
543 matches!(v, Value::Set(_) | Value::Array(_))
544 }
545
546 fn cast(v: Value) -> Result<Self, CastError> {
547 match v {
548 Value::Set(x) => Ok(x),
549 Value::Array(x) => {
550 Ok(Set::from(x.0))
552 }
553 _ => Err(CastError::InvalidKind {
554 from: v,
555 into: "set".into(),
556 }),
557 }
558 }
559}
560
561impl Cast for Regex {
562 fn can_cast(v: &Value) -> bool {
563 match v {
564 Value::Regex(_) => true,
565 Value::String(x) => Regex::from_str(x).is_ok(),
566 _ => false,
567 }
568 }
569
570 fn cast(v: Value) -> Result<Self, CastError> {
571 match v {
572 Value::Regex(x) => Ok(x),
573 Value::String(x) => match Regex::from_str(&x) {
574 Ok(x) => Ok(x),
575 Err(_) => Err(CastError::InvalidKind {
576 from: Value::String(x),
577 into: "regex".to_string(),
578 }),
579 },
580 x => Err(CastError::InvalidKind {
581 from: x,
582 into: "regex".to_string(),
583 }),
584 }
585 }
586}
587
588impl Cast for Box<Range> {
589 fn can_cast(v: &Value) -> bool {
590 match v {
591 Value::Range(_) => true,
592 Value::Array(x) => x.len() == 2,
593 _ => false,
594 }
595 }
596
597 fn cast(v: Value) -> Result<Self, CastError> {
598 match v {
599 Value::Range(x) => Ok(x),
600 Value::Array(x) => {
601 if x.len() != 2 {
602 return Err(CastError::InvalidKind {
603 from: Value::Array(x),
604 into: "range".to_string(),
605 });
606 }
607
608 let mut iter = x.into_iter();
609 let beg = iter.next().expect("array length checked above");
611 let end = iter.next().expect("array length checked above");
613
614 Ok(Box::new(Range {
615 start: Bound::Included(beg),
616 end: Bound::Excluded(end),
617 }))
618 }
619 _ => Err(CastError::InvalidKind {
620 from: v,
621 into: "range".into(),
622 }),
623 }
624 }
625}
626
627impl Cast for Point<f64> {
628 fn can_cast(v: &Value) -> bool {
629 match v {
630 Value::Geometry(Geometry::Point(_)) => true,
631 Value::Array(x) => x.len() == 2,
632 _ => false,
633 }
634 }
635
636 fn cast(v: Value) -> Result<Self, CastError> {
637 match v {
638 Value::Geometry(Geometry::Point(v)) => Ok(v),
639 Value::Array(x) => {
640 if x.len() != 2 {
641 return Err(CastError::InvalidKind {
642 from: Value::Array(x),
643 into: "point".to_string(),
644 });
645 }
646
647 if !x[0].can_coerce_to::<f64>() || !x[1].can_coerce_to::<f64>() {
648 return Err(CastError::InvalidKind {
649 from: Value::Array(x),
650 into: "point".to_string(),
651 });
652 }
653
654 let mut iter = x.into_iter();
655 let x = iter
657 .next()
658 .expect("array length checked above")
659 .cast_to::<f64>()
660 .expect("value type checked above");
661 let y = iter
663 .next()
664 .expect("array length checked above")
665 .cast_to::<f64>()
666 .expect("value type checked above");
667
668 Ok(Point::new(x, y))
669 }
670 _ => Err(CastError::InvalidKind {
671 from: v,
672 into: "point".into(),
673 }),
674 }
675 }
676}
677
678impl Cast for RecordId {
679 fn can_cast(v: &Value) -> bool {
680 match v {
681 Value::RecordId(_) => true,
682 Value::String(x) => syn::record_id(x).is_ok(),
683 _ => false,
684 }
685 }
686
687 fn cast(v: Value) -> Result<Self, CastError> {
688 match v {
689 Value::RecordId(x) => Ok(x),
690 Value::String(x) => match syn::record_id(&x) {
691 Ok(x) => Ok(x.into()),
692 Err(_) => Err(CastError::InvalidKind {
693 from: Value::String(x),
694 into: "record".to_string(),
695 }),
696 },
697 from => Err(CastError::InvalidKind {
698 from,
699 into: "record".to_string(),
700 }),
701 }
702 }
703}
704
705impl Cast for surrealdb_strand::TableName {
706 fn can_cast(v: &Value) -> bool {
707 matches!(v, Value::Table(_) | Value::String(_))
708 }
709
710 fn cast(v: Value) -> Result<Self, CastError> {
711 match v {
712 Value::Table(x) => Ok(x),
713 Value::String(x) => Ok(surrealdb_strand::TableName::new(x)),
714 from => Err(CastError::InvalidKind {
715 from,
716 into: "table".to_string(),
717 }),
718 }
719 }
720}
721
722impl<T: Cast> Cast for Option<T> {
723 fn can_cast(v: &Value) -> bool {
724 if let Value::None = v {
725 return true;
726 }
727 T::can_cast(v)
728 }
729
730 fn cast(v: Value) -> Result<Self, CastError> {
731 match v {
732 Value::None => Ok(None),
733 x => T::cast(x).map(Some),
734 }
735 }
736}
737
738macro_rules! impl_direct {
739 ($($name:ident => $inner:ty $(= $kind:ident)?),*$(,)?) => {
740 $(
741 impl Cast for $inner {
742 fn can_cast(v: &Value) -> bool{
743 matches!(v, Value::$name(_))
744 }
745
746 fn cast(v: Value) -> Result<Self, CastError> {
747 if let Value::$name(x) = v {
748 return Ok(x);
749 } else {
750 return Err(CastError::InvalidKind{
751 from: v,
752 into: impl_direct!(@kindof $inner $(= $kind)?),
753 });
754 }
755 }
756 }
757 )*
758 };
759
760 (@kindof $inner:ty = $kind:ident) => {
761 <$kind as HasKind>::kind().to_sql()
762 };
763
764 (@kindof $inner:ty) => {
765 <$inner as HasKind>::kind().to_sql()
766 };
767}
768
769impl_direct! {
771 Closure => Box<Closure> = Closure,
772 Object => Object,
773 Geometry => Geometry,
774 File => File,
775}
776
777impl Value {
778 pub fn can_cast_to<T: Cast>(&self) -> bool {
779 T::can_cast(self)
780 }
781
782 pub fn can_cast_to_kind(&self, kind: &Kind) -> bool {
783 match kind {
784 Kind::Any => true,
785 Kind::None => self.can_cast_to::<SqlNone>(),
786 Kind::Null => self.can_cast_to::<Null>(),
787 Kind::Bool => self.can_cast_to::<bool>(),
788 Kind::Int => self.can_cast_to::<i64>(),
789 Kind::Float => self.can_cast_to::<f64>(),
790 Kind::Decimal => self.can_cast_to::<Decimal>(),
791 Kind::Number => self.can_cast_to::<Number>(),
792 Kind::String => self.can_cast_to::<String>(),
793 Kind::Datetime => self.can_cast_to::<Datetime>(),
794 Kind::Duration => self.can_cast_to::<Duration>(),
795 Kind::Object => self.can_cast_to::<crate::val::Object>(),
796 Kind::Bytes => self.can_cast_to::<Bytes>(),
797 Kind::Uuid => self.can_cast_to::<Uuid>(),
798 Kind::Regex => self.can_cast_to::<Regex>(),
799 Kind::Range => self.can_cast_to::<Box<Range>>(),
800 Kind::Function(_, _) => self.can_cast_to::<Box<Closure>>(),
801 Kind::Set(t, l) => match l {
802 Some(l) => self.can_cast_to_set_len(t, *l),
803 None => self.can_cast_to_set(t),
804 },
805 Kind::Array(t, l) => match l {
806 Some(l) => self.can_cast_to_array_len(t, *l),
807 None => self.can_cast_to_array(t),
808 },
809 Kind::Table(t) => {
810 if t.is_empty() {
811 self.can_cast_to::<String>()
812 } else {
813 self.can_cast_to_table(t)
814 }
815 }
816 Kind::Record(t) => {
817 if t.is_empty() {
818 self.can_cast_to::<RecordId>()
819 } else {
820 self.can_cast_to_record(t)
821 }
822 }
823 Kind::Geometry(t) => {
824 if t.is_empty() {
825 self.can_cast_to::<Geometry>()
826 } else {
827 self.can_cast_to_geometry(t)
828 }
829 }
830 Kind::Either(k) => k.iter().any(|x| self.can_cast_to_kind(x)),
831 Kind::Literal(lit) => self.can_cast_to_literal(lit),
832 Kind::File(buckets) => {
833 if buckets.is_empty() {
834 self.can_cast_to::<File>()
835 } else {
836 self.can_cast_to_file_buckets(buckets)
837 }
838 }
839 }
840 }
841
842 fn can_cast_to_array_len(&self, kind: &Kind, len: u64) -> bool {
843 match self {
844 Value::Array(a) => a.len() as u64 == len && a.iter().all(|x| x.can_cast_to_kind(kind)),
845 _ => false,
846 }
847 }
848
849 fn can_cast_to_array(&self, kind: &Kind) -> bool {
850 match self {
851 Value::Array(a) => a.iter().all(|x| x.can_cast_to_kind(kind)),
852 _ => false,
853 }
854 }
855
856 fn can_cast_to_set_len(&self, kind: &Kind, len: u64) -> bool {
857 match self {
858 Value::Set(s) => s.len() as u64 == len && s.iter().all(|x| x.can_cast_to_kind(kind)),
859 _ => false,
860 }
861 }
862
863 fn can_cast_to_set(&self, kind: &Kind) -> bool {
864 match self {
865 Value::Set(s) => s.iter().all(|x| x.can_cast_to_kind(kind)),
866 _ => false,
867 }
868 }
869
870 fn can_cast_to_table(&self, val: &[TableName]) -> bool {
871 match self {
872 Value::Table(t) => t.is_table_type(val),
873 Value::String(_) => true, _ => false,
875 }
876 }
877
878 fn can_cast_to_record(&self, val: &[TableName]) -> bool {
879 match self {
880 Value::RecordId(t) => t.is_table_type(val),
881 _ => false,
882 }
883 }
884
885 fn can_cast_to_geometry(&self, val: &[GeometryKind]) -> bool {
886 self.is_geometry_type(val)
887 }
888
889 fn can_cast_to_literal(&self, val: &KindLiteral) -> bool {
890 val.validate_value(self)
891 }
892
893 fn can_cast_to_file_buckets(&self, buckets: &[String]) -> bool {
894 matches!(self, Value::File(f) if f.is_bucket_type(buckets))
895 }
896
897 pub fn cast_to<T: Cast>(self) -> Result<T, CastError> {
898 T::cast(self)
899 }
900
901 pub fn cast_to_kind(self, kind: &Kind) -> Result<Value, CastError> {
903 match kind {
905 Kind::Any => Ok(self),
906 Kind::None => self.cast_to::<SqlNone>().map(|_| Value::None),
907 Kind::Null => self.cast_to::<Null>().map(|_| Value::Null),
908 Kind::Bool => self.cast_to::<bool>().map(Value::from),
909 Kind::Int => self.cast_to::<i64>().map(Value::from),
910 Kind::Float => self.cast_to::<f64>().map(Value::from),
911 Kind::Decimal => self.cast_to::<Decimal>().map(Value::from),
912 Kind::Number => self.cast_to::<Number>().map(Value::from),
913 Kind::String => self.cast_to::<String>().map(Value::from),
914 Kind::Datetime => self.cast_to::<Datetime>().map(Value::from),
915 Kind::Duration => self.cast_to::<Duration>().map(Value::from),
916 Kind::Object => self.cast_to::<crate::val::Object>().map(Value::from),
917 Kind::Bytes => self.cast_to::<Bytes>().map(Value::from),
918 Kind::Uuid => self.cast_to::<Uuid>().map(Value::from),
919 Kind::Regex => self.cast_to::<Regex>().map(Value::from),
920 Kind::Range => self.cast_to::<Box<Range>>().map(Value::from),
921 Kind::Function(_, _) => self.cast_to::<Box<Closure>>().map(Value::from),
922 Kind::Set(t, l) => match l {
923 Some(l) => self.cast_to_set_type_len(t, *l).map(Value::from),
924 None => self.cast_to_set_type(t).map(Value::from),
925 },
926 Kind::Array(t, l) => match l {
927 Some(l) => self.cast_to_array_len(t, *l).map(Value::from),
928 None => self.cast_to_array(t).map(Value::from),
929 },
930 Kind::Table(t) => match t.is_empty() {
931 true => self
932 .cast_to::<String>()
933 .map(|s| Value::Table(surrealdb_strand::TableName::new(s))),
934 false => self.cast_to_table(t).map(Value::from),
935 },
936 Kind::Record(t) => match t.is_empty() {
937 true => self.cast_to::<RecordId>().map(Value::from),
938 false => self.cast_to_record(t).map(Value::from),
939 },
940 Kind::Geometry(t) => match t.is_empty() {
941 true => self.cast_to::<Geometry>().map(Value::from),
942 false => self.cast_to_geometry(t).map(Value::from),
943 },
944 Kind::Either(k) => {
945 let Some(k) = k.iter().find(|x| self.can_cast_to_kind(x)) else {
946 return Err(CastError::InvalidKind {
947 from: self,
948 into: kind.to_sql(),
949 });
950 };
951
952 Ok(self.cast_to_kind(k).expect(
953 "If can_coerce_to_kind returns true then coerce_to_kind must not error",
954 ))
955 }
956 Kind::Literal(lit) => self.cast_to_literal(lit),
957 Kind::File(buckets) => {
958 if buckets.is_empty() {
959 self.cast_to::<File>().map(Value::from)
960 } else {
961 self.cast_to_file_buckets(buckets).map(Value::from)
962 }
963 }
964 }
965 }
966
967 pub fn cast_to_literal(self, literal: &KindLiteral) -> Result<Value, CastError> {
970 if literal.validate_value(&self) {
971 Ok(self)
972 } else {
973 Err(CastError::InvalidKind {
974 from: self,
975 into: literal.to_sql(),
976 })
977 }
978 }
979
980 fn cast_to_table(self, val: &[TableName]) -> Result<surrealdb_strand::TableName, CastError> {
982 match self {
983 Value::Table(v) if v.is_table_type(val) => Ok(v),
984 Value::String(v) => {
985 let table = surrealdb_strand::TableName::new(v.clone());
987 if table.is_table_type(val) {
988 Ok(table)
989 } else {
990 let mut kind = "table<".to_string();
991 for (idx, t) in val.iter().enumerate() {
992 if idx != 0 {
993 kind.push('|');
994 }
995 kind.push_str(t.as_str())
996 }
997 kind.push('>');
998
999 Err(CastError::InvalidKind {
1000 from: Value::String(v),
1001 into: kind,
1002 })
1003 }
1004 }
1005 x => {
1006 let mut kind = "table<".to_string();
1007 for (idx, t) in val.iter().enumerate() {
1008 if idx != 0 {
1009 kind.push('|');
1010 }
1011 kind.push_str(t.as_str())
1012 }
1013 kind.push('>');
1014
1015 Err(CastError::InvalidKind {
1016 from: x,
1017 into: kind,
1018 })
1019 }
1020 }
1021 }
1022
1023 fn cast_to_record(self, val: &[TableName]) -> Result<RecordId, CastError> {
1025 let expected_kind = || -> String {
1026 let mut kind = "record<".to_string();
1027 for (idx, t) in val.iter().enumerate() {
1028 if idx != 0 {
1029 kind.push('|');
1030 }
1031 kind.push_str(t.as_str())
1032 }
1033 kind.push('>');
1034 kind
1035 };
1036
1037 match self {
1038 Value::RecordId(v) if v.is_table_type(val) => Ok(v),
1039 Value::String(v) => {
1040 let record_id = match syn::record_id(v.as_str()) {
1041 Ok(x) => RecordId::from(x),
1042 Err(_) => {
1043 return Err(CastError::InvalidKind {
1044 from: Value::String(v),
1045 into: expected_kind(),
1046 });
1047 }
1048 };
1049
1050 if !record_id.is_table_type(val) {
1051 return Err(CastError::InvalidKind {
1052 from: Value::String(v),
1053 into: expected_kind(),
1054 });
1055 }
1056
1057 Ok(record_id)
1058 }
1059 x => Err(CastError::InvalidKind {
1060 from: x,
1061 into: expected_kind(),
1062 }),
1063 }
1064 }
1065
1066 fn cast_to_geometry(self, val: &[GeometryKind]) -> Result<Geometry, CastError> {
1068 match self {
1069 Value::Geometry(v) if self.is_geometry_type(val) => Ok(v),
1071 Value::Array(_) => {
1072 if val.contains(&GeometryKind::Point)
1074 && let Some(p) = Geometry::array_to_point(&self)
1075 {
1076 Ok(Geometry::Point(p))
1077 } else {
1078 Err(CastError::InvalidKind {
1079 from: self,
1080 into: "geometry".into(),
1081 })
1082 }
1083 }
1084 _ => Err(CastError::InvalidKind {
1086 from: self,
1087 into: "geometry".into(),
1088 }),
1089 }
1090 }
1091
1092 fn cast_to_array(self, kind: &Kind) -> Result<Array, CastError> {
1094 self.cast_to::<Array>()?
1095 .into_iter()
1096 .enumerate()
1097 .map(|(i, value)| {
1098 value
1099 .cast_to_kind(kind)
1100 .with_element_of_at_index(i, || format!("array<{}>", kind.to_sql()))
1101 })
1102 .collect::<Result<Array, CastError>>()
1103 }
1104
1105 fn cast_to_array_len(self, kind: &Kind, len: u64) -> Result<Array, CastError> {
1107 let array = self.cast_to::<Array>()?;
1108
1109 if (array.len() as u64) != len {
1110 return Err(CastError::InvalidLength {
1111 len: array.len(),
1112 into: format!("array<{},{}>", kind.to_sql(), len),
1113 });
1114 }
1115
1116 array
1117 .into_iter()
1118 .enumerate()
1119 .map(|(i, value)| {
1120 value
1121 .cast_to_kind(kind)
1122 .with_element_of_at_index(i, || format!("array<{}>", kind.to_sql()))
1123 })
1124 .collect::<Result<Array, CastError>>()
1125 }
1126
1127 pub fn cast_to_set_type(self, kind: &Kind) -> Result<Set, CastError> {
1129 self.cast_to::<Array>()?
1130 .into_iter()
1131 .enumerate()
1132 .map(|(i, value)| {
1133 value
1134 .cast_to_kind(kind)
1135 .with_element_of_at_index(i, || format!("set<{}>", kind.to_sql()))
1136 })
1137 .collect::<Result<Set, CastError>>()
1138 }
1139
1140 pub fn cast_to_set_type_len(self, kind: &Kind, len: u64) -> Result<Set, CastError> {
1142 let set = self
1143 .cast_to::<Array>()?
1144 .into_iter()
1145 .enumerate()
1146 .map(|(i, value)| {
1147 value
1148 .cast_to_kind(kind)
1149 .with_element_of_at_index(i, || format!("set<{}>", kind.to_sql()))
1150 })
1151 .collect::<Result<Set, CastError>>()?;
1152
1153 if (set.len() as u64) != len {
1154 return Err(CastError::InvalidLength {
1155 len: set.len(),
1156 into: format!("set<{},{}>", kind.to_sql(), len),
1157 });
1158 }
1159
1160 Ok(set)
1161 }
1162
1163 pub fn cast_to_file_buckets(self, buckets: &[String]) -> Result<File, CastError> {
1164 let v = self.cast_to::<File>()?;
1165
1166 if v.is_bucket_type(buckets) {
1167 return Ok(v);
1168 }
1169
1170 let mut kind = "file<".to_owned();
1171 for (idx, t) in buckets.iter().enumerate() {
1172 if idx != 0 {
1173 kind.push('|');
1174 }
1175 kind.push_str(t.as_str())
1176 }
1177 kind.push('>');
1178 Err(CastError::InvalidKind {
1179 from: v.into(),
1180 into: kind,
1181 })
1182 }
1183}
1184
1185#[cfg(test)]
1186mod tests {
1187 use surrealdb_strand::Strand;
1188
1189 use super::*;
1190
1191 #[test]
1192 fn test_cast_to_table_generic() {
1193 let value = Value::String(Strand::new_static("users"));
1195 let kind = Kind::Table(vec![]);
1196 let result = value.cast_to_kind(&kind);
1197 assert!(result.is_ok());
1198 if let Ok(Value::Table(table)) = result {
1199 assert_eq!(table.as_str(), "users");
1200 } else {
1201 panic!("Expected Value::Table");
1202 }
1203 }
1204
1205 #[test]
1206 fn test_cast_to_table_specific() {
1207 let value = Value::String(Strand::new_static("users"));
1209 let kind = Kind::Table(vec!["users".into()]);
1210 let result = value.cast_to_kind(&kind);
1211 assert!(result.is_ok());
1212 if let Ok(Value::Table(table)) = result {
1213 assert_eq!(table.as_str(), "users");
1214 }
1215
1216 let value = Value::String(Strand::new_static("posts"));
1218 let kind = Kind::Table(vec!["users".into()]);
1219 let result = value.cast_to_kind(&kind);
1220 assert!(result.is_err());
1221 }
1222
1223 #[test]
1224 fn test_cast_to_table_union() {
1225 let value = Value::String(Strand::new_static("posts"));
1227 let kind = Kind::Table(vec!["users".into(), "posts".into()]);
1228 let result = value.cast_to_kind(&kind);
1229 assert!(result.is_ok());
1230 if let Ok(Value::Table(table)) = result {
1231 assert_eq!(table.as_str(), "posts");
1232 }
1233
1234 let value = Value::String(Strand::new_static("comments"));
1236 let kind = Kind::Table(vec!["users".into(), "posts".into()]);
1237 let result = value.cast_to_kind(&kind);
1238 assert!(result.is_err());
1239 }
1240
1241 #[test]
1242 fn test_cast_table_to_table() {
1243 let value = Value::Table(surrealdb_strand::TableName::new("users".to_string()));
1245 let kind = Kind::Table(vec!["users".into()]);
1246 let result = value.cast_to_kind(&kind);
1247 assert!(result.is_ok());
1248 }
1249
1250 #[test]
1251 fn test_can_cast_to_table() {
1252 let value = Value::String(Strand::new_static("users"));
1254 let kind = Kind::Table(vec![]);
1255 assert!(value.can_cast_to_kind(&kind));
1256
1257 let value = Value::Table(surrealdb_strand::TableName::new("users".to_string()));
1259 let kind = Kind::Table(vec!["users".into()]);
1260 assert!(value.can_cast_to_kind(&kind));
1261
1262 let value = Value::Table(surrealdb_strand::TableName::new("posts".to_string()));
1264 let kind = Kind::Table(vec!["users".into()]);
1265 assert!(!value.can_cast_to_kind(&kind));
1266 }
1267}