1use std::{
2 borrow::Cow,
3 ops::{Deref, DerefMut},
4};
5
6use serde::{de::DeserializeOwned, Deserialize, Serialize};
7
8use crate::{
9 from_value,
10 parser::types::Field,
11 registry::{MetaType, MetaTypeId, Registry},
12 to_value, ContextSelectionSet, InputType, InputValueResult, OutputType, Positioned,
13 ServerResult, Value,
14};
15
16#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Hash, Default)]
21#[serde(transparent)]
22pub struct Json<T>(pub T);
23
24impl<T> Deref for Json<T> {
25 type Target = T;
26
27 fn deref(&self) -> &Self::Target {
28 &self.0
29 }
30}
31
32impl<T> DerefMut for Json<T> {
33 fn deref_mut(&mut self) -> &mut Self::Target {
34 &mut self.0
35 }
36}
37
38impl<T> From<T> for Json<T> {
39 fn from(value: T) -> Self {
40 Self(value)
41 }
42}
43
44impl<T: DeserializeOwned + Serialize + Send + Sync> InputType for Json<T> {
45 type RawValueType = T;
46
47 fn type_name() -> Cow<'static, str> {
48 Cow::Borrowed("JSON")
49 }
50
51 fn create_type_info(registry: &mut Registry) -> String {
52 registry.create_input_type::<Json<T>, _>(MetaTypeId::Scalar, |_| MetaType::Scalar {
53 name: <Self as InputType>::type_name().to_string(),
54 description: Some("A scalar that can represent any JSON value.".to_string()),
55 is_valid: None,
56 visible: None,
57 inaccessible: false,
58 tags: Default::default(),
59 specified_by_url: None,
60 directive_invocations: Default::default(),
61 })
62 }
63
64 fn parse(value: Option<Value>) -> InputValueResult<Self> {
65 Ok(from_value(value.unwrap_or_default())?)
66 }
67
68 fn to_value(&self) -> Value {
69 Value::String(serde_json::to_string(&self.0).unwrap_or_default())
70 }
71
72 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
73 Some(&self.0)
74 }
75}
76
77#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
78impl<T: Serialize + Send + Sync> OutputType for Json<T> {
79 fn type_name() -> Cow<'static, str> {
80 Cow::Borrowed("JSON")
81 }
82
83 fn create_type_info(registry: &mut Registry) -> String {
84 registry.create_output_type::<Json<T>, _>(MetaTypeId::Scalar, |_| MetaType::Scalar {
85 name: <Self as OutputType>::type_name().to_string(),
86 description: Some("A scalar that can represent any JSON value.".to_string()),
87 is_valid: None,
88 visible: None,
89 inaccessible: false,
90 tags: Default::default(),
91 specified_by_url: None,
92 directive_invocations: Default::default(),
93 })
94 }
95
96 async fn resolve(
97 &self,
98 _ctx: &ContextSelectionSet<'_>,
99 _field: &Positioned<Field>,
100 ) -> ServerResult<Value> {
101 Ok(to_value(&self.0).ok().unwrap_or_default())
102 }
103}
104
105impl InputType for serde_json::Value {
106 type RawValueType = serde_json::Value;
107
108 fn type_name() -> Cow<'static, str> {
109 Cow::Borrowed("JSON")
110 }
111
112 fn create_type_info(registry: &mut Registry) -> String {
113 registry.create_input_type::<serde_json::Value, _>(MetaTypeId::Scalar, |_| {
114 MetaType::Scalar {
115 name: <Self as InputType>::type_name().to_string(),
116 description: Some("A scalar that can represent any JSON value.".to_string()),
117 is_valid: None,
118 visible: None,
119 inaccessible: false,
120 tags: Default::default(),
121 specified_by_url: None,
122 directive_invocations: Default::default(),
123 }
124 })
125 }
126
127 fn parse(value: Option<Value>) -> InputValueResult<Self> {
128 Ok(from_value(value.unwrap_or_default())?)
129 }
130
131 fn to_value(&self) -> Value {
132 Value::String(self.to_string())
133 }
134
135 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
136 Some(&self)
137 }
138}
139
140#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
141impl OutputType for serde_json::Value {
142 fn type_name() -> Cow<'static, str> {
143 Cow::Borrowed("JSON")
144 }
145
146 fn create_type_info(registry: &mut Registry) -> String {
147 registry.create_output_type::<serde_json::Value, _>(MetaTypeId::Scalar, |_| {
148 MetaType::Scalar {
149 name: <Self as OutputType>::type_name().to_string(),
150 description: Some("A scalar that can represent any JSON value.".to_string()),
151 is_valid: None,
152 visible: None,
153 inaccessible: false,
154 tags: Default::default(),
155 specified_by_url: None,
156 directive_invocations: Default::default(),
157 }
158 })
159 }
160
161 async fn resolve(
162 &self,
163 _ctx: &ContextSelectionSet<'_>,
164 _field: &Positioned<Field>,
165 ) -> ServerResult<Value> {
166 Ok(to_value(self).ok().unwrap_or_default())
167 }
168}
169
170#[cfg(test)]
171mod test {
172 use std::collections::HashMap;
173
174 use serde::{Deserialize, Serialize};
175
176 use crate::*;
177
178 #[tokio::test]
179 async fn test_json_type() {
180 #[derive(Serialize, Deserialize)]
181 struct MyStruct {
182 a: i32,
183 b: i32,
184 c: HashMap<String, i32>,
185 }
186
187 struct Query;
188
189 #[Object(internal)]
190 impl Query {
191 async fn obj(&self, input: Json<MyStruct>) -> Json<MyStruct> {
192 input
193 }
194 }
195
196 let query = r#"{ obj(input: { a: 1, b: 2, c: { a: 11, b: 22 } } ) }"#;
197 let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
198 assert_eq!(
199 schema.execute(query).await.into_result().unwrap().data,
200 value!({
201 "obj": {
202 "a": 1,
203 "b": 2,
204 "c": { "a": 11, "b": 22 }
205 }
206 })
207 );
208 }
209
210 #[tokio::test]
211 async fn test_json_type_for_serialize_only() {
212 #[derive(Serialize)]
213 struct MyStruct {
214 a: i32,
215 b: i32,
216 c: HashMap<String, i32>,
217 }
218
219 struct Query;
220
221 #[Object(internal)]
222 impl Query {
223 async fn obj(&self) -> Json<MyStruct> {
224 MyStruct {
225 a: 1,
226 b: 2,
227 c: {
228 let mut values = HashMap::new();
229 values.insert("a".to_string(), 11);
230 values.insert("b".to_string(), 22);
231 values
232 },
233 }
234 .into()
235 }
236 }
237
238 let query = r#"{ obj }"#;
239 let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
240 assert_eq!(
241 schema.execute(query).await.into_result().unwrap().data,
242 value!({
243 "obj": {
244 "a": 1,
245 "b": 2,
246 "c": { "a": 11, "b": 22 }
247 }
248 })
249 );
250 }
251}