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