surrealdb_types/value/
range.rs1use std::cmp::Ordering;
2use std::ops::{Bound, RangeBounds};
3
4use serde::{Deserialize, Serialize};
5
6use crate::sql::{SqlFormat, ToSql};
7use crate::{SurrealValue, Value};
8
9#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
15#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
16pub struct Range {
17 pub start: Bound<Value>,
19 pub end: Bound<Value>,
21}
22
23impl Range {
24 pub const fn new(start: Bound<Value>, end: Bound<Value>) -> Self {
26 Range {
27 start,
28 end,
29 }
30 }
31
32 pub const fn unbounded() -> Self {
34 Range {
35 start: Bound::Unbounded,
36 end: Bound::Unbounded,
37 }
38 }
39
40 pub fn start(&self) -> Bound<&Value> {
42 self.start.as_ref()
43 }
44
45 pub fn end(&self) -> Bound<&Value> {
47 self.end.as_ref()
48 }
49
50 pub fn into_inner(self) -> (Bound<Value>, Bound<Value>) {
52 (self.start, self.end)
53 }
54}
55
56impl From<(Bound<Value>, Bound<Value>)> for Range {
57 fn from((start, end): (Bound<Value>, Bound<Value>)) -> Self {
58 Range {
59 start,
60 end,
61 }
62 }
63}
64
65impl<T: SurrealValue> From<std::ops::Range<T>> for Range {
66 fn from(range: std::ops::Range<T>) -> Self {
67 Range {
68 start: Bound::Included(range.start.into_value()),
69 end: Bound::Excluded(range.end.into_value()),
70 }
71 }
72}
73
74impl<T: SurrealValue> From<std::ops::RangeInclusive<T>> for Range {
75 fn from(range: std::ops::RangeInclusive<T>) -> Self {
76 let (start, end) = range.into_inner();
77 Range {
78 start: Bound::Included(start.into_value()),
79 end: Bound::Included(end.into_value()),
80 }
81 }
82}
83
84impl<T: SurrealValue> From<std::ops::RangeFrom<T>> for Range {
85 fn from(range: std::ops::RangeFrom<T>) -> Self {
86 Range {
87 start: Bound::Included(range.start.into_value()),
88 end: Bound::Unbounded,
89 }
90 }
91}
92
93impl<T: SurrealValue> From<std::ops::RangeTo<T>> for Range {
94 fn from(range: std::ops::RangeTo<T>) -> Self {
95 Range {
96 start: Bound::Unbounded,
97 end: Bound::Excluded(range.end.into_value()),
98 }
99 }
100}
101
102impl From<std::ops::RangeFull> for Range {
103 fn from(_: std::ops::RangeFull) -> Self {
104 Range {
105 start: Bound::Unbounded,
106 end: Bound::Unbounded,
107 }
108 }
109}
110
111impl RangeBounds<Value> for Range {
112 fn start_bound(&self) -> Bound<&Value> {
113 self.start.as_ref()
114 }
115
116 fn end_bound(&self) -> Bound<&Value> {
117 self.end.as_ref()
118 }
119
120 fn contains<U>(&self, item: &U) -> bool
121 where
122 U: ?Sized + PartialOrd<Value>,
123 Value: PartialOrd<U>,
124 {
125 (match self.start_bound() {
126 Bound::Unbounded => true,
127 Bound::Included(start) => start <= item,
128 Bound::Excluded(start) => start < item,
129 }) && (match self.end_bound() {
130 Bound::Unbounded => true,
131 Bound::Included(end) => item <= end,
132 Bound::Excluded(end) => item < end,
133 })
134 }
135}
136
137impl PartialOrd for Range {
138 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
139 Some(self.cmp(other))
140 }
141}
142
143impl Ord for Range {
144 fn cmp(&self, other: &Self) -> Ordering {
145 fn compare_bounds(a: &Bound<Value>, b: &Bound<Value>) -> Ordering {
146 match a {
147 Bound::Unbounded => match b {
148 Bound::Unbounded => Ordering::Equal,
149 _ => Ordering::Less,
150 },
151 Bound::Included(a) => match b {
152 Bound::Unbounded => Ordering::Greater,
153 Bound::Included(b) => a.cmp(b),
154 Bound::Excluded(_) => Ordering::Less,
155 },
156 Bound::Excluded(a) => match b {
157 Bound::Excluded(b) => a.cmp(b),
158 _ => Ordering::Greater,
159 },
160 }
161 }
162 match compare_bounds(&self.start, &other.start) {
163 Ordering::Equal => compare_bounds(&self.end, &other.end),
164 x => x,
165 }
166 }
167}
168
169impl ToSql for Range {
170 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
171 match self.start {
172 Bound::Unbounded => {}
173 Bound::Included(ref x) => x.fmt_sql(f, fmt),
174 Bound::Excluded(ref x) => {
175 x.fmt_sql(f, fmt);
176 f.push('>');
177 }
178 }
179 f.push_str("..");
180 match self.end {
181 Bound::Unbounded => {}
182 Bound::Included(ref x) => {
183 f.push('=');
184 x.fmt_sql(f, fmt);
185 }
186 Bound::Excluded(ref x) => {
187 x.fmt_sql(f, fmt);
188 }
189 }
190 }
191}