cynic/
core.rs

1use std::borrow::Cow;
2
3use crate::{queries::SelectionBuilder, QueryVariablesFields};
4
5/// A trait that marks a type as part of a GraphQL query.
6///
7/// This will usually be derived, but can be manually implemented if required.
8pub trait QueryFragment: Sized {
9    /// The type in a schema that this `QueryFragment` represents
10    type SchemaType;
11
12    /// The variables that are required to execute this `QueryFragment`
13    type VariablesFields: QueryVariablesFields;
14
15    /// The name of the type in the GraphQL schema
16    const TYPE: Option<&'static str> = None;
17
18    /// Adds this fragment to the query being built by `builder`
19    fn query(builder: SelectionBuilder<'_, Self::SchemaType, Self::VariablesFields>);
20
21    /// The name of this fragment, useful for operations, maybe fragments if we ever support them...
22    fn name() -> Option<Cow<'static, str>> {
23        // Most QueryFragments don't need a name so return None
24        None
25    }
26}
27
28impl<T> QueryFragment for Option<T>
29where
30    T: QueryFragment,
31{
32    type SchemaType = Option<T::SchemaType>;
33    type VariablesFields = T::VariablesFields;
34
35    fn query(builder: SelectionBuilder<'_, Self::SchemaType, Self::VariablesFields>) {
36        T::query(builder.into_inner())
37    }
38}
39
40impl<T> QueryFragment for Vec<T>
41where
42    T: QueryFragment,
43{
44    type SchemaType = Vec<T::SchemaType>;
45    type VariablesFields = T::VariablesFields;
46
47    fn query(builder: SelectionBuilder<'_, Self::SchemaType, Self::VariablesFields>) {
48        T::query(builder.into_inner())
49    }
50}
51
52impl<T> QueryFragment for Box<T>
53where
54    T: QueryFragment,
55{
56    type SchemaType = T::SchemaType;
57    type VariablesFields = T::VariablesFields;
58
59    const TYPE: Option<&'static str> = T::TYPE;
60
61    fn query(builder: SelectionBuilder<'_, Self::SchemaType, Self::VariablesFields>) {
62        T::query(builder)
63    }
64}
65
66impl<T> QueryFragment for std::rc::Rc<T>
67where
68    T: QueryFragment,
69{
70    type SchemaType = T::SchemaType;
71    type VariablesFields = T::VariablesFields;
72
73    const TYPE: Option<&'static str> = T::TYPE;
74
75    fn query(builder: SelectionBuilder<'_, Self::SchemaType, Self::VariablesFields>) {
76        T::query(builder)
77    }
78}
79
80impl<T> QueryFragment for std::sync::Arc<T>
81where
82    T: QueryFragment,
83{
84    type SchemaType = T::SchemaType;
85    type VariablesFields = T::VariablesFields;
86
87    const TYPE: Option<&'static str> = T::TYPE;
88
89    fn query(builder: SelectionBuilder<'_, Self::SchemaType, Self::VariablesFields>) {
90        T::query(builder)
91    }
92}
93
94impl QueryFragment for bool {
95    type SchemaType = bool;
96    type VariablesFields = ();
97
98    fn query(_builder: SelectionBuilder<'_, Self::SchemaType, Self::VariablesFields>) {}
99}
100
101impl QueryFragment for String {
102    type SchemaType = String;
103    type VariablesFields = ();
104
105    fn query(_builder: SelectionBuilder<'_, Self::SchemaType, Self::VariablesFields>) {}
106}
107
108/// A QueryFragment that contains a set of inline fragments
109///
110/// This should be derived on an enum with newtype variants where each
111/// inner type is a `QueryFragment` for an appropriate type.
112pub trait InlineFragments<'de>: QueryFragment + serde::de::Deserialize<'de> {
113    /// Attempts to deserialize a variant with the given typename.
114    fn deserialize_variant<D>(typename: &str, deserializer: D) -> Result<Self, D::Error>
115    where
116        D: serde::Deserializer<'de>;
117}
118
119/// A GraphQL Enum.
120///
121/// Note that in GraphQL these can't contain data - they are just a set of
122/// strings.
123///
124/// This should be be derived on an enum with unit variants.
125pub trait Enum: serde::de::DeserializeOwned + serde::Serialize {
126    /// The enum in the schema that this type represents.
127    type SchemaType;
128}
129
130impl<T> Enum for Option<T>
131where
132    T: Enum,
133{
134    type SchemaType = Option<T::SchemaType>;
135}
136
137impl<T> Enum for Vec<T>
138where
139    T: Enum,
140{
141    type SchemaType = Vec<T::SchemaType>;
142}
143
144impl<T> Enum for Box<T>
145where
146    T: Enum,
147{
148    type SchemaType = T::SchemaType;
149}
150
151/// A GraphQL input object.
152///
153/// This should be derived on a struct.
154pub trait InputObject: serde::Serialize {
155    /// The input object in the schema that this type represents.
156    type SchemaType;
157}
158
159impl<T> InputObject for Option<T>
160where
161    T: InputObject,
162{
163    type SchemaType = Option<T::SchemaType>;
164}
165
166impl<T> InputObject for Vec<T>
167where
168    T: InputObject,
169{
170    type SchemaType = Vec<T::SchemaType>;
171}
172
173impl<T> InputObject for [T]
174where
175    T: InputObject,
176{
177    type SchemaType = Vec<T::SchemaType>;
178}
179
180impl<T, const SIZE: usize> InputObject for [T; SIZE]
181where
182    T: InputObject,
183    Self: serde::Serialize,
184{
185    type SchemaType = Vec<T::SchemaType>;
186}
187
188impl<T> InputObject for Box<T>
189where
190    T: InputObject,
191{
192    type SchemaType = T::SchemaType;
193}
194
195impl<T: ?Sized> InputObject for &T
196where
197    T: InputObject,
198{
199    type SchemaType = T::SchemaType;
200}