1#![allow(clippy::derive_ord_xor_partial_ord)]
2
3use std::cmp::Ordering;
4use std::collections::{BTreeMap, HashMap};
5use std::ops::Bound;
6use std::time::Duration as StdDuration;
7
8use anyhow::{Result, bail};
9use chrono::{DateTime, Utc};
10use common::fmt::{EscapeIdent, QuoteStr};
11use geo::Point;
12use revision::revisioned;
13use rust_decimal::prelude::*;
14use storekey::{BorrowDecode, Encode};
15use surrealdb_collections::VecMap;
16pub use surrealdb_strand::Strand;
17use surrealdb_types::{SqlFormat, ToSql, write_sql};
18
19use crate::expr;
20use crate::expr::Error;
21use crate::expr::kind::GeometryKind;
22use crate::expr::statements::info::InfoStructure;
23use crate::val::table_name_public::IntoPublicTable;
24
25pub mod array;
26pub mod bytes;
27pub mod closure;
28pub mod convert_public;
29pub mod datetime;
30pub mod duration;
31pub mod evaluator;
32pub mod field_path;
33pub mod file;
34pub mod geometry;
35pub mod number;
36pub mod object;
37pub mod range;
38pub mod record_id;
39pub mod regex;
40pub mod rnd;
41pub mod set;
42pub mod table_name_public;
43pub mod uuid;
44pub mod value;
45
46pub use surrealdb_strand::TableName;
47
48pub use self::array::Array;
49pub use self::bytes::Bytes;
50pub use self::closure::Closure;
51pub use self::convert_public::convert_public_value_to_internal;
52pub use self::datetime::Datetime;
53pub use self::duration::Duration;
54pub use self::evaluator::{BoxInvokeFut, ClosureEvaluator};
55pub use self::file::File;
56pub use self::geometry::Geometry;
57pub use self::number::Number;
58pub use self::object::Object;
59pub use self::range::Range;
60pub use self::record_id::{RecordId, RecordIdKey, RecordIdKeyRange, RecordIdentity};
61pub use self::regex::Regex;
62pub use self::set::Set;
63pub use self::uuid::Uuid;
64pub use self::value::{CastError, CoerceError};
65
66pub enum IndexFormat {}
69
70#[derive(Clone, Copy, Eq, PartialEq, PartialOrd)]
72pub struct SqlNone;
73
74#[derive(Clone, Copy, Eq, PartialEq, PartialOrd)]
76pub struct Null;
77
78#[revisioned(revision(1), revision(2, optimised))]
101#[derive(Clone, Debug, Default, PartialEq, PartialOrd, Hash, Encode, BorrowDecode)]
102#[storekey(format = "()")]
103#[storekey(format = "IndexFormat")]
104pub enum Value {
105 #[default]
106 #[revision(size = "inline")]
107 None,
108 #[revision(size = "inline")]
109 Null,
110 #[revision(size = "fixed(1)")]
111 Bool(bool),
112 #[revision(size = "varlen")]
113 Number(Number),
114 #[revision(size = "varlen")]
115 String(Strand),
116 #[revision(size = "varlen")]
117 Duration(Duration),
118 #[revision(size = "varlen")]
119 Datetime(Datetime),
120 #[revision(size = "varlen")]
121 Uuid(Uuid),
122 #[revision(size = "varlen")]
123 Array(Array),
124 #[revision(size = "varlen")]
125 Set(Set),
126 #[revision(size = "varlen")]
127 Object(Object),
128 #[revision(size = "varlen")]
129 Geometry(Geometry),
130 #[revision(size = "varlen")]
131 Bytes(Bytes),
132 #[revision(size = "varlen")]
133 Table(TableName),
134 #[revision(size = "varlen")]
135 RecordId(RecordId),
136 #[revision(size = "varlen")]
137 File(File),
138 #[revision(size = "varlen")]
139 Regex(Regex),
140 #[revision(size = "varlen")]
141 Range(Box<Range>),
142 #[revision(size = "varlen")]
146 Closure(Box<Closure>),
147 }
149
150impl Eq for Value {}
151
152impl Ord for Value {
153 fn cmp(&self, other: &Self) -> Ordering {
154 self.partial_cmp(other).unwrap_or(Ordering::Equal)
155 }
156}
157
158impl Value {
159 pub fn hash_agrees_with_eq(&self) -> bool {
189 match self {
190 Value::None
191 | Value::Null
192 | Value::Bool(_)
193 | Value::String(_)
194 | Value::Duration(_)
195 | Value::Datetime(_)
196 | Value::Uuid(_)
197 | Value::Bytes(_)
198 | Value::Table(_)
199 | Value::File(_) => true,
200 Value::Number(_)
201 | Value::Geometry(_)
202 | Value::Regex(_)
203 | Value::Range(_)
204 | Value::Closure(_) => false,
205 Value::Array(a) => a.iter().all(Value::hash_agrees_with_eq),
206 Value::Set(s) => s.iter().all(Value::hash_agrees_with_eq),
207 Value::Object(o) => o.values().all(Value::hash_agrees_with_eq),
210 Value::RecordId(r) => r.key.hash_agrees_with_eq(),
211 }
212 }
213
214 pub const NONE: Self = Self::None;
215
216 pub fn empty_object() -> Self {
222 Value::Object(Object::default())
223 }
224
225 pub fn is_some(&self) -> bool {
231 !matches!(self, Value::None)
232 }
233
234 pub fn is_nullish(&self) -> bool {
236 matches!(self, Value::None | Value::Null)
237 }
238
239 pub fn is_empty_array(&self) -> bool {
241 if let Value::Array(v) = self {
242 v.is_empty()
243 } else {
244 false
245 }
246 }
247
248 pub fn is_truthy(&self) -> bool {
250 match self {
251 Value::Bool(v) => *v,
252 Value::Uuid(_) => true,
253 Value::RecordId(_) => true,
254 Value::Geometry(_) => true,
255 Value::Datetime(_) => true,
256 Value::Bytes(v) => !v.is_empty(),
257 Value::Array(v) => !v.is_empty(),
258 Value::Set(v) => !v.is_empty(),
259 Value::Object(v) => !v.is_empty(),
260 Value::String(v) => !v.is_empty(),
261 Value::Number(v) => v.is_truthy(),
262 Value::Duration(v) => v.as_nanos() > 0,
263 _ => false,
264 }
265 }
266
267 pub fn is_int(&self) -> bool {
269 matches!(self, Value::Number(Number::Int(_)))
270 }
271
272 pub fn is_float(&self) -> bool {
274 matches!(self, Value::Number(Number::Float(_)))
275 }
276
277 pub fn is_decimal(&self) -> bool {
279 matches!(self, Value::Number(Number::Decimal(_)))
280 }
281
282 pub fn is_record_type(&self, types: &[TableName]) -> bool {
284 match self {
285 Value::RecordId(v) => v.is_table_type(types),
286 _ => false,
287 }
288 }
289
290 pub fn is_geometry_type(&self, types: &[GeometryKind]) -> bool {
292 match self {
293 Value::Geometry(Geometry::Point(_)) => {
294 types.iter().any(|t| matches!(t, GeometryKind::Point))
295 }
296 Value::Geometry(Geometry::Line(_)) => {
297 types.iter().any(|t| matches!(t, GeometryKind::Line))
298 }
299 Value::Geometry(Geometry::Polygon(_)) => {
300 types.iter().any(|t| matches!(t, GeometryKind::Polygon))
301 }
302 Value::Geometry(Geometry::MultiPoint(_)) => {
303 types.iter().any(|t| matches!(t, GeometryKind::MultiPoint))
304 }
305 Value::Geometry(Geometry::MultiLine(_)) => {
306 types.iter().any(|t| matches!(t, GeometryKind::MultiLine))
307 }
308 Value::Geometry(Geometry::MultiPolygon(_)) => {
309 types.iter().any(|t| matches!(t, GeometryKind::MultiPolygon))
310 }
311 Value::Geometry(Geometry::Collection(_)) => {
312 types.iter().any(|t| matches!(t, GeometryKind::Collection))
313 }
314 _ => false,
315 }
316 }
317
318 pub fn into_raw_string(self) -> String {
324 match self {
325 Value::String(v) => v.into_string(),
326 Value::Uuid(v) => v.to_string(),
327 Value::Datetime(v) => v.to_string(),
328 _ => self.to_sql(),
329 }
330 }
331
332 pub fn to_raw_string(&self) -> String {
334 match self {
335 Value::String(v) => v.as_str().to_owned(),
336 Value::Uuid(v) => v.to_string(),
337 Value::Datetime(v) => v.to_string(),
338 _ => self.to_sql(),
339 }
340 }
341
342 pub fn kind_of(&self) -> &'static str {
348 match self {
349 Self::None => "none",
350 Self::Null => "null",
351 Self::Bool(_) => "bool",
352 Self::Uuid(_) => "uuid",
353 Self::Array(_) => "array",
354 Self::Set(_) => "set",
355 Self::Object(_) => "object",
356 Self::String(_) => "string",
357 Self::Duration(_) => "duration",
358 Self::Datetime(_) => "datetime",
359 Self::Closure(_) => "function",
360 Self::Number(Number::Int(_)) => "int",
361 Self::Number(Number::Float(_)) => "float",
362 Self::Number(Number::Decimal(_)) => "decimal",
363 Self::Geometry(Geometry::Point(_)) => "geometry<point>",
364 Self::Geometry(Geometry::Line(_)) => "geometry<line>",
365 Self::Geometry(Geometry::Polygon(_)) => "geometry<polygon>",
366 Self::Geometry(Geometry::MultiPoint(_)) => "geometry<multipoint>",
367 Self::Geometry(Geometry::MultiLine(_)) => "geometry<multiline>",
368 Self::Geometry(Geometry::MultiPolygon(_)) => "geometry<multipolygon>",
369 Self::Geometry(Geometry::Collection(_)) => "geometry<collection>",
370 Self::Regex(_) => "regex",
371 Self::File(_) => "file",
372 Self::Bytes(_) => "bytes",
373 Self::Range(_) => "range",
374 Self::RecordId(_) => "record",
375 Self::Table(_) => "table",
376 }
377 }
378
379 pub fn equal(&self, other: &Value) -> bool {
385 match self {
386 Value::None => other.is_none(),
387 Value::Null => other.is_null(),
388 Value::Bool(v) => match other {
389 Value::Bool(w) => v == w,
390 _ => false,
391 },
392 Value::Uuid(v) => match other {
393 Value::Uuid(w) => v == w,
394 _ => false,
395 },
396 Value::RecordId(v) => match other {
397 Value::RecordId(w) => v == w,
398 _ => false,
399 },
400 Value::String(v) => match other {
401 Value::String(w) => v == w,
402 Value::Regex(w) => w.inner().is_match(v.as_str()),
403 _ => false,
404 },
405 Value::Regex(v) => match other {
406 Value::Regex(w) => v == w,
407 Value::String(w) => v.inner().is_match(w.as_str()),
408 _ => false,
409 },
410 Value::Array(v) => match other {
411 Value::Array(w) => v == w,
412 _ => false,
413 },
414 Value::Set(v) => match other {
415 Value::Set(w) => v == w,
416 _ => false,
417 },
418 Value::Object(v) => match other {
419 Value::Object(w) => v == w,
420 _ => false,
421 },
422 Value::Number(v) => match other {
423 Value::Number(w) => v == w,
424 _ => false,
425 },
426 Value::Geometry(v) => match other {
427 Value::Geometry(w) => v == w,
428 _ => false,
429 },
430 Value::Duration(v) => match other {
431 Value::Duration(w) => v == w,
432 _ => false,
433 },
434 Value::Datetime(v) => match other {
435 Value::Datetime(w) => v == w,
436 _ => false,
437 },
438 _ => self == other,
439 }
440 }
441
442 pub fn all_equal(&self, other: &Value) -> bool {
444 match self {
445 Value::Array(v) => v.iter().all(|v| v.equal(other)),
446 Value::Set(v) => v.iter().all(|v| v.equal(other)),
447 _ => self.equal(other),
448 }
449 }
450
451 pub fn any_equal(&self, other: &Value) -> bool {
453 match self {
454 Value::Array(v) => v.iter().any(|v| v.equal(other)),
455 Value::Set(v) => v.iter().any(|v| v.equal(other)),
456 _ => self.equal(other),
457 }
458 }
459
460 pub fn contains(&self, other: &Value) -> bool {
462 match self {
463 Value::Array(v) => v.iter().any(|v| v.equal(other)),
464 Value::Set(v) => v.contains(other),
465 Value::Uuid(v) => match other {
466 Value::String(w) => v.to_string().contains(w.as_str()),
467 _ => false,
468 },
469 Value::String(v) => match other {
470 Value::String(w) => v.contains(w.as_str()),
471 _ => false,
472 },
473 Value::Geometry(v) => match other {
474 Value::Geometry(w) => v.contains(w),
475 _ => false,
476 },
477 Value::Object(v) => match other {
478 Value::String(w) => v.contains_key(w.as_str()),
479 _ => false,
480 },
481 Value::Range(r) => {
482 let beg = match &r.start {
483 Bound::Unbounded => true,
484 Bound::Included(beg) => beg.le(other),
485 Bound::Excluded(beg) => beg.lt(other),
486 };
487
488 beg && match &r.end {
489 Bound::Unbounded => true,
490 Bound::Included(end) => end.ge(other),
491 Bound::Excluded(end) => end.gt(other),
492 }
493 }
494 _ => false,
495 }
496 }
497
498 pub fn contains_all(&self, other: &Value) -> bool {
500 match other {
501 Value::Array(v) if v.iter().all(|v| v.is_strand()) && self.is_strand() => {
502 let Value::String(this) = self else {
504 return false;
505 };
506 v.iter().all(|s| {
507 let Value::String(other_string) = s else {
508 return false;
509 };
510 this.contains(&**other_string)
511 })
512 }
513 Value::Set(v) if v.iter().all(|v| v.is_strand()) && self.is_strand() => {
514 let Value::String(this) = self else {
516 return false;
517 };
518 v.iter().all(|s| {
519 let Value::String(other_string) = s else {
520 return false;
521 };
522 this.contains(&**other_string)
523 })
524 }
525 Value::Array(v) => v.iter().all(|v| match self {
526 Value::Array(w) => w.iter().any(|w| v.equal(w)),
527 Value::Set(w) => w.iter().any(|w| v.equal(w)),
528 Value::Geometry(_) => self.contains(v),
529 _ => false,
530 }),
531 Value::Set(v) => v.iter().all(|v| match self {
532 Value::Array(w) => w.iter().any(|w| v.equal(w)),
533 Value::Set(w) => w.iter().any(|w| v.equal(w)),
534 Value::Geometry(_) => self.contains(v),
535 _ => false,
536 }),
537 Value::String(other_strand) => match self {
538 Value::String(s) => s.contains(&**other_strand),
539 _ => false,
540 },
541 _ => false,
542 }
543 }
544
545 pub fn contains_any(&self, other: &Value) -> bool {
547 match other {
548 Value::Array(v) if v.iter().all(|v| v.is_strand()) && self.is_strand() => {
549 let Value::String(this) = self else {
551 return false;
552 };
553 v.iter().any(|s| {
554 let Value::String(other_string) = s else {
555 return false;
556 };
557 this.contains(&**other_string)
558 })
559 }
560 Value::Set(v) if v.iter().all(|v| v.is_strand()) && self.is_strand() => {
561 let Value::String(this) = self else {
563 return false;
564 };
565 v.iter().any(|s| {
566 let Value::String(other_string) = s else {
567 return false;
568 };
569 this.contains(&**other_string)
570 })
571 }
572 Value::Array(v) => v.iter().any(|v| match self {
573 Value::Array(w) => w.iter().any(|w| v.equal(w)),
574 Value::Set(w) => w.iter().any(|w| v.equal(w)),
575 Value::Geometry(_) => self.contains(v),
576 _ => false,
577 }),
578 Value::Set(v) => v.iter().any(|v| match self {
579 Value::Array(w) => w.iter().any(|w| v.equal(w)),
580 Value::Set(w) => w.iter().any(|w| v.equal(w)),
581 Value::Geometry(_) => self.contains(v),
582 _ => false,
583 }),
584 Value::String(other_strand) => match self {
585 Value::String(s) => s.contains(&**other_strand),
586 _ => false,
587 },
588 _ => false,
589 }
590 }
591
592 pub fn intersects(&self, other: &Value) -> bool {
594 match self {
595 Value::Geometry(v) => match other {
596 Value::Geometry(w) => v.intersects(w),
597 _ => false,
598 },
599 _ => false,
600 }
601 }
602
603 pub fn lexical_cmp(&self, other: &Value) -> Option<Ordering> {
609 match (self, other) {
610 (Value::String(a), Value::String(b)) => Some(lexicmp::lexical_cmp(a, b)),
611 _ => self.partial_cmp(other),
612 }
613 }
614
615 pub fn natural_cmp(&self, other: &Value) -> Option<Ordering> {
617 match (self, other) {
618 (Value::String(a), Value::String(b)) => Some(lexicmp::natural_cmp(a, b)),
619 _ => self.partial_cmp(other),
620 }
621 }
622
623 pub fn natural_lexical_cmp(&self, other: &Value) -> Option<Ordering> {
626 match (self, other) {
627 (Value::String(a), Value::String(b)) => Some(lexicmp::natural_lexical_cmp(a, b)),
628 _ => self.partial_cmp(other),
629 }
630 }
631
632 pub fn into_literal(self) -> expr::Expr {
634 match self {
635 Value::None => expr::Expr::Literal(expr::Literal::None),
636 Value::Null => expr::Expr::Literal(expr::Literal::Null),
637 Value::Bool(x) => expr::Expr::Literal(expr::Literal::Bool(x)),
638 Value::Number(Number::Int(i)) => expr::Expr::Literal(expr::Literal::Integer(i)),
639 Value::Number(Number::Float(f)) => expr::Expr::Literal(expr::Literal::Float(f)),
640 Value::Number(Number::Decimal(d)) => expr::Expr::Literal(expr::Literal::Decimal(d)),
641 Value::String(strand) => expr::Expr::Literal(expr::Literal::String(strand)),
642 Value::Duration(duration) => expr::Expr::Literal(expr::Literal::Duration(duration)),
643 Value::Datetime(datetime) => expr::Expr::Literal(expr::Literal::Datetime(datetime)),
644 Value::Uuid(uuid) => expr::Expr::Literal(expr::Literal::Uuid(uuid)),
645 Value::Array(array) => expr::Expr::Literal(expr::Literal::Array(array.into_literal())),
646 Value::Set(set) => {
647 expr::Expr::Literal(expr::Literal::Array(set.into_literal()))
650 }
651 Value::Object(object) => {
652 expr::Expr::Literal(expr::Literal::Object(object.into_literal()))
653 }
654 Value::Geometry(geometry) => expr::Expr::Literal(expr::Literal::Geometry(geometry)),
655 Value::Bytes(bytes) => expr::Expr::Literal(expr::Literal::Bytes(bytes)),
656 Value::RecordId(record_id) => {
657 expr::Expr::Literal(expr::Literal::RecordId(record_id.into_literal()))
658 }
659 Value::Regex(regex) => expr::Expr::Literal(expr::Literal::Regex(regex)),
660 Value::File(file) => expr::Expr::Literal(expr::Literal::File(file)),
661 Value::Closure(closure) => closure.into_expr(),
662 Value::Range(range) => range.into_literal(),
663 Value::Table(t) => expr::Expr::Table(t),
664 }
665 }
666}
667
668impl ToSql for Value {
669 fn fmt_sql(&self, f: &mut String, sql_fmt: SqlFormat) {
670 match self {
671 Value::None => f.push_str("NONE"),
672 Value::Null => f.push_str("NULL"),
673 Value::Bool(v) => v.fmt_sql(f, sql_fmt),
674 Value::Number(v) => v.fmt_sql(f, sql_fmt),
675 Value::String(v) => write_sql!(f, sql_fmt, "{}", QuoteStr(v.as_str())),
676 Value::Duration(v) => v.fmt_sql(f, sql_fmt),
677 Value::Datetime(v) => v.fmt_sql(f, sql_fmt),
678 Value::Uuid(v) => v.fmt_sql(f, sql_fmt),
679 Value::Array(v) => v.fmt_sql(f, sql_fmt),
680 Value::Set(v) => v.fmt_sql(f, sql_fmt),
681 Value::Object(v) => v.fmt_sql(f, sql_fmt),
682 Value::Geometry(v) => v.fmt_sql(f, sql_fmt),
683 Value::Bytes(v) => v.fmt_sql(f, sql_fmt),
684 Value::Table(v) => EscapeIdent(v.as_str()).fmt_sql(f, sql_fmt),
689 Value::RecordId(v) => v.fmt_sql(f, sql_fmt),
690 Value::File(v) => v.fmt_sql(f, sql_fmt),
691 Value::Regex(v) => v.fmt_sql(f, sql_fmt),
692 Value::Range(v) => v.fmt_sql(f, sql_fmt),
693 Value::Closure(v) => v.fmt_sql(f, sql_fmt),
694 }
695 }
696}
697
698impl InfoStructure for Value {
699 fn structure(self) -> Value {
700 self.to_sql().into()
701 }
702}
703
704pub trait TryAdd<Rhs = Self> {
707 type Output;
708 fn try_add(self, rhs: Rhs) -> Result<Self::Output>;
709}
710
711use std::ops::Add;
712
713impl TryAdd for Value {
714 type Output = Self;
715 fn try_add(self, other: Self) -> Result<Self> {
716 Ok(match (self, other) {
717 (Self::Number(v), Self::Number(w)) => Self::Number(v.try_add(w)?),
718 (Self::String(v), Self::String(w)) => {
719 let mut s = String::with_capacity(v.len() + w.len());
720 s.push_str(v.as_str());
721 s.push_str(w.as_str());
722 Value::String(s.into())
723 }
724 (Self::Datetime(v), Self::Duration(w)) => Self::Datetime(w.try_add(v)?),
725 (Self::Duration(v), Self::Datetime(w)) => Self::Datetime(v.try_add(w)?),
726 (Self::Duration(v), Self::Duration(w)) => Self::Duration(v.try_add(w)?),
727 (Self::Array(v), Self::Array(w)) => Self::Array(v.concat(w)),
728 (Self::Array(v), Self::Set(w)) => Self::Array(v.concat_set(w)),
729
730 (Self::Set(mut v), Self::Set(w)) => {
731 v.0.extend(w.0);
732 Self::Set(v)
733 }
734 (Self::Set(mut v), Self::Array(w)) => {
735 v.0.extend(w.0);
736 Self::Set(v)
737 }
738 (Self::Object(v), Self::Object(w)) => Self::Object(v.add(w)),
739 (v, w) => bail!(Error::TryAdd(v.kind_of().to_owned(), w.kind_of().to_owned())),
740 })
741 }
742}
743
744pub trait TrySub<Rhs = Self> {
747 type Output;
748 fn try_sub(self, v: Rhs) -> Result<Self::Output>;
749}
750
751impl TrySub for Value {
752 type Output = Self;
753 fn try_sub(self, other: Self) -> Result<Self> {
754 Ok(match (self, other) {
755 (Self::Number(v), Self::Number(w)) => Self::Number(v.try_sub(w)?),
756 (Self::Datetime(v), Self::Datetime(w)) => Self::Duration(v.try_sub(w)?),
757 (Self::Datetime(v), Self::Duration(w)) => Self::Datetime(w.try_sub(v)?),
758 (Self::Duration(v), Self::Datetime(w)) => Self::Datetime(v.try_sub(w)?),
759 (Self::Duration(v), Self::Duration(w)) => Self::Duration(v.try_sub(w)?),
760 (Self::Array(v), Self::Array(x)) => Self::from(v.remove_all(&x.0)),
761 (Self::Array(v), Self::Set(x)) => Self::from(v.remove_all_set(&x)),
762 (Self::Set(mut v), Self::Array(x)) => {
763 for item in x.0 {
764 v.remove(&item);
765 }
766 Self::from(v)
767 }
768 (Self::Set(mut v), Self::Set(x)) => {
769 for item in x {
770 v.remove(&item);
771 }
772 Self::from(v)
773 }
774 (v, w) => bail!(Error::TrySub(v.kind_of().to_owned(), w.kind_of().to_owned())),
775 })
776 }
777}
778
779pub trait TryMul<Rhs = Self> {
782 type Output;
783 fn try_mul(self, v: Self) -> Result<Self::Output>;
784}
785
786impl TryMul for Value {
787 type Output = Self;
788 fn try_mul(self, other: Self) -> Result<Self> {
789 match (self, other) {
790 (Self::Number(v), Self::Number(w)) => Ok(Self::Number(v.try_mul(w)?)),
791 (Self::Duration(d), Self::Number(Number::Int(i))) => {
792 if i < 0 {
793 bail!("Cannot multiply a duration with a negative number");
794 }
795
796 let factor: u32 = i.try_into()?;
797
798 let res =
799 d.0.checked_mul(factor)
800 .ok_or_else(|| Error::ArithmeticOverflow(format!("{d} * {i}")))?;
801
802 Ok(Value::Duration(Duration(res)))
803 }
804 (Self::Duration(d), Self::Number(Number::Float(f))) => {
805 if !(f.is_finite() && f >= 0.0) {
806 bail!("Cannot multiply a duration with a non-finite or negative number");
807 }
808
809 let secs = d.0.as_secs_f64() * f;
810 let res = StdDuration::try_from_secs_f64(secs)
811 .map_err(|_| Error::ArithmeticOverflow(format!("{d} * {f}")))?;
812
813 Ok(Value::Duration(Duration(res)))
814 }
815 (Self::Duration(d), Self::Number(Number::Decimal(dec))) => {
816 if !dec.is_sign_positive() && !dec.is_zero() {
817 bail!("Cannot multiply a duration with a negative number");
818 }
819
820 let nanos: Decimal = d.nanos().into();
821 let scaled = (nanos * dec).trunc();
822
823 let scaled_nanos: u128 = scaled
824 .to_u128()
825 .ok_or_else(|| Error::ArithmeticOverflow(format!("{d} * {dec}")))?;
826
827 let secs: u64 = (scaled_nanos / 1_000_000_000)
828 .try_into()
829 .map_err(|_| Error::ArithmeticOverflow(format!("{d} * {dec}")))?;
830
831 let subsec_nanos: u32 = (scaled_nanos % 1_000_000_000).try_into()?;
832
833 Ok(Value::Duration(Duration(StdDuration::new(secs, subsec_nanos))))
834 }
835 (v, w) => bail!(Error::TryMul(v.kind_of().to_owned(), w.kind_of().to_owned())),
836 }
837 }
838}
839
840pub trait TryDiv<Rhs = Self> {
843 type Output;
844 fn try_div(self, v: Self) -> Result<Self::Output>;
845}
846
847impl TryDiv for Value {
848 type Output = Self;
849 fn try_div(self, other: Self) -> Result<Self> {
850 match (self, other) {
851 (Self::Number(v), Self::Number(w)) => Ok(Self::Number(v.try_div(w)?)),
852 (Self::Duration(d), Self::Number(Number::Int(i))) => {
853 if i <= 0 {
854 bail!("A duration can only be divided by a value greater than 0.");
855 }
856
857 let denom: u32 = i.try_into()?;
858 let res = d.0 / denom;
859 Ok(Value::Duration(Duration(res)))
860 }
861 (Self::Duration(d), Self::Number(Number::Float(f))) => {
862 if !(f.is_finite() && f > 0.0) {
863 bail!("A duration can only be divided by a finite value greater than 0.");
864 }
865 let secs = d.as_secs_f64() / f;
866
867 let res = StdDuration::try_from_secs_f64(secs)?;
868 Ok(Value::Duration(Duration(res)))
869 }
870 (Self::Duration(d), Self::Number(Number::Decimal(dec))) => {
871 if !dec.is_sign_positive() || dec.is_zero() {
872 bail!("A duration can only be divided by a value greater than 0.");
873 }
874
875 let nanos: Decimal = d.nanos().into();
876
877 let divided = (nanos / dec).trunc();
878
879 let divided_nanos: u128 = divided
880 .to_u128()
881 .ok_or_else(|| anyhow::anyhow!("Resulting duration is out of range"))?;
882
883 let secs: u64 = (divided_nanos / 1_000_000_000)
884 .try_into()
885 .map_err(|_| anyhow::anyhow!("Resulting duration seconds out of range"))?;
886
887 let subsec_nanos: u32 = (divided_nanos % 1_000_000_000).try_into()?;
888
889 Ok(Value::Duration(Duration(StdDuration::new(secs, subsec_nanos))))
890 }
891
892 (v, w) => bail!(Error::TryDiv(v.kind_of().to_owned(), w.kind_of().to_owned())),
893 }
894 }
895}
896
897pub trait TryFloatDiv<Rhs = Self> {
900 type Output;
901 fn try_float_div(self, v: Self) -> Result<Self::Output>;
902}
903
904impl TryFloatDiv for Value {
905 type Output = Self;
906 fn try_float_div(self, other: Self) -> Result<Self::Output> {
907 Ok(match (self, other) {
908 (Self::Number(v), Self::Number(w)) => Self::Number(v.try_float_div(w)?),
909 (v, w) => bail!(Error::TryDiv(v.kind_of().to_owned(), w.kind_of().to_owned())),
910 })
911 }
912}
913
914pub trait TryRem<Rhs = Self> {
917 type Output;
918 fn try_rem(self, v: Self) -> Result<Self::Output>;
919}
920
921impl TryRem for Value {
922 type Output = Self;
923 fn try_rem(self, other: Self) -> Result<Self> {
924 Ok(match (self, other) {
925 (Self::Number(v), Self::Number(w)) => Self::Number(v.try_rem(w)?),
926 (v, w) => bail!(Error::TryRem(v.kind_of().to_owned(), w.kind_of().to_owned())),
927 })
928 }
929}
930
931pub trait TryPow<Rhs = Self> {
934 type Output;
935 fn try_pow(self, v: Self) -> Result<Self::Output>;
936}
937
938impl TryPow for Value {
939 type Output = Self;
940 fn try_pow(self, other: Self) -> Result<Self> {
941 Ok(match (self, other) {
942 (Value::Number(v), Value::Number(w)) => Self::Number(v.try_pow(w)?),
943 (v, w) => bail!(Error::TryPow(v.kind_of().to_owned(), w.kind_of().to_owned())),
944 })
945 }
946}
947
948pub trait TryNeg<Rhs = Self> {
951 type Output;
952 fn try_neg(self) -> Result<Self::Output>;
953}
954
955impl TryNeg for Value {
956 type Output = Self;
957 fn try_neg(self) -> Result<Self> {
958 Ok(match self {
959 Self::Number(n) => Self::Number(n.try_neg()?),
960 v => bail!(Error::TryNeg(v.kind_of().to_owned())),
961 })
962 }
963}
964
965macro_rules! subtypes {
969 ($($name:ident$( ( $($t:tt)* ) )? => ($is:ident,$as:ident,$into:ident)),*$(,)?) => {
970 impl Value {
971 $(
972 subtypes!{@method $name $( ($($t)*) )? => $is,$as,$into}
973 )*
974 }
975
976 $(
977 subtypes!{@from $name $( ($($t)*) )? => $is,$as,$into}
978 )*
979
980 };
981
982 (@pat $name:ident($t:ty)) => {
983 Value::$name(_)
984 };
985
986 (@pat $name:ident) => {
987 Value::$name
988 };
989
990 (@method $name:ident($t:ty) => $is:ident,$as:ident,$into:ident) => {
991 #[doc = concat!("Check if the value is a [`",stringify!($name),"`]")]
992 #[allow(dead_code)]
993 pub fn $is(&self) -> bool{
994 matches!(self,Value::$name(_))
995 }
996
997 #[doc = concat!("Return a reference to [`",stringify!($name),"`] if the value is of that type")]
998 #[allow(dead_code)]
999 pub fn $as(&self) -> Option<&$t>{
1000 if let Value::$name(x) = self{
1001 Some(x)
1002 }else{
1003 None
1004 }
1005 }
1006
1007 #[doc = concat!("Turns the value into a [`",stringify!($name),"`] returning None if the value is not of that type")]
1008 #[allow(dead_code)]
1009 pub fn $into(self) -> Option<$t>{
1010 if let Value::$name(x) = self{
1011 Some(x)
1012 }else{
1013 None
1014 }
1015 }
1016 };
1017
1018 (@method $name:ident => $is:ident,$as:ident,$into:ident) => {
1019 #[doc = concat!("Check if the value is a [`",stringify!($name),"`]")]
1020 #[allow(dead_code)]
1021 pub fn $is(&self) -> bool{
1022 matches!(self,Value::$name)
1023 }
1024 };
1025
1026
1027 (@from $name:ident(Box<$inner:ident>) => $is:ident,$as:ident,$into:ident) => {
1028 impl From<$inner> for Value {
1029 fn from(v: $inner) -> Self{
1030 Value::$name(Box::new(v))
1031 }
1032 }
1033
1034 impl From<Box<$inner>> for Value {
1035 fn from(v: Box<$inner>) -> Self{
1036 Value::$name(v)
1037 }
1038 }
1039 };
1040
1041 (@from $name:ident($t:ident) => $is:ident,$as:ident,$into:ident) => {
1042 impl From<$t> for Value {
1043 fn from(v: $t) -> Self{
1044 Value::$name(v)
1045 }
1046 }
1047 };
1048
1049 (@from $name:ident => $is:ident,$as:ident,$into:ident) => {
1050 };
1052
1053}
1054
1055subtypes! {
1056 None => (is_none,_unused,_unused),
1057 Null => (is_null,_unused,_unused),
1058 Bool(bool) => (is_bool,as_bool,into_bool),
1059 Number(Number) => (is_number,as_number,into_number),
1060 String(Strand) => (is_strand,as_strand,into_strand),
1061 Table(TableName) => (is_table,as_table,into_table),
1062 Duration(Duration) => (is_duration,as_duration,into_duration),
1063 Datetime(Datetime) => (is_datetime,as_datetime,into_datetime),
1064 Uuid(Uuid) => (is_uuid,as_uuid,into_uuid),
1065 Array(Array) => (is_array,as_array,into_array),
1066 Set(Set) => (is_set,as_set,into_set),
1067 Object(Object) => (is_object,as_object,into_object),
1068 Geometry(Geometry) => (is_geometry,as_geometry,into_geometry),
1069 Bytes(Bytes) => (is_bytes,as_bytes,into_bytes),
1070 RecordId(RecordId) => (is_record,as_record,into_record),
1071 Regex(Regex) => (is_regex,as_regex,into_regex),
1072 Range(Box<Range>) => (is_range,as_range,into_range),
1073 Closure(Box<Closure>) => (is_closure,as_closure,into_closure),
1074 File(File) => (is_file,as_file,into_file),
1075}
1076
1077macro_rules! impl_from_number {
1078 ($($n:ident),*$(,)?) => {
1079 $(
1080 impl From<$n> for Value{
1081 fn from(v: $n) -> Self{
1082 Value::Number(Number::from(v))
1083 }
1084 }
1085 )*
1086 };
1087}
1088impl_from_number!(i8, i16, i32, i64, u8, u16, u32, isize, f32, f64, Decimal);
1089
1090impl From<Vec<Value>> for Value {
1091 fn from(value: Vec<Value>) -> Self {
1092 Value::Array(Array(value))
1093 }
1094}
1095
1096impl From<Null> for Value {
1097 fn from(_v: Null) -> Self {
1098 Value::Null
1099 }
1100}
1101
1102impl From<u64> for Value {
1105 fn from(v: u64) -> Self {
1106 Value::Number(Number::from(v))
1107 }
1108}
1109
1110impl From<usize> for Value {
1111 fn from(v: usize) -> Self {
1112 Value::Number(Number::from(v))
1113 }
1114}
1115
1116impl TryFrom<i128> for Value {
1119 type Error = Error;
1120 fn try_from(v: i128) -> Result<Self, Self::Error> {
1121 Ok(Value::Number(Number::try_from(v)?))
1122 }
1123}
1124
1125impl TryFrom<u128> for Value {
1126 type Error = Error;
1127 fn try_from(v: u128) -> Result<Self, Self::Error> {
1128 Ok(Value::Number(Number::try_from(v)?))
1129 }
1130}
1131
1132impl From<&str> for Value {
1133 fn from(v: &str) -> Self {
1134 Self::String(Strand::from(v))
1135 }
1136}
1137
1138impl From<String> for Value {
1139 fn from(v: String) -> Self {
1140 Self::String(Strand::from(v))
1141 }
1142}
1143
1144impl From<::uuid::Uuid> for Value {
1145 fn from(v: ::uuid::Uuid) -> Self {
1146 Value::Uuid(Uuid::from(v))
1147 }
1148}
1149
1150impl From<DateTime<Utc>> for Value {
1151 fn from(v: DateTime<Utc>) -> Self {
1152 Value::Datetime(Datetime::from(v))
1153 }
1154}
1155
1156impl From<Point<f64>> for Value {
1157 fn from(v: Point<f64>) -> Self {
1158 Value::Geometry(Geometry::from(v))
1159 }
1160}
1161
1162impl From<HashMap<&str, Value>> for Value {
1163 fn from(v: HashMap<&str, Value>) -> Self {
1164 Value::Object(Object::from(v))
1165 }
1166}
1167
1168impl From<HashMap<String, Value>> for Value {
1169 fn from(v: HashMap<String, Value>) -> Self {
1170 Value::Object(Object::from(v))
1171 }
1172}
1173
1174impl From<BTreeMap<String, Value>> for Value {
1175 fn from(v: BTreeMap<String, Value>) -> Self {
1176 Value::Object(Object::from(v))
1177 }
1178}
1179
1180impl From<VecMap<String, Value>> for Value {
1181 fn from(v: VecMap<String, Value>) -> Self {
1182 Value::Object(Object::from(v))
1183 }
1184}
1185
1186impl From<VecMap<Strand, Value>> for Value {
1187 fn from(v: VecMap<Strand, Value>) -> Self {
1188 Value::Object(Object(v))
1189 }
1190}
1191
1192impl From<VecMap<&str, Value>> for Value {
1193 fn from(v: VecMap<&str, Value>) -> Self {
1194 Value::Object(Object::from(v))
1195 }
1196}
1197
1198impl From<BTreeMap<&str, Value>> for Value {
1199 fn from(v: BTreeMap<&str, Value>) -> Self {
1200 Value::Object(Object::from(v))
1201 }
1202}
1203
1204impl TryFrom<Value> for crate::types::PublicValue {
1205 type Error = anyhow::Error;
1206
1207 fn try_from(s: Value) -> Result<Self, Self::Error> {
1208 convert_value_to_public_value(s)
1209 }
1210}
1211
1212impl From<crate::types::PublicValue> for Value {
1213 fn from(s: crate::types::PublicValue) -> Self {
1214 convert_public_value_to_internal(s)
1215 }
1216}
1217
1218impl FromIterator<Value> for Value {
1219 fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
1220 Value::Array(Array(iter.into_iter().collect()))
1221 }
1222}
1223
1224impl FromIterator<(String, Value)> for Value {
1225 fn from_iter<I: IntoIterator<Item = (String, Value)>>(iter: I) -> Self {
1226 Value::Object(Object::from_iter(iter))
1227 }
1228}
1229
1230pub const MAX_VALUE_DEPTH: usize = 256;
1253
1254enum DepthNode<'a> {
1259 Value(&'a Value),
1260 Key(&'a crate::val::RecordIdKey),
1261 Geo(&'a crate::val::Geometry),
1262 Closure(&'a crate::val::Closure),
1263}
1264
1265pub fn check_value_depth(value: &Value) -> Result<()> {
1278 use crate::val::RecordIdKey;
1279 if !matches!(
1286 value,
1287 Value::Array(_)
1288 | Value::Set(_)
1289 | Value::Object(_)
1290 | Value::Range(_)
1291 | Value::RecordId(_)
1292 | Value::Geometry(_)
1293 | Value::Closure(_)
1294 ) {
1295 return Ok(());
1296 }
1297 let mut stack: Vec<(DepthNode<'_>, usize)> = vec![(DepthNode::Value(value), 1)];
1299 while let Some((node, depth)) = stack.pop() {
1300 if depth > MAX_VALUE_DEPTH {
1301 bail!(Error::ValueTooDeep {
1302 max: MAX_VALUE_DEPTH,
1303 });
1304 }
1305 match node {
1306 DepthNode::Value(value) => match value {
1307 Value::Array(v) => {
1308 stack.extend(v.0.iter().map(|v| (DepthNode::Value(v), depth + 1)))
1309 }
1310 Value::Set(v) => stack.extend(v.0.iter().map(|v| (DepthNode::Value(v), depth + 1))),
1311 Value::Object(v) => {
1312 stack.extend(v.0.values().map(|v| (DepthNode::Value(v), depth + 1)))
1313 }
1314 Value::Range(v) => {
1315 for bound in [&v.start, &v.end] {
1316 match bound {
1317 Bound::Included(v) | Bound::Excluded(v) => {
1318 stack.push((DepthNode::Value(v), depth + 1))
1319 }
1320 Bound::Unbounded => {}
1321 }
1322 }
1323 }
1324 Value::RecordId(v) => stack.push((DepthNode::Key(&v.key), depth + 1)),
1325 Value::Geometry(g) => stack.push((DepthNode::Geo(g), depth)),
1329 Value::Closure(c) => stack.push((DepthNode::Closure(c), depth)),
1330 Value::None
1333 | Value::Null
1334 | Value::Bool(_)
1335 | Value::Number(_)
1336 | Value::String(_)
1337 | Value::Duration(_)
1338 | Value::Datetime(_)
1339 | Value::Uuid(_)
1340 | Value::Bytes(_)
1341 | Value::Table(_)
1342 | Value::File(_)
1343 | Value::Regex(_) => {}
1344 },
1345 DepthNode::Key(key) => match key {
1346 RecordIdKey::Array(a) => {
1347 stack.extend(a.0.iter().map(|v| (DepthNode::Value(v), depth + 1)))
1348 }
1349 RecordIdKey::Object(o) => {
1350 stack.extend(o.0.values().map(|v| (DepthNode::Value(v), depth + 1)))
1351 }
1352 RecordIdKey::Range(r) => {
1353 for bound in [&r.start, &r.end] {
1354 match bound {
1355 Bound::Included(k) | Bound::Excluded(k) => {
1356 stack.push((DepthNode::Key(k), depth + 1))
1357 }
1358 Bound::Unbounded => {}
1359 }
1360 }
1361 }
1362 RecordIdKey::Number(_) | RecordIdKey::String(_) | RecordIdKey::Uuid(_) => {}
1363 },
1364 DepthNode::Geo(geo) => {
1365 if let crate::val::Geometry::Collection(geoms) = geo {
1368 stack.extend(geoms.iter().map(|g| (DepthNode::Geo(g), depth + 1)));
1369 }
1370 }
1371 DepthNode::Closure(closure) => {
1372 match closure {
1379 crate::val::Closure::Expr {
1380 captures,
1381 ..
1382 } => {
1383 stack.extend(captures.0.values().map(|v| (DepthNode::Value(v), depth + 1)));
1384 }
1385 crate::val::Closure::Builtin(builtin) => {
1386 stack.extend(
1387 builtin
1388 .captured_values()
1389 .into_iter()
1390 .map(|v| (DepthNode::Value(v), depth + 1)),
1391 );
1392 }
1393 }
1394 }
1395 }
1396 }
1397 Ok(())
1398}
1399
1400pub fn convert_value_to_public_value(value: crate::val::Value) -> Result<surrealdb_types::Value> {
1401 convert_value_to_public_value_at(value, 1)
1402}
1403
1404pub fn convert_result_rows_to_public(value: crate::val::Value) -> Result<surrealdb_types::Value> {
1418 let crate::val::Value::Array(rows) = value else {
1419 return convert_value_to_public_value(value);
1422 };
1423 let converted =
1424 rows.0.into_iter().map(convert_value_to_public_value).collect::<Result<Vec<_>>>()?;
1425 Ok(surrealdb_types::Value::Array(surrealdb_types::Array::from(converted)))
1426}
1427
1428fn convert_value_to_public_value_at(
1435 value: crate::val::Value,
1436 depth: usize,
1437) -> Result<surrealdb_types::Value> {
1438 if depth > MAX_VALUE_DEPTH {
1439 bail!(Error::ValueTooDeep {
1440 max: MAX_VALUE_DEPTH,
1441 });
1442 }
1443 match value {
1444 crate::val::Value::None => Ok(surrealdb_types::Value::None),
1445 crate::val::Value::Null => Ok(surrealdb_types::Value::Null),
1446 crate::val::Value::Bool(value) => Ok(surrealdb_types::Value::Bool(value)),
1447 crate::val::Value::Number(value) => convert_number_to_public(value),
1448 crate::val::Value::String(value) => Ok(surrealdb_types::Value::String(value.into())),
1449 crate::val::Value::Datetime(value) => convert_datetime_to_public(value),
1450 crate::val::Value::Duration(value) => convert_duration_to_public(value),
1451 crate::val::Value::Uuid(value) => convert_uuid_to_public(value),
1452 crate::val::Value::Array(value) => convert_array_to_public(value, depth),
1453 crate::val::Value::Set(value) => convert_set_to_public(value, depth),
1454 crate::val::Value::Object(value) => convert_object_to_public(value, depth),
1455 crate::val::Value::Geometry(value) => convert_geometry_to_public(value, depth),
1456 crate::val::Value::Bytes(value) => convert_bytes_to_public(value),
1457 crate::val::Value::RecordId(value) => convert_record_id_to_public(value, depth),
1458 crate::val::Value::File(value) => convert_file_to_public(value),
1459 crate::val::Value::Range(value) => convert_range_to_public(*value, depth),
1460 crate::val::Value::Regex(value) => convert_regex_to_public(value),
1461 crate::val::Value::Table(value) => {
1462 Ok(surrealdb_types::Value::Table(value.into_public_table()))
1463 }
1464 crate::val::Value::Closure(_) => {
1465 Err(anyhow::anyhow!("Closure values cannot be converted to public value"))
1466 }
1467 }
1468}
1469
1470fn convert_number_to_public(value: crate::val::Number) -> Result<surrealdb_types::Value> {
1471 let number = match value {
1472 crate::val::Number::Int(i) => surrealdb_types::Number::Int(i),
1473 crate::val::Number::Float(f) => surrealdb_types::Number::Float(f),
1474 crate::val::Number::Decimal(d) => surrealdb_types::Number::Decimal(d),
1475 };
1476 Ok(surrealdb_types::Value::Number(number))
1477}
1478
1479fn convert_datetime_to_public(value: crate::val::Datetime) -> Result<surrealdb_types::Value> {
1480 Ok(surrealdb_types::Value::Datetime(surrealdb_types::Datetime::from(value.0)))
1481}
1482
1483fn convert_duration_to_public(value: crate::val::Duration) -> Result<surrealdb_types::Value> {
1484 Ok(surrealdb_types::Value::Duration(surrealdb_types::Duration::from_std(value.0)))
1485}
1486
1487fn convert_uuid_to_public(value: crate::val::Uuid) -> Result<surrealdb_types::Value> {
1488 Ok(surrealdb_types::Value::Uuid(surrealdb_types::Uuid::from(value.0)))
1489}
1490
1491fn convert_bytes_to_public(value: crate::val::Bytes) -> Result<surrealdb_types::Value> {
1492 Ok(surrealdb_types::Value::Bytes(surrealdb_types::Bytes::from(value.0)))
1493}
1494
1495fn convert_regex_to_public(value: crate::val::Regex) -> Result<surrealdb_types::Value> {
1496 Ok(surrealdb_types::Value::Regex(surrealdb_types::Regex::from(value.0)))
1497}
1498
1499fn convert_file_to_public(value: crate::val::File) -> Result<surrealdb_types::Value> {
1500 Ok(surrealdb_types::Value::File(surrealdb_types::File::new(value.bucket, value.key)))
1501}
1502
1503fn convert_geometry_to_public(
1504 value: crate::val::Geometry,
1505 depth: usize,
1506) -> Result<surrealdb_types::Value> {
1507 if depth > MAX_VALUE_DEPTH {
1511 bail!(Error::ValueTooDeep {
1512 max: MAX_VALUE_DEPTH,
1513 });
1514 }
1515 use surrealdb_types::Geometry as PublicGeometry;
1516 let geometry = match value {
1517 crate::val::Geometry::Point(p) => PublicGeometry::Point(p),
1518 crate::val::Geometry::Line(l) => PublicGeometry::Line(l),
1519 crate::val::Geometry::Polygon(p) => PublicGeometry::Polygon(p),
1520 crate::val::Geometry::MultiPoint(mp) => PublicGeometry::MultiPoint(mp),
1521 crate::val::Geometry::MultiLine(ml) => PublicGeometry::MultiLine(ml),
1522 crate::val::Geometry::MultiPolygon(mp) => PublicGeometry::MultiPolygon(mp),
1523 crate::val::Geometry::Collection(c) => {
1524 let converted: Result<Vec<_>> = c
1525 .into_iter()
1526 .map(|g| {
1527 if let surrealdb_types::Value::Geometry(g) =
1528 convert_geometry_to_public(g, depth + 1)?
1529 {
1530 Ok(g)
1531 } else {
1532 Err(anyhow::anyhow!("Failed to convert geometry collection item"))
1533 }
1534 })
1535 .collect();
1536 PublicGeometry::Collection(converted?)
1537 }
1538 };
1539 Ok(surrealdb_types::Value::Geometry(geometry))
1540}
1541
1542fn convert_array_to_public(
1543 value: crate::val::Array,
1544 depth: usize,
1545) -> Result<surrealdb_types::Value> {
1546 let converted: Result<Vec<_>> =
1547 value.0.into_iter().map(|v| convert_value_to_public_value_at(v, depth + 1)).collect();
1548 Ok(surrealdb_types::Value::Array(surrealdb_types::Array::from(converted?)))
1549}
1550
1551fn convert_set_to_public(value: crate::val::Set, depth: usize) -> Result<surrealdb_types::Value> {
1552 let converted: Result<Vec<surrealdb_types::Value>> =
1554 value.0.into_iter().map(|v| convert_value_to_public_value_at(v, depth + 1)).collect();
1555 Ok(surrealdb_types::Value::Set(surrealdb_types::Set::from(converted?)))
1556}
1557
1558fn convert_object_to_public(
1559 value: crate::val::Object,
1560 depth: usize,
1561) -> Result<surrealdb_types::Value> {
1562 let converted = convert_object_to_public_map_at(value, depth)?;
1563 Ok(surrealdb_types::Value::Object(surrealdb_types::Object::from(converted)))
1564}
1565
1566pub fn convert_object_to_public_map(
1567 value: crate::val::Object,
1568) -> Result<BTreeMap<String, surrealdb_types::Value>> {
1569 convert_object_to_public_map_at(value, 1)
1570}
1571
1572fn convert_object_to_public_map_at(
1573 value: crate::val::Object,
1574 depth: usize,
1575) -> Result<BTreeMap<String, surrealdb_types::Value>> {
1576 value
1577 .0
1578 .into_iter()
1579 .map(|(k, v)| convert_value_to_public_value_at(v, depth + 1).map(|v| (k.into_string(), v)))
1580 .collect()
1581}
1582
1583fn convert_record_id_to_public(
1584 value: crate::val::RecordId,
1585 depth: usize,
1586) -> Result<surrealdb_types::Value> {
1587 let key = convert_record_id_key_to_public(value.key, depth + 1)?;
1591 Ok(surrealdb_types::Value::RecordId(surrealdb_types::RecordId {
1592 table: value.table.into_public_table(),
1593 key,
1594 }))
1595}
1596
1597fn convert_record_id_key_to_public(
1598 key: crate::val::RecordIdKey,
1599 depth: usize,
1600) -> Result<surrealdb_types::RecordIdKey> {
1601 if depth > MAX_VALUE_DEPTH {
1602 bail!(Error::ValueTooDeep {
1603 max: MAX_VALUE_DEPTH,
1604 });
1605 }
1606 match key {
1607 crate::val::RecordIdKey::Number(n) => Ok(surrealdb_types::RecordIdKey::Number(n)),
1608 crate::val::RecordIdKey::String(s) => Ok(surrealdb_types::RecordIdKey::String(s.into())),
1609 crate::val::RecordIdKey::Uuid(u) => {
1610 Ok(surrealdb_types::RecordIdKey::Uuid(surrealdb_types::Uuid::from(u.0)))
1611 }
1612 crate::val::RecordIdKey::Array(a) => {
1613 let converted_array = convert_array_to_public(a, depth)?;
1614 if let surrealdb_types::Value::Array(arr) = converted_array {
1615 Ok(surrealdb_types::RecordIdKey::Array(arr))
1616 } else {
1617 Err(anyhow::anyhow!("Failed to convert record id key array"))
1618 }
1619 }
1620 crate::val::RecordIdKey::Object(o) => {
1621 let converted_object = convert_object_to_public(o, depth)?;
1622 if let surrealdb_types::Value::Object(obj) = converted_object {
1623 Ok(surrealdb_types::RecordIdKey::Object(obj))
1624 } else {
1625 Err(anyhow::anyhow!("Failed to convert record id key object"))
1626 }
1627 }
1628 crate::val::RecordIdKey::Range(r) => {
1629 Ok(surrealdb_types::RecordIdKey::Range(Box::new(surrealdb_types::RecordIdKeyRange {
1630 start: match r.start {
1631 Bound::Included(k) => {
1632 Bound::Included(convert_record_id_key_to_public(k, depth + 1)?)
1633 }
1634 Bound::Excluded(k) => {
1635 Bound::Excluded(convert_record_id_key_to_public(k, depth + 1)?)
1636 }
1637 Bound::Unbounded => Bound::Unbounded,
1638 },
1639 end: match r.end {
1640 Bound::Included(k) => {
1641 Bound::Included(convert_record_id_key_to_public(k, depth + 1)?)
1642 }
1643 Bound::Excluded(k) => {
1644 Bound::Excluded(convert_record_id_key_to_public(k, depth + 1)?)
1645 }
1646 Bound::Unbounded => Bound::Unbounded,
1647 },
1648 })))
1649 }
1650 }
1651}
1652
1653fn convert_range_to_public(
1654 value: crate::val::Range,
1655 depth: usize,
1656) -> Result<surrealdb_types::Value> {
1657 Ok(surrealdb_types::Value::Range(Box::new(surrealdb_types::Range {
1663 start: match value.start {
1664 Bound::Included(v) => Bound::Included(convert_value_to_public_value_at(v, depth + 1)?),
1665 Bound::Excluded(v) => Bound::Excluded(convert_value_to_public_value_at(v, depth + 1)?),
1666 Bound::Unbounded => Bound::Unbounded,
1667 },
1668 end: match value.end {
1669 Bound::Included(v) => Bound::Included(convert_value_to_public_value_at(v, depth + 1)?),
1670 Bound::Excluded(v) => Bound::Excluded(convert_value_to_public_value_at(v, depth + 1)?),
1671 Bound::Unbounded => Bound::Unbounded,
1672 },
1673 })))
1674}
1675
1676#[cfg(test)]
1677mod tests {
1678 use super::{MAX_VALUE_DEPTH, check_value_depth, convert_value_to_public_value};
1679 use crate::val::{Array, Object, Value};
1680
1681 fn nested_array(depth: usize) -> Value {
1684 let mut value = Value::from(1i64);
1685 for _ in 1..depth {
1686 value = Value::Array(Array::from(vec![value]));
1687 }
1688 value
1689 }
1690
1691 fn nested_object(depth: usize) -> Value {
1692 let mut value = Value::from(1i64);
1693 for _ in 1..depth {
1694 let mut obj = Object::default();
1695 obj.insert("v".to_owned(), value);
1696 value = Value::Object(obj);
1697 }
1698 value
1699 }
1700
1701 #[test]
1708 fn value_depth_within_the_cap_is_accepted() {
1709 check_value_depth(&nested_array(MAX_VALUE_DEPTH))
1710 .expect("a value exactly at the cap must be accepted");
1711 check_value_depth(&nested_object(MAX_VALUE_DEPTH))
1712 .expect("objects nest the same way as arrays");
1713 check_value_depth(&Value::from(1i64)).expect("a scalar is depth 1");
1714 }
1715
1716 #[test]
1717 fn value_depth_past_the_cap_is_rejected() {
1718 let err = check_value_depth(&nested_array(MAX_VALUE_DEPTH + 1))
1719 .expect_err("a value one level past the cap must be rejected");
1720 assert!(err.to_string().contains("nested too deeply"), "unexpected error: {err}");
1721 assert!(check_value_depth(&nested_object(MAX_VALUE_DEPTH + 1)).is_err());
1722 }
1723
1724 #[test]
1736 fn value_depth_check_does_not_recurse() {
1737 let deep = std::mem::ManuallyDrop::new(nested_array(200_000));
1738 assert!(
1739 check_value_depth(&deep).is_err(),
1740 "a very deeply nested value must be rejected, not overflow the stack"
1741 );
1742 }
1743
1744 #[test]
1748 fn public_value_conversion_rejects_values_past_the_cap() {
1749 convert_value_to_public_value(nested_array(MAX_VALUE_DEPTH))
1750 .expect("a value at the cap must still convert");
1751 let err = convert_value_to_public_value(nested_array(MAX_VALUE_DEPTH + 1))
1752 .expect_err("a value past the cap must not convert");
1753 assert!(err.to_string().contains("nested too deeply"), "unexpected error: {err}");
1754 }
1755
1756 #[test]
1762 fn result_rows_conversion_does_not_charge_the_envelope() {
1763 use super::convert_result_rows_to_public;
1764
1765 let row = nested_array(MAX_VALUE_DEPTH);
1766 let result = Value::Array(Array::from(vec![row]));
1767
1768 assert!(
1770 convert_value_to_public_value(result.clone()).is_err(),
1771 "the envelope-charging path must reject a row at the cap"
1772 );
1773 convert_result_rows_to_public(result).expect("a row at the cap must convert as a row");
1775 }
1776
1777 #[test]
1782 fn public_value_conversion_threads_depth_through_ranges() {
1783 use std::ops::Bound;
1784
1785 use crate::val::Range;
1786
1787 let range_bound = |v: Value| {
1788 Value::Range(Box::new(Range {
1789 start: Bound::Included(v),
1790 end: Bound::Unbounded,
1791 }))
1792 };
1793
1794 convert_value_to_public_value(range_bound(nested_array(8)))
1796 .expect("a shallow range-nested value must convert");
1797 let err = convert_value_to_public_value(range_bound(nested_array(MAX_VALUE_DEPTH)))
1799 .expect_err("a range-nested value past the cap must not convert");
1800 assert!(err.to_string().contains("nested too deeply"), "unexpected error: {err}");
1801 }
1802
1803 #[test]
1808 fn geometry_collection_depth_is_walked() {
1809 use crate::val::Geometry;
1810
1811 fn nested_geometry(depth: usize) -> Value {
1813 let mut g = Geometry::Collection(vec![]);
1814 for _ in 1..depth {
1815 g = Geometry::Collection(vec![g]);
1816 }
1817 Value::Geometry(g)
1818 }
1819
1820 check_value_depth(&nested_geometry(MAX_VALUE_DEPTH))
1825 .expect("a geometry collection exactly at the cap must be accepted");
1826 convert_value_to_public_value(nested_geometry(MAX_VALUE_DEPTH))
1827 .expect("a geometry collection at the cap must also convert");
1828 let err = check_value_depth(&nested_geometry(MAX_VALUE_DEPTH + 1))
1829 .expect_err("a geometry one level past the cap must be rejected");
1830 assert!(err.to_string().contains("nested too deeply"), "unexpected error: {err}");
1831 let err = convert_value_to_public_value(nested_geometry(MAX_VALUE_DEPTH + 1))
1832 .expect_err("a geometry one level past the cap must not convert");
1833 assert!(err.to_string().contains("nested too deeply"), "unexpected error: {err}");
1834
1835 let deep = std::mem::ManuallyDrop::new(nested_geometry(200_000));
1839 assert!(
1840 check_value_depth(&deep).is_err(),
1841 "a very deep geometry must be rejected, not overflow the stack"
1842 );
1843 }
1844
1845 #[test]
1852 fn record_id_key_depth_is_walked() {
1853 use crate::val::{RecordId, RecordIdKey};
1854
1855 fn record_id_with_nested_key(inner: usize) -> Value {
1857 Value::RecordId(RecordId {
1858 table: "t".into(),
1859 key: RecordIdKey::Array(Array::from(vec![nested_array(inner)])),
1860 })
1861 }
1862
1863 check_value_depth(&record_id_with_nested_key(MAX_VALUE_DEPTH - 2))
1864 .expect("a compound key exactly at the cap must be accepted");
1865 convert_value_to_public_value(record_id_with_nested_key(MAX_VALUE_DEPTH - 2))
1866 .expect("a compound key at the cap must also convert");
1867 let err = check_value_depth(&record_id_with_nested_key(MAX_VALUE_DEPTH - 1))
1868 .expect_err("a record id whose key nests one past the cap must be rejected");
1869 assert!(err.to_string().contains("nested too deeply"), "unexpected error: {err}");
1870 let err = convert_value_to_public_value(record_id_with_nested_key(MAX_VALUE_DEPTH - 1))
1871 .expect_err("a record id whose key nests one past the cap must not convert");
1872 assert!(err.to_string().contains("nested too deeply"), "unexpected error: {err}");
1873 }
1874
1875 #[test]
1881 fn closure_capture_depth_is_walked() {
1882 use crate::expr::Expr;
1883 use crate::expr::variables::Variables;
1884 use crate::val::Closure;
1885
1886 fn closure_with_nested_capture(inner: usize) -> Value {
1890 let mut captures = Variables::default();
1891 captures.insert("a", nested_array(inner));
1892 Value::Closure(Box::new(Closure::Expr {
1893 args: vec![],
1894 returns: None,
1895 body: Expr::Break,
1896 captures,
1897 }))
1898 }
1899
1900 check_value_depth(&closure_with_nested_capture(MAX_VALUE_DEPTH - 1))
1901 .expect("a closure whose capture sits at the cap must be accepted");
1902 let err = check_value_depth(&closure_with_nested_capture(MAX_VALUE_DEPTH))
1903 .expect_err("a closure whose capture nests past the cap must be rejected");
1904 assert!(err.to_string().contains("nested too deeply"), "unexpected error: {err}");
1905
1906 let deep = std::mem::ManuallyDrop::new(closure_with_nested_capture(200_000));
1908 assert!(
1909 check_value_depth(&deep).is_err(),
1910 "a very deep closure capture must be rejected, not overflow the stack"
1911 );
1912 }
1913
1914 #[test]
1920 fn builtin_closure_captures_are_walked() {
1921 use std::sync::Arc;
1922
1923 use crate::val::Closure;
1924 use crate::val::closure::BuiltinClosureObj;
1925
1926 #[derive(Debug)]
1929 struct Captured(Vec<Value>);
1930 impl BuiltinClosureObj for Captured {
1931 fn as_any(&self) -> &dyn std::any::Any {
1932 self
1933 }
1934 fn captured_values(&self) -> Vec<&Value> {
1935 self.0.iter().collect()
1936 }
1937 }
1938 fn builtin_capturing(inner: usize) -> Value {
1939 Value::Closure(Box::new(Closure::Builtin(Arc::new(Captured(vec![nested_array(
1940 inner,
1941 )])))))
1942 }
1943
1944 check_value_depth(&builtin_capturing(MAX_VALUE_DEPTH - 1))
1945 .expect("a builtin closure whose capture sits at the cap must be accepted");
1946 let err = check_value_depth(&builtin_capturing(MAX_VALUE_DEPTH))
1947 .expect_err("a builtin closure whose capture nests past the cap must be rejected");
1948 assert!(err.to_string().contains("nested too deeply"), "unexpected error: {err}");
1949 }
1950
1951 #[test]
1958 fn hash_agrees_with_eq_flags_numbers_at_any_depth() {
1959 use std::collections::BTreeMap;
1960
1961 use crate::val::{Number, Object, RecordId, RecordIdKey, Value};
1962
1963 let num = Value::Number(Number::Float(0.1));
1964 let nested =
1965 |v: Value| Value::Object(Object::from(BTreeMap::from([(Strand::from("v"), v)])));
1966
1967 for v in [
1968 Value::None,
1969 Value::Null,
1970 Value::Bool(true),
1971 Value::String("x".into()),
1972 Value::from(vec![Value::String("x".into())]),
1973 nested(Value::String("x".into())),
1974 Value::RecordId(RecordId {
1975 table: "t".into(),
1976 key: RecordIdKey::Number(1),
1977 }),
1978 ] {
1979 assert!(v.hash_agrees_with_eq(), "{v:?}");
1980 }
1981
1982 for v in [
1983 num.clone(),
1984 Value::from(vec![num.clone()]),
1985 nested(num.clone()),
1986 nested(Value::from(vec![num.clone()])),
1987 Value::RecordId(RecordId {
1988 table: "t".into(),
1989 key: RecordIdKey::Array(vec![num].into()),
1990 }),
1991 ] {
1992 assert!(!v.hash_agrees_with_eq(), "{v:?}");
1993 }
1994 }
1995
1996 #[test]
1997 fn table_value_renders_escaped() {
1998 use surrealdb_types::ToSql;
1999
2000 use crate::val::{TableName, Value};
2001
2002 assert_eq!(Value::Table(TableName::from("users")).to_sql(), "users");
2003 assert_eq!(Value::Table(TableName::from("table")).to_sql(), "`table`");
2004 assert_eq!(Value::Table(TableName::from("a b")).to_sql(), "`a b`");
2005 }
2006 use chrono::{TimeZone, Utc};
2007 use geo::{MultiLineString, MultiPoint, MultiPolygon, line_string, point, polygon};
2008 use rstest::rstest;
2009 use rust_decimal::Decimal;
2010 use serde_json::{Value as Json, json};
2011
2012 use super::*;
2013 use crate::syn;
2014 use crate::types::{
2015 PublicArray, PublicBytes, PublicDatetime, PublicDuration, PublicGeometry, PublicNumber,
2016 PublicObject, PublicRecordId, PublicRecordIdKey, PublicUuid, PublicValue,
2017 };
2018 use crate::val::Uuid;
2019
2020 macro_rules! parse_val {
2021 ($input:expr) => {
2022 crate::val::convert_public_value_to_internal(syn::value($input).unwrap())
2023 };
2024 }
2025
2026 #[test]
2027 fn check_none() {
2028 assert!(Value::None.is_none());
2029 assert!(!Value::Null.is_none());
2030 assert!(!Value::from(1).is_none());
2031 }
2032
2033 #[test]
2034 fn check_null() {
2035 assert!(Value::Null.is_null());
2036 assert!(!Value::None.is_null());
2037 assert!(!Value::from(1).is_null());
2038 }
2039
2040 #[test]
2041 fn convert_truthy() {
2042 assert!(!Value::None.is_truthy());
2043 assert!(!Value::Null.is_truthy());
2044 assert!(Value::Bool(true).is_truthy());
2045 assert!(!Value::Bool(false).is_truthy());
2046 assert!(!Value::from(0).is_truthy());
2047 assert!(Value::from(1).is_truthy());
2048 assert!(Value::from(-1).is_truthy());
2049 assert!(Value::from(1.1).is_truthy());
2050 assert!(Value::from(-1.1).is_truthy());
2051 assert!(Value::from("true").is_truthy());
2052 assert!(Value::from("false").is_truthy());
2053 assert!(Value::from("falsey").is_truthy());
2054 assert!(Value::from("something").is_truthy());
2055 assert!(Value::from(Uuid::nil()).is_truthy());
2056 assert!(Value::from(Utc.with_ymd_and_hms(1948, 12, 3, 0, 0, 0).unwrap()).is_truthy());
2057 }
2058
2059 #[test]
2060 fn convert_string() {
2061 assert_eq!(String::from("NONE"), Value::None.into_raw_string());
2062 assert_eq!(String::from("NULL"), Value::Null.into_raw_string());
2063 assert_eq!(String::from("true"), Value::Bool(true).into_raw_string());
2064 assert_eq!(String::from("false"), Value::Bool(false).into_raw_string());
2065 assert_eq!(String::from("0"), Value::from(0).into_raw_string());
2066 assert_eq!(String::from("1"), Value::from(1).into_raw_string());
2067 assert_eq!(String::from("-1"), Value::from(-1).into_raw_string());
2068 assert_eq!(String::from("1.1f"), Value::from(1.1).into_raw_string());
2069 assert_eq!(String::from("-1.1f"), Value::from(-1.1).into_raw_string());
2070 assert_eq!(String::from("3"), Value::from("3").into_raw_string());
2071 assert_eq!(String::from("true"), Value::from("true").into_raw_string());
2072 assert_eq!(String::from("false"), Value::from("false").into_raw_string());
2073 assert_eq!(String::from("something"), Value::from("something").into_raw_string());
2074 }
2075
2076 #[test]
2077 fn check_size() {
2078 assert!(64 >= std::mem::size_of::<Value>(), "size of value too big");
2079 }
2080
2081 #[rstest]
2082 #[case::none(Value::None, 2)]
2087 #[case::null(Value::Null, 2)]
2088 #[case::bool(Value::Bool(true), 3)]
2089 #[case::bool(Value::Bool(false), 3)]
2090 #[case::string(Value::from("test"), 11)]
2094 #[case::object(Value::from(syn::value("{ hello: 'world' }").unwrap()), 31)]
2103 #[case::object(Value::from(syn::value("{ compact: true, schema: 0 }").unwrap()), 40)]
2104 fn check_serialize(#[case] value: Value, #[case] expected: usize) {
2105 let enc: Vec<u8> = revision::to_vec(&value).unwrap();
2106 assert_eq!(expected, enc.len());
2107 }
2108
2109 #[test]
2110 fn serialize_deserialize() {
2111 let val = parse_val!(
2112 "{ test: { something: [1, 'two', null, test:tobie, { trueee: false, noneee: null }] } }"
2113 );
2114 let res = parse_val!(
2115 "{ test: { something: [1, 'two', null, test:tobie, { trueee: false, noneee: null }] } }"
2116 );
2117 let enc: Vec<u8> = revision::to_vec(&val).unwrap();
2118 let dec: Value = revision::from_slice(&enc).unwrap();
2119 assert_eq!(res, dec);
2120 }
2121
2122 #[rstest]
2123 #[case::none(PublicValue::None, json!(null), PublicValue::Null)]
2124 #[case::null(PublicValue::Null, json!(null), PublicValue::Null)]
2125 #[case::bool(PublicValue::Bool(true), json!(true), PublicValue::Bool(true))]
2126 #[case::bool(PublicValue::Bool(false), json!(false), PublicValue::Bool(false))]
2127 #[case::number(
2128 PublicValue::Number(PublicNumber::Int(i64::MIN)),
2129 json!(i64::MIN),
2130 PublicValue::Number(PublicNumber::Int(i64::MIN)),
2131 )]
2132 #[case::number(
2133 PublicValue::Number(PublicNumber::Int(i64::MAX)),
2134 json!(i64::MAX),
2135 PublicValue::Number(PublicNumber::Int(i64::MAX)),
2136 )]
2137 #[case::number(
2138 PublicValue::Number(PublicNumber::Float(1.23)),
2139 json!(1.23),
2140 PublicValue::Number(PublicNumber::Float(1.23)),
2141 )]
2142 #[case::number(
2143 PublicValue::Number(PublicNumber::Float(f64::NEG_INFINITY)),
2144 json!(null),
2145 PublicValue::Null,
2146 )]
2147 #[case::number(
2148 PublicValue::Number(PublicNumber::Float(f64::MIN)),
2149 json!(-1.7976931348623157e308),
2150 PublicValue::Number(PublicNumber::Float(f64::MIN)),
2151 )]
2152 #[case::number(
2153 PublicValue::Number(PublicNumber::Float(0.0)),
2154 json!(0.0),
2155 PublicValue::Number(PublicNumber::Float(0.0)),
2156 )]
2157 #[case::number(
2158 PublicValue::Number(PublicNumber::Float(f64::MAX)),
2159 json!(1.7976931348623157e308),
2160 PublicValue::Number(PublicNumber::Float(f64::MAX)),
2161 )]
2162 #[case::number(
2163 PublicValue::Number(PublicNumber::Float(f64::INFINITY)),
2164 json!(null),
2165 PublicValue::Null,
2166 )]
2167 #[case::number(
2168 PublicValue::Number(PublicNumber::Float(f64::NAN)),
2169 json!(null),
2170 PublicValue::Null,
2171 )]
2172 #[case::number(
2173 PublicValue::Number(PublicNumber::Decimal(Decimal::new(123, 2))),
2174 json!("1.23"),
2175 PublicValue::String("1.23".to_string()),
2176 )]
2177 #[case::strand(
2178 PublicValue::String("".to_string()),
2179 json!(""),
2180 PublicValue::String("".to_string()),
2181 )]
2182 #[case::strand(
2183 PublicValue::String("foo".to_string()),
2184 json!("foo"),
2185 PublicValue::String("foo".to_string()),
2186 )]
2187 #[case::duration(
2188 PublicValue::Duration(PublicDuration::ZERO),
2189 json!("0ns"),
2190 PublicValue::String("0ns".to_string()),
2191 )]
2192 #[case::duration(
2193 PublicValue::Duration(PublicDuration::MAX),
2194 json!("584942417355y3w5d7h15s999ms999µs999ns"),
2195 PublicValue::String("584942417355y3w5d7h15s999ms999µs999ns".to_string()),
2196 )]
2197 #[case::datetime(
2198 PublicValue::Datetime(PublicDatetime::MIN_UTC),
2199 json!("-262143-01-01T00:00:00Z"),
2200 PublicValue::Datetime(PublicDatetime::MIN_UTC),
2201 )]
2202 #[case::datetime(
2203 PublicValue::Datetime(PublicDatetime::MAX_UTC),
2204 json!("+262142-12-31T23:59:59.999999999Z"),
2205 PublicValue::Datetime(PublicDatetime::MAX_UTC),
2206 )]
2207 #[case::uuid(
2208 PublicValue::Uuid(PublicUuid::nil()),
2209 json!("00000000-0000-0000-0000-000000000000"),
2210 PublicValue::Uuid(PublicUuid::nil()),
2211 )]
2212 #[case::uuid(
2213 PublicValue::Uuid(PublicUuid::max()),
2214 json!("ffffffff-ffff-ffff-ffff-ffffffffffff"),
2215 PublicValue::Uuid(PublicUuid::max()),
2216 )]
2217 #[case::bytes(
2218 PublicValue::Bytes(PublicBytes::default()),
2219 json!([]),
2220 PublicValue::Array(PublicArray::new()),
2221 )]
2222 #[case::bytes(
2223 PublicValue::Bytes(PublicBytes::from(b"foo".to_vec())),
2224 json!([102, 111, 111]),
2225 PublicValue::Array(PublicArray::from(vec![
2226 PublicValue::Number(PublicNumber::Int(102)),
2227 PublicValue::Number(PublicNumber::Int(111)),
2228 PublicValue::Number(PublicNumber::Int(111)),
2229 ])),
2230 )]
2231 #[case::record_id(
2232 PublicValue::RecordId(PublicRecordId::new("foo", PublicRecordIdKey::String("bar".to_string()))) ,
2233 json!("foo:bar"),
2234 PublicValue::RecordId(PublicRecordId::new("foo", PublicRecordIdKey::String("bar".to_string()))) ,
2235 )]
2236 #[case::array(
2237 PublicValue::Array(PublicArray::new()),
2238 json!([]),
2239 PublicValue::Array(PublicArray::new()),
2240 )]
2241 #[case::array(
2242 PublicValue::Array(PublicArray::from(vec![PublicValue::Bool(true), PublicValue::Bool(false)])),
2243 json!([true, false]),
2244 PublicValue::Array(PublicArray::from(vec![PublicValue::Bool(true), PublicValue::Bool(false)])),
2245 )]
2246 #[case::object(
2247 PublicValue::Object(PublicObject::new()),
2248 json!({}),
2249 PublicValue::Object(PublicObject::new()),
2250 )]
2251 #[case::object(
2252 PublicValue::Object(PublicObject::from_iter([("done".to_owned(), PublicValue::Bool(true))])),
2253 json!({"done": true}),
2254 PublicValue::Object(PublicObject::from_iter([("done".to_owned(), PublicValue::Bool(true))])),
2255 )]
2256 #[case::geometry_point(
2257 PublicValue::Geometry(PublicGeometry::Point(point! { x: 10., y: 20. })),
2258 json!({ "type": "Point", "coordinates": [10., 20.]}),
2259 PublicValue::Geometry(PublicGeometry::Point(point! { x: 10., y: 20. })),
2260 )]
2261 #[case::geometry_line(
2262 PublicValue::Geometry(PublicGeometry::Line(line_string![
2263 ( x: 0., y: 0. ),
2264 ( x: 10., y: 0. ),
2265 ])),
2266 json!({ "type": "LineString", "coordinates": [[0., 0.], [10., 0.]]}),
2267 PublicValue::Geometry(PublicGeometry::Line(line_string![
2268 ( x: 0., y: 0. ),
2269 ( x: 10., y: 0. ),
2270 ])),
2271 )]
2272 #[case::geometry_polygon(
2273 PublicValue::Geometry(PublicGeometry::Polygon(polygon![
2274 (x: -111., y: 45.),
2275 (x: -111., y: 41.),
2276 (x: -104., y: 41.),
2277 (x: -104., y: 45.),
2278 ])),
2279 json!({ "type": "Polygon", "coordinates": [[
2280 [-111., 45.],
2281 [-111., 41.],
2282 [-104., 41.],
2283 [-104., 45.],
2284 [-111., 45.],
2285 ]]}),
2286 PublicValue::Geometry(PublicGeometry::Polygon(polygon![
2287 (x: -111., y: 45.),
2288 (x: -111., y: 41.),
2289 (x: -104., y: 41.),
2290 (x: -104., y: 45.),
2291 ])),
2292 )]
2293 #[case::geometry_multi_point(
2294 PublicValue::Geometry(PublicGeometry::MultiPoint(MultiPoint::new(vec![
2295 point! { x: 0., y: 0. },
2296 point! { x: 1., y: 2. },
2297 ]))),
2298 json!({ "type": "MultiPoint", "coordinates": [[0., 0.], [1., 2.]]}),
2299 PublicValue::Geometry(PublicGeometry::MultiPoint(MultiPoint::new(vec![
2300 point! { x: 0., y: 0. },
2301 point! { x: 1., y: 2. },
2302 ]))),
2303 )]
2304 #[case::geometry_multi_line(
2305 PublicValue::Geometry(
2306 PublicGeometry::MultiLine(
2307 MultiLineString::new(vec![
2308 line_string![( x: 0., y: 0. ), ( x: 1., y: 2. )],
2309 ])
2310 )
2311 ),
2312 json!({ "type": "MultiLineString", "coordinates": [[[0., 0.], [1., 2.]]]}),
2313 PublicValue::Geometry(
2314 PublicGeometry::MultiLine(
2315 MultiLineString::new(vec![
2316 line_string![( x: 0., y: 0. ), ( x: 1., y: 2. )],
2317 ])
2318 )
2319 ),
2320 )]
2321 #[case::geometry_multi_polygon(
2322 PublicValue::Geometry(PublicGeometry::MultiPolygon(MultiPolygon::new(vec![
2323 polygon![
2324 (x: -111., y: 45.),
2325 (x: -111., y: 41.),
2326 (x: -104., y: 41.),
2327 (x: -104., y: 45.),
2328 ],
2329 ]))),
2330 json!({ "type": "MultiPolygon", "coordinates": [[[
2331 [-111., 45.],
2332 [-111., 41.],
2333 [-104., 41.],
2334 [-104., 45.],
2335 [-111., 45.],
2336 ]]]})
2337 , PublicValue::Geometry(PublicGeometry::MultiPolygon(MultiPolygon::new(vec![
2338 polygon![
2339 (x: -111., y: 45.),
2340 (x: -111., y: 41.),
2341 (x: -104., y: 41.),
2342 (x: -104., y: 45.),
2343 ],
2344 ]))),
2345 )]
2346 #[case::geometry_collection(
2347 PublicValue::Geometry(PublicGeometry::Collection(vec![])),
2348 json!({
2349 "type": "GeometryCollection",
2350 "geometries": [],
2351 }),
2352 PublicValue::Geometry(PublicGeometry::Collection(vec![])),
2353 )]
2354 #[case::geometry_collection_with_point(
2355 PublicValue::Geometry(PublicGeometry::Collection(vec![PublicGeometry::Point(point! { x: 10., y: 20. })])),
2356 json!({
2357 "type": "GeometryCollection",
2358 "geometries": [ { "type": "Point", "coordinates": [10., 20.] } ],
2359 }),
2360 PublicValue::Geometry(PublicGeometry::Collection(vec![PublicGeometry::Point(point! { x: 10., y: 20. })])),
2361 )]
2362 #[case::geometry_collection_with_line(
2363 PublicValue::Geometry(PublicGeometry::Collection(vec![PublicGeometry::Line(line_string![
2364 ( x: 0., y: 0. ),
2365 ( x: 10., y: 0. ),
2366 ])])),
2367 json!({
2368 "type": "GeometryCollection",
2369 "geometries": [ { "type": "LineString", "coordinates": [[0., 0.], [10., 0.]] } ],
2370 }),
2371 PublicValue::Geometry(PublicGeometry::Collection(vec![PublicGeometry::Line(line_string![
2372 ( x: 0., y: 0. ),
2373 ( x: 10., y: 0. ),
2374 ])])),
2375 )]
2376
2377 fn test_json(
2378 #[case] value: PublicValue,
2379 #[case] expected: Json,
2380 #[case] expected_deserialized: PublicValue,
2381 ) {
2382 use surrealdb_syn::ParserConfig;
2383
2384 let json_value = value.into_json_value();
2385 assert_eq!(json_value, expected);
2386
2387 let json_str = serde_json::to_string(&json_value).expect("Failed to serialize to JSON");
2388 let deserialized_sql_value =
2389 crate::syn::value_legacy_strand(&json_str, &ParserConfig::default()).unwrap();
2390 assert_eq!(deserialized_sql_value, expected_deserialized);
2391 }
2392}