subgraph/graphql/entity/create_field/resolve_fields/resolve_document_field/
mod.rs

1use async_graphql::{indexmap::IndexMap, Name, Value};
2use bson::{Bson, Document};
3use log::{debug, trace};
4
5use crate::{
6    configuration::subgraph::entities::service_entity_field::ServiceEntityFieldConfig,
7    graphql::entity::ServiceEntity, utils::document::get_from_document::DocumentValue,
8};
9
10impl ServiceEntity {
11    pub fn resolve_document_object_id_scalar(
12        document: &Document,
13        field: &ServiceEntityFieldConfig,
14    ) -> Result<Option<Value>, async_graphql::Error> {
15        debug!("Resolving Object ID Scalar");
16        let resolved =
17            field
18                .scalar
19                .get_from_document(document, &field.name, field.list.unwrap_or(false))?;
20
21        match resolved {
22            DocumentValue::ObjectID(object_id) => Ok(Some(Value::from(object_id.to_string()))),
23            DocumentValue::ObjectIDArray(object_ids) => Ok(Some(Value::List(
24                object_ids
25                    .into_iter()
26                    .map(|object_id| Value::from(object_id.to_string()))
27                    .collect(),
28            ))),
29            DocumentValue::Null => Ok(Some(Value::Null)),
30            DocumentValue::None => Ok(None),
31            _ => Err(async_graphql::Error::from(
32                "Invalid result type for object id scalar",
33            )),
34        }
35    }
36
37    pub fn resolve_document_string_scalar(
38        document: &Document,
39        field: &ServiceEntityFieldConfig,
40    ) -> Result<Option<Value>, async_graphql::Error> {
41        debug!("Resolving String Scalar");
42        let resolved =
43            field
44                .scalar
45                .get_from_document(document, &field.name, field.list.unwrap_or(false))?;
46
47        match resolved {
48            DocumentValue::String(value) => Ok(Some(Value::from(value))),
49            DocumentValue::StringArray(values) => Ok(Some(Value::List(
50                values.into_iter().map(|value| Value::from(value)).collect(),
51            ))),
52            DocumentValue::None => Ok(None),
53            DocumentValue::Null => Ok(Some(Value::Null)),
54            _ => Err(async_graphql::Error::from(
55                "Invalid result type for string scalar",
56            )),
57        }
58    }
59
60    pub fn resolve_document_int_scalar(
61        document: &Document,
62        field: &ServiceEntityFieldConfig,
63    ) -> Result<Option<Value>, async_graphql::Error> {
64        debug!("Resolving Int Scalar");
65
66        let resolved =
67            field
68                .scalar
69                .get_from_document(document, &field.name, field.list.unwrap_or(false))?;
70
71        match resolved {
72            DocumentValue::Int(value) => Ok(Some(Value::from(value))),
73            DocumentValue::IntArray(values) => Ok(Some(Value::List(
74                values.into_iter().map(|value| Value::from(value)).collect(),
75            ))),
76            DocumentValue::None => Ok(None),
77            DocumentValue::Null => Ok(Some(Value::Null)),
78            _ => Err(async_graphql::Error::from(
79                "Invalid result type for int scalar",
80            )),
81        }
82    }
83
84    pub fn resolve_document_boolean_scalar(
85        document: &Document,
86        field: &ServiceEntityFieldConfig,
87    ) -> Result<Option<Value>, async_graphql::Error> {
88        debug!("Resolving Boolean Scalar");
89
90        let resolved =
91            field
92                .scalar
93                .get_from_document(document, &field.name, field.list.unwrap_or(false))?;
94
95        match resolved {
96            DocumentValue::Boolean(value) => Ok(Some(Value::from(value))),
97            DocumentValue::BooleanArray(values) => Ok(Some(Value::List(
98                values.into_iter().map(|value| Value::from(value)).collect(),
99            ))),
100            DocumentValue::Null => Ok(Some(Value::Null)),
101            DocumentValue::None => Ok(None),
102            _ => Err(async_graphql::Error::from(
103                "Invalid result type for boolean scalar",
104            )),
105        }
106    }
107
108    pub fn resolve_document_uuid_scalar(
109        document: &Document,
110        field: &ServiceEntityFieldConfig,
111    ) -> Result<Option<Value>, async_graphql::Error> {
112        debug!("Resolving UUID Scalar");
113
114        let resolved =
115            field
116                .scalar
117                .get_from_document(document, &field.name, field.list.unwrap_or(false))?;
118
119        match resolved {
120            DocumentValue::UUID(value) => Ok(Some(Value::from(value.to_string()))),
121            DocumentValue::UUIDArray(values) => Ok(Some(Value::List(
122                values
123                    .into_iter()
124                    .map(|value| Value::from(value.to_string()))
125                    .collect(),
126            ))),
127            DocumentValue::Null => Ok(Some(Value::Null)),
128            DocumentValue::None => Ok(None),
129            _ => Err(async_graphql::Error::from(
130                "Invalid result type for UUID scalar",
131            )),
132        }
133    }
134
135    pub fn resolve_document_datetime_scalar(
136        document: &Document,
137        field: &ServiceEntityFieldConfig,
138    ) -> Result<Option<Value>, async_graphql::Error> {
139        debug!("Resolving DateTime Scalar");
140
141        let resolved =
142            field
143                .scalar
144                .get_from_document(document, &field.name, field.list.unwrap_or(false))?;
145
146        match resolved {
147            DocumentValue::DateTime(value) => Ok(Some(Value::from(value.to_rfc3339()))),
148            DocumentValue::DateTimeArray(values) => Ok(Some(Value::List(
149                values
150                    .into_iter()
151                    .map(|value| Value::from(value.to_rfc3339()))
152                    .collect(),
153            ))),
154            DocumentValue::Null => Ok(Some(Value::Null)),
155            DocumentValue::None => Ok(None),
156            _ => Err(async_graphql::Error::from(
157                "Invalid result type for DateTime scalar",
158            )),
159        }
160    }
161
162    pub fn parse_bson_object(
163        value: &Bson,
164        field: &ServiceEntityFieldConfig,
165    ) -> Result<IndexMap<Name, Value>, async_graphql::Error> {
166        let document = match value.as_document() {
167            Some(document) => document,
168            None => return Err(async_graphql::Error::from("Invalid BSON Document")),
169        };
170
171        let mut index_map = IndexMap::new();
172
173        for (key, bson) in document.into_iter() {
174            let name = Name::new(key);
175            trace!("Found BSON Element Type: {:?}", bson.element_type());
176
177            let field = ServiceEntityFieldConfig::get_field(
178                field.fields.clone().unwrap_or(Vec::new()),
179                key.clone(),
180            )?;
181            let value = field
182                .scalar
183                .clone()
184                .document_field_to_async_graphql_value(document, &field)?;
185            if let Some(value) = value {
186                index_map.insert(name, value);
187            }
188        }
189        Ok(index_map)
190    }
191
192    pub fn resolve_document_object_scalar(
193        document: &Document,
194        field: &ServiceEntityFieldConfig,
195    ) -> Result<Option<Value>, async_graphql::Error> {
196        debug!("Resolve Document Object Scalar");
197        let value = document.get(&field.name);
198
199        if value.is_none() {
200            trace!("Value is None, returning null");
201            return Ok(None);
202        }
203
204        if field.list.unwrap_or(false) {
205            if let Some(Bson::Array(documents)) = document.get(field.name.clone()) {
206                let mut values = vec![];
207                for document in documents {
208                    let value = ServiceEntity::parse_bson_object(document, field)?;
209                    values.push(Value::Object(value));
210                }
211
212                return Ok(Some(Value::List(values)));
213            } else {
214                return Ok(Some(Value::List(vec![])));
215            }
216        }
217
218        let index_map = ServiceEntity::parse_bson_object(value.unwrap(), field)?;
219
220        Ok(Some(Value::from(index_map)))
221    }
222
223    pub fn resolve_document_enum_scalar(
224        document: &Document,
225        field: &ServiceEntityFieldConfig,
226    ) -> Result<Option<Value>, async_graphql::Error> {
227        debug!("Resolving Enum Scalar");
228
229        let resolved =
230            field
231                .scalar
232                .get_from_document(document, &field.name, field.list.unwrap_or(false))?;
233
234        match resolved {
235            DocumentValue::String(value) => Ok(Some(Value::from(value))),
236            DocumentValue::StringArray(values) => Ok(Some(Value::List(
237                values.into_iter().map(|value| Value::from(value)).collect(),
238            ))),
239            DocumentValue::None => Ok(None),
240            DocumentValue::Null => Ok(Some(Value::Null)),
241            _ => Err(async_graphql::Error::from(
242                "Invalid result type for enum scalar",
243            )),
244        }
245    }
246}