use std::collections::{BTreeMap, HashMap};
use std::ops::{Deref, DerefMut};
use anyhow::Result;
use http::{HeaderMap, HeaderName, HeaderValue};
use revision::revisioned;
use storekey::{BorrowDecode, Encode};
use surrealdb_collections::{Entry as VecMapEntry, VecMap, VecMapIntoIter};
use surrealdb_types::{SqlFormat, ToSql, write_sql};
use crate::err::Error;
use crate::expr::literal::ObjectEntry;
use crate::fmt::EscapeObjectKey;
use crate::val::{IndexFormat, RecordId, Strand, Value};
#[revisioned(revision(1), revision(2, optimised))]
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Hash, Encode, BorrowDecode)]
#[storekey(format = "()")]
#[storekey(format = "IndexFormat")]
pub(crate) struct Object(#[revision(indexed_map)] pub(crate) VecMap<Strand, Value>);
impl From<BTreeMap<&str, Value>> for Object {
fn from(v: BTreeMap<&str, Value>) -> Self {
let mut entries = Vec::with_capacity(v.len());
entries.extend(v.into_iter().map(|(k, val)| (Strand::from(k), val)));
Self(VecMap::from_sorted_vec_unchecked(entries))
}
}
impl From<BTreeMap<String, Value>> for Object {
fn from(v: BTreeMap<String, Value>) -> Self {
let mut entries = Vec::with_capacity(v.len());
entries.extend(v.into_iter().map(|(k, val)| (Strand::from(k), val)));
Self(VecMap::from_sorted_vec_unchecked(entries))
}
}
impl From<BTreeMap<Strand, Value>> for Object {
fn from(v: BTreeMap<Strand, Value>) -> Self {
Self(VecMap::from(v))
}
}
impl From<VecMap<Strand, Value>> for Object {
fn from(v: VecMap<Strand, Value>) -> Self {
Self(v)
}
}
impl From<VecMap<String, Value>> for Object {
fn from(v: VecMap<String, Value>) -> Self {
let mut entries = Vec::with_capacity(v.len());
entries.extend(v.into_iter().map(|(k, val)| (Strand::from(k), val)));
Self(VecMap::from_sorted_vec_unchecked(entries))
}
}
impl From<VecMap<&str, Value>> for Object {
fn from(v: VecMap<&str, Value>) -> Self {
let mut entries = Vec::with_capacity(v.len());
entries.extend(v.into_iter().map(|(k, val)| (Strand::from(k), val)));
Self(VecMap::from_sorted_vec_unchecked(entries))
}
}
impl FromIterator<(String, Value)> for Object {
fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
Self(VecMap::from_iter(iter.into_iter().map(|(k, v)| (Strand::from(k), v))))
}
}
impl FromIterator<(Strand, Value)> for Object {
fn from_iter<T: IntoIterator<Item = (Strand, Value)>>(iter: T) -> Self {
Self(VecMap::from_iter(iter))
}
}
impl<'a> FromIterator<(&'a str, Value)> for Object {
fn from_iter<T: IntoIterator<Item = (&'a str, Value)>>(iter: T) -> Self {
Self(VecMap::from_iter(iter.into_iter().map(|(k, v)| (Strand::from(k), v))))
}
}
impl From<BTreeMap<String, String>> for Object {
fn from(v: BTreeMap<String, String>) -> Self {
let mut entries = Vec::with_capacity(v.len());
entries.extend(v.into_iter().map(|(k, v)| (Strand::from(k), Value::from(v))));
Self(VecMap::from_sorted_vec_unchecked(entries))
}
}
impl From<Vec<(String, Value)>> for Object {
fn from(v: Vec<(String, Value)>) -> Self {
Self(VecMap::from_iter(v.into_iter().map(|(k, val)| (Strand::from(k), val))))
}
}
impl From<HashMap<&str, Value>> for Object {
fn from(v: HashMap<&str, Value>) -> Self {
Self(VecMap::from_iter(v.into_iter().map(|(key, val)| (Strand::from(key), val))))
}
}
impl From<HashMap<String, Value>> for Object {
fn from(v: HashMap<String, Value>) -> Self {
Self(VecMap::from_iter(v.into_iter().map(|(k, val)| (Strand::from(k), val))))
}
}
impl From<Option<Self>> for Object {
fn from(v: Option<Self>) -> Self {
v.unwrap_or_default()
}
}
impl TryFrom<Object> for crate::types::PublicObject {
type Error = anyhow::Error;
fn try_from(s: Object) -> Result<Self, Self::Error> {
s.0.into_iter()
.map(|(k, v)| crate::types::PublicValue::try_from(v).map(|v| (k.into_string(), v)))
.collect()
}
}
impl From<crate::types::PublicObject> for Object {
fn from(s: crate::types::PublicObject) -> Self {
let mut entries = Vec::with_capacity(s.len());
entries.extend(s.into_iter().map(|(k, v)| (Strand::from(k), Value::from(v))));
Self(VecMap::from_sorted_vec_unchecked(entries))
}
}
impl Deref for Object {
type Target = VecMap<Strand, Value>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Object {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl IntoIterator for Object {
type Item = (Strand, Value);
type IntoIter = VecMapIntoIter<Strand, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl TryInto<BTreeMap<String, String>> for Object {
type Error = Error;
fn try_into(self) -> Result<BTreeMap<String, String>, Self::Error> {
self.into_iter().map(|(k, v)| Ok((k.into_string(), v.coerce_to()?))).collect()
}
}
impl TryInto<HeaderMap> for Object {
type Error = Error;
fn try_into(self) -> Result<HeaderMap, Self::Error> {
let mut headermap = HeaderMap::new();
for (k, v) in self {
let k: HeaderName = k.as_str().parse()?;
let v: HeaderValue = v.coerce_to::<String>()?.parse()?;
headermap.insert(k, v);
}
Ok(headermap)
}
}
impl Object {
#[inline]
pub fn insert(&mut self, key: impl Into<Strand>, value: Value) -> Option<Value> {
self.0.insert(key.into(), value)
}
#[inline]
pub fn get(&self, key: &str) -> Option<&Value> {
self.0.get(key)
}
#[inline]
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
self.0.get_mut(key)
}
#[inline]
pub fn contains_key(&self, key: &str) -> bool {
self.0.contains_key(key)
}
#[inline]
pub fn remove(&mut self, key: &str) -> Option<Value> {
self.0.remove(key)
}
#[inline]
pub fn entry(&mut self, key: impl Into<Strand>) -> VecMapEntry<'_, Strand, Value> {
self.0.entry(key.into())
}
pub fn rid(&self) -> Option<RecordId> {
match self.get("id") {
Some(Value::RecordId(v)) => Some(v.clone()),
_ => None,
}
}
pub fn into_literal(self) -> Vec<ObjectEntry> {
self.0
.into_iter()
.map(|(k, v)| ObjectEntry {
key: k,
value: v.into_literal(),
})
.collect()
}
}
impl std::ops::Add for Object {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(VecMap::merge_sorted_prefer_rhs(self.0, rhs.0))
}
}
impl ToSql for Object {
fn fmt_sql(&self, f: &mut String, sql_fmt: SqlFormat) {
if self.is_empty() {
return f.push_str("{ }");
}
if sql_fmt.is_pretty() {
f.push('{');
} else {
f.push_str("{ ");
}
if !self.is_empty() {
let inner_fmt = sql_fmt.increment();
if sql_fmt.is_pretty() {
f.push('\n');
inner_fmt.write_indent(f);
}
for (i, (key, value)) in self.0.iter().enumerate() {
if i > 0 {
inner_fmt.write_separator(f);
}
write_sql!(f, sql_fmt, "{}: ", EscapeObjectKey(key.as_str()));
value.fmt_sql(f, inner_fmt);
}
if sql_fmt.is_pretty() {
f.push('\n');
sql_fmt.write_indent(f);
}
}
if sql_fmt.is_pretty() {
f.push('}');
} else {
f.push_str(" }");
}
}
}