1use crate::compat::types::PublicDuration;
2use crate::upstream::fmt::{EscapeKwFreeIdent, EscapeObjectKey, Float, Fmt, QuoteStr};
3use rust_decimal::Decimal;
4use std::collections::{BTreeMap, HashSet};
5use std::fmt::Display;
6use std::hash;
7use surrealdb_types::{SqlFormat, ToSql, write_sql};
8#[derive(Clone, Debug, Eq, PartialEq, Hash)]
9#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
10pub enum GeometryKind {
11 Point,
12 Line,
13 Polygon,
14 MultiPoint,
15 MultiLine,
16 MultiPolygon,
17 Collection,
18}
19impl ToSql for GeometryKind {
20 fn fmt_sql(&self, f: &mut String, _fmt: SqlFormat) {
21 match self {
22 GeometryKind::Point => f.push_str("point"),
23 GeometryKind::Line => f.push_str("line"),
24 GeometryKind::Polygon => f.push_str("polygon"),
25 GeometryKind::MultiPoint => f.push_str("multipoint"),
26 GeometryKind::MultiLine => f.push_str("multiline"),
27 GeometryKind::MultiPolygon => f.push_str("multipolygon"),
28 GeometryKind::Collection => f.push_str("collection"),
29 }
30 }
31}
32impl From<GeometryKind> for crate::compat::types::PublicGeometryKind {
33 fn from(v: GeometryKind) -> Self {
34 match v {
35 GeometryKind::Point => crate::compat::types::PublicGeometryKind::Point,
36 GeometryKind::Line => crate::compat::types::PublicGeometryKind::Line,
37 GeometryKind::Polygon => crate::compat::types::PublicGeometryKind::Polygon,
38 GeometryKind::MultiPoint => crate::compat::types::PublicGeometryKind::MultiPoint,
39 GeometryKind::MultiLine => crate::compat::types::PublicGeometryKind::MultiLine,
40 GeometryKind::MultiPolygon => crate::compat::types::PublicGeometryKind::MultiPolygon,
41 GeometryKind::Collection => crate::compat::types::PublicGeometryKind::Collection,
42 }
43 }
44}
45impl From<crate::compat::types::PublicGeometryKind> for GeometryKind {
46 fn from(v: crate::compat::types::PublicGeometryKind) -> Self {
47 match v {
48 crate::compat::types::PublicGeometryKind::Point => GeometryKind::Point,
49 crate::compat::types::PublicGeometryKind::Line => GeometryKind::Line,
50 crate::compat::types::PublicGeometryKind::Polygon => GeometryKind::Polygon,
51 crate::compat::types::PublicGeometryKind::MultiPoint => GeometryKind::MultiPoint,
52 crate::compat::types::PublicGeometryKind::MultiLine => GeometryKind::MultiLine,
53 crate::compat::types::PublicGeometryKind::MultiPolygon => GeometryKind::MultiPolygon,
54 crate::compat::types::PublicGeometryKind::Collection => GeometryKind::Collection,
55 }
56 }
57}
58#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
60#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
61pub enum Kind {
62 #[default]
64 Any,
65 None,
67 Null,
69 Bool,
71 Bytes,
73 Datetime,
75 Decimal,
77 Duration,
79 Float,
81 Int,
83 Number,
86 Object,
88 String,
90 Uuid,
92 Regex,
94 Table(Vec<String>),
96 Record(Vec<String>),
98 Geometry(Vec<GeometryKind>),
100 Either(
103 #[cfg_attr(
104 feature = "arbitrary",
105 arbitrary(with = crate::upstream::sql::arbitrary::either_kind)
106 )]
107 Vec<Kind>,
108 ),
109 Set(Box<Kind>, Option<u64>),
111 Array(Box<Kind>, Option<u64>),
113 Function(Option<Vec<Kind>>, Option<Box<Kind>>),
117 Range,
119 Literal(KindLiteral),
125 File(Vec<String>),
129}
130impl Kind {
131 pub fn flatten(self) -> Vec<Kind> {
132 match self {
133 Kind::Either(x) => x.into_iter().flat_map(|k| k.flatten()).collect(),
134 _ => vec![self],
135 }
136 }
137 pub fn either(kinds: Vec<Kind>) -> Kind {
138 let mut seen = HashSet::new();
139 let mut kinds = kinds
140 .into_iter()
141 .flat_map(|k| k.flatten())
142 .filter(|k| seen.insert(k.clone()))
143 .collect::<Vec<_>>();
144 match kinds.len() {
145 0 => Kind::None,
146 1 => kinds.remove(0),
147 _ => Kind::Either(kinds),
148 }
149 }
150}
151impl From<Kind> for crate::compat::types::PublicKind {
152 fn from(v: Kind) -> Self {
153 match v {
154 Kind::Any => crate::compat::types::PublicKind::Any,
155 Kind::None => crate::compat::types::PublicKind::None,
156 Kind::Null => crate::compat::types::PublicKind::Null,
157 Kind::Bool => crate::compat::types::PublicKind::Bool,
158 Kind::Bytes => crate::compat::types::PublicKind::Bytes,
159 Kind::Datetime => crate::compat::types::PublicKind::Datetime,
160 Kind::Decimal => crate::compat::types::PublicKind::Decimal,
161 Kind::Duration => crate::compat::types::PublicKind::Duration,
162 Kind::Float => crate::compat::types::PublicKind::Float,
163 Kind::Int => crate::compat::types::PublicKind::Int,
164 Kind::Number => crate::compat::types::PublicKind::Number,
165 Kind::Object => crate::compat::types::PublicKind::Object,
166 Kind::String => crate::compat::types::PublicKind::String,
167 Kind::Uuid => crate::compat::types::PublicKind::Uuid,
168 Kind::Regex => crate::compat::types::PublicKind::Regex,
169 Kind::Table(k) => {
170 crate::compat::types::PublicKind::Table(k.into_iter().map(Into::into).collect())
171 }
172 Kind::Record(k) => {
173 crate::compat::types::PublicKind::Record(k.into_iter().map(Into::into).collect())
174 }
175 Kind::Geometry(k) => {
176 crate::compat::types::PublicKind::Geometry(k.into_iter().map(Into::into).collect())
177 }
178 Kind::Either(k) => {
179 crate::compat::types::PublicKind::Either(k.into_iter().map(Into::into).collect())
180 }
181 Kind::Set(k, l) => crate::compat::types::PublicKind::Set(Box::new((*k).into()), l),
182 Kind::Array(k, l) => crate::compat::types::PublicKind::Array(Box::new((*k).into()), l),
183 Kind::Function(args, ret) => crate::compat::types::PublicKind::Function(
184 args.map(|args| args.into_iter().map(Into::into).collect()),
185 ret.map(|ret| Box::new((*ret).into())),
186 ),
187 Kind::Range => crate::compat::types::PublicKind::Range,
188 Kind::Literal(l) => crate::compat::types::PublicKind::Literal(l.into()),
189 Kind::File(k) => crate::compat::types::PublicKind::File(k),
190 }
191 }
192}
193impl From<crate::compat::types::PublicKind> for Kind {
194 fn from(v: crate::compat::types::PublicKind) -> Self {
195 match v {
196 crate::compat::types::PublicKind::None => Kind::None,
197 crate::compat::types::PublicKind::Null => Kind::Null,
198 crate::compat::types::PublicKind::Any => Kind::Any,
199 crate::compat::types::PublicKind::Bool => Kind::Bool,
200 crate::compat::types::PublicKind::Bytes => Kind::Bytes,
201 crate::compat::types::PublicKind::Datetime => Kind::Datetime,
202 crate::compat::types::PublicKind::Decimal => Kind::Decimal,
203 crate::compat::types::PublicKind::Duration => Kind::Duration,
204 crate::compat::types::PublicKind::Float => Kind::Float,
205 crate::compat::types::PublicKind::Int => Kind::Int,
206 crate::compat::types::PublicKind::Number => Kind::Number,
207 crate::compat::types::PublicKind::Object => Kind::Object,
208 crate::compat::types::PublicKind::String => Kind::String,
209 crate::compat::types::PublicKind::Uuid => Kind::Uuid,
210 crate::compat::types::PublicKind::Regex => Kind::Regex,
211 crate::compat::types::PublicKind::Table(k) => {
212 Kind::Table(k.into_iter().map(Into::into).collect())
213 }
214 crate::compat::types::PublicKind::Record(k) => {
215 Kind::Record(k.into_iter().map(Into::into).collect())
216 }
217 crate::compat::types::PublicKind::Geometry(k) => {
218 Kind::Geometry(k.into_iter().map(Into::into).collect())
219 }
220 crate::compat::types::PublicKind::Either(k) => {
221 Kind::Either(k.into_iter().map(Into::into).collect())
222 }
223 crate::compat::types::PublicKind::Set(k, l) => Kind::Set(Box::new((*k).into()), l),
224 crate::compat::types::PublicKind::Array(k, l) => Kind::Array(Box::new((*k).into()), l),
225 crate::compat::types::PublicKind::Function(args, ret) => Kind::Function(
226 args.map(|args| args.into_iter().map(Into::into).collect()),
227 ret.map(|ret| Box::new((*ret).into())),
228 ),
229 crate::compat::types::PublicKind::Range => Kind::Range,
230 crate::compat::types::PublicKind::Literal(l) => Kind::Literal(l.into()),
231 crate::compat::types::PublicKind::File(k) => Kind::File(k),
232 }
233 }
234}
235impl ToSql for Kind {
236 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
237 match self {
238 Kind::Any => f.push_str("any"),
239 Kind::None => f.push_str("none"),
240 Kind::Null => f.push_str("null"),
241 Kind::Bool => f.push_str("bool"),
242 Kind::Bytes => f.push_str("bytes"),
243 Kind::Datetime => f.push_str("datetime"),
244 Kind::Decimal => f.push_str("decimal"),
245 Kind::Duration => f.push_str("duration"),
246 Kind::Float => f.push_str("float"),
247 Kind::Int => f.push_str("int"),
248 Kind::Number => f.push_str("number"),
249 Kind::Object => f.push_str("object"),
250 Kind::String => f.push_str("string"),
251 Kind::Uuid => f.push_str("uuid"),
252 Kind::Regex => f.push_str("regex"),
253 Kind::Function(_, _) => f.push_str("function"),
254 Kind::Table(k) => {
255 if k.is_empty() {
256 f.push_str("table");
257 } else {
258 write_sql!(
259 f,
260 fmt,
261 "table<{}>",
262 Fmt::verbar_separated(k.iter().map(|x| EscapeKwFreeIdent(x)))
263 );
264 }
265 }
266 Kind::Record(k) => {
267 if k.is_empty() {
268 f.push_str("record");
269 } else {
270 write_sql!(
271 f,
272 fmt,
273 "record<{}>",
274 Fmt::verbar_separated(k.iter().map(|x| EscapeKwFreeIdent(x)))
275 );
276 }
277 }
278 Kind::Geometry(k) => {
279 if k.is_empty() {
280 f.push_str("geometry");
281 } else {
282 write_sql!(f, fmt, "geometry<{}>", Fmt::verbar_separated(k));
283 }
284 }
285 Kind::Set(k, l) => match (k, l) {
286 (k, None) if matches!(**k, Kind::Any) => f.push_str("set"),
287 (k, None) => write_sql!(f, fmt, "set<{k}>"),
288 (k, Some(l)) => write_sql!(f, fmt, "set<{k}, {l}>"),
289 },
290 Kind::Array(k, l) => match (k, l) {
291 (k, None) if matches!(**k, Kind::Any) => f.push_str("array"),
292 (k, None) => write_sql!(f, fmt, "array<{k}>"),
293 (k, Some(l)) => write_sql!(f, fmt, "array<{k}, {l}>"),
294 },
295 Kind::Either(k) => write_sql!(f, fmt, "{}", Fmt::verbar_separated(k)),
296 Kind::Range => f.push_str("range"),
297 Kind::Literal(l) => l.fmt_sql(f, fmt),
298 Kind::File(k) => {
299 if k.is_empty() {
300 f.push_str("file");
301 } else {
302 write_sql!(
303 f,
304 fmt,
305 "file<{}>",
306 Fmt::verbar_separated(k.iter().map(|x| EscapeKwFreeIdent(x)))
307 );
308 }
309 }
310 }
311 }
312}
313#[derive(Clone, Debug)]
314#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
315pub enum KindLiteral {
316 String(String),
317 Integer(i64),
318 Float(f64),
319 Decimal(Decimal),
320 Duration(PublicDuration),
321 Array(Vec<Kind>),
322 Object(BTreeMap<String, Kind>),
323 Bool(bool),
324}
325impl hash::Hash for KindLiteral {
326 fn hash<H: hash::Hasher>(&self, state: &mut H) {
327 match self {
328 Self::String(v) => v.hash(state),
329 Self::Integer(v) => v.hash(state),
330 Self::Float(v) => v.to_bits().hash(state),
331 Self::Decimal(v) => v.hash(state),
332 Self::Duration(v) => v.hash(state),
333 Self::Array(v) => v.hash(state),
334 Self::Object(v) => v.hash(state),
335 Self::Bool(v) => v.hash(state),
336 }
337 }
338}
339impl PartialEq for KindLiteral {
340 fn eq(&self, other: &Self) -> bool {
341 match self {
342 KindLiteral::String(a) => {
343 if let KindLiteral::String(b) = other {
344 a == b
345 } else {
346 false
347 }
348 }
349 KindLiteral::Integer(a) => {
350 if let KindLiteral::Integer(b) = other {
351 a == b
352 } else {
353 false
354 }
355 }
356 KindLiteral::Float(a) => {
357 if let KindLiteral::Float(b) = other {
358 a.to_bits() == b.to_bits()
359 } else {
360 false
361 }
362 }
363 KindLiteral::Decimal(a) => {
364 if let KindLiteral::Decimal(b) = other {
365 a == b
366 } else {
367 false
368 }
369 }
370 KindLiteral::Duration(a) => {
371 if let KindLiteral::Duration(b) = other {
372 a == b
373 } else {
374 false
375 }
376 }
377 KindLiteral::Array(a) => {
378 if let KindLiteral::Array(b) = other {
379 a == b
380 } else {
381 false
382 }
383 }
384 KindLiteral::Object(a) => {
385 if let KindLiteral::Object(b) = other {
386 a == b
387 } else {
388 false
389 }
390 }
391 KindLiteral::Bool(a) => {
392 if let KindLiteral::Bool(b) = other {
393 a == b
394 } else {
395 false
396 }
397 }
398 }
399 }
400}
401impl Eq for KindLiteral {}
402impl ToSql for KindLiteral {
403 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
404 match self {
405 KindLiteral::String(s) => write_sql!(f, fmt, "{}", QuoteStr(s)),
406 KindLiteral::Integer(n) => write_sql!(f, fmt, "{}", n),
407 KindLiteral::Float(n) => write_sql!(f, fmt, " {}", Float(*n)),
408 KindLiteral::Decimal(n) => write_sql!(f, fmt, " {}", n),
409 KindLiteral::Duration(d) => write_sql!(f, fmt, "{}", d),
410 KindLiteral::Bool(b) => write_sql!(f, fmt, "{}", b),
411 KindLiteral::Array(a) => {
412 f.push('[');
413 if !a.is_empty() {
414 let fmt = fmt.increment();
415 write_sql!(f, fmt, "{}", Fmt::pretty_comma_separated(a.as_slice()));
416 }
417 f.push(']');
418 }
419 KindLiteral::Object(o) => {
420 if fmt.is_pretty() {
421 f.push('{');
422 } else {
423 f.push_str("{ ");
424 }
425 if !o.is_empty() {
426 let fmt = fmt.increment();
427 write_sql!(
428 f,
429 fmt,
430 "{}",
431 Fmt::pretty_comma_separated(o.iter().map(|args| Fmt::new(
432 args,
433 |(k, v), f, fmt| {
434 write_sql!(f, fmt, "{}: {}", EscapeObjectKey(k), v)
435 }
436 )),)
437 );
438 }
439 if fmt.is_pretty() {
440 f.push('}');
441 } else {
442 f.push_str(" }");
443 }
444 }
445 }
446 }
447}
448impl Display for Kind {
449 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
450 write!(f, "{}", self.to_sql())
451 }
452}
453impl From<KindLiteral> for crate::compat::types::PublicKindLiteral {
454 fn from(v: KindLiteral) -> Self {
455 match v {
456 KindLiteral::Bool(b) => crate::compat::types::PublicKindLiteral::Bool(b),
457 KindLiteral::Integer(i) => crate::compat::types::PublicKindLiteral::Integer(i),
458 KindLiteral::Float(f) => crate::compat::types::PublicKindLiteral::Float(f),
459 KindLiteral::Decimal(d) => crate::compat::types::PublicKindLiteral::Decimal(d),
460 KindLiteral::String(s) => crate::compat::types::PublicKindLiteral::String(s),
461 KindLiteral::Duration(d) => crate::compat::types::PublicKindLiteral::Duration(d),
462 KindLiteral::Array(a) => crate::compat::types::PublicKindLiteral::Array(
463 a.into_iter().map(Into::into).collect(),
464 ),
465 KindLiteral::Object(o) => crate::compat::types::PublicKindLiteral::Object(
466 o.into_iter().map(|(k, v)| (k, v.into())).collect(),
467 ),
468 }
469 }
470}
471impl From<crate::compat::types::PublicKindLiteral> for KindLiteral {
472 fn from(v: crate::compat::types::PublicKindLiteral) -> Self {
473 match v {
474 crate::compat::types::PublicKindLiteral::Bool(b) => Self::Bool(b),
475 crate::compat::types::PublicKindLiteral::Integer(i) => Self::Integer(i),
476 crate::compat::types::PublicKindLiteral::Float(f) => Self::Float(f),
477 crate::compat::types::PublicKindLiteral::Decimal(d) => Self::Decimal(d),
478 crate::compat::types::PublicKindLiteral::String(s) => Self::String(s),
479 crate::compat::types::PublicKindLiteral::Duration(d) => Self::Duration(d),
480 crate::compat::types::PublicKindLiteral::Array(a) => {
481 Self::Array(a.into_iter().map(Into::into).collect())
482 }
483 crate::compat::types::PublicKindLiteral::Object(o) => {
484 Self::Object(o.into_iter().map(|(k, v)| (k, v.into())).collect())
485 }
486 }
487 }
488}