Skip to main content

surrealdb_sql/record_id/
key.rs

1use std::ops::Bound;
2
3use common::fmt::{EscapeObjectKey, EscapeRidKey, Fmt, QuoteStr};
4use surrealdb_strand::Strand;
5use surrealdb_types::{RecordIdKey as PublicRecordIdKey, SqlFormat, ToSql, write_sql};
6
7use crate::literal::ObjectEntry;
8use crate::{CoverStmts, Expr, RecordIdKeyRangeLit};
9
10#[derive(Clone, Debug, Eq, PartialEq, Hash)]
11#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
12pub enum RecordIdKeyGen {
13	Rand,
14	Ulid,
15	Uuid,
16}
17
18#[derive(Clone, Debug, PartialEq, Eq)]
19#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
20pub enum RecordIdKeyLit {
21	Number(i64),
22	String(Strand),
23	Uuid(uuid::Uuid),
24	Array(Vec<Expr>),
25	Object(Vec<ObjectEntry>),
26	Generate(RecordIdKeyGen),
27	Range(Box<RecordIdKeyRangeLit>),
28}
29
30impl RecordIdKeyLit {
31	pub fn from_record_id_key(key: PublicRecordIdKey) -> Self {
32		match key {
33			PublicRecordIdKey::Number(x) => RecordIdKeyLit::Number(x),
34			PublicRecordIdKey::String(x) => RecordIdKeyLit::String(x.into()),
35			PublicRecordIdKey::Uuid(x) => RecordIdKeyLit::Uuid(x.into_inner()),
36			PublicRecordIdKey::Array(x) => {
37				RecordIdKeyLit::Array(x.into_iter().map(Expr::from_public_value).collect())
38			}
39			PublicRecordIdKey::Object(x) => RecordIdKeyLit::Object(
40				x.into_iter()
41					.map(|(k, v)| ObjectEntry {
42						key: k.into(),
43						value: Expr::from_public_value(v),
44					})
45					.collect(),
46			),
47			PublicRecordIdKey::Range(x) => {
48				let range = x.into_inner();
49				RecordIdKeyLit::Range(Box::new(RecordIdKeyRangeLit {
50					start: match range.0 {
51						Bound::Included(x) => Bound::Included(Self::from_record_id_key(x)),
52						Bound::Excluded(x) => Bound::Excluded(Self::from_record_id_key(x)),
53						Bound::Unbounded => Bound::Unbounded,
54					},
55					end: match range.1 {
56						Bound::Included(x) => Bound::Included(Self::from_record_id_key(x)),
57						Bound::Excluded(x) => Bound::Excluded(Self::from_record_id_key(x)),
58						Bound::Unbounded => Bound::Unbounded,
59					},
60				}))
61			}
62		}
63	}
64}
65
66impl ToSql for RecordIdKeyLit {
67	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
68		match self {
69			Self::Number(v) => write_sql!(f, fmt, "{v}"),
70			Self::String(v) => EscapeRidKey(v).fmt_sql(f, fmt),
71			Self::Uuid(v) => write_sql!(f, fmt, "u{}", QuoteStr(&v.to_string())),
72			Self::Array(v) => {
73				f.push('[');
74				if !v.is_empty() {
75					let fmt = fmt.increment();
76					write_sql!(f, fmt, "{}", Fmt::pretty_comma_separated(v.iter().map(CoverStmts)));
77				}
78				f.push(']');
79			}
80			Self::Object(v) => {
81				if fmt.is_pretty() {
82					f.push('{');
83				} else {
84					f.push_str("{ ");
85				}
86				if !v.is_empty() {
87					let fmt = fmt.increment();
88					write_sql!(
89						f,
90						fmt,
91						"{}",
92						Fmt::pretty_comma_separated(v.iter().map(|args| Fmt::new(
93							args,
94							|entry, f, fmt| write_sql!(
95								f,
96								fmt,
97								"{}: {}",
98								EscapeObjectKey(&entry.key),
99								CoverStmts(&entry.value)
100							)
101						)),)
102					);
103				}
104				if fmt.is_pretty() {
105					f.push('}');
106				} else {
107					f.push_str(" }");
108				}
109			}
110			Self::Generate(v) => match v {
111				RecordIdKeyGen::Rand => f.push_str("rand()"),
112				RecordIdKeyGen::Ulid => f.push_str("ulid()"),
113				RecordIdKeyGen::Uuid => f.push_str("uuid()"),
114			},
115			Self::Range(v) => v.fmt_sql(f, fmt),
116		}
117	}
118}