juniper/types/
scalars.rs

1use std::{char, fmt, marker::PhantomData, ops::Deref, rc::Rc, thread::JoinHandle, u32};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    ast::{InputValue, Selection, ToInputValue},
7    executor::{ExecutionResult, Executor, Registry},
8    graphql_scalar,
9    macros::reflect,
10    parser::{LexerError, ParseError, ScalarToken, Token},
11    schema::meta::MetaType,
12    types::{
13        async_await::GraphQLValueAsync,
14        base::{GraphQLType, GraphQLValue},
15        subscriptions::GraphQLSubscriptionValue,
16    },
17    value::{ParseScalarResult, ScalarValue, Value},
18    GraphQLScalar,
19};
20
21/// An ID as defined by the GraphQL specification
22///
23/// Represented as a string, but can be converted _to_ from an integer as well.
24#[derive(Clone, Debug, Deserialize, Eq, GraphQLScalar, PartialEq, Serialize)]
25#[graphql(parse_token(String, i32))]
26pub struct ID(String);
27
28impl ID {
29    fn to_output<S: ScalarValue>(&self) -> Value<S> {
30        Value::scalar(self.0.clone())
31    }
32
33    fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
34        v.as_string_value()
35            .map(str::to_owned)
36            .or_else(|| v.as_int_value().as_ref().map(ToString::to_string))
37            .map(Self)
38            .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
39    }
40}
41
42impl From<String> for ID {
43    fn from(s: String) -> ID {
44        ID(s)
45    }
46}
47
48impl ID {
49    /// Construct a new ID from anything implementing `Into<String>`
50    pub fn new<S: Into<String>>(value: S) -> Self {
51        ID(value.into())
52    }
53}
54
55impl Deref for ID {
56    type Target = str;
57
58    fn deref(&self) -> &str {
59        &self.0
60    }
61}
62
63impl fmt::Display for ID {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        self.0.fmt(f)
66    }
67}
68
69#[graphql_scalar(with = impl_string_scalar)]
70type String = std::string::String;
71
72mod impl_string_scalar {
73    use super::*;
74
75    pub(super) fn to_output<S: ScalarValue>(v: &str) -> Value<S> {
76        Value::scalar(v.to_owned())
77    }
78
79    pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<String, String> {
80        v.as_string_value()
81            .map(str::to_owned)
82            .ok_or_else(|| format!("Expected `String`, found: {v}"))
83    }
84
85    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
86        if let ScalarToken::String(value) = value {
87            let mut ret = String::with_capacity(value.len());
88            let mut char_iter = value.chars();
89            while let Some(ch) = char_iter.next() {
90                match ch {
91                    '\\' => match char_iter.next() {
92                        Some('"') => {
93                            ret.push('"');
94                        }
95                        Some('/') => {
96                            ret.push('/');
97                        }
98                        Some('n') => {
99                            ret.push('\n');
100                        }
101                        Some('r') => {
102                            ret.push('\r');
103                        }
104                        Some('t') => {
105                            ret.push('\t');
106                        }
107                        Some('\\') => {
108                            ret.push('\\');
109                        }
110                        Some('f') => {
111                            ret.push('\u{000c}');
112                        }
113                        Some('b') => {
114                            ret.push('\u{0008}');
115                        }
116                        Some('u') => {
117                            ret.push(parse_unicode_codepoint(&mut char_iter)?);
118                        }
119                        Some(s) => {
120                            return Err(ParseError::LexerError(LexerError::UnknownEscapeSequence(
121                                format!("\\{s}"),
122                            )))
123                        }
124                        None => return Err(ParseError::LexerError(LexerError::UnterminatedString)),
125                    },
126                    ch => {
127                        ret.push(ch);
128                    }
129                }
130            }
131            Ok(ret.into())
132        } else {
133            Err(ParseError::unexpected_token(Token::Scalar(value)))
134        }
135    }
136}
137
138fn parse_unicode_codepoint<I>(char_iter: &mut I) -> Result<char, ParseError>
139where
140    I: Iterator<Item = char>,
141{
142    let escaped_code_point = char_iter
143        .next()
144        .ok_or_else(|| {
145            ParseError::LexerError(LexerError::UnknownEscapeSequence(String::from("\\u")))
146        })
147        .and_then(|c1| {
148            char_iter
149                .next()
150                .map(|c2| format!("{c1}{c2}"))
151                .ok_or_else(|| {
152                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{c1}")))
153                })
154        })
155        .and_then(|mut s| {
156            char_iter
157                .next()
158                .ok_or_else(|| {
159                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{s}")))
160                })
161                .map(|c2| {
162                    s.push(c2);
163                    s
164                })
165        })
166        .and_then(|mut s| {
167            char_iter
168                .next()
169                .ok_or_else(|| {
170                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{s}")))
171                })
172                .map(|c2| {
173                    s.push(c2);
174                    s
175                })
176        })?;
177    let code_point = u32::from_str_radix(&escaped_code_point, 16).map_err(|_| {
178        ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
179            "\\u{escaped_code_point}",
180        )))
181    })?;
182    char::from_u32(code_point).ok_or_else(|| {
183        ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
184            "\\u{escaped_code_point}",
185        )))
186    })
187}
188
189impl<S> reflect::WrappedType<S> for str {
190    const VALUE: reflect::WrappedValue = 1;
191}
192
193impl<S> reflect::BaseType<S> for str {
194    const NAME: reflect::Type = "String";
195}
196
197impl<S> reflect::BaseSubTypes<S> for str {
198    const NAMES: reflect::Types = &[<Self as reflect::BaseType<S>>::NAME];
199}
200
201impl<S> GraphQLType<S> for str
202where
203    S: ScalarValue,
204{
205    fn name(_: &()) -> Option<&'static str> {
206        Some("String")
207    }
208
209    fn meta<'r>(_: &(), registry: &mut Registry<'r, S>) -> MetaType<'r, S>
210    where
211        S: 'r,
212    {
213        registry.build_scalar_type::<String>(&()).into_meta()
214    }
215}
216
217impl<S> GraphQLValue<S> for str
218where
219    S: ScalarValue,
220{
221    type Context = ();
222    type TypeInfo = ();
223
224    fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
225        <Self as GraphQLType<S>>::name(info)
226    }
227
228    fn resolve(
229        &self,
230        _: &(),
231        _: Option<&[Selection<S>]>,
232        _: &Executor<Self::Context, S>,
233    ) -> ExecutionResult<S> {
234        Ok(Value::scalar(String::from(self)))
235    }
236}
237
238impl<S> GraphQLValueAsync<S> for str
239where
240    S: ScalarValue + Send + Sync,
241{
242    fn resolve_async<'a>(
243        &'a self,
244        info: &'a Self::TypeInfo,
245        selection_set: Option<&'a [Selection<S>]>,
246        executor: &'a Executor<Self::Context, S>,
247    ) -> crate::BoxFuture<'a, crate::ExecutionResult<S>> {
248        use futures::future;
249        Box::pin(future::ready(self.resolve(info, selection_set, executor)))
250    }
251}
252
253impl<'a, S> ToInputValue<S> for &'a str
254where
255    S: ScalarValue,
256{
257    fn to_input_value(&self) -> InputValue<S> {
258        InputValue::scalar(String::from(*self))
259    }
260}
261
262#[graphql_scalar(with = impl_boolean_scalar)]
263type Boolean = bool;
264
265mod impl_boolean_scalar {
266    use super::*;
267
268    pub(super) fn to_output<S: ScalarValue>(v: &Boolean) -> Value<S> {
269        Value::scalar(*v)
270    }
271
272    pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Boolean, String> {
273        v.as_scalar_value()
274            .and_then(ScalarValue::as_bool)
275            .ok_or_else(|| format!("Expected `Boolean`, found: {v}"))
276    }
277
278    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
279        // `Boolean`s are parsed separately, they shouldn't reach this code path.
280        Err(ParseError::unexpected_token(Token::Scalar(value)))
281    }
282}
283
284#[graphql_scalar(with = impl_int_scalar)]
285type Int = i32;
286
287mod impl_int_scalar {
288    use super::*;
289
290    pub(super) fn to_output<S: ScalarValue>(v: &Int) -> Value<S> {
291        Value::scalar(*v)
292    }
293
294    pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Int, String> {
295        v.as_int_value()
296            .ok_or_else(|| format!("Expected `Int`, found: {v}"))
297    }
298
299    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
300        if let ScalarToken::Int(v) = value {
301            v.parse()
302                .map_err(|_| ParseError::unexpected_token(Token::Scalar(value)))
303                .map(|s: i32| s.into())
304        } else {
305            Err(ParseError::unexpected_token(Token::Scalar(value)))
306        }
307    }
308}
309
310#[graphql_scalar(with = impl_float_scalar)]
311type Float = f64;
312
313mod impl_float_scalar {
314    use super::*;
315
316    pub(super) fn to_output<S: ScalarValue>(v: &Float) -> Value<S> {
317        Value::scalar(*v)
318    }
319
320    pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Float, String> {
321        v.as_float_value()
322            .ok_or_else(|| format!("Expected `Float`, found: {v}"))
323    }
324
325    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
326        match value {
327            ScalarToken::Int(v) => v
328                .parse()
329                .map_err(|_| ParseError::unexpected_token(Token::Scalar(value)))
330                .map(|s: i32| f64::from(s).into()),
331            ScalarToken::Float(v) => v
332                .parse()
333                .map_err(|_| ParseError::unexpected_token(Token::Scalar(value)))
334                .map(|s: f64| s.into()),
335            ScalarToken::String(_) => Err(ParseError::unexpected_token(Token::Scalar(value))),
336        }
337    }
338}
339
340/// Utility type to define read-only schemas
341///
342/// If you instantiate `RootNode` with this as the mutation, no mutation will be
343/// generated for the schema.
344#[derive(Debug)]
345pub struct EmptyMutation<T: ?Sized = ()>(PhantomData<JoinHandle<Box<T>>>);
346
347// `EmptyMutation` doesn't use `T`, so should be `Send` and `Sync` even when `T` is not.
348crate::sa::assert_impl_all!(EmptyMutation<Rc<String>>: Send, Sync);
349
350impl<T: ?Sized> EmptyMutation<T> {
351    /// Construct a new empty mutation
352    #[inline]
353    pub fn new() -> Self {
354        Self(PhantomData)
355    }
356}
357
358impl<S, T> GraphQLType<S> for EmptyMutation<T>
359where
360    S: ScalarValue,
361{
362    fn name(_: &()) -> Option<&'static str> {
363        Some("_EmptyMutation")
364    }
365
366    fn meta<'r>(_: &(), registry: &mut Registry<'r, S>) -> MetaType<'r, S>
367    where
368        S: 'r,
369    {
370        registry.build_object_type::<Self>(&(), &[]).into_meta()
371    }
372}
373
374impl<S, T> GraphQLValue<S> for EmptyMutation<T>
375where
376    S: ScalarValue,
377{
378    type Context = T;
379    type TypeInfo = ();
380
381    fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
382        <Self as GraphQLType<S>>::name(info)
383    }
384}
385
386impl<S, T> GraphQLValueAsync<S> for EmptyMutation<T>
387where
388    Self::TypeInfo: Sync,
389    Self::Context: Sync,
390    S: ScalarValue + Send + Sync,
391{
392}
393
394// Implemented manually to omit redundant `T: Default` trait bound, imposed by
395// `#[derive(Default)]`.
396impl<T> Default for EmptyMutation<T> {
397    fn default() -> Self {
398        Self::new()
399    }
400}
401
402/// Utillity type to define read-only schemas
403///
404/// If you instantiate `RootNode` with this as the subscription,
405/// no subscriptions will be generated for the schema.
406pub struct EmptySubscription<T: ?Sized = ()>(PhantomData<JoinHandle<Box<T>>>);
407
408// `EmptySubscription` doesn't use `T`, so should be `Send` and `Sync` even when `T` is not.
409crate::sa::assert_impl_all!(EmptySubscription<Rc<String>>: Send, Sync);
410
411impl<T: ?Sized> EmptySubscription<T> {
412    /// Construct a new empty subscription
413    #[inline]
414    pub fn new() -> Self {
415        Self(PhantomData)
416    }
417}
418
419impl<S, T> GraphQLType<S> for EmptySubscription<T>
420where
421    S: ScalarValue,
422{
423    fn name(_: &()) -> Option<&'static str> {
424        Some("_EmptySubscription")
425    }
426
427    fn meta<'r>(_: &(), registry: &mut Registry<'r, S>) -> MetaType<'r, S>
428    where
429        S: 'r,
430    {
431        registry.build_object_type::<Self>(&(), &[]).into_meta()
432    }
433}
434
435impl<S, T> GraphQLValue<S> for EmptySubscription<T>
436where
437    S: ScalarValue,
438{
439    type Context = T;
440    type TypeInfo = ();
441
442    fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
443        <Self as GraphQLType<S>>::name(info)
444    }
445}
446
447impl<T, S> GraphQLSubscriptionValue<S> for EmptySubscription<T>
448where
449    Self::TypeInfo: Sync,
450    Self::Context: Sync,
451    S: ScalarValue + Send + Sync + 'static,
452{
453}
454
455// Implemented manually to omit redundant `T: Default` trait bound, imposed by
456// `#[derive(Default)]`.
457impl<T> Default for EmptySubscription<T> {
458    fn default() -> Self {
459        Self::new()
460    }
461}
462
463#[cfg(test)]
464mod tests {
465    use crate::{
466        parser::ScalarToken,
467        value::{DefaultScalarValue, ParseScalarValue},
468    };
469
470    use super::{EmptyMutation, EmptySubscription, ID};
471
472    #[test]
473    fn test_id_from_string() {
474        let actual = ID::from(String::from("foo"));
475        let expected = ID(String::from("foo"));
476        assert_eq!(actual, expected);
477    }
478
479    #[test]
480    fn test_id_new() {
481        let actual = ID::new("foo");
482        let expected = ID(String::from("foo"));
483        assert_eq!(actual, expected);
484    }
485
486    #[test]
487    fn test_id_deref() {
488        let id = ID(String::from("foo"));
489        assert_eq!(id.len(), 3);
490    }
491
492    #[test]
493    fn test_id_display() {
494        let id = ID("foo".into());
495        assert_eq!(id.to_string(), "foo");
496    }
497
498    #[test]
499    fn parse_strings() {
500        fn parse_string(s: &str, expected: &str) {
501            let s =
502                <String as ParseScalarValue<DefaultScalarValue>>::from_str(ScalarToken::String(s));
503            assert!(s.is_ok(), "A parsing error occurred: {s:?}");
504            let s: Option<String> = s.unwrap().into();
505            assert!(s.is_some(), "No string returned");
506            assert_eq!(s.unwrap(), expected);
507        }
508
509        parse_string("simple", "simple");
510        parse_string(" white space ", " white space ");
511        parse_string(r#"quote \""#, "quote \"");
512        parse_string(r"escaped \n\r\b\t\f", "escaped \n\r\u{0008}\t\u{000c}");
513        parse_string(r"slashes \\ \/", "slashes \\ /");
514        parse_string(
515            r"unicode \u1234\u5678\u90AB\uCDEF",
516            "unicode \u{1234}\u{5678}\u{90ab}\u{cdef}",
517        );
518    }
519
520    #[test]
521    fn parse_f64_from_int() {
522        for (v, expected) in [
523            ("0", 0),
524            ("128", 128),
525            ("1601942400", 1601942400),
526            ("1696550400", 1696550400),
527            ("-1", -1),
528        ] {
529            let n = <f64 as ParseScalarValue<DefaultScalarValue>>::from_str(ScalarToken::Int(v));
530            assert!(n.is_ok(), "A parsing error occurred: {:?}", n.unwrap_err());
531
532            let n: Option<f64> = n.unwrap().into();
533            assert!(n.is_some(), "No `f64` returned");
534            assert_eq!(n.unwrap(), f64::from(expected));
535        }
536    }
537
538    #[test]
539    fn parse_f64_from_float() {
540        for (v, expected) in [
541            ("0.", 0.),
542            ("1.2", 1.2),
543            ("1601942400.", 1601942400.),
544            ("1696550400.", 1696550400.),
545            ("-1.2", -1.2),
546        ] {
547            let n = <f64 as ParseScalarValue<DefaultScalarValue>>::from_str(ScalarToken::Float(v));
548            assert!(n.is_ok(), "A parsing error occurred: {:?}", n.unwrap_err());
549
550            let n: Option<f64> = n.unwrap().into();
551            assert!(n.is_some(), "No `f64` returned");
552            assert_eq!(n.unwrap(), expected);
553        }
554    }
555
556    #[test]
557    fn empty_mutation_is_send() {
558        fn check_if_send<T: Send>() {}
559        check_if_send::<EmptyMutation<()>>();
560    }
561
562    #[test]
563    fn empty_subscription_is_send() {
564        fn check_if_send<T: Send>() {}
565        check_if_send::<EmptySubscription<()>>();
566    }
567
568    #[test]
569    fn default_is_invariant_over_type() {
570        struct Bar;
571        let _ = EmptySubscription::<Bar>::default();
572        let _ = EmptyMutation::<Bar>::default();
573    }
574}