teo 0.0.52-beta.3

REDEFINED HTTP server framework.
Documentation
use std::collections::{BTreeMap, HashMap};
use bson::Bson;
use key_path::KeyPath;

use crate::core::error::Error;
use crate::core::field::r#type::{FieldType, FieldTypeOwner};
use crate::core::model::Model;
use crate::core::result::Result;
use crate::prelude::{Graph, Value};

pub(crate) struct BsonCoder { }

impl BsonCoder {

    pub(crate) fn encode_without_default_type(value: &Value) -> Bson {
        value.clone().into()
    }

    pub(crate) fn encode<'a>(r#type: &FieldType, value: Value) -> Result<Bson> {
        match r#type {
            FieldType::I32 => Ok(Bson::Int32(value.as_i32().unwrap())),
            FieldType::I64 => Ok(Bson::Int64(value.as_i64().unwrap())),
            _ => Ok(value.into()),
        }
    }

    pub(crate) fn decode<'a>(model: &Model, graph: &Graph, r#type: &FieldType, optional: bool, bson_value: &Bson, path: impl AsRef<KeyPath<'a>>) -> Result<Value> {
        if bson_value.as_null().is_some() && optional {
            return Ok(Value::Null);
        }
        let path = path.as_ref();
        match r#type {
            FieldType::ObjectId => match bson_value.as_object_id() {
                Some(oid) => Ok(Value::ObjectId(oid)),
                None => Err(Error::record_decoding_error(model.name(), path, "object id")),
            }
            FieldType::Bool => match bson_value.as_bool() {
                Some(b) => Ok(Value::Bool(b)),
                None => Err(Error::record_decoding_error(model.name(), path, "bool")),
            }
            FieldType::I32 => match bson_value.as_i32() {
                Some(n) => Ok(Value::I32(n)),
                None => Err(Error::record_decoding_error(model.name(), path, "int 32")),
            }
            FieldType::I64 => match bson_value.as_i64() {
                Some(n) => Ok(Value::I64(n)),
                None => Err(Error::record_decoding_error(model.name(), path, "int 64")),
            }
            FieldType::F32 => match bson_value.as_f64() {
                Some(n) => Ok(Value::F32(n as f32)),
                None => Err(Error::record_decoding_error(model.name(), path, "double")),
            }
            FieldType::F64 => match bson_value.as_f64() {
                Some(n) => Ok(Value::F64(n)),
                None => Err(Error::record_decoding_error(model.name(), path, "double")),
            }
            FieldType::Decimal => panic!("Decimal is not implemented by MongoDB."),
            FieldType::String => match bson_value.as_str() {
                Some(s) => Ok(Value::String(s.to_owned())),
                None => Err(Error::record_decoding_error(model.name(), path, "string")),
            }
            FieldType::Date => match bson_value.as_datetime() {
                Some(val) => Ok(Value::Date(val.to_chrono().date_naive())),
                None => Err(Error::record_decoding_error(model.name(), path, "datetime")),
            }
            FieldType::DateTime => match bson_value.as_datetime() {
                Some(val) => Ok(Value::DateTime(val.to_chrono())),
                None => Err(Error::record_decoding_error(model.name(), path, "datetime")),
            }
            FieldType::Enum(enum_name) => match bson_value.as_str() {
                Some(val) => {
                    if graph.enum_values(enum_name).unwrap().contains(&val.to_string()) {
                        Ok(Value::String(val.to_owned()))
                    } else {
                        Err(Error::record_decoding_error(model.name(), path, format!("string value for enum `{enum_name}'")))
                    }
                },
                None => Err(Error::record_decoding_error(model.name(), path, "string")),
            }
            FieldType::Vec(inner_field) => {
                match bson_value.as_array() {
                    Some(arr) => Ok(Value::Vec(arr.iter().enumerate().map(|(i, v)| {
                        let path = path + i;
                        Self::decode(model, graph, inner_field.field_type(), inner_field.is_optional(), v, path)
                    }).collect::<Result<Vec<Value>>>()?)),
                    None => Err(Error::record_decoding_error(model.name(), path, "array")),
                }
            }
            FieldType::HashMap(inner_field) => {
                match bson_value.as_document() {
                    Some(doc) => Ok(Value::HashMap(doc.iter().map(|(k, v)| {
                        let path = path + k;
                        Ok((k.to_owned(), Self::decode(model, graph, inner_field.field_type(), inner_field.is_optional(), v, path)?))
                    }).collect::<Result<HashMap<String, Value>>>()?)),
                    None => Err(Error::record_decoding_error(model.name(), path, "document")),
                }
            }
            FieldType::BTreeMap(inner_field) => {
                match bson_value.as_document() {
                    Some(doc) => Ok(Value::BTreeMap(doc.iter().map(|(k, v)| {
                        let path = path + k;
                        Ok((k.to_owned(), Self::decode(model, graph, inner_field.field_type(), inner_field.is_optional(), v, path)?))
                    }).collect::<Result<BTreeMap<String, Value>>>()?)),
                    None => Err(Error::record_decoding_error(model.name(), path, "document")),
                }
            }
            FieldType::Object(_) => panic!("Saving embedded object into database is not implemented yet.")
        }
    }
}