Skip to main content

surql_parser/upstream/sql/
kind.rs

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/// The kind, or data type, of a value or field.
59#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
60#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
61pub enum Kind {
62	/// The most generic type, can be anything.
63	#[default]
64	Any,
65	/// None type.
66	None,
67	/// Null type.
68	Null,
69	/// Boolean type.
70	Bool,
71	/// Bytes type.
72	Bytes,
73	/// Datetime type.
74	Datetime,
75	/// Decimal type.
76	Decimal,
77	/// Duration type.
78	Duration,
79	/// 64-bit floating point type.
80	Float,
81	/// 64-bit signed integer type.
82	Int,
83	/// Number type, can be either a float, int or decimal.
84	/// This is the most generic type for numbers.
85	Number,
86	/// Object type.
87	Object,
88	/// String type.
89	String,
90	/// UUID type.
91	Uuid,
92	/// Regular expression type.
93	Regex,
94	/// A table type.
95	Table(Vec<String>),
96	/// A record type.
97	Record(Vec<String>),
98	/// A geometry type.
99	Geometry(Vec<GeometryKind>),
100	/// An either type.
101	/// Can be any of the kinds in the vec.
102	Either(
103		#[cfg_attr(
104            feature = "arbitrary",
105            arbitrary(with = crate::upstream::sql::arbitrary::either_kind)
106        )]
107		Vec<Kind>,
108	),
109	/// A set type.
110	Set(Box<Kind>, Option<u64>),
111	/// An array type.
112	Array(Box<Kind>, Option<u64>),
113	/// A function type.
114	/// The first option is the argument types, the second is the optional
115	/// return type.
116	Function(Option<Vec<Kind>>, Option<Box<Kind>>),
117	/// A range type.
118	Range,
119	/// A literal type.
120	/// The literal type is used to represent a type that can only be a single
121	/// value. For example, `"a"` is a literal type which can only ever be
122	/// `"a"`. This can be used in the `Kind::Either` type to represent an
123	/// enum.
124	Literal(KindLiteral),
125	/// A file type.
126	/// If the kind was specified without a bucket the vec will be empty.
127	/// So `<file>` is just `Kind::File(Vec::new())`
128	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}