Skip to main content

surrealdb_types/value/
mod.rs

1/// Array value types for SurrealDB
2pub mod array;
3/// Binary data value types for SurrealDB
4pub mod bytes;
5/// Datetime value types for SurrealDB
6pub mod datetime;
7/// Duration value types for SurrealDB
8pub mod duration;
9/// File reference value types for SurrealDB
10pub mod file;
11mod format;
12/// Geometric value types for SurrealDB
13pub mod geometry;
14/// JSON value types for SurrealDB
15pub mod into_json;
16/// Numeric value types for SurrealDB
17pub mod number;
18/// Object value types for SurrealDB
19pub mod object;
20/// Range value types for SurrealDB
21pub mod range;
22/// Record identifier value types for SurrealDB
23pub mod record_id;
24/// Regular expression value types for SurrealDB
25pub mod regex;
26/// Set value types for SurrealDB
27pub mod set;
28/// Table value types for SurrealDB
29pub mod table;
30/// UUID value types for SurrealDB
31pub mod uuid;
32
33use std::cmp::Ordering;
34use std::ops::Index;
35
36pub use rust_decimal::Decimal;
37use serde::{Deserialize, Serialize};
38
39pub use self::array::Array;
40pub use self::bytes::Bytes;
41pub use self::datetime::Datetime;
42pub use self::duration::Duration;
43pub use self::file::File;
44pub use self::geometry::Geometry;
45pub use self::number::Number;
46pub use self::object::Object;
47pub use self::range::Range;
48pub use self::record_id::{RecordId, RecordIdKey, RecordIdKeyRange};
49pub use self::regex::Regex;
50pub use self::set::Set;
51pub use self::table::Table;
52pub use self::uuid::Uuid;
53use crate::sql::{SqlFormat, ToSql};
54use crate::utils::escape::QuoteStr;
55use crate::{Kind, SurrealValue};
56
57/// Marker type for value conversions from Value::None
58///
59/// This type represents the absence of a value in SurrealDB.
60/// It is used as a marker type for type-safe conversions.
61#[derive(
62	Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize,
63)]
64#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
65pub struct SurrealNone;
66
67/// Marker type for value conversions from Value::Null
68///
69/// This type represents a null value in SurrealDB.
70/// It is used as a marker type for type-safe conversions.
71#[derive(
72	Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize,
73)]
74#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
75pub struct SurrealNull;
76
77/// Represents a value in SurrealDB
78///
79/// This enum contains all possible value types that can be stored in SurrealDB.
80/// Each variant corresponds to a different data type supported by the database.
81
82#[derive(Clone, Debug, Default, Hash, PartialEq, Serialize, Deserialize)]
83#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
84pub enum Value {
85	/// Represents the absence of a value
86	#[default]
87	None,
88	/// Represents a null value
89	Null,
90	/// A boolean value (true or false)
91	Bool(bool),
92	/// A numeric value (integer, float, or decimal)
93	Number(Number),
94	/// A string value
95	String(String),
96	/// Binary data
97	Bytes(Bytes),
98	/// A duration value representing a time span
99	Duration(Duration),
100	/// A datetime value representing a point in time
101	Datetime(Datetime),
102	/// A UUID value
103	Uuid(Uuid),
104	/// A geometric value (point, line, polygon, etc.)
105	Geometry(Geometry),
106	/// A table value
107	Table(Table),
108	/// A record identifier
109	RecordId(RecordId),
110	/// A file reference
111	File(File),
112	/// A range of values
113	Range(Box<Range>),
114	/// A regular expression
115	Regex(Regex),
116	/// An array of values
117	Array(Array),
118	/// An object containing key-value pairs
119	Object(Object),
120	/// A set of values
121	Set(Set),
122}
123
124impl Eq for Value {}
125
126impl PartialOrd for Value {
127	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
128		Some(self.cmp(other))
129	}
130}
131
132impl Ord for Value {
133	fn cmp(&self, other: &Self) -> Ordering {
134		match (self, other) {
135			// Same variant comparisons - delegate to inner type
136			(Value::None, Value::None) => Ordering::Equal,
137			(Value::Null, Value::Null) => Ordering::Equal,
138			(Value::Bool(a), Value::Bool(b)) => a.cmp(b),
139			(Value::Number(a), Value::Number(b)) => a.cmp(b),
140			(Value::String(a), Value::String(b)) => a.cmp(b),
141			(Value::Duration(a), Value::Duration(b)) => a.cmp(b),
142			(Value::Datetime(a), Value::Datetime(b)) => a.cmp(b),
143			(Value::Uuid(a), Value::Uuid(b)) => a.cmp(b),
144			(Value::Array(a), Value::Array(b)) => a.cmp(b),
145			(Value::Set(a), Value::Set(b)) => a.cmp(b),
146			(Value::Object(a), Value::Object(b)) => a.cmp(b),
147			(Value::Geometry(a), Value::Geometry(b)) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
148			(Value::Bytes(a), Value::Bytes(b)) => a.cmp(b),
149			(Value::Table(a), Value::Table(b)) => a.cmp(b),
150			(Value::RecordId(a), Value::RecordId(b)) => a.cmp(b),
151			(Value::File(a), Value::File(b)) => a.cmp(b),
152			(Value::Range(a), Value::Range(b)) => a.cmp(b),
153			(Value::Regex(a), Value::Regex(b)) => a.cmp(b),
154
155			// Different variant types - define a total order
156			// Order: None < Null < Bool < Number < String < Duration < Datetime < Uuid
157			//        < Array < Object < Geometry < Bytes < RecordId < File < Range < Regex
158			(Value::None, _) => Ordering::Less,
159			(_, Value::None) => Ordering::Greater,
160
161			(Value::Null, _) => Ordering::Less,
162			(_, Value::Null) => Ordering::Greater,
163
164			(
165				Value::Bool(_),
166				Value::Number(_)
167				| Value::String(_)
168				| Value::Duration(_)
169				| Value::Datetime(_)
170				| Value::Uuid(_)
171				| Value::Array(_)
172				| Value::Set(_)
173				| Value::Object(_)
174				| Value::Geometry(_)
175				| Value::Bytes(_)
176				| Value::Table(_)
177				| Value::RecordId(_)
178				| Value::File(_)
179				| Value::Range(_)
180				| Value::Regex(_),
181			) => Ordering::Less,
182			(
183				Value::Number(_)
184				| Value::String(_)
185				| Value::Duration(_)
186				| Value::Datetime(_)
187				| Value::Uuid(_)
188				| Value::Array(_)
189				| Value::Set(_)
190				| Value::Object(_)
191				| Value::Geometry(_)
192				| Value::Bytes(_)
193				| Value::Table(_)
194				| Value::RecordId(_)
195				| Value::File(_)
196				| Value::Range(_)
197				| Value::Regex(_),
198				Value::Bool(_),
199			) => Ordering::Greater,
200
201			(
202				Value::Number(_),
203				Value::String(_)
204				| Value::Duration(_)
205				| Value::Datetime(_)
206				| Value::Uuid(_)
207				| Value::Array(_)
208				| Value::Set(_)
209				| Value::Object(_)
210				| Value::Geometry(_)
211				| Value::Bytes(_)
212				| Value::Table(_)
213				| Value::RecordId(_)
214				| Value::File(_)
215				| Value::Range(_)
216				| Value::Regex(_),
217			) => Ordering::Less,
218			(
219				Value::String(_)
220				| Value::Duration(_)
221				| Value::Datetime(_)
222				| Value::Uuid(_)
223				| Value::Array(_)
224				| Value::Set(_)
225				| Value::Object(_)
226				| Value::Geometry(_)
227				| Value::Bytes(_)
228				| Value::Table(_)
229				| Value::RecordId(_)
230				| Value::File(_)
231				| Value::Range(_)
232				| Value::Regex(_),
233				Value::Number(_),
234			) => Ordering::Greater,
235
236			(
237				Value::String(_),
238				Value::Duration(_)
239				| Value::Datetime(_)
240				| Value::Uuid(_)
241				| Value::Array(_)
242				| Value::Set(_)
243				| Value::Object(_)
244				| Value::Geometry(_)
245				| Value::Bytes(_)
246				| Value::Table(_)
247				| Value::RecordId(_)
248				| Value::File(_)
249				| Value::Range(_)
250				| Value::Regex(_),
251			) => Ordering::Less,
252			(
253				Value::Duration(_)
254				| Value::Datetime(_)
255				| Value::Uuid(_)
256				| Value::Array(_)
257				| Value::Set(_)
258				| Value::Object(_)
259				| Value::Geometry(_)
260				| Value::Bytes(_)
261				| Value::Table(_)
262				| Value::RecordId(_)
263				| Value::File(_)
264				| Value::Range(_)
265				| Value::Regex(_),
266				Value::String(_),
267			) => Ordering::Greater,
268
269			(
270				Value::Duration(_),
271				Value::Datetime(_)
272				| Value::Uuid(_)
273				| Value::Array(_)
274				| Value::Set(_)
275				| Value::Object(_)
276				| Value::Geometry(_)
277				| Value::Bytes(_)
278				| Value::Table(_)
279				| Value::RecordId(_)
280				| Value::File(_)
281				| Value::Range(_)
282				| Value::Regex(_),
283			) => Ordering::Less,
284			(
285				Value::Datetime(_)
286				| Value::Uuid(_)
287				| Value::Array(_)
288				| Value::Set(_)
289				| Value::Object(_)
290				| Value::Geometry(_)
291				| Value::Bytes(_)
292				| Value::Table(_)
293				| Value::RecordId(_)
294				| Value::File(_)
295				| Value::Range(_)
296				| Value::Regex(_),
297				Value::Duration(_),
298			) => Ordering::Greater,
299
300			(
301				Value::Datetime(_),
302				Value::Uuid(_)
303				| Value::Array(_)
304				| Value::Set(_)
305				| Value::Object(_)
306				| Value::Geometry(_)
307				| Value::Bytes(_)
308				| Value::Table(_)
309				| Value::RecordId(_)
310				| Value::File(_)
311				| Value::Range(_)
312				| Value::Regex(_),
313			) => Ordering::Less,
314			(
315				Value::Uuid(_)
316				| Value::Array(_)
317				| Value::Set(_)
318				| Value::Object(_)
319				| Value::Geometry(_)
320				| Value::Bytes(_)
321				| Value::Table(_)
322				| Value::RecordId(_)
323				| Value::File(_)
324				| Value::Range(_)
325				| Value::Regex(_),
326				Value::Datetime(_),
327			) => Ordering::Greater,
328
329			(
330				Value::Uuid(_),
331				Value::Array(_)
332				| Value::Set(_)
333				| Value::Object(_)
334				| Value::Geometry(_)
335				| Value::Bytes(_)
336				| Value::Table(_)
337				| Value::RecordId(_)
338				| Value::File(_)
339				| Value::Range(_)
340				| Value::Regex(_),
341			) => Ordering::Less,
342			(
343				Value::Array(_)
344				| Value::Set(_)
345				| Value::Object(_)
346				| Value::Geometry(_)
347				| Value::Bytes(_)
348				| Value::Table(_)
349				| Value::RecordId(_)
350				| Value::File(_)
351				| Value::Range(_)
352				| Value::Regex(_),
353				Value::Uuid(_),
354			) => Ordering::Greater,
355
356			(
357				Value::Array(_),
358				Value::Object(_)
359				| Value::Geometry(_)
360				| Value::Bytes(_)
361				| Value::Table(_)
362				| Value::RecordId(_)
363				| Value::File(_)
364				| Value::Range(_)
365				| Value::Regex(_)
366				| Value::Set(_),
367			) => Ordering::Less,
368			(
369				Value::Object(_)
370				| Value::Geometry(_)
371				| Value::Bytes(_)
372				| Value::Table(_)
373				| Value::RecordId(_)
374				| Value::File(_)
375				| Value::Range(_)
376				| Value::Regex(_)
377				| Value::Set(_),
378				Value::Array(_),
379			) => Ordering::Greater,
380
381			(
382				Value::Set(_),
383				Value::Object(_)
384				| Value::Geometry(_)
385				| Value::Bytes(_)
386				| Value::Table(_)
387				| Value::RecordId(_)
388				| Value::File(_)
389				| Value::Range(_)
390				| Value::Regex(_),
391			) => Ordering::Less,
392			(
393				Value::Object(_)
394				| Value::Geometry(_)
395				| Value::Bytes(_)
396				| Value::Table(_)
397				| Value::RecordId(_)
398				| Value::File(_)
399				| Value::Range(_)
400				| Value::Regex(_),
401				Value::Set(_),
402			) => Ordering::Greater,
403
404			(
405				Value::Object(_),
406				Value::Geometry(_)
407				| Value::Bytes(_)
408				| Value::Table(_)
409				| Value::RecordId(_)
410				| Value::File(_)
411				| Value::Range(_)
412				| Value::Regex(_),
413			) => Ordering::Less,
414			(
415				Value::Geometry(_)
416				| Value::Bytes(_)
417				| Value::Table(_)
418				| Value::RecordId(_)
419				| Value::File(_)
420				| Value::Range(_)
421				| Value::Regex(_),
422				Value::Object(_),
423			) => Ordering::Greater,
424
425			(
426				Value::Geometry(_),
427				Value::Bytes(_)
428				| Value::Table(_)
429				| Value::RecordId(_)
430				| Value::File(_)
431				| Value::Range(_)
432				| Value::Regex(_),
433			) => Ordering::Less,
434			(
435				Value::Bytes(_)
436				| Value::Table(_)
437				| Value::RecordId(_)
438				| Value::File(_)
439				| Value::Range(_)
440				| Value::Regex(_),
441				Value::Geometry(_),
442			) => Ordering::Greater,
443
444			(
445				Value::Bytes(_),
446				Value::Table(_)
447				| Value::RecordId(_)
448				| Value::File(_)
449				| Value::Range(_)
450				| Value::Regex(_),
451			) => Ordering::Less,
452			(
453				Value::Table(_)
454				| Value::RecordId(_)
455				| Value::File(_)
456				| Value::Range(_)
457				| Value::Regex(_),
458				Value::Bytes(_),
459			) => Ordering::Greater,
460
461			(Value::Table(t), Value::RecordId(record_id)) => t.cmp(&record_id.table),
462			(Value::RecordId(record_id), Value::Table(t)) => record_id.table.cmp(t),
463
464			(Value::Table(_), Value::File(_) | Value::Range(_) | Value::Regex(_)) => Ordering::Less,
465			(Value::File(_) | Value::Range(_) | Value::Regex(_), Value::Table(_)) => {
466				Ordering::Greater
467			}
468
469			(Value::RecordId(_), Value::File(_) | Value::Range(_) | Value::Regex(_)) => {
470				Ordering::Less
471			}
472			(Value::File(_) | Value::Range(_) | Value::Regex(_), Value::RecordId(_)) => {
473				Ordering::Greater
474			}
475
476			(Value::File(_), Value::Range(_) | Value::Regex(_)) => Ordering::Less,
477			(Value::Range(_) | Value::Regex(_), Value::File(_)) => Ordering::Greater,
478
479			(Value::Range(_), Value::Regex(_)) => Ordering::Less,
480			(Value::Regex(_), Value::Range(_)) => Ordering::Greater,
481		}
482	}
483}
484
485impl Value {
486	/// Returns the kind of this value
487	///
488	/// This method maps each value variant to its corresponding `Kind`.
489	pub fn kind(&self) -> Kind {
490		match self {
491			Value::None => Kind::None,
492			Value::Null => Kind::Null,
493			Value::Bool(_) => Kind::Bool,
494			Value::Number(_) => Kind::Number,
495			Value::String(_) => Kind::String,
496			Value::Duration(_) => Kind::Duration,
497			Value::Datetime(_) => Kind::Datetime,
498			Value::Uuid(_) => Kind::Uuid,
499			Value::Array(_) => Kind::Array(Box::new(Kind::Any), None),
500			Value::Set(_) => Kind::Set(Box::new(Kind::Any), None),
501			Value::Object(_) => Kind::Object,
502			Value::Geometry(_) => Kind::Geometry(Vec::new()),
503			Value::Bytes(_) => Kind::Bytes,
504			Value::Table(_) => Kind::Table(Vec::new()),
505			Value::RecordId(_) => Kind::Record(Vec::new()),
506			Value::File(_) => Kind::File(Vec::new()),
507			Value::Range(_) => Kind::Range,
508			Value::Regex(_) => Kind::Regex,
509		}
510	}
511
512	/// Returns the first value in the array.
513	///
514	/// Returns `None` if the value is not an array or the array is empty.
515	pub fn first(&self) -> Option<Value> {
516		match self {
517			Value::Array(arr) => arr.first().cloned(),
518			_ => None,
519		}
520	}
521
522	/// Check if this Value is NONE or NULL
523	pub fn is_nullish(&self) -> bool {
524		matches!(self, Value::None | Value::Null)
525	}
526
527	/// Check if this Value is empty.
528	pub fn is_empty(&self) -> bool {
529		match self {
530			Value::None => true,
531			Value::Null => true,
532			Value::String(s) => s.is_empty(),
533			Value::Bytes(b) => b.is_empty(),
534			Value::Object(obj) => obj.is_empty(),
535			Value::Array(arr) => arr.is_empty(),
536			Value::Set(set) => set.is_empty(),
537			_ => false,
538		}
539	}
540
541	/// Accesses the value found at a certain field
542	/// if an object, and a certain index if an array.
543	/// Will not err if no value is found at this point,
544	/// instead returning a Value::None. If an Option<&Value>
545	/// is desired, the .into_option() method can be used
546	/// to perform the conversion.
547	pub fn get<Idx>(&self, index: Idx) -> &Value
548	where
549		Value: Indexable<Idx>,
550	{
551		Indexable::get(self, index)
552	}
553
554	/// Removes the value at the given index.
555	///
556	/// Returns `Some(Value)` if the value was removed, `None` if the value was not found.
557	pub fn remove<Idx>(&mut self, index: Idx) -> Value
558	where
559		Value: Indexable<Idx>,
560	{
561		Indexable::remove(self, index)
562	}
563
564	/// Checks if this value is of the specified type
565	///
566	/// Returns `true` if the value can be converted to the given type `T`.
567	pub fn is<T: SurrealValue>(&self) -> bool {
568		T::is_value(self)
569	}
570
571	/// Converts this value to the specified type
572	///
573	/// Returns `Ok(T)` if the conversion is successful, `Err(Error)` otherwise.
574	pub fn into_t<T: SurrealValue>(self) -> Result<T, crate::Error> {
575		T::from_value(self)
576	}
577
578	/// Creates a value from the specified type
579	///
580	/// Converts the given value of type `T` into a `Value`.
581	pub fn from_t<T: SurrealValue>(value: T) -> Value {
582		value.into_value()
583	}
584
585	/// Check if this value matches the specified kind
586	///
587	/// Returns `true` if the value conforms to the given kind specification.
588	/// This includes checking nested types for arrays, objects, records, etc.
589	pub fn is_kind(&self, kind: &Kind) -> bool {
590		match kind {
591			Kind::Any => true,
592			Kind::None => self.is_none(),
593			Kind::Null => self.is_null(),
594			Kind::Bool => self.is_bool(),
595			Kind::Bytes => self.is_bytes(),
596			Kind::Datetime => self.is_datetime(),
597			Kind::Decimal => self.is_decimal(),
598			Kind::Duration => self.is_duration(),
599			Kind::Float => self.is_float(),
600			Kind::Int => self.is_int(),
601			Kind::Number => self.is_number(),
602			Kind::Object => self.is_object(),
603			Kind::String => self.is_string(),
604			Kind::Uuid => self.is_uuid(),
605			Kind::Regex => matches!(self, Value::Regex(_)),
606			Kind::Table(table) => self.is_table_and(|t| table.is_empty() || table.contains(t)),
607			Kind::Record(table) => self.is_record_and(|r| r.is_table_type(table)),
608			Kind::Geometry(kinds) => {
609				self.is_geometry_and(|g| kinds.is_empty() || kinds.contains(&g.kind()))
610			}
611			Kind::Either(kinds) => kinds.iter().any(|k| self.is_kind(k)),
612			Kind::Set(kind, max) => {
613				self.is_set_and(|set| {
614					// Check max length if specified
615					if let Some(max_len) = max
616						&& set.len() > *max_len as usize
617					{
618						return false;
619					}
620					// Check all elements match the kind
621					set.iter().all(|v| v.is_kind(kind))
622				})
623			}
624			Kind::Array(kind, max) => {
625				self.is_array_and(|arr| {
626					// Check max length if specified
627					if let Some(max_len) = max
628						&& arr.len() > *max_len as usize
629					{
630						return false;
631					}
632					// Check all elements match the kind
633					arr.iter().all(|v| v.is_kind(kind))
634				})
635			}
636			Kind::Range => self.is_range(),
637			Kind::Literal(literal) => literal.matches(self),
638			Kind::File(bucket) => {
639				self.is_file_and(|f| bucket.is_empty() || bucket.contains(&f.bucket().to_string()))
640			}
641			Kind::Function(_, _) => {
642				// Functions are not a value type
643				false
644			}
645		}
646	}
647}
648
649impl Index<usize> for Value {
650	type Output = Self;
651
652	fn index(&self, index: usize) -> &Self::Output {
653		match &self {
654			Value::Array(map) => map.0.get(index).unwrap_or(&Value::None),
655			_ => &Value::None,
656		}
657	}
658}
659
660impl Index<&str> for Value {
661	type Output = Self;
662
663	fn index(&self, index: &str) -> &Self::Output {
664		match &self {
665			Value::Object(map) => map.0.get(index).unwrap_or(&Value::None),
666			_ => &Value::None,
667		}
668	}
669}
670
671impl PartialEq<&Value> for Value {
672	fn eq(&self, other: &&Value) -> bool {
673		self == *other
674	}
675}
676
677impl PartialEq<Value> for &Value {
678	fn eq(&self, other: &Value) -> bool {
679		**self == *other
680	}
681}
682
683/// Trait for values that can be indexed
684pub trait Indexable<Idx> {
685	/// Get the value at the given index.
686	fn get(&self, index: Idx) -> &Value;
687	/// Remove the value at the given index.
688	fn remove(&mut self, index: Idx) -> Value;
689}
690
691impl Indexable<usize> for Value {
692	fn get(&self, index: usize) -> &Value {
693		match self {
694			Value::Array(arr) => arr.index(index),
695			_ => &Value::None,
696		}
697	}
698	fn remove(&mut self, index: usize) -> Value {
699		match self {
700			Value::Array(arr) => arr.remove(index),
701			_ => Value::None,
702		}
703	}
704}
705
706impl Indexable<&str> for Value {
707	fn get(&self, index: &str) -> &Value {
708		match self {
709			Value::Object(obj) => match obj.get(index) {
710				Some(v) => v,
711				None => &Value::None,
712			},
713			_ => &Value::None,
714		}
715	}
716
717	fn remove(&mut self, index: &str) -> Value {
718		match self {
719			Value::Object(obj) => match obj.remove(index) {
720				Some(v) => v,
721				None => Value::None,
722			},
723			_ => Value::None,
724		}
725	}
726}
727
728impl FromIterator<Value> for Value {
729	fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
730		Value::Array(Array::from_iter(iter))
731	}
732}
733
734impl From<Object> for Value {
735	fn from(o: Object) -> Self {
736		Value::Object(o)
737	}
738}
739
740impl ToSql for Value {
741	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
742		match self {
743			Value::None => f.push_str("NONE"),
744			Value::Null => f.push_str("NULL"),
745			Value::Bool(v) => v.fmt_sql(f, fmt),
746			Value::Number(v) => v.fmt_sql(f, fmt),
747			Value::String(v) => {
748				QuoteStr(v.as_str()).fmt_sql(f, fmt);
749			}
750			Value::Duration(v) => v.fmt_sql(f, fmt),
751			Value::Datetime(v) => v.fmt_sql(f, fmt),
752			Value::Uuid(v) => v.fmt_sql(f, fmt),
753			Value::Array(v) => v.fmt_sql(f, fmt),
754			Value::Object(v) => v.fmt_sql(f, fmt),
755			Value::Geometry(v) => v.fmt_sql(f, fmt),
756			Value::Bytes(v) => v.fmt_sql(f, fmt),
757			Value::Table(v) => v.fmt_sql(f, fmt),
758			Value::RecordId(v) => v.fmt_sql(f, fmt),
759			Value::File(v) => v.fmt_sql(f, fmt),
760			Value::Range(v) => v.fmt_sql(f, fmt),
761			Value::Regex(v) => v.fmt_sql(f, fmt),
762			Value::Set(v) => v.fmt_sql(f, fmt),
763		}
764	}
765}
766
767#[cfg(test)]
768mod tests {
769	use std::collections::BTreeMap;
770
771	use rstest::rstest;
772
773	use super::*;
774	use crate::{GeometryKind, Kind, KindLiteral, object};
775
776	#[rstest]
777	#[case::none(Value::None, true)]
778	#[case::null(Value::Null, true)]
779	#[case::string(Value::String("".to_string()), true)]
780	#[case::string(Value::String("hello".to_string()), false)]
781	#[case::bytes(Value::Bytes(Bytes::default()), true)]
782	#[case::bytes(Value::Bytes(Bytes::from(::bytes::Bytes::from(vec![1_u8, 2, 3]))), false)]
783	#[case::object(Value::Object(Object::default()), true)]
784	#[case::object(Value::Object(Object::from_iter([("key".to_string(), Value::String("value".to_string()))])), false)]
785	#[case::array(Value::Array(Array::new()), true)]
786	#[case::array(Value::Array(Array::from(vec![Value::String("hello".to_string())])), false)]
787	#[case::geometry(Value::Geometry(Geometry::Point(geo::Point::new(1.0, 2.0))), false)]
788	#[case::record_id(Value::RecordId(RecordId::new("test", "key")), false)]
789	#[case::file(Value::File(File::default()), false)]
790	#[case::range(Value::Range(Box::new(Range::unbounded())), false)]
791	#[case::regex(Value::Regex("hello".parse().unwrap()), false)]
792	#[case::duration(Value::Duration(Duration::new(1, 0)), false)]
793	#[case::datetime(Value::Datetime(Datetime::from_timestamp(1, 0).unwrap()), false)]
794	#[case::uuid(Value::Uuid(Uuid::new_v4()), false)]
795	#[case::bool(Value::Bool(true), false)]
796	#[case::bool(Value::Bool(false), false)]
797	#[case::number(Value::Number(Number::Int(1)), false)]
798	#[case::number(Value::Number(Number::Float(1.0)), false)]
799	#[case::number(Value::Number(Number::Decimal(Decimal::new(1, 0))), false)]
800	fn test_is_empty(#[case] value: Value, #[case] expected: bool) {
801		assert_eq!(value.is_empty(), expected);
802	}
803
804	// Test ordering between same variants
805	#[rstest]
806	#[case::none_eq_none(Value::None, Value::None, Ordering::Equal)]
807	#[case::null_eq_null(Value::Null, Value::Null, Ordering::Equal)]
808	#[case::bool_false_lt_true(Value::Bool(false), Value::Bool(true), Ordering::Less)]
809	#[case::bool_true_gt_false(Value::Bool(true), Value::Bool(false), Ordering::Greater)]
810	#[case::bool_true_eq_true(Value::Bool(true), Value::Bool(true), Ordering::Equal)]
811	#[case::string_a_lt_b(Value::String("a".to_string()), Value::String("b".to_string()), Ordering::Less)]
812	#[case::string_b_gt_a(Value::String("b".to_string()), Value::String("a".to_string()), Ordering::Greater)]
813	#[case::string_a_eq_a(Value::String("a".to_string()), Value::String("a".to_string()), Ordering::Equal)]
814	fn test_value_ordering_same_variant(
815		#[case] left: Value,
816		#[case] right: Value,
817		#[case] expected: Ordering,
818	) {
819		assert_eq!(left.cmp(&right), expected);
820		assert_eq!(left.partial_cmp(&right), Some(expected));
821	}
822
823	// Test ordering between numbers (cross-type numeric comparisons)
824	#[rstest]
825	#[case::int_0_lt_int_1(
826		Value::Number(Number::Int(0)),
827		Value::Number(Number::Int(1)),
828		Ordering::Less
829	)]
830	#[case::int_1_gt_int_0(
831		Value::Number(Number::Int(1)),
832		Value::Number(Number::Int(0)),
833		Ordering::Greater
834	)]
835	#[case::int_5_eq_int_5(
836		Value::Number(Number::Int(5)),
837		Value::Number(Number::Int(5)),
838		Ordering::Equal
839	)]
840	#[case::float_0_lt_float_1(
841		Value::Number(Number::Float(0.0)),
842		Value::Number(Number::Float(1.0)),
843		Ordering::Less
844	)]
845	#[case::int_5_lt_float_5_5(
846		Value::Number(Number::Int(5)),
847		Value::Number(Number::Float(5.5)),
848		Ordering::Less
849	)]
850	#[case::int_5_eq_float_5(
851		Value::Number(Number::Int(5)),
852		Value::Number(Number::Float(5.0)),
853		Ordering::Equal
854	)]
855	#[case::float_5_eq_int_5(
856		Value::Number(Number::Float(5.0)),
857		Value::Number(Number::Int(5)),
858		Ordering::Equal
859	)]
860	#[case::int_10_gt_float_9_9(
861		Value::Number(Number::Int(10)),
862		Value::Number(Number::Float(9.9)),
863		Ordering::Greater
864	)]
865	#[case::decimal_5_eq_int_5(
866		Value::Number(Number::Decimal(Decimal::new(5, 0))),
867		Value::Number(Number::Int(5)),
868		Ordering::Equal
869	)]
870	#[case::int_5_eq_decimal_5(
871		Value::Number(Number::Int(5)),
872		Value::Number(Number::Decimal(Decimal::new(5, 0))),
873		Ordering::Equal
874	)]
875	#[case::decimal_5_5_gt_int_5(
876		Value::Number(Number::Decimal(Decimal::new(55, 1))), // 5.5
877		Value::Number(Number::Int(5)),
878		Ordering::Greater
879	)]
880	fn test_value_ordering_numbers(
881		#[case] left: Value,
882		#[case] right: Value,
883		#[case] expected: Ordering,
884	) {
885		assert_eq!(left.cmp(&right), expected);
886		assert_eq!(left.partial_cmp(&right), Some(expected));
887	}
888
889	// Test ordering between different variant types
890	// Order: None < Null < Bool < Number < String < Duration < Datetime < Uuid
891	//        < Array < Object < Geometry < Bytes < RecordId < File < Range < Regex
892	#[rstest]
893	#[case::none_lt_null(Value::None, Value::Null, Ordering::Less)]
894	#[case::null_gt_none(Value::Null, Value::None, Ordering::Greater)]
895	#[case::null_lt_bool(Value::Null, Value::Bool(false), Ordering::Less)]
896	#[case::bool_gt_null(Value::Bool(true), Value::Null, Ordering::Greater)]
897	#[case::bool_lt_number(Value::Bool(true), Value::Number(Number::Int(0)), Ordering::Less)]
898	#[case::number_gt_bool(Value::Number(Number::Int(100)), Value::Bool(true), Ordering::Greater)]
899	#[case::number_lt_string(
900		Value::Number(Number::Int(100)),
901		Value::String("a".to_string()),
902		Ordering::Less
903	)]
904	#[case::string_gt_number(
905		Value::String("a".to_string()),
906		Value::Number(Number::Int(100)),
907		Ordering::Greater
908	)]
909	#[case::string_lt_duration(
910		Value::String("z".to_string()),
911		Value::Duration(Duration::new(1, 0)),
912		Ordering::Less
913	)]
914	#[case::duration_gt_string(
915		Value::Duration(Duration::new(1, 0)),
916		Value::String("z".to_string()),
917		Ordering::Greater
918	)]
919	#[case::duration_lt_datetime(
920		Value::Duration(Duration::new(100, 0)),
921		Value::Datetime(Datetime::from_timestamp(1, 0).unwrap()),
922		Ordering::Less
923	)]
924	#[case::datetime_gt_duration(
925		Value::Datetime(Datetime::from_timestamp(1, 0).unwrap()),
926		Value::Duration(Duration::new(100, 0)),
927		Ordering::Greater
928	)]
929	#[case::datetime_lt_uuid(
930		Value::Datetime(Datetime::from_timestamp(1000000, 0).unwrap()),
931		Value::Uuid(Uuid::new_v4()),
932		Ordering::Less
933	)]
934	#[case::uuid_gt_datetime(
935		Value::Uuid(Uuid::new_v4()),
936		Value::Datetime(Datetime::from_timestamp(1000000, 0).unwrap()),
937		Ordering::Greater
938	)]
939	#[case::uuid_lt_array(Value::Uuid(Uuid::new_v4()), Value::Array(Array::new()), Ordering::Less)]
940	#[case::array_gt_uuid(
941		Value::Array(Array::new()),
942		Value::Uuid(Uuid::new_v4()),
943		Ordering::Greater
944	)]
945	#[case::array_lt_object(
946		Value::Array(Array::new()),
947		Value::Object(Object::default()),
948		Ordering::Less
949	)]
950	#[case::object_gt_array(
951		Value::Object(Object::default()),
952		Value::Array(Array::new()),
953		Ordering::Greater
954	)]
955	#[case::object_lt_geometry(
956		Value::Object(Object::default()),
957		Value::Geometry(Geometry::Point(geo::Point::new(1.0, 2.0))),
958		Ordering::Less
959	)]
960	#[case::geometry_gt_object(
961		Value::Geometry(Geometry::Point(geo::Point::new(1.0, 2.0))),
962		Value::Object(Object::default()),
963		Ordering::Greater
964	)]
965	#[case::geometry_lt_bytes(
966		Value::Geometry(Geometry::Point(geo::Point::new(1.0, 2.0))),
967		Value::Bytes(Bytes::default()),
968		Ordering::Less
969	)]
970	#[case::bytes_gt_geometry(
971		Value::Bytes(Bytes::default()),
972		Value::Geometry(Geometry::Point(geo::Point::new(1.0, 2.0))),
973		Ordering::Greater
974	)]
975	#[case::bytes_lt_record(
976		Value::Bytes(Bytes::default()),
977		Value::RecordId(RecordId::new("test", "key")),
978		Ordering::Less
979	)]
980	#[case::record_gt_bytes(
981		Value::RecordId(RecordId::new("test", "key")),
982		Value::Bytes(Bytes::default()),
983		Ordering::Greater
984	)]
985	#[case::record_lt_file(
986		Value::RecordId(RecordId::new("test", "key")),
987		Value::File(File::default()),
988		Ordering::Less
989	)]
990	#[case::file_gt_record(
991		Value::File(File::default()),
992		Value::RecordId(RecordId::new("test", "key")),
993		Ordering::Greater
994	)]
995	#[case::file_lt_range(
996		Value::File(File::default()),
997		Value::Range(Box::new(Range::unbounded())),
998		Ordering::Less
999	)]
1000	#[case::range_gt_file(
1001		Value::Range(Box::new(Range::unbounded())),
1002		Value::File(File::default()),
1003		Ordering::Greater
1004	)]
1005	#[case::range_lt_regex(
1006		Value::Range(Box::new(Range::unbounded())),
1007		Value::Regex("test".parse().unwrap()),
1008		Ordering::Less
1009	)]
1010	#[case::regex_gt_range(
1011		Value::Regex("test".parse().unwrap()),
1012		Value::Range(Box::new(Range::unbounded())),
1013		Ordering::Greater
1014	)]
1015	fn test_value_ordering_cross_variant(
1016		#[case] left: Value,
1017		#[case] right: Value,
1018		#[case] expected: Ordering,
1019	) {
1020		assert_eq!(left.cmp(&right), expected);
1021		assert_eq!(left.partial_cmp(&right), Some(expected));
1022	}
1023
1024	// Test equality with cross-type numeric comparisons
1025	#[rstest]
1026	#[case::int_eq_float(Value::Number(Number::Int(5)), Value::Number(Number::Float(5.0)))]
1027	#[case::float_eq_int(Value::Number(Number::Float(5.0)), Value::Number(Number::Int(5)))]
1028	#[case::int_eq_decimal(
1029		Value::Number(Number::Int(5)),
1030		Value::Number(Number::Decimal(Decimal::new(5, 0)))
1031	)]
1032	#[case::decimal_eq_int(
1033		Value::Number(Number::Decimal(Decimal::new(5, 0))),
1034		Value::Number(Number::Int(5))
1035	)]
1036	#[case::none_eq_none(Value::None, Value::None)]
1037	#[case::null_eq_null(Value::Null, Value::Null)]
1038	fn test_value_equality(#[case] left: Value, #[case] right: Value) {
1039		assert_eq!(left, right);
1040		assert_eq!(right, left);
1041		assert_eq!(left.cmp(&right), Ordering::Equal);
1042	}
1043
1044	// Test inequality
1045	#[rstest]
1046	#[case::none_ne_null(Value::None, Value::Null)]
1047	#[case::int_ne_float(Value::Number(Number::Int(5)), Value::Number(Number::Float(5.5)))]
1048	#[case::bool_ne_number(Value::Bool(true), Value::Number(Number::Int(1)))]
1049	#[case::string_ne_number(Value::String("5".to_string()), Value::Number(Number::Int(5)))]
1050	fn test_value_inequality(#[case] left: Value, #[case] right: Value) {
1051		assert_ne!(left, right);
1052		assert_ne!(right, left);
1053		assert_ne!(left.cmp(&right), Ordering::Equal);
1054	}
1055
1056	// Test that sorting works correctly
1057	#[test]
1058	fn test_value_sorting() {
1059		let mut values = vec![
1060			Value::String("b".to_string()),
1061			Value::None,
1062			Value::Number(Number::Int(10)),
1063			Value::Null,
1064			Value::Bool(true),
1065			Value::Number(Number::Int(5)),
1066			Value::String("a".to_string()),
1067			Value::Bool(false),
1068			Value::Number(Number::Float(7.5)),
1069			Value::Table("test".into()),
1070			Value::RecordId(RecordId::new("test", "key")),
1071		];
1072
1073		values.sort();
1074
1075		assert_eq!(values[0], Value::None);
1076		assert_eq!(values[1], Value::Null);
1077		assert_eq!(values[2], Value::Bool(false));
1078		assert_eq!(values[3], Value::Bool(true));
1079		assert_eq!(values[4], Value::Number(Number::Int(5)));
1080		assert_eq!(values[5], Value::Number(Number::Float(7.5)));
1081		assert_eq!(values[6], Value::Number(Number::Int(10)));
1082		assert_eq!(values[7], Value::String("a".to_string()));
1083		assert_eq!(values[8], Value::String("b".to_string()));
1084	}
1085
1086	#[rstest]
1087	// None and Null
1088	#[case::none(Value::None, "NONE")]
1089	#[case::null(Value::Null, "NULL")]
1090	// Booleans
1091	#[case::bool(Value::Bool(true), "true")]
1092	#[case::bool(Value::Bool(false), "false")]
1093	// Numbers - integers
1094	#[case::number(Value::Number(Number::Int(0)), "0")]
1095	#[case::number(Value::Number(Number::Int(5)), "5")]
1096	#[case::number(Value::Number(Number::Int(-5)), "-5")]
1097	#[case::number(Value::Number(Number::Int(i64::MAX)), "9223372036854775807")]
1098	#[case::number(Value::Number(Number::Int(i64::MIN)), "-9223372036854775808")]
1099	// Numbers - floats
1100	#[case::number(Value::Number(Number::Float(0.0)), "0f")]
1101	#[case::number(Value::Number(Number::Float(5.0)), "5f")]
1102	#[case::number(Value::Number(Number::Float(-5.5)), "-5.5f")]
1103	#[case::number(Value::Number(Number::Float(3.12345)), "3.12345f")]
1104	// Numbers - decimals
1105	#[case::number(Value::Number(Number::Decimal(Decimal::new(0, 0))), "0dec")]
1106	#[case::number(Value::Number(Number::Decimal(Decimal::new(5, 0))), "5dec")]
1107	#[case::number(Value::Number(Number::Decimal(Decimal::new(-5, 0))), "-5dec")]
1108	#[case::number(Value::Number(Number::Decimal(Decimal::new(12345, 2))), "123.45dec")]
1109	// Strings - basic
1110	#[case::string(Value::String("".to_string()), "''")]
1111	#[case::string(Value::String("hello".to_string()), "'hello'")]
1112	#[case::string(Value::String("hello world".to_string()), "'hello world'")]
1113	// Strings - escaping
1114	#[case::string(Value::String("escap'd".to_string()), "\"escap'd\"")]
1115	#[case::string(Value::String("\"escaped\"".to_string()), "'\"escaped\"'")]
1116	#[case::string(Value::String("mix'd \"quotes\"".to_string()), "\"mix'd \\\"quotes\\\"\"")]
1117	#[case::string(Value::String("tab\there".to_string()), "'tab\\there'")]
1118	#[case::string(Value::String("new\nline".to_string()), "'new\\nline'")]
1119	// Strings - unicode
1120	#[case::string(Value::String("你好".to_string()), "'你好'")]
1121	#[case::string(Value::String("emoji 🎉".to_string()), "'emoji 🎉'")]
1122	// Durations
1123	#[case::duration(Value::Duration(Duration::new(0, 0)), "0ns")]
1124	#[case::duration(Value::Duration(Duration::new(1, 0)), "1s")]
1125	#[case::duration(Value::Duration(Duration::new(60, 0)), "1m")]
1126	#[case::duration(Value::Duration(Duration::new(3600, 0)), "1h")]
1127	#[case::duration(Value::Duration(Duration::new(90, 0)), "1m30s")]
1128	// Datetimes
1129	#[case::datetime(Value::Datetime(Datetime::from_timestamp(0, 0).unwrap()), "d'1970-01-01T00:00:00Z'")]
1130	#[case::datetime(Value::Datetime(Datetime::from_timestamp(1, 0).unwrap()), "d'1970-01-01T00:00:01Z'")]
1131	#[case::datetime(Value::Datetime(Datetime::from_timestamp(1234567890, 0).unwrap()), "d'2009-02-13T23:31:30Z'")]
1132	// UUIDs
1133	#[case::uuid(Value::Uuid(Uuid::nil()), "u'00000000-0000-0000-0000-000000000000'")]
1134	// Arrays - basic
1135	#[case::array(Value::Array(Array::new()), "[]")]
1136	#[case::array(Value::Array(vec![Value::Number(Number::Int(1))].into()), "[1]")]
1137	#[case::array(Value::Array(vec![Value::Number(Number::Int(1)), Value::Number(Number::Int(2)), Value::Number(Number::Int(3))].into()), "[1, 2, 3]")]
1138	// Arrays - mixed types
1139	#[case::array(Value::Array(vec![Value::String("hello".to_string()), Value::Number(Number::Int(42)), Value::Bool(true)].into()), "['hello', 42, true]")]
1140	// Arrays - nested
1141	#[case::array(Value::Array(vec![Value::Array(vec![Value::Number(Number::Int(1))].into())].into()), "[[1]]")]
1142	#[case::array(Value::Array(vec![Value::Array(vec![Value::Number(Number::Int(1)), Value::Number(Number::Int(2))].into()), Value::Array(vec![Value::Number(Number::Int(3))].into())].into()), "[[1, 2], [3]]")]
1143	// Objects - basic
1144	#[case::object(Value::Object(Object::default()), "{  }")]
1145	#[case::object(Value::Object(object! {
1146		"hello": "world".to_string(),
1147	}), "{ hello: 'world' }")]
1148	// Objects - multiple keys
1149	#[case::object(Value::Object(object! {
1150		"name": "John".to_string(),
1151		"age": 30,
1152	}), "{ age: 30, name: 'John' }")]
1153	// Objects - nested
1154	#[case::object(Value::Object(object! {
1155		"user": object! {
1156			"name": "Jane".to_string(),
1157		}
1158	}), "{ user: { name: 'Jane' } }")]
1159	// Objects - arrays in objects
1160	#[case::object(Value::Object(object! {
1161		"items": vec![Value::Number(Number::Int(1)), Value::Number(Number::Int(2))],
1162	}), "{ items: [1, 2] }")]
1163	// Geometry
1164	#[case::geometry(Value::Geometry(Geometry::Point(geo::Point::new(0.0, 0.0))), "(0f, 0f)")]
1165	#[case::geometry(Value::Geometry(Geometry::Point(geo::Point::new(1.0, 2.0))), "(1f, 2f)")]
1166	#[case::geometry(Value::Geometry(Geometry::Point(geo::Point::new(-123.45, 67.89))), "(-123.45f, 67.89f)")]
1167	// Bytes
1168	#[case::bytes(Value::Bytes(Bytes::default()), "b\"\"")]
1169	#[case::bytes(Value::Bytes(Bytes::from(::bytes::Bytes::from(vec![1_u8, 2, 3]))), "b\"010203\"")]
1170	#[case::bytes(Value::Bytes(Bytes::from(::bytes::Bytes::from(vec![255_u8, 0, 128]))), "b\"FF0080\"")]
1171	// Tables
1172	#[case::table(Value::Table("test".into()), "test")]
1173	#[case::table(Value::Table("escap'd".into()), "`escap'd`")]
1174	// Record IDs
1175	#[case::record_id(Value::RecordId(RecordId::new("test", "key")), "test:key")]
1176	#[case::record_id(Value::RecordId(RecordId::new("user", 123)), "user:123")]
1177	#[case::record_id(Value::RecordId(RecordId::new("table", "complex_id")), "table:complex_id")]
1178	// Ranges
1179	#[case::range(Value::Range(Box::new(Range::unbounded())), "..")]
1180	#[case::range(
1181		Value::Range(Box::new(Range::new(
1182			std::ops::Bound::Included(Value::Number(Number::Int(1))),
1183			std::ops::Bound::Excluded(Value::Number(Number::Int(10)))
1184		))),
1185		"1..10"
1186	)]
1187	#[case::range(
1188		Value::Range(Box::new(Range::new(
1189			std::ops::Bound::Included(Value::Number(Number::Int(0))),
1190			std::ops::Bound::Included(Value::Number(Number::Int(100)))
1191		))),
1192		"0..=100"
1193	)]
1194	#[case::range(
1195		Value::Range(Box::new(Range::new(
1196			std::ops::Bound::Unbounded,
1197			std::ops::Bound::Excluded(Value::Number(Number::Int(50)))
1198		))),
1199		"..50"
1200	)]
1201	#[case::range(
1202		Value::Range(Box::new(Range::new(
1203			std::ops::Bound::Included(Value::Number(Number::Int(10))),
1204			std::ops::Bound::Unbounded
1205		))),
1206		"10.."
1207	)]
1208	// Regex
1209	#[case::regex(Value::Regex("hello".parse().unwrap()), "/hello/")]
1210	#[case::regex(Value::Regex("[a-z]+".parse().unwrap()), "/[a-z]+/")]
1211	#[case::regex(Value::Regex("^test$".parse().unwrap()), "/^test$/")]
1212	fn test_to_sql(#[case] value: Value, #[case] expected_sql: &str) {
1213		assert_eq!(&value.to_sql(), expected_sql);
1214	}
1215
1216	#[rstest]
1217	#[case::none(Value::None, vec![Kind::None, Kind::Any], vec![Kind::Null])]
1218	#[case::null(Value::Null, vec![Kind::Null, Kind::Any], vec![Kind::None])]
1219	#[case::bool(
1220		Value::Bool(true),
1221		vec![Kind::Bool, Kind::Any, Kind::Literal(KindLiteral::Bool(true))],
1222		vec![Kind::None, Kind::Null, Kind::Literal(KindLiteral::Bool(false))]
1223	)]
1224	#[case::bool_false(
1225		Value::Bool(false),
1226		vec![Kind::Bool, Kind::Any, Kind::Literal(KindLiteral::Bool(false))],
1227		vec![Kind::None, Kind::Null, Kind::Literal(KindLiteral::Bool(true))]
1228	)]
1229	#[case::bytes(Value::Bytes(Bytes::default()), vec![Kind::Bytes, Kind::Any], vec![Kind::None, Kind::Null])]
1230	#[case::datetime(
1231		Value::Datetime(Datetime::default()),
1232		vec![Kind::Datetime, Kind::Any],
1233		vec![Kind::None, Kind::Null]
1234	)]
1235	#[case::duration(
1236		Value::Duration(Duration::default()),
1237		vec![
1238			Kind::Duration,
1239			Kind::Any,
1240			Kind::Literal(KindLiteral::Duration(Duration::default()))
1241		],
1242		vec![Kind::None, Kind::Null, Kind::Literal(KindLiteral::Duration(Duration::new(1, 0)))]
1243	)]
1244	#[case::int(
1245		Value::Number(Number::Int(0)),
1246		vec![Kind::Int, Kind::Number, Kind::Any, Kind::Literal(KindLiteral::Integer(0))],
1247		vec![Kind::None, Kind::Null, Kind::Literal(KindLiteral::Integer(1))]
1248	)]
1249	#[case::float(
1250		Value::Number(Number::Float(0.0)),
1251		vec![Kind::Float, Kind::Number, Kind::Any, Kind::Literal(KindLiteral::Float(0.0))],
1252		vec![Kind::None, Kind::Null, Kind::Literal(KindLiteral::Float(1.0))]
1253	)]
1254	#[case::decimal(
1255		Value::Number(Number::Decimal(Decimal::default())),
1256		vec![
1257			Kind::Decimal,
1258			Kind::Number,
1259			Kind::Any,
1260			Kind::Literal(KindLiteral::Decimal(Decimal::default()))
1261		],
1262		vec![Kind::None, Kind::Null]
1263	)]
1264	#[case::string(
1265		Value::String("".to_string()),
1266		vec![Kind::String, Kind::Any, Kind::Literal(KindLiteral::String("".to_string()))],
1267		vec![Kind::None, Kind::Null, Kind::Literal(KindLiteral::String("foo".to_string()))]
1268	)]
1269	#[case::string(
1270		Value::String("foo".to_string()),
1271		vec![Kind::String, Kind::Any, Kind::Literal(KindLiteral::String("foo".to_string()))],
1272		vec![Kind::None, Kind::Null, Kind::Literal(KindLiteral::String("bar".to_string()))]
1273	)]
1274	#[case::uuid(Value::Uuid(Uuid::new_v4()), vec![Kind::Uuid, Kind::Any], vec![Kind::None, Kind::Null])]
1275	#[case::regex(
1276		Value::Regex("hello".parse().unwrap()),
1277		vec![Kind::Regex, Kind::Any],
1278		vec![Kind::None, Kind::Null]
1279	)]
1280	#[case::table(
1281		Value::Table("test".into()),
1282		vec![Kind::Table(vec!["test".into()]), Kind::Table(vec![]), Kind::Any],
1283		vec![Kind::None, Kind::Null]
1284	)]
1285	#[case::record(
1286		Value::RecordId(RecordId::new("test", "key")),
1287		vec![Kind::Record(vec!["test".into()]), Kind::Record(vec![]), Kind::Any],
1288		vec![Kind::None, Kind::Null, Kind::Record(vec!["other".into()])]
1289	)]
1290	#[case::record_multi_table(
1291		Value::RecordId(RecordId::new("user", "id")),
1292		vec![Kind::Record(vec!["user".into(), "admin".into()]), Kind::Any],
1293		vec![Kind::Record(vec!["post".into(), "comment".into()])]
1294	)]
1295	#[case::geometry_point(
1296		Value::Geometry(Geometry::Point(geo::Point::new(1.0, 2.0))),
1297		vec![Kind::Geometry(vec![GeometryKind::Point]), Kind::Geometry(vec![]), Kind::Any],
1298		vec![Kind::None, Kind::Null, Kind::Geometry(vec![GeometryKind::Line])]
1299	)]
1300	#[case::geometry_line(
1301		Value::Geometry(Geometry::Line(geo::LineString::from(vec![(0.0, 0.0), (1.0, 1.0)]))),
1302		vec![Kind::Geometry(vec![GeometryKind::Line]), Kind::Geometry(vec![]), Kind::Any],
1303		vec![Kind::Geometry(vec![GeometryKind::Point])]
1304	)]
1305	#[case::geometry_polygon(
1306		Value::Geometry(Geometry::Polygon(geo::Polygon::new(
1307			geo::LineString::from(vec![
1308				(0.0, 0.0),
1309				(1.0, 0.0),
1310				(1.0, 1.0),
1311				(0.0, 1.0),
1312				(0.0, 0.0)
1313			]),
1314			vec![]
1315		))),
1316		vec![Kind::Geometry(vec![GeometryKind::Polygon]), Kind::Geometry(vec![]), Kind::Any],
1317		vec![Kind::Geometry(vec![GeometryKind::Point])]
1318	)]
1319	#[case::geometry_multi(
1320		Value::Geometry(Geometry::Point(geo::Point::new(1.0, 2.0))),
1321		vec![Kind::Geometry(vec![GeometryKind::Point, GeometryKind::Line]), Kind::Any],
1322		vec![Kind::Geometry(vec![GeometryKind::Line, GeometryKind::Polygon])]
1323	)]
1324	#[case::array_empty(
1325		Value::Array(Array::new()),
1326		vec![
1327			Kind::Array(Box::new(Kind::Any), None),
1328			Kind::Array(Box::new(Kind::String), None),
1329			Kind::Any
1330		],
1331		vec![Kind::None, Kind::Null]
1332	)]
1333	#[case::array_strings(
1334		Value::Array(Array::from(vec![
1335			Value::String("a".to_string()),
1336			Value::String("b".to_string())
1337		])),
1338		vec![
1339			Kind::Array(Box::new(Kind::String), None),
1340			Kind::Array(Box::new(Kind::String), Some(5)),
1341			Kind::Any
1342		],
1343		vec![Kind::Array(Box::new(Kind::Int), None), Kind::Array(Box::new(Kind::String), Some(1))]
1344	)]
1345	#[case::array_mixed_fails(
1346		Value::Array(Array::from(vec![
1347			Value::String("a".to_string()),
1348			Value::Number(Number::Int(1))
1349		])),
1350		vec![Kind::Array(Box::new(Kind::Any), None), Kind::Any],
1351		vec![Kind::Array(Box::new(Kind::String), None), Kind::Array(Box::new(Kind::Int), None)]
1352	)]
1353	#[case::array_with_max(
1354		Value::Array(Array::from(vec![
1355			Value::Number(Number::Int(1)),
1356			Value::Number(Number::Int(2)),
1357			Value::Number(Number::Int(3))
1358		])),
1359		vec![
1360			Kind::Array(Box::new(Kind::Int), Some(3)),
1361			Kind::Array(Box::new(Kind::Int), Some(10)),
1362			Kind::Any
1363		],
1364		vec![Kind::Array(Box::new(Kind::Int), Some(2))]
1365	)]
1366	#[case::range(
1367		Value::Range(Box::new(Range::unbounded())),
1368		vec![Kind::Range, Kind::Any],
1369		vec![Kind::None, Kind::Null]
1370	)]
1371	#[case::file_empty_bucket(
1372		Value::File(File::default()),
1373		vec![Kind::File(vec!["".to_string()]), Kind::File(vec![]), Kind::Any],
1374		vec![Kind::None, Kind::Null]
1375	)]
1376	#[case::file_specific_bucket(
1377		Value::File(File::new("mybucket", "file.txt")),
1378		vec![Kind::File(vec!["mybucket".to_string()]), Kind::File(vec![]), Kind::Any],
1379		vec![Kind::File(vec!["other".to_string()])]
1380	)]
1381	#[case::object_empty(
1382		Value::Object(Object::default()),
1383		vec![Kind::Object, Kind::Any, Kind::Literal(KindLiteral::Object(BTreeMap::new()))],
1384		vec![Kind::None, Kind::Null]
1385	)]
1386	#[case::object_with_fields(
1387		Value::Object(object! { key: "value".to_string() }),
1388		vec![
1389			Kind::Object,
1390			Kind::Any,
1391			Kind::Literal(KindLiteral::Object(BTreeMap::from([(
1392				"key".to_string(),
1393				Kind::String
1394			)])))
1395		],
1396		vec![Kind::None, Kind::Null, Kind::Literal(KindLiteral::Object(BTreeMap::new()))]
1397	)]
1398	#[case::literal_array(
1399		Value::Array(Array::from(vec![
1400			Value::Number(Number::Int(1)),
1401			Value::String("test".to_string())
1402		])),
1403		vec![Kind::Literal(KindLiteral::Array(vec![Kind::Int, Kind::String])), Kind::Any],
1404		vec![
1405			Kind::Literal(KindLiteral::Array(vec![Kind::String, Kind::Int])),
1406			Kind::Literal(KindLiteral::Array(vec![Kind::Int]))
1407		]
1408	)]
1409	#[case::either_string_or_int(
1410		Value::String("test".to_string()),
1411		vec![Kind::Either(vec![Kind::String, Kind::Int]), Kind::Any],
1412		vec![Kind::Either(vec![Kind::Int, Kind::Bool])]
1413	)]
1414	#[case::either_int_matches(
1415		Value::Number(Number::Int(42)),
1416		vec![Kind::Either(vec![Kind::String, Kind::Int]), Kind::Any],
1417		vec![Kind::Either(vec![Kind::String, Kind::Bool])]
1418	)]
1419	#[case::option_kind_none(
1420		Value::None,
1421		vec![Kind::option(Kind::String), Kind::Any],
1422		vec![Kind::String]
1423	)]
1424	#[case::option_kind_value(
1425		Value::String("test".to_string()),
1426		vec![Kind::option(Kind::String), Kind::Any],
1427		vec![Kind::Int]
1428	)]
1429	fn test_is_kind(#[case] value: Value, #[case] kinds: Vec<Kind>, #[case] not_kinds: Vec<Kind>) {
1430		for kind in kinds {
1431			assert!(value.is_kind(&kind), "{value:?} is not a {kind}");
1432		}
1433		for kind in not_kinds {
1434			assert!(!value.is_kind(&kind), "{value:?} is a {kind} but should not be");
1435		}
1436	}
1437}