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