use bson::oid::ObjectId;
use bson::spec::BinarySubtype;
use bson::{Binary, Bson, DateTime, Document};
use vantage_core::{Result, error};
use vantage_rhai::rhai::{Array, Blob, Dynamic, Map};
pub fn dynamic_to_bson(d: Dynamic) -> Result<Bson> {
if d.is_unit() {
return Ok(Bson::Null);
}
if d.is::<bool>() {
return Ok(Bson::Boolean(d.cast::<bool>()));
}
if d.is::<i64>() {
return Ok(Bson::Int64(d.cast::<i64>()));
}
if d.is::<f64>() {
return Ok(Bson::Double(d.cast::<f64>()));
}
if d.is::<String>() {
return Ok(Bson::String(d.cast::<String>()));
}
if d.is::<char>() {
return Ok(Bson::String(d.cast::<char>().to_string()));
}
if d.is::<Blob>() {
return Ok(Bson::Binary(Binary {
subtype: BinarySubtype::Generic,
bytes: d.cast::<Blob>(),
}));
}
if d.is::<Array>() {
return d
.cast::<Array>()
.into_iter()
.map(dynamic_to_bson)
.collect::<Result<Vec<_>>>()
.map(Bson::Array);
}
if d.is::<Map>() {
return map_to_document(d.cast::<Map>()).map(Bson::Document);
}
if d.is::<ObjectId>() {
return Ok(Bson::ObjectId(d.cast::<ObjectId>()));
}
if d.is::<DateTime>() {
return Ok(Bson::DateTime(d.cast::<DateTime>()));
}
if d.is::<Document>() {
return Ok(Bson::Document(d.cast::<Document>()));
}
if d.is::<Bson>() {
return Ok(d.cast::<Bson>());
}
Err(error!(
"no BSON representation for rhai value",
rhai_type = d.type_name()
))
}
pub fn map_to_document(map: Map) -> Result<Document> {
let mut doc = Document::new();
for (key, value) in map {
let value = dynamic_to_bson(value).map_err(|e| {
error!(
"map value has no BSON representation",
key = key.to_string(),
details = e.to_string()
)
})?;
doc.insert(key.to_string(), value);
}
Ok(doc)
}
pub fn dynamic_to_document(d: Dynamic) -> Result<Document> {
let type_name = d.type_name();
match dynamic_to_bson(d)? {
Bson::Document(doc) => Ok(doc),
_ => Err(error!("expected a map or document", rhai_type = type_name)),
}
}
pub fn bson_to_dynamic(value: &Bson) -> Dynamic {
match value {
Bson::Null | Bson::Undefined => Dynamic::UNIT,
Bson::Boolean(b) => Dynamic::from_bool(*b),
Bson::Int32(i) => Dynamic::from_int(i64::from(*i)),
Bson::Int64(i) => Dynamic::from_int(*i),
Bson::Double(f) => Dynamic::from_float(*f),
Bson::String(s) => Dynamic::from(s.clone()),
Bson::Array(items) => Dynamic::from_array(items.iter().map(bson_to_dynamic).collect()),
Bson::Document(doc) => Dynamic::from_map(
doc.iter()
.map(|(k, v)| (k.as_str().into(), bson_to_dynamic(v)))
.collect(),
),
Bson::ObjectId(oid) => Dynamic::from(*oid),
Bson::DateTime(dt) => Dynamic::from(*dt),
Bson::Binary(bin) if bin.subtype == BinarySubtype::Generic => {
Dynamic::from_blob(bin.bytes.clone())
}
other => Dynamic::from(other.clone()),
}
}