surrealdb_sql/
range.rs

1use crate::ctx::Context;
2use crate::dbs::{Options, Transaction};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::syn;
6use crate::{strand::no_nul_bytes, Id, Value};
7use revision::revisioned;
8use serde::{Deserialize, Serialize};
9use std::cmp::Ordering;
10use std::fmt;
11use std::ops::Bound;
12use std::str::FromStr;
13
14pub(crate) const TOKEN: &str = "$surrealdb::private::crate::Range";
15
16#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
17#[serde(rename = "$surrealdb::private::crate::Range")]
18#[revisioned(revision = 1)]
19pub struct Range {
20	#[serde(with = "no_nul_bytes")]
21	pub tb: String,
22	pub beg: Bound<Id>,
23	pub end: Bound<Id>,
24}
25
26impl FromStr for Range {
27	type Err = ();
28	fn from_str(s: &str) -> Result<Self, Self::Err> {
29		Self::try_from(s)
30	}
31}
32
33impl TryFrom<&str> for Range {
34	type Error = ();
35	fn try_from(v: &str) -> Result<Self, Self::Error> {
36		match syn::range(v) {
37			Ok(v) => Ok(v),
38			_ => Err(()),
39		}
40	}
41}
42
43impl Range {
44	/// Process this type returning a computed simple Value
45	pub(crate) async fn compute(
46		&self,
47		ctx: &Context<'_>,
48		opt: &Options,
49		txn: &Transaction,
50		doc: Option<&CursorDoc<'_>>,
51	) -> Result<Value, Error> {
52		Ok(Value::Range(Box::new(Range {
53			tb: self.tb.clone(),
54			beg: match &self.beg {
55				Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?),
56				Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?),
57				Bound::Unbounded => Bound::Unbounded,
58			},
59			end: match &self.end {
60				Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?),
61				Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?),
62				Bound::Unbounded => Bound::Unbounded,
63			},
64		})))
65	}
66}
67
68impl PartialOrd for Range {
69	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
70		match self.tb.partial_cmp(&other.tb) {
71			Some(Ordering::Equal) => match &self.beg {
72				Bound::Unbounded => match &other.beg {
73					Bound::Unbounded => Some(Ordering::Equal),
74					_ => Some(Ordering::Less),
75				},
76				Bound::Included(v) => match &other.beg {
77					Bound::Unbounded => Some(Ordering::Greater),
78					Bound::Included(w) => match v.partial_cmp(w) {
79						Some(Ordering::Equal) => match &self.end {
80							Bound::Unbounded => match &other.end {
81								Bound::Unbounded => Some(Ordering::Equal),
82								_ => Some(Ordering::Greater),
83							},
84							Bound::Included(v) => match &other.end {
85								Bound::Unbounded => Some(Ordering::Less),
86								Bound::Included(w) => v.partial_cmp(w),
87								_ => Some(Ordering::Greater),
88							},
89							Bound::Excluded(v) => match &other.end {
90								Bound::Excluded(w) => v.partial_cmp(w),
91								_ => Some(Ordering::Less),
92							},
93						},
94						ordering => ordering,
95					},
96					_ => Some(Ordering::Less),
97				},
98				Bound::Excluded(v) => match &other.beg {
99					Bound::Excluded(w) => match v.partial_cmp(w) {
100						Some(Ordering::Equal) => match &self.end {
101							Bound::Unbounded => match &other.end {
102								Bound::Unbounded => Some(Ordering::Equal),
103								_ => Some(Ordering::Greater),
104							},
105							Bound::Included(v) => match &other.end {
106								Bound::Unbounded => Some(Ordering::Less),
107								Bound::Included(w) => v.partial_cmp(w),
108								_ => Some(Ordering::Greater),
109							},
110							Bound::Excluded(v) => match &other.end {
111								Bound::Excluded(w) => v.partial_cmp(w),
112								_ => Some(Ordering::Less),
113							},
114						},
115						ordering => ordering,
116					},
117					_ => Some(Ordering::Greater),
118				},
119			},
120			ordering => ordering,
121		}
122	}
123}
124
125impl fmt::Display for Range {
126	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127		write!(f, "{}:", self.tb)?;
128		match &self.beg {
129			Bound::Unbounded => write!(f, ""),
130			Bound::Included(id) => write!(f, "{id}"),
131			Bound::Excluded(id) => write!(f, "{id}>"),
132		}?;
133		match &self.end {
134			Bound::Unbounded => write!(f, ".."),
135			Bound::Excluded(id) => write!(f, "..{id}"),
136			Bound::Included(id) => write!(f, "..={id}"),
137		}?;
138		Ok(())
139	}
140}