juniper/types/
nullable.rs

1use arcstr::ArcStr;
2
3use crate::{
4    ast::{FromInputValue, InputValue, Selection, ToInputValue},
5    executor::{ExecutionResult, Executor, Registry},
6    schema::meta::MetaType,
7    types::{
8        async_await::GraphQLValueAsync,
9        base::{GraphQLType, GraphQLValue},
10        marker::IsInputType,
11    },
12    value::{ScalarValue, Value},
13};
14
15/// `Nullable` can be used in situations where you need to distinguish between an implicitly and
16/// explicitly null input value.
17///
18/// The GraphQL spec states that these two field calls are similar, but are not identical:
19///
20/// ```graphql
21/// {
22///   field(arg: null)
23///   field
24/// }
25/// ```
26///
27/// The first has explicitly provided null to the argument “arg”, while the second has implicitly
28/// not provided a value to the argument “arg”. These two forms may be interpreted differently. For
29/// example, a mutation representing deleting a field vs not altering a field, respectively.
30///
31/// In cases where you do not need to be able to distinguish between the two types of null, you
32/// should simply use `Option<T>`.
33#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
34pub enum Nullable<T> {
35    /// No value
36    ImplicitNull,
37
38    /// No value, explicitly specified to be null
39    ExplicitNull,
40
41    /// Some value `T`
42    Some(T),
43}
44
45// Implemented manually to omit redundant `T: Default` trait bound, imposed by
46// `#[derive(Default)]`.
47impl<T> Default for Nullable<T> {
48    fn default() -> Self {
49        Self::ImplicitNull
50    }
51}
52
53impl<T> Nullable<T> {
54    /// Returns `true` if the nullable is a `ExplicitNull` value.
55    #[inline]
56    pub fn is_explicit_null(&self) -> bool {
57        matches!(self, Self::ExplicitNull)
58    }
59
60    /// Returns `true` if the nullable is a `ImplicitNull` value.
61    #[inline]
62    pub fn is_implicit_null(&self) -> bool {
63        matches!(self, Self::ImplicitNull)
64    }
65
66    /// Returns `true` if the nullable is a `Some` value.
67    #[inline]
68    pub fn is_some(&self) -> bool {
69        matches!(self, Self::Some(_))
70    }
71
72    /// Returns `true` if the nullable is not a `Some` value.
73    #[inline]
74    pub fn is_null(&self) -> bool {
75        !matches!(self, Self::Some(_))
76    }
77
78    /// Converts from `&mut Nullable<T>` to `Nullable<&mut T>`.
79    #[inline]
80    pub fn as_mut(&mut self) -> Nullable<&mut T> {
81        match *self {
82            Self::Some(ref mut x) => Nullable::Some(x),
83            Self::ImplicitNull => Nullable::ImplicitNull,
84            Self::ExplicitNull => Nullable::ExplicitNull,
85        }
86    }
87
88    /// Returns the contained `Some` value, consuming the `self` value.
89    ///
90    /// # Panics
91    ///
92    /// Panics if the value is not a `Some` with a custom panic message provided by `msg`.
93    #[inline]
94    #[track_caller]
95    pub fn expect(self, msg: &str) -> T {
96        self.some().expect(msg)
97    }
98
99    /// Returns the contained `Some` value or a provided default.
100    #[inline]
101    pub fn unwrap_or(self, default: T) -> T {
102        self.some().unwrap_or(default)
103    }
104
105    /// Returns the contained `Some` value or computes it from a closure.
106    #[inline]
107    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
108        self.some().unwrap_or_else(f)
109    }
110
111    /// Maps a `Nullable<T>` to `Nullable<U>` by applying a function to a contained value.
112    #[inline]
113    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
114        match self {
115            Self::Some(x) => Nullable::Some(f(x)),
116            Self::ImplicitNull => Nullable::ImplicitNull,
117            Self::ExplicitNull => Nullable::ExplicitNull,
118        }
119    }
120
121    /// Applies a function to the contained value (if any), or returns the provided default (if
122    /// not).
123    #[inline]
124    pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
125        self.some().map_or(default, f)
126    }
127
128    /// Applies a function to the contained value (if any), or computes a default (if not).
129    #[inline]
130    pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
131        self.some().map_or_else(default, f)
132    }
133
134    /// Transforms the `Nullable<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and
135    /// `ImplicitNull` or `ExplicitNull` to `Err(err)`.
136    #[inline]
137    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
138        self.some().ok_or(err)
139    }
140
141    /// Transforms the `Nullable<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and
142    /// `ImplicitNull` or `ExplicitNull` to `Err(err())`.
143    #[inline]
144    pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
145        self.some().ok_or_else(err)
146    }
147
148    /// Returns the nullable if it contains a value, otherwise returns `b`.
149    #[inline]
150    #[must_use]
151    pub fn or(self, b: Self) -> Self {
152        match self {
153            Self::Some(_) => self,
154            _ => b,
155        }
156    }
157
158    /// Returns the nullable if it contains a value, otherwise calls `f` and
159    /// returns the result.
160    #[inline]
161    #[must_use]
162    pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
163        match self {
164            Self::Some(_) => self,
165            _ => f(),
166        }
167    }
168
169    /// Replaces the actual value in the nullable by the value given in parameter, returning the
170    /// old value if present, leaving a `Some` in its place without deinitializing either one.
171    #[inline]
172    #[must_use]
173    pub fn replace(&mut self, value: T) -> Self {
174        std::mem::replace(self, Self::Some(value))
175    }
176
177    /// Converts from `Nullable<T>` to `Option<T>`.
178    pub fn some(self) -> Option<T> {
179        match self {
180            Self::Some(v) => Some(v),
181            _ => None,
182        }
183    }
184
185    /// Converts from `Nullable<T>` to `Option<Option<T>>`, mapping `Some(v)` to `Some(Some(v))`,
186    /// `ExplicitNull` to `Some(None)`, and `ImplicitNull` to `None`.
187    pub fn explicit(self) -> Option<Option<T>> {
188        match self {
189            Self::Some(v) => Some(Some(v)),
190            Self::ExplicitNull => Some(None),
191            Self::ImplicitNull => None,
192        }
193    }
194}
195
196impl<T: Copy> Nullable<&T> {
197    /// Maps a `Nullable<&T>` to a `Nullable<T>` by copying the contents of the nullable.
198    pub fn copied(self) -> Nullable<T> {
199        self.map(|&t| t)
200    }
201}
202
203impl<T: Copy> Nullable<&mut T> {
204    /// Maps a `Nullable<&mut T>` to a `Nullable<T>` by copying the contents of the nullable.
205    pub fn copied(self) -> Nullable<T> {
206        self.map(|&mut t| t)
207    }
208}
209
210impl<T: Clone> Nullable<&T> {
211    /// Maps a `Nullable<&T>` to a `Nullable<T>` by cloning the contents of the nullable.
212    pub fn cloned(self) -> Nullable<T> {
213        self.map(|t| t.clone())
214    }
215}
216
217impl<T: Clone> Nullable<&mut T> {
218    /// Maps a `Nullable<&mut T>` to a `Nullable<T>` by cloning the contents of the nullable.
219    pub fn cloned(self) -> Nullable<T> {
220        self.map(|t| t.clone())
221    }
222}
223
224impl<S, T> GraphQLType<S> for Nullable<T>
225where
226    T: GraphQLType<S>,
227    S: ScalarValue,
228{
229    fn name(_: &Self::TypeInfo) -> Option<ArcStr> {
230        None
231    }
232
233    fn meta(info: &Self::TypeInfo, registry: &mut Registry<S>) -> MetaType<S> {
234        registry.build_nullable_type::<T>(info).into_meta()
235    }
236}
237
238impl<S, T> GraphQLValue<S> for Nullable<T>
239where
240    S: ScalarValue,
241    T: GraphQLValue<S>,
242{
243    type Context = T::Context;
244    type TypeInfo = T::TypeInfo;
245
246    fn type_name(&self, _: &Self::TypeInfo) -> Option<ArcStr> {
247        None
248    }
249
250    fn resolve(
251        &self,
252        info: &Self::TypeInfo,
253        _: Option<&[Selection<S>]>,
254        executor: &Executor<Self::Context, S>,
255    ) -> ExecutionResult<S> {
256        match *self {
257            Self::Some(ref obj) => executor.resolve(info, obj),
258            _ => Ok(Value::null()),
259        }
260    }
261}
262
263impl<S, T> GraphQLValueAsync<S> for Nullable<T>
264where
265    T: GraphQLValueAsync<S>,
266    T::TypeInfo: Sync,
267    T::Context: Sync,
268    S: ScalarValue + Send + Sync,
269{
270    fn resolve_async<'a>(
271        &'a self,
272        info: &'a Self::TypeInfo,
273        _: Option<&'a [Selection<S>]>,
274        executor: &'a Executor<Self::Context, S>,
275    ) -> crate::BoxFuture<'a, ExecutionResult<S>> {
276        let f = async move {
277            let value = match self {
278                Self::Some(obj) => executor.resolve_into_value_async(info, obj).await,
279                _ => Value::null(),
280            };
281            Ok(value)
282        };
283        Box::pin(f)
284    }
285}
286
287impl<S, T: FromInputValue<S>> FromInputValue<S> for Nullable<T> {
288    type Error = <T as FromInputValue<S>>::Error;
289
290    fn from_input_value(v: &InputValue<S>) -> Result<Self, Self::Error> {
291        match v {
292            &InputValue::Null => Ok(Self::ExplicitNull),
293            v => v.convert().map(Self::Some),
294        }
295    }
296
297    fn from_implicit_null() -> Result<Self, Self::Error> {
298        Ok(Self::ImplicitNull)
299    }
300}
301
302impl<S, T> ToInputValue<S> for Nullable<T>
303where
304    T: ToInputValue<S>,
305{
306    fn to_input_value(&self) -> InputValue<S> {
307        match self {
308            Self::Some(v) => v.to_input_value(),
309            _ => InputValue::null(),
310        }
311    }
312}
313
314impl<S, T> IsInputType<S> for Nullable<T>
315where
316    T: IsInputType<S>,
317    S: ScalarValue,
318{
319}