1use std::collections::{BTreeMap, HashMap};
2use std::ops::{Deref, DerefMut};
3
4use anyhow::Result;
5use common::fmt::EscapeObjectKey;
6use http::{HeaderMap, HeaderName, HeaderValue};
7use revision::revisioned;
8use storekey::{BorrowDecode, Encode};
9use surrealdb_collections::{Entry as VecMapEntry, VecMap, VecMapIntoIter};
10use surrealdb_types::{SqlFormat, ToSql, write_sql};
11
12use crate::expr::literal::ObjectEntry;
13use crate::val::{IndexFormat, RecordId, Strand, Value};
14
15#[revisioned(revision(1), revision(2, optimised))]
25#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Hash, Encode, BorrowDecode)]
26#[storekey(format = "()")]
27#[storekey(format = "IndexFormat")]
28pub struct Object(#[revision(indexed_map)] pub VecMap<Strand, Value>);
29
30impl From<BTreeMap<&str, Value>> for Object {
31 fn from(v: BTreeMap<&str, Value>) -> Self {
32 let mut entries = Vec::with_capacity(v.len());
33 entries.extend(v.into_iter().map(|(k, val)| (Strand::from(k), val)));
34 Self(VecMap::from_sorted_vec_unchecked(entries))
35 }
36}
37
38impl From<BTreeMap<String, Value>> for Object {
39 fn from(v: BTreeMap<String, Value>) -> Self {
40 let mut entries = Vec::with_capacity(v.len());
41 entries.extend(v.into_iter().map(|(k, val)| (Strand::from(k), val)));
42 Self(VecMap::from_sorted_vec_unchecked(entries))
43 }
44}
45
46impl From<BTreeMap<Strand, Value>> for Object {
47 fn from(v: BTreeMap<Strand, Value>) -> Self {
48 Self(VecMap::from(v))
49 }
50}
51
52impl From<VecMap<Strand, Value>> for Object {
53 fn from(v: VecMap<Strand, Value>) -> Self {
54 Self(v)
55 }
56}
57
58impl From<VecMap<String, Value>> for Object {
59 fn from(v: VecMap<String, Value>) -> Self {
60 let mut entries = Vec::with_capacity(v.len());
61 entries.extend(v.into_iter().map(|(k, val)| (Strand::from(k), val)));
62 Self(VecMap::from_sorted_vec_unchecked(entries))
63 }
64}
65
66impl From<VecMap<&str, Value>> for Object {
67 fn from(v: VecMap<&str, Value>) -> Self {
68 let mut entries = Vec::with_capacity(v.len());
69 entries.extend(v.into_iter().map(|(k, val)| (Strand::from(k), val)));
70 Self(VecMap::from_sorted_vec_unchecked(entries))
71 }
72}
73
74impl FromIterator<(String, Value)> for Object {
75 fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
76 Self(VecMap::from_iter(iter.into_iter().map(|(k, v)| (Strand::from(k), v))))
77 }
78}
79
80impl FromIterator<(Strand, Value)> for Object {
81 fn from_iter<T: IntoIterator<Item = (Strand, Value)>>(iter: T) -> Self {
82 Self(VecMap::from_iter(iter))
83 }
84}
85
86impl<'a> FromIterator<(&'a str, Value)> for Object {
87 fn from_iter<T: IntoIterator<Item = (&'a str, Value)>>(iter: T) -> Self {
88 Self(VecMap::from_iter(iter.into_iter().map(|(k, v)| (Strand::from(k), v))))
89 }
90}
91
92impl From<BTreeMap<String, String>> for Object {
93 fn from(v: BTreeMap<String, String>) -> Self {
94 let mut entries = Vec::with_capacity(v.len());
95 entries.extend(v.into_iter().map(|(k, v)| (Strand::from(k), Value::from(v))));
96 Self(VecMap::from_sorted_vec_unchecked(entries))
97 }
98}
99
100impl From<Vec<(String, Value)>> for Object {
101 fn from(v: Vec<(String, Value)>) -> Self {
102 Self(VecMap::from_iter(v.into_iter().map(|(k, val)| (Strand::from(k), val))))
103 }
104}
105
106impl From<HashMap<&str, Value>> for Object {
107 fn from(v: HashMap<&str, Value>) -> Self {
108 Self(VecMap::from_iter(v.into_iter().map(|(key, val)| (Strand::from(key), val))))
109 }
110}
111
112impl From<HashMap<String, Value>> for Object {
113 fn from(v: HashMap<String, Value>) -> Self {
114 Self(VecMap::from_iter(v.into_iter().map(|(k, val)| (Strand::from(k), val))))
115 }
116}
117
118impl TryFrom<Object> for crate::types::PublicObject {
119 type Error = anyhow::Error;
120
121 fn try_from(s: Object) -> Result<Self, Self::Error> {
122 s.0.into_iter()
123 .map(|(k, v)| crate::types::PublicValue::try_from(v).map(|v| (k.into_string(), v)))
124 .collect()
125 }
126}
127
128impl From<crate::types::PublicObject> for Object {
129 fn from(s: crate::types::PublicObject) -> Self {
130 let mut entries = Vec::with_capacity(s.len());
131 entries.extend(s.into_iter().map(|(k, v)| (Strand::from(k), Value::from(v))));
132 Self(VecMap::from_sorted_vec_unchecked(entries))
133 }
134}
135
136impl Deref for Object {
137 type Target = VecMap<Strand, Value>;
138 fn deref(&self) -> &Self::Target {
139 &self.0
140 }
141}
142
143impl DerefMut for Object {
144 fn deref_mut(&mut self) -> &mut Self::Target {
145 &mut self.0
146 }
147}
148
149impl IntoIterator for Object {
150 type Item = (Strand, Value);
151 type IntoIter = VecMapIntoIter<Strand, Value>;
152 fn into_iter(self) -> Self::IntoIter {
153 self.0.into_iter()
154 }
155}
156
157impl TryInto<BTreeMap<String, String>> for Object {
158 type Error = anyhow::Error;
159 fn try_into(self) -> Result<BTreeMap<String, String>, Self::Error> {
160 self.into_iter().map(|(k, v)| Ok((k.into_string(), v.coerce_to()?))).collect()
161 }
162}
163
164impl TryInto<HeaderMap> for Object {
165 type Error = anyhow::Error;
166 fn try_into(self) -> Result<HeaderMap, Self::Error> {
167 let mut headermap = HeaderMap::new();
168 for (k, v) in self {
169 let k: HeaderName = k.as_str().parse()?;
170 let v: HeaderValue = v.coerce_to::<String>()?.parse()?;
171 headermap.insert(k, v);
172 }
173
174 Ok(headermap)
175 }
176}
177
178impl Object {
179 #[inline]
185 pub fn insert(&mut self, key: impl Into<Strand>, value: Value) -> Option<Value> {
186 self.0.insert(key.into(), value)
187 }
188
189 #[inline]
195 pub fn get(&self, key: &str) -> Option<&Value> {
196 self.0.get(key)
197 }
198
199 #[inline]
201 pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
202 self.0.get_mut(key)
203 }
204
205 #[inline]
207 pub fn contains_key(&self, key: &str) -> bool {
208 self.0.contains_key(key)
209 }
210
211 #[inline]
213 pub fn remove(&mut self, key: &str) -> Option<Value> {
214 self.0.remove(key)
215 }
216
217 #[inline]
220 pub fn entry(&mut self, key: impl Into<Strand>) -> VecMapEntry<'_, Strand, Value> {
221 self.0.entry(key.into())
222 }
223
224 pub fn rid(&self) -> Option<RecordId> {
226 match self.get("id") {
227 Some(Value::RecordId(v)) => Some(v.clone()),
228 _ => None,
229 }
230 }
231
232 pub fn into_literal(self) -> Vec<ObjectEntry> {
233 self.0
234 .into_iter()
235 .map(|(k, v)| ObjectEntry {
236 key: k,
237 value: v.into_literal(),
238 })
239 .collect()
240 }
241}
242
243impl std::ops::Add for Object {
244 type Output = Self;
245
246 fn add(self, rhs: Self) -> Self::Output {
247 Self(VecMap::merge_sorted_prefer_rhs(self.0, rhs.0))
248 }
249}
250
251impl ToSql for Object {
252 fn fmt_sql(&self, f: &mut String, sql_fmt: SqlFormat) {
253 if self.is_empty() {
254 return f.push_str("{ }");
255 }
256
257 if sql_fmt.is_pretty() {
258 f.push('{');
259 } else {
260 f.push_str("{ ");
261 }
262
263 if !self.is_empty() {
264 let inner_fmt = sql_fmt.increment();
265 if sql_fmt.is_pretty() {
266 f.push('\n');
267 inner_fmt.write_indent(f);
268 }
269 for (i, (key, value)) in self.0.iter().enumerate() {
270 if i > 0 {
271 inner_fmt.write_separator(f);
272 }
273 write_sql!(f, sql_fmt, "{}: ", EscapeObjectKey(key.as_str()));
274 value.fmt_sql(f, inner_fmt);
275 }
276 if sql_fmt.is_pretty() {
277 f.push('\n');
278 sql_fmt.write_indent(f);
279 }
280 }
281
282 if sql_fmt.is_pretty() {
283 f.push('}');
284 } else {
285 f.push_str(" }");
286 }
287 }
288}