1use super::escape::EscapeKey;
2use super::{Duration, Idiom, Number, Part, Strand};
3use crate::sql::statements::info::InfoStructure;
4use crate::sql::{
5 fmt::{is_pretty, pretty_indent, Fmt, Pretty},
6 Table, Value,
7};
8use revision::revisioned;
9use serde::{Deserialize, Serialize};
10use std::collections::BTreeMap;
11use std::fmt::{self, Display, Formatter, Write};
12
13#[revisioned(revision = 2)]
14#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
15#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
16#[non_exhaustive]
17#[derive(Default)]
18pub enum Kind {
19 #[default]
20 Any,
21 Null,
22 Bool,
23 Bytes,
24 Datetime,
25 Decimal,
26 Duration,
27 Float,
28 Int,
29 Number,
30 Object,
31 Point,
32 String,
33 Uuid,
34 #[revision(start = 2)]
35 Regex,
36 Record(Vec<Table>),
37 Geometry(Vec<String>),
38 Option(Box<Kind>),
39 Either(Vec<Kind>),
40 Set(Box<Kind>, Option<u64>),
41 Array(Box<Kind>, Option<u64>),
42 Function(Option<Vec<Kind>>, Option<Box<Kind>>),
43 Range,
44 Literal(Literal),
45 References(Option<Table>, Option<Idiom>),
46}
47
48impl Kind {
49 pub(crate) fn is_any(&self) -> bool {
51 matches!(self, Kind::Any)
52 }
53
54 pub(crate) fn is_record(&self) -> bool {
56 matches!(self, Kind::Record(_))
57 }
58
59 pub(crate) fn can_be_none(&self) -> bool {
61 matches!(self, Kind::Option(_) | Kind::Any)
62 }
63
64 fn to_kind(&self) -> Self {
66 match self {
67 Kind::Literal(l) => l.to_kind(),
68 k => k.to_owned(),
69 }
70 }
71
72 pub(crate) fn is_literal_nested(&self) -> bool {
74 if matches!(self, Kind::Literal(_)) {
75 return true;
76 }
77
78 if let Kind::Option(x) = self {
79 return x.is_literal_nested();
80 }
81
82 if let Kind::Either(x) = self {
83 return x.iter().any(|x| x.is_literal_nested());
84 }
85
86 false
87 }
88
89 pub(crate) fn to_discriminated(&self) -> Option<Kind> {
91 match self {
92 Kind::Either(nested) => {
93 if let Some(nested) = nested
94 .iter()
95 .map(|k| match k {
96 Kind::Literal(Literal::Object(o)) => Some(o),
97 _ => None,
98 })
99 .collect::<Option<Vec<&BTreeMap<String, Kind>>>>()
100 {
101 if let Some(first) = nested.first() {
102 let mut key: Option<String> = None;
103
104 'key: for (k, v) in first.iter() {
105 let mut kinds: Vec<Kind> = vec![v.to_owned()];
106 for item in nested[1..].iter() {
107 if let Some(kind) = item.get(k) {
108 match kind {
109 Kind::Literal(l)
110 if kinds.contains(&l.to_kind())
111 || kinds.contains(&Kind::Literal(l.to_owned())) =>
112 {
113 continue 'key;
114 }
115 kind if kinds.iter().any(|k| *kind == k.to_kind()) => {
116 continue 'key;
117 }
118 kind => {
119 kinds.push(kind.to_owned());
120 }
121 }
122 } else {
123 continue 'key;
124 }
125 }
126
127 key = Some(k.clone());
128 break;
129 }
130
131 if let Some(key) = key {
132 return Some(Kind::Literal(Literal::DiscriminatedObject(
133 key.clone(),
134 nested.into_iter().map(|o| o.to_owned()).collect(),
135 )));
136 }
137 }
138 }
139
140 None
141 }
142 _ => None,
143 }
144 }
145
146 pub(crate) fn inner_kind(&self) -> Option<Kind> {
151 let mut this = self;
152 loop {
153 match &this {
154 Kind::Any
155 | Kind::Null
156 | Kind::Bool
157 | Kind::Bytes
158 | Kind::Datetime
159 | Kind::Decimal
160 | Kind::Duration
161 | Kind::Float
162 | Kind::Int
163 | Kind::Number
164 | Kind::Object
165 | Kind::Point
166 | Kind::String
167 | Kind::Uuid
168 | Kind::Regex
169 | Kind::Record(_)
170 | Kind::Geometry(_)
171 | Kind::Function(_, _)
172 | Kind::Range
173 | Kind::Literal(_)
174 | Kind::References(_, _) => return None,
175 Kind::Option(x) => {
176 this = x;
177 }
178 Kind::Array(x, _) | Kind::Set(x, _) => return Some(x.as_ref().clone()),
179 Kind::Either(x) => {
180 let kinds: Vec<Kind> = x.iter().filter_map(Self::inner_kind).collect();
183 if kinds.is_empty() {
184 return None;
185 }
186 return Some(Kind::Either(kinds));
187 }
188 }
189 }
190 }
191
192 pub(crate) fn non_optional(&self) -> &Kind {
193 match self {
194 Kind::Option(k) => k.as_ref().non_optional(),
195 _ => self,
196 }
197 }
198
199 pub(crate) fn allows_nested_kind(&self, path: &[Part], kind: &Kind) -> bool {
200 if self.is_any() || kind.is_any() {
202 return true;
203 }
204
205 if !path.is_empty() {
206 match self {
207 Kind::Object => return matches!(path.first(), Some(Part::Field(_) | Part::All)),
208 Kind::Either(kinds) => {
209 return kinds.iter().all(|k| k.allows_nested_kind(path, kind))
210 }
211 Kind::Array(inner, len) | Kind::Set(inner, len) => {
212 return match path.first() {
213 Some(Part::All) => inner.allows_nested_kind(&path[1..], kind),
214 Some(Part::Index(i)) => {
215 if let Some(len) = len {
216 if i.as_usize() >= *len as usize {
217 return false;
218 }
219 }
220
221 inner.allows_nested_kind(&path[1..], kind)
222 }
223 _ => false,
224 }
225 }
226 _ => (),
227 }
228 }
229
230 match self {
231 Kind::Literal(lit) => lit.allows_nested_kind(path, kind),
232 Kind::Option(inner) => inner.allows_nested_kind(path, kind),
233 _ if path.is_empty() => self == kind,
234 _ => false,
235 }
236 }
237}
238
239impl From<&Kind> for Box<Kind> {
240 #[inline]
241 fn from(v: &Kind) -> Self {
242 Box::new(v.clone())
243 }
244}
245
246impl Display for Kind {
247 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
248 match self {
249 Kind::Any => f.write_str("any"),
250 Kind::Null => f.write_str("null"),
251 Kind::Bool => f.write_str("bool"),
252 Kind::Bytes => f.write_str("bytes"),
253 Kind::Datetime => f.write_str("datetime"),
254 Kind::Decimal => f.write_str("decimal"),
255 Kind::Duration => f.write_str("duration"),
256 Kind::Float => f.write_str("float"),
257 Kind::Int => f.write_str("int"),
258 Kind::Number => f.write_str("number"),
259 Kind::Object => f.write_str("object"),
260 Kind::Point => f.write_str("point"),
261 Kind::String => f.write_str("string"),
262 Kind::Uuid => f.write_str("uuid"),
263 Kind::Regex => f.write_str("regex"),
264 Kind::Function(_, _) => f.write_str("function"),
265 Kind::Option(k) => write!(f, "option<{}>", k),
266 Kind::Record(k) => match k {
267 k if k.is_empty() => write!(f, "record"),
268 k => write!(f, "record<{}>", Fmt::verbar_separated(k)),
269 },
270 Kind::Geometry(k) => match k {
271 k if k.is_empty() => write!(f, "geometry"),
272 k => write!(f, "geometry<{}>", Fmt::verbar_separated(k)),
273 },
274 Kind::Set(k, l) => match (k, l) {
275 (k, None) if k.is_any() => write!(f, "set"),
276 (k, None) => write!(f, "set<{k}>"),
277 (k, Some(l)) => write!(f, "set<{k}, {l}>"),
278 },
279 Kind::Array(k, l) => match (k, l) {
280 (k, None) if k.is_any() => write!(f, "array"),
281 (k, None) => write!(f, "array<{k}>"),
282 (k, Some(l)) => write!(f, "array<{k}, {l}>"),
283 },
284 Kind::Either(k) => write!(f, "{}", Fmt::verbar_separated(k)),
285 Kind::Range => f.write_str("range"),
286 Kind::Literal(l) => write!(f, "{}", l),
287 Kind::References(t, i) => match (t, i) {
288 (Some(t), None) => write!(f, "references<{}>", t),
289 (Some(t), Some(i)) => write!(f, "references<{}, {}>", t, i),
290 (None, _) => f.write_str("references"),
291 },
292 }
293 }
294}
295
296impl InfoStructure for Kind {
297 fn structure(self) -> Value {
298 self.to_string().into()
299 }
300}
301
302#[revisioned(revision = 1)]
303#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
304#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
305#[non_exhaustive]
306pub enum Literal {
307 String(Strand),
308 Number(Number),
309 Duration(Duration),
310 Array(Vec<Kind>),
311 Object(BTreeMap<String, Kind>),
312 DiscriminatedObject(String, Vec<BTreeMap<String, Kind>>),
313 Bool(bool),
314}
315
316impl Literal {
317 pub fn to_kind(&self) -> Kind {
318 match self {
319 Self::String(_) => Kind::String,
320 Self::Number(_) => Kind::Number,
321 Self::Duration(_) => Kind::Duration,
322 Self::Array(a) => {
323 if let Some(inner) = a.first() {
324 if a.iter().all(|x| x == inner) {
325 return Kind::Array(Box::new(inner.to_owned()), Some(a.len() as u64));
326 }
327 }
328
329 Kind::Array(Box::new(Kind::Any), None)
330 }
331 Self::Object(_) => Kind::Object,
332 Self::DiscriminatedObject(_, _) => Kind::Object,
333 Self::Bool(_) => Kind::Bool,
334 }
335 }
336
337 pub fn validate_value(&self, value: &Value) -> bool {
338 match self {
339 Self::String(v) => match value {
340 Value::Strand(s) => s == v,
341 _ => false,
342 },
343 Self::Number(v) => match value {
344 Value::Number(n) => n == v,
345 _ => false,
346 },
347 Self::Duration(v) => match value {
348 Value::Duration(n) => n == v,
349 _ => false,
350 },
351 Self::Bool(v) => match value {
352 Value::Bool(b) => b == v,
353 _ => false,
354 },
355 Self::Array(a) => match value {
356 Value::Array(x) => {
357 if a.len() != x.len() {
358 return false;
359 }
360
361 for (i, inner) in a.iter().enumerate() {
362 if let Some(value) = x.get(i) {
363 if value.to_owned().coerce_to(inner).is_err() {
364 return false;
365 }
366 } else {
367 return false;
368 }
369 }
370
371 true
372 }
373 _ => false,
374 },
375 Self::Object(o) => match value {
376 Value::Object(x) => {
377 if o.len() < x.len() {
378 return false;
379 }
380
381 for (k, v) in o.iter() {
382 if let Some(value) = x.get(k) {
383 if value.to_owned().coerce_to(v).is_err() {
384 return false;
385 }
386 } else if !v.can_be_none() {
387 return false;
388 }
389 }
390
391 true
392 }
393 _ => false,
394 },
395 Self::DiscriminatedObject(key, discriminants) => match value {
396 Value::Object(x) => {
397 let value = x.get(key).unwrap_or(&Value::None);
398 if let Some(o) = discriminants
399 .iter()
400 .find(|o| value.to_owned().coerce_to(o.get(key).unwrap()).is_ok())
401 {
402 if o.len() < x.len() {
403 return false;
404 }
405
406 for (k, v) in o.iter() {
407 if let Some(value) = x.get(k) {
408 if value.to_owned().coerce_to(v).is_err() {
409 return false;
410 }
411 } else if !v.can_be_none() {
412 return false;
413 }
414 }
415
416 true
417 } else {
418 false
419 }
420 }
421 _ => false,
422 },
423 }
424 }
425
426 pub(crate) fn allows_nested_kind(&self, path: &[Part], kind: &Kind) -> bool {
427 if kind.is_any() {
429 return true;
430 }
431
432 if path.is_empty() {
435 return match kind {
436 Kind::Literal(lit) => self == lit,
437 _ => &self.to_kind() == kind,
438 };
439 }
440
441 match self {
442 Literal::Array(x) => match path.first() {
443 Some(Part::All) => x.iter().all(|y| y.allows_nested_kind(&path[1..], kind)),
444 Some(Part::Index(i)) => {
445 if let Some(y) = x.get(i.as_usize()) {
446 y.allows_nested_kind(&path[1..], kind)
447 } else {
448 false
449 }
450 }
451 _ => false,
452 },
453 Literal::Object(x) => match path.first() {
454 Some(Part::All) => x.iter().all(|(_, y)| y.allows_nested_kind(&path[1..], kind)),
455 Some(Part::Field(k)) => {
456 if let Some(y) = x.get(&k.0) {
457 y.allows_nested_kind(&path[1..], kind)
458 } else {
459 false
460 }
461 }
462 _ => false,
463 },
464 Literal::DiscriminatedObject(_, discriminants) => match path.first() {
465 Some(Part::All) => discriminants
466 .iter()
467 .all(|o| o.iter().all(|(_, y)| y.allows_nested_kind(&path[1..], kind))),
468 Some(Part::Field(k)) => discriminants.iter().all(|o| {
469 if let Some(y) = o.get(&k.0) {
470 y.allows_nested_kind(&path[1..], kind)
471 } else {
472 false
473 }
474 }),
475 _ => false,
476 },
477 _ => false,
478 }
479 }
480}
481
482impl Display for Literal {
483 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
484 match self {
485 Literal::String(s) => write!(f, "{}", s),
486 Literal::Number(n) => write!(f, "{}", n),
487 Literal::Duration(d) => write!(f, "{}", d),
488 Literal::Bool(b) => write!(f, "{}", b),
489 Literal::Array(a) => {
490 let mut f = Pretty::from(f);
491 f.write_char('[')?;
492 if !a.is_empty() {
493 let indent = pretty_indent();
494 write!(f, "{}", Fmt::pretty_comma_separated(a.as_slice()))?;
495 drop(indent);
496 }
497 f.write_char(']')
498 }
499 Literal::Object(o) => {
500 let mut f = Pretty::from(f);
501 if is_pretty() {
502 f.write_char('{')?;
503 } else {
504 f.write_str("{ ")?;
505 }
506 if !o.is_empty() {
507 let indent = pretty_indent();
508 write!(
509 f,
510 "{}",
511 Fmt::pretty_comma_separated(o.iter().map(|args| Fmt::new(
512 args,
513 |(k, v), f| write!(f, "{}: {}", EscapeKey(k), v)
514 )),)
515 )?;
516 drop(indent);
517 }
518 if is_pretty() {
519 f.write_char('}')
520 } else {
521 f.write_str(" }")
522 }
523 }
524 Literal::DiscriminatedObject(_, discriminants) => {
525 let mut f = Pretty::from(f);
526
527 for (i, o) in discriminants.iter().enumerate() {
528 if i > 0 {
529 f.write_str(" | ")?;
530 }
531
532 if is_pretty() {
533 f.write_char('{')?;
534 } else {
535 f.write_str("{ ")?;
536 }
537 if !o.is_empty() {
538 let indent = pretty_indent();
539 write!(
540 f,
541 "{}",
542 Fmt::pretty_comma_separated(o.iter().map(|args| Fmt::new(
543 args,
544 |(k, v), f| write!(f, "{}: {}", EscapeKey(k), v)
545 )),)
546 )?;
547 drop(indent);
548 }
549 if is_pretty() {
550 f.write_char('}')?;
551 } else {
552 f.write_str(" }")?;
553 }
554 }
555
556 Ok(())
557 }
558 }
559 }
560}