Skip to main content

surrealdb_expr/val/value/convert/
cast.rs

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	// Coercion error at the end.
24	InvalidKind {
25		from: Value,
26		into: String,
27	},
28	InvalidLength {
29		len: usize,
30		into: String,
31	},
32	/// Cast failed because element of type didn't match.
33	ElementOf {
34		inner: Box<CastError>,
35		into: String,
36		position: Option<ElementPosition>,
37	},
38	// Annoying error which doesn't fit in with the rest of the errors and breaks the trait
39	// pattern.
40	//
41	// Remove once the move to anyhow is complete.
42	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
113/// Trait for converting the value using casting rules, calling the functions on
114/// this trait results in similar behavior as casting does in surrealql like
115/// `<string> 1`.
116///
117/// Casting rules are more loose then coercing rules.
118pub trait Cast: Sized {
119	/// Returns true if calling cast on the value will succeed.
120	///
121	/// If `T::can_cast(&v)` returns `true` then `T::cast(v) should not return
122	/// an error.
123	fn can_cast(v: &Value) -> bool;
124
125	/// Cast a value to the self type.
126	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	/// Must agree with `cast`: a union kind casts to the first member
201	/// `can_cast` accepts and then requires `cast` to succeed.
202	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			// Allow any int number
213			Value::Number(Number::Int(x)) => Ok(x),
214			// A float or decimal casts only when it is a whole number within
215			// the `i64` range. Anything else is refused, never rounded or
216			// clamped to the nearest bound.
217			Value::Number(n) => n.as_int_lossless().ok_or_else(|| CastError::InvalidKind {
218				from: v,
219				into: "int".into(),
220			}),
221			// Attempt to convert a string value
222			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				// The Decimal can be parsed as a Float
253				Ok(v) => Ok(v),
254				// The Decimal loses precision
255				_ => Err(CastError::InvalidKind {
256					from: v,
257					into: "float".into(),
258				}),
259			},
260			// Attempt to convert a string value
261			Value::String(ref s) => match s.parse::<f64>() {
262				// The string can be parsed as a Float
263				Ok(v) => Ok(v),
264				// This string is not a float
265				_ => Err(CastError::InvalidKind {
266					from: v,
267					into: "float".into(),
268				}),
269			},
270			// Anything else raises an error
271			_ => 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			// Attempt to convert an int number
292			Value::Number(Number::Int(ref i)) => Ok(Decimal::from(*i)),
293			// Attempt to convert an float number
294			Value::Number(Number::Float(ref f)) => match Decimal::try_from(*f) {
295				// The Float can be represented as a Decimal
296				Ok(d) => Ok(d),
297				// This Float does not convert to a Decimal
298				_ => Err(CastError::InvalidKind {
299					from: v,
300					into: "decimal".into(),
301				}),
302			},
303			// Attempt to convert a string value
304			Value::String(ref s) => match Decimal::from_str_normalized(s) {
305				// The string can be parsed as a Decimal
306				Ok(v) => Ok(v),
307				// This string is not a Decimal
308				_ => Err(CastError::InvalidKind {
309					from: v,
310					into: "decimal".into(),
311				}),
312			},
313			// Anything else raises an error
314			_ => 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			// Anything else raises an error
339			_ => 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			// Datetimes are allowed
413			Value::Datetime(v) => Ok(v),
414			// Attempt to parse a string
415			Value::String(ref s) => Datetime::from_str(s).map_err(|_| CastError::InvalidKind {
416				from: v,
417				into: "datetime".into(),
418			}),
419			// Anything else raises an error
420			_ => 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			// Datetimes are allowed
440			Value::Duration(v) => Ok(v),
441			// Attempt to parse a string
442			Value::String(ref s) => Duration::from_str(s).map_err(|_| CastError::InvalidKind {
443				from: v,
444				into: "duration".into(),
445			}),
446			// Anything else raises an error
447			_ => 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
483// `TryFrom<Number> for u8` is intentionally not reused: it truncates fractional
484// floats (via `num_traits::ToPrimitive::to_u8`) instead of rejecting them, which
485// would reintroduce the truncation bug this helper is here to prevent.
486fn 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				// checked above
519				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				// Convert array to set, automatically deduplicating
548				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				// checked above
607				let beg = iter.next().expect("array length checked above");
608				// checked above
609				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				// checked above
653				let x = iter
654					.next()
655					.expect("array length checked above")
656					.cast_to::<f64>()
657					.expect("value type checked above");
658				// checked above
659				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
766// Types which directly match one enum variant or fail
767impl_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, // Strings can be cast to tables
871			_ => 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	/// Try to convert this value to the specified `Kind`
899	pub fn cast_to_kind(self, kind: &Kind) -> Result<Value, CastError> {
900		// Attempt to convert to the desired type
901		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	/// Try to convert this value to a Literal, returns a `Value` with the
965	/// coerced value
966	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	/// Try to convert this value to a Table of a certain type
978	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				// Check if the string is a valid table name and matches the allowed types
983				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	/// Try to convert this value to a Record of a certain type
1021	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	/// Try to convert this value to a `Geometry` of a certain type
1064	fn cast_to_geometry(self, val: &[GeometryKind]) -> Result<Geometry, CastError> {
1065		match self {
1066			// Geometries are allowed if correct type
1067			Value::Geometry(v) if self.is_geometry_type(val) => Ok(v),
1068			Value::Array(_) => {
1069				// An array of two numbers can be cast into a point
1070				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			// Anything else raises an error
1082			_ => Err(CastError::InvalidKind {
1083				from: self,
1084				into: "geometry".into(),
1085			}),
1086		}
1087	}
1088
1089	/// Try to convert this value to ab `Array` of a certain type
1090	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	/// Try to convert this value to ab `Array` of a certain type and length
1103	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	/// Try to convert this value to a `Set` of a certain type
1125	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	/// Try to convert this value to a `Set` of a certain type and length
1138	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		// Test casting string to generic table type
1191		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		// Test casting string to specific table type (matching)
1205		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		// Test casting string to specific table type (not matching)
1214		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		// Test casting string to union of table types
1223		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		// Test casting string that doesn't match any in the union
1232		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		// Test casting table value to table type
1241		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		// Test can_cast_to_kind for tables - String can always cast to generic table
1250		let value = Value::String(Strand::new_static("users"));
1251		let kind = Kind::Table(vec![]);
1252		assert!(value.can_cast_to_kind(&kind));
1253
1254		// Table value can cast to table type
1255		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		// Table value cannot cast to wrong table type
1260		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		// Negative zero is the integer zero
1278		assert_eq!(float(-0.0).cast_to::<i64>().unwrap(), 0);
1279		// 2^53: every smaller integer is also an f64
1280		assert_eq!(float(9_007_199_254_740_992.0).cast_to::<i64>().unwrap(), 9_007_199_254_740_992);
1281		// -2^63 is `i64::MIN`
1282		assert_eq!(float(i64::MIN as f64).cast_to::<i64>().unwrap(), i64::MIN);
1283		// The largest f64 below 2^63
1284		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			// 2^63: one past `i64::MAX`, which `i64::MAX as f64` also rounds up to
1291			2f64.powi(63),
1292			i64::MAX as f64,
1293			// The f64 below -2^63
1294			-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	/// Values of every shape that matter to an `int` cast: the bounds, the
1315	/// first value past each bound, fractions, the non-finite floats and
1316	/// strings.
1317	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			// A whole decimal carrying a trailing scale
1326			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		// A union kind casts to the first member `can_cast_to_kind` accepts
1361		// and treats a failure there as unreachable, so the two must never
1362		// disagree.
1363		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		// The alternatives that can hold the value are still reached
1378		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		// An in-range whole float is the first member's int
1387		assert!(matches!(float(5.0).cast_to_kind(&either).unwrap(), Value::Number(Number::Int(5))));
1388		// No alternative takes the value: an error, not a panic
1389		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}