1mod geometry;
2mod literal;
3
4use std::collections::HashSet;
5use std::fmt::Display;
6
7pub use geometry::*;
8pub use literal::*;
9use serde::{Deserialize, Serialize};
10use surrealdb_types_derive::write_sql;
11
12use crate::utils::display::format_seperated;
13use crate::{self as surrealdb_types, SqlFormat, Table, ToSql};
14
15#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
17pub enum Kind {
18 #[default]
20 Any,
21 None,
23 Null,
25 Bool,
27 Bytes,
29 Datetime,
31 Decimal,
33 Duration,
35 Float,
37 Int,
39 Number,
42 Object,
44 String,
46 Uuid,
48 Regex,
50 Table(Vec<Table>),
52 Record(Vec<Table>),
54 Geometry(Vec<GeometryKind>),
56 Either(Vec<Kind>),
59 Set(Box<Kind>, Option<u64>),
61 Array(Box<Kind>, Option<u64>),
63 Function(Option<Vec<Kind>>, Option<Box<Kind>>),
67 Range,
69 Literal(KindLiteral),
75 File(Vec<String>),
79}
80
81impl Kind {
82 pub fn flatten(self) -> Vec<Kind> {
84 match self {
85 Kind::Either(x) => x.into_iter().flat_map(|k| k.flatten()).collect(),
86 _ => vec![self],
87 }
88 }
89
90 pub fn either(kinds: Vec<Kind>) -> Kind {
96 let mut seen = HashSet::new();
97 let mut kinds = kinds
98 .into_iter()
99 .flat_map(|k| k.flatten())
100 .filter(|k| seen.insert(k.clone()))
101 .collect::<Vec<_>>();
102 match kinds.len() {
103 0 => Kind::None,
104 1 => kinds.remove(0),
105 _ => Kind::Either(kinds),
106 }
107 }
108
109 pub fn option(kind: Kind) -> Kind {
111 Kind::either(vec![Kind::None, kind])
112 }
113}
114
115impl ToSql for Kind {
116 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
117 match self {
118 Kind::Any => f.push_str("any"),
119 Kind::None => f.push_str("none"),
120 Kind::Null => f.push_str("null"),
121 Kind::Bool => f.push_str("bool"),
122 Kind::Bytes => f.push_str("bytes"),
123 Kind::Datetime => f.push_str("datetime"),
124 Kind::Decimal => f.push_str("decimal"),
125 Kind::Duration => f.push_str("duration"),
126 Kind::Float => f.push_str("float"),
127 Kind::Int => f.push_str("int"),
128 Kind::Number => f.push_str("number"),
129 Kind::Object => f.push_str("object"),
130 Kind::String => f.push_str("string"),
131 Kind::Uuid => f.push_str("uuid"),
132 Kind::Regex => f.push_str("regex"),
133 Kind::Table(tables) => {
134 if tables.is_empty() {
135 f.push_str("table")
136 } else {
137 write_sql!(f, fmt, "table<{}>", format_seperated(tables, " | "));
138 }
139 }
140 Kind::Record(table) => {
141 if table.is_empty() {
142 f.push_str("record")
143 } else {
144 write_sql!(f, fmt, "record<{}>", format_seperated(table, " | "))
145 }
146 }
147 Kind::Geometry(kinds) => {
148 if kinds.is_empty() {
149 f.push_str("geometry")
150 } else {
151 write_sql!(f, fmt, "geometry<{}>", format_seperated(kinds, " | "))
152 }
153 }
154 Kind::Either(kinds) => write_sql!(f, fmt, "{}", format_seperated(kinds, " | ")),
155 Kind::Set(kind, max) => match max {
156 Some(max) => write_sql!(f, fmt, "set<{}, {}>", kind, max),
157 None => write_sql!(f, fmt, "set<{}>", kind),
158 },
159 Kind::Array(kind, max) => match max {
160 Some(max) => write_sql!(f, fmt, "array<{}, {}>", kind, max),
161 None => write_sql!(f, fmt, "array<{}>", kind),
162 },
163 Kind::Function(_, _) => f.push_str("function"),
164 Kind::Range => f.push_str("range"),
165 Kind::Literal(literal) => literal.fmt_sql(f, fmt),
166 Kind::File(bucket) => {
167 if bucket.is_empty() {
168 f.push_str("file")
169 } else {
170 write_sql!(f, fmt, "file<{}>", format_seperated(bucket, " | "))
171 }
172 }
173 }
174 }
175}
176
177impl Display for Kind {
178 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179 f.write_str(&self.to_sql())
180 }
181}