apollo_encoder/
schema_def.rs

1use std::fmt;
2
3use crate::{Directive, StringValue};
4
5/// A GraphQL service’s collective type system capabilities are referred to as
6/// that service’s “schema”.
7///
8/// *SchemaDefinition*:
9///     Description? **schema** Directives? **{** RootOperationTypeDefinition* **}**
10///
11/// Detailed documentation can be found in [GraphQL spec](https://spec.graphql.org/October2021/#sec-Schema).
12///
13/// ### Example
14/// ```rust
15/// use apollo_encoder::{SchemaDefinition};
16/// use indoc::indoc;
17///
18/// let mut schema_def = SchemaDefinition::new();
19/// schema_def.query("TryingToFindCatQuery".to_string());
20/// schema_def.mutation("MyMutation".to_string());
21/// schema_def.subscription("MySubscription".to_string());
22///
23/// assert_eq!(
24///    schema_def.to_string(),
25///    indoc! { r#"
26///        schema {
27///          query: TryingToFindCatQuery
28///          mutation: MyMutation
29///          subscription: MySubscription
30///        }
31///    "#}
32/// );
33/// ```
34
35#[derive(Debug, Clone)]
36pub struct SchemaDefinition {
37    // Description may be a String.
38    description: Option<StringValue>,
39    // The vector of fields in a schema to represent root operation type
40    // definition.
41    query: Option<String>,
42    mutation: Option<String>,
43    subscription: Option<String>,
44    directives: Vec<Directive>,
45    // Extend a schema
46    extend: bool,
47}
48
49impl SchemaDefinition {
50    /// Create a new instance of SchemaDef.
51    pub fn new() -> Self {
52        Self {
53            description: None,
54            query: None,
55            mutation: None,
56            subscription: None,
57            directives: Vec::new(),
58            extend: false,
59        }
60    }
61
62    /// Set the SchemaDef's description.
63    pub fn description(&mut self, description: String) {
64        self.description = Some(StringValue::Top {
65            source: description,
66        });
67    }
68
69    /// Add a directive.
70    pub fn directive(&mut self, directive: Directive) {
71        self.directives.push(directive);
72    }
73
74    /// Set as an extension
75    pub fn extend(&mut self) {
76        self.extend = true;
77    }
78
79    /// Set the schema def's query type.
80    pub fn query(&mut self, query: String) {
81        self.query = Some(query);
82    }
83
84    /// Set the schema def's mutation type.
85    pub fn mutation(&mut self, mutation: String) {
86        self.mutation = Some(mutation);
87    }
88
89    /// Set the schema def's subscription type.
90    pub fn subscription(&mut self, subscription: String) {
91        self.subscription = Some(subscription);
92    }
93}
94
95impl Default for SchemaDefinition {
96    fn default() -> Self {
97        Self::new()
98    }
99}
100
101impl fmt::Display for SchemaDefinition {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        if self.extend {
104            write!(f, "extend ")?;
105        // No description when it's an extension schema
106        } else if let Some(description) = &self.description {
107            writeln!(f, "{description}")?;
108        }
109
110        write!(f, "schema")?;
111
112        for directive in &self.directives {
113            write!(f, " {directive}")?;
114        }
115
116        if self.query.is_some() || self.mutation.is_some() || self.subscription.is_some() {
117            writeln!(f, " {{")?;
118
119            if let Some(query) = &self.query {
120                writeln!(f, "  query: {query}")?;
121            }
122
123            if let Some(mutation) = &self.mutation {
124                writeln!(f, "  mutation: {mutation}")?;
125            }
126
127            if let Some(subscription) = &self.subscription {
128                writeln!(f, "  subscription: {subscription}")?;
129            }
130
131            writeln!(f, "}}")
132        } else {
133            writeln!(f)
134        }
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141    use indoc::indoc;
142    use pretty_assertions::assert_eq;
143
144    #[test]
145    fn it_encodes_schema_with_mutation_and_subscription() {
146        let mut schema_def = SchemaDefinition::new();
147        schema_def.query("TryingToFindCatQuery".to_string());
148        schema_def.mutation("MyMutation".to_string());
149        schema_def.subscription("MySubscription".to_string());
150
151        assert_eq!(
152            schema_def.to_string(),
153            indoc! { r#"
154            schema {
155              query: TryingToFindCatQuery
156              mutation: MyMutation
157              subscription: MySubscription
158            }
159        "#}
160        );
161    }
162
163    #[test]
164    fn it_encodes_extend_schema_with_mutation_and_subscription() {
165        let mut schema_def = SchemaDefinition::new();
166        schema_def.query("TryingToFindCatQuery".to_string());
167        schema_def.mutation("MyMutation".to_string());
168        schema_def.subscription("MySubscription".to_string());
169        schema_def.extend();
170
171        assert_eq!(
172            schema_def.to_string(),
173            indoc! { r#"
174            extend schema {
175              query: TryingToFindCatQuery
176              mutation: MyMutation
177              subscription: MySubscription
178            }
179        "#}
180        );
181    }
182
183    #[test]
184    fn it_encodes_extend_schema_with_directives_only() {
185        let mut schema_def = SchemaDefinition::new();
186        schema_def.directive(Directive::new("foo".to_string()));
187        schema_def.extend();
188
189        assert_eq!(
190            schema_def.to_string(),
191            indoc! { r#"
192            extend schema @foo
193        "#}
194        )
195    }
196}