use crate::error::GraphQLError;
use crate::schema::definition::{CollectionDef, FieldType, RelationKind};
use async_graphql::dynamic::FieldValue;
use mongodb::bson::Bson;
pub fn document_to_graphql_value(
doc: &mongodb::bson::Document,
collection_def: &CollectionDef,
) -> serde_json::Value {
let mut map = serde_json::Map::new();
for field_def in &collection_def.fields {
if let FieldType::Relation(rel) = &field_def.field_type {
match rel.kind {
RelationKind::OneToMany | RelationKind::OneToOne => {
if let Some(bson) = doc.get(&field_def.name) {
map.insert(field_def.name.clone(), bson_to_json(bson));
}
}
RelationKind::ManyToMany => {}
}
continue;
}
let gql_name = field_def.graphql_name();
match doc.get(&field_def.name) {
Some(bson) => {
map.insert(gql_name, bson_to_json(bson));
}
None => {}
}
}
serde_json::Value::Object(map)
}
pub fn bson_to_json(bson: &Bson) -> serde_json::Value {
match bson {
Bson::ObjectId(oid) => serde_json::Value::String(oid.to_hex()),
Bson::String(s) => serde_json::Value::String(s.clone()),
Bson::Int32(i) => serde_json::Value::Number((*i).into()),
Bson::Int64(i) => serde_json::Value::Number((*i).into()),
Bson::Double(f) => serde_json::Number::from_f64(*f)
.map(serde_json::Value::Number)
.unwrap_or(serde_json::Value::Null),
Bson::Boolean(b) => serde_json::Value::Bool(*b),
Bson::DateTime(dt) => {
let millis = dt.timestamp_millis();
let secs = millis / 1000;
let nanos = ((millis % 1000) * 1_000_000) as u32;
match chrono::DateTime::from_timestamp(secs, nanos) {
Some(chrono_dt) => serde_json::Value::String(chrono_dt.to_rfc3339()),
None => serde_json::Value::Null,
}
}
Bson::Array(arr) => {
serde_json::Value::Array(arr.iter().map(bson_to_json).collect())
}
Bson::Document(subdoc) => {
serde_json::Value::Object(
subdoc.iter().map(|(key, value)| (key.clone(), bson_to_json(value))).collect(),
)
}
Bson::Null | Bson::Undefined => serde_json::Value::Null,
_ => serde_json::Value::Null,
}
}
pub fn input_doc_to_mongo(doc: mongodb::bson::Document, collection_def: &CollectionDef) -> mongodb::bson::Document {
let mut mapped = mongodb::bson::Document::new();
for (key, value) in doc {
let field_def = collection_def
.fields
.iter()
.find(|field| field.graphql_name() == key);
let mongo_name = field_def
.map(|field| field.name.clone())
.unwrap_or_else(|| key.clone());
let mapped_value = match field_def {
Some(f) if matches!(f.field_type, FieldType::Relation(_)) => {
continue;
}
_ => value,
};
mapped.insert(mongo_name, mapped_value);
}
mapped
}
pub fn json_to_field_value(json: serde_json::Value) -> Result<FieldValue<'static>, GraphQLError> {
async_graphql::Value::try_from(json)
.map(FieldValue::value)
.map_err(|e| GraphQLError::Internal(format!("Value conversion: {}", e)))
}