juniper/integrations/
bson.rs1use crate::graphql_scalar;
17
18mod for_minimal_versions_check_only {
20 use tap as _;
21}
22
23#[graphql_scalar]
33#[graphql(
34 name = "ObjectID",
35 with = object_id,
36 parse_token(String),
37 specified_by_url = "https://graphql-scalars.dev/docs/scalars/object-id",
38)]
39type ObjectId = bson::oid::ObjectId;
40
41mod object_id {
42 use super::ObjectId;
43
44 pub(super) fn to_output(v: &ObjectId) -> String {
45 v.to_hex()
46 }
47
48 pub(super) fn from_input(s: &str) -> Result<ObjectId, Box<str>> {
49 ObjectId::parse_str(s).map_err(|e| format!("Failed to parse `ObjectID`: {e}").into())
50 }
51}
52
53#[graphql_scalar]
67#[graphql(
68 with = date_time,
69 parse_token(String),
70 specified_by_url = "https://graphql-scalars.dev/docs/scalars/date-time",
71)]
72type DateTime = bson::DateTime;
73
74mod date_time {
75 use super::DateTime;
76
77 pub(super) fn to_output(v: &DateTime) -> String {
78 (*v).try_to_rfc3339_string()
79 .unwrap_or_else(|e| panic!("failed to format `DateTime` as RFC 3339: {e}"))
80 }
81
82 pub(super) fn from_input(s: &str) -> Result<DateTime, Box<str>> {
83 DateTime::parse_rfc3339_str(s)
84 .map_err(|e| format!("Failed to parse `DateTime`: {e}").into())
85 }
86}
87
88#[cfg(test)]
89mod test {
90 use bson::oid::ObjectId;
91
92 use crate::{FromInputValue, InputValue, graphql_input_value};
93
94 #[test]
95 fn objectid_from_input() {
96 let raw = "53e37d08776f724e42000000";
97 let input: InputValue = graphql_input_value!((raw));
98
99 let parsed: ObjectId = FromInputValue::from_input_value(&input).unwrap();
100 let id = ObjectId::parse_str(raw).unwrap();
101
102 assert_eq!(parsed, id);
103 }
104}
105
106#[cfg(test)]
107mod date_time_test {
108 use crate::{FromInputValue as _, InputValue, ToInputValue as _, graphql_input_value};
109
110 use super::DateTime;
111
112 #[test]
113 fn parses_correct_input() {
114 for (raw, expected) in [
115 (
116 "2014-11-28T21:00:09+09:00",
117 DateTime::builder()
118 .year(2014)
119 .month(11)
120 .day(28)
121 .hour(12)
122 .second(9)
123 .build()
124 .unwrap(),
125 ),
126 (
127 "2014-11-28T21:00:09Z",
128 DateTime::builder()
129 .year(2014)
130 .month(11)
131 .day(28)
132 .hour(21)
133 .second(9)
134 .build()
135 .unwrap(),
136 ),
137 (
138 "2014-11-28 21:00:09z",
139 DateTime::builder()
140 .year(2014)
141 .month(11)
142 .day(28)
143 .hour(21)
144 .second(9)
145 .build()
146 .unwrap(),
147 ),
148 (
149 "2014-11-28T21:00:09+00:00",
150 DateTime::builder()
151 .year(2014)
152 .month(11)
153 .day(28)
154 .hour(21)
155 .second(9)
156 .build()
157 .unwrap(),
158 ),
159 (
160 "2014-11-28T21:00:09.05+09:00",
161 DateTime::builder()
162 .year(2014)
163 .month(11)
164 .day(28)
165 .hour(12)
166 .second(9)
167 .millisecond(50)
168 .build()
169 .unwrap(),
170 ),
171 (
172 "2014-11-28 21:00:09.05+09:00",
173 DateTime::builder()
174 .year(2014)
175 .month(11)
176 .day(28)
177 .hour(12)
178 .second(9)
179 .millisecond(50)
180 .build()
181 .unwrap(),
182 ),
183 ] {
184 let input: InputValue = graphql_input_value!((raw));
185 let parsed = DateTime::from_input_value(&input);
186
187 assert!(
188 parsed.is_ok(),
189 "failed to parse `{raw}`: {:?}",
190 parsed.unwrap_err(),
191 );
192 assert_eq!(parsed.unwrap(), expected, "input: {raw}");
193 }
194 }
195
196 #[test]
197 fn fails_on_invalid_input() {
198 for input in [
199 graphql_input_value!("12"),
200 graphql_input_value!("12:"),
201 graphql_input_value!("56:34:22"),
202 graphql_input_value!("56:34:22.000"),
203 graphql_input_value!("1996-12-1914:23:43"),
204 graphql_input_value!("1996-12-19T14:23:43"),
205 graphql_input_value!("1996-12-19T14:23:43ZZ"),
206 graphql_input_value!("1996-12-19T14:23:43.543"),
207 graphql_input_value!("1996-12-19T14:23"),
208 graphql_input_value!("1996-12-19T14:23:1"),
209 graphql_input_value!("1996-12-19T14:23:"),
210 graphql_input_value!("1996-12-19T23:78:43Z"),
211 graphql_input_value!("1996-12-19T23:18:99Z"),
212 graphql_input_value!("1996-12-19T24:00:00Z"),
213 graphql_input_value!("1996-12-19T99:02:13Z"),
214 graphql_input_value!("1996-12-19T99:02:13Z"),
215 graphql_input_value!("1996-12-19T12:02:13+4444444"),
216 graphql_input_value!("i'm not even a datetime"),
217 graphql_input_value!(2.32),
218 graphql_input_value!(1),
219 graphql_input_value!(null),
220 graphql_input_value!(false),
221 ] {
222 let input: InputValue = input;
223 let parsed = DateTime::from_input_value(&input);
224
225 assert!(parsed.is_err(), "allows input: {input:?}");
226 }
227 }
228
229 #[test]
230 fn formats_correctly() {
231 for (val, expected) in [
232 (
233 DateTime::builder()
234 .year(1996)
235 .month(12)
236 .day(19)
237 .hour(12)
238 .build()
239 .unwrap(),
240 graphql_input_value!("1996-12-19T12:00:00Z"),
241 ),
242 (
243 DateTime::builder()
244 .year(1564)
245 .month(1)
246 .day(30)
247 .hour(5)
248 .minute(3)
249 .second(3)
250 .millisecond(1)
251 .build()
252 .unwrap(),
253 graphql_input_value!("1564-01-30T05:03:03.001Z"),
254 ),
255 ] {
256 let actual: InputValue = val.to_input_value();
257
258 assert_eq!(actual, expected, "on value: {val}");
259 }
260 }
261}