Skip to main content

juniper/types/
scalars.rs

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