async_graphql/types/external/
bson.rs1#[cfg(feature = "chrono")]
2use bson::DateTime as UtcDateTime;
3use bson::{oid::ObjectId, Bson, Document, Uuid};
4#[cfg(feature = "chrono")]
5use chrono::{DateTime, Utc};
6
7use crate::{InputValueError, InputValueResult, Scalar, ScalarType, Value};
8
9#[Scalar(internal)]
10impl ScalarType for ObjectId {
11 fn parse(value: Value) -> InputValueResult<Self> {
12 match value {
13 Value::String(s) => Ok(ObjectId::parse_str(s)?),
14 Value::Object(o) => {
15 let json = Value::Object(o).into_json()?;
16 let bson = Bson::try_from(json)?;
17 bson.as_object_id().ok_or(InputValueError::custom(
18 "could not parse the value as a BSON ObjectId",
19 ))
20 }
21 _ => Err(InputValueError::expected_type(value)),
22 }
23 }
24
25 fn to_value(&self) -> Value {
26 Value::String(self.to_string())
27 }
28}
29
30#[Scalar(internal, name = "UUID")]
31impl ScalarType for Uuid {
32 fn parse(value: Value) -> InputValueResult<Self> {
33 match value {
34 Value::String(s) => Ok(Uuid::parse_str(s)?),
35 Value::Object(o) => {
36 let json = Value::Object(o).into_json()?;
37 let Bson::Binary(binary) = Bson::try_from(json)? else {
38 return Err(InputValueError::custom(
39 "could not parse the value as BSON Binary",
40 ));
41 };
42 binary.to_uuid().map_err(|_| {
43 InputValueError::custom("could not deserialize BSON Binary to Uuid")
44 })
45 }
46 _ => Err(InputValueError::expected_type(value)),
47 }
48 }
49
50 fn to_value(&self) -> Value {
51 Value::String(self.to_string())
52 }
53}
54
55#[cfg(feature = "chrono")]
56#[Scalar(internal, name = "DateTime")]
57impl ScalarType for UtcDateTime {
58 fn parse(value: Value) -> InputValueResult<Self> {
59 <DateTime<Utc>>::parse(value)
60 .map_err(InputValueError::propagate)
61 .map(UtcDateTime::from_chrono)
62 }
63
64 fn to_value(&self) -> Value {
65 self.to_chrono().to_value()
66 }
67}
68
69#[Scalar(internal, name = "JSON")]
70impl ScalarType for Bson {
71 fn parse(value: Value) -> InputValueResult<Self> {
72 bson::to_bson(&value).map_err(InputValueError::custom)
73 }
74
75 fn to_value(&self) -> Value {
76 bson::from_bson(self.clone()).unwrap_or_default()
77 }
78}
79
80#[Scalar(internal, name = "JSONObject")]
81impl ScalarType for Document {
82 fn parse(value: Value) -> InputValueResult<Self> {
83 bson::to_document(&value).map_err(InputValueError::custom)
84 }
85
86 fn to_value(&self) -> Value {
87 bson::from_document(self.clone()).unwrap_or_default()
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use serde_json::json;
94
95 use super::*;
96
97 #[test]
98 fn test_parse_bson_uuid() {
99 let id = Uuid::new();
100 let bson_value = bson::bson!(id);
101 let extended_json_value = json!(bson_value);
102 let gql_value = Value::from_json(extended_json_value).expect("valid json");
103 assert_eq!(
104 id,
105 <Uuid as ScalarType>::parse(gql_value).expect("parsing succeeds")
106 );
107 }
108
109 #[test]
110 fn test_parse_bson_object_id() {
111 let id = ObjectId::from_bytes([42; 12]);
112 let bson_value = bson::bson!(id);
113 let extended_json_value = json!(bson_value);
114 let gql_value = Value::from_json(extended_json_value).expect("valid json");
115 assert_eq!(
116 id,
117 <ObjectId as ScalarType>::parse(gql_value).expect("parsing succeeds")
118 );
119 }
120}