async_graphql/validation/rules/
default_values_of_correct_type.rs

1use async_graphql_parser::types::BaseType;
2
3use crate::{
4    Positioned, QueryPathSegment,
5    context::QueryPathNode,
6    parser::types::VariableDefinition,
7    validation::{
8        utils::is_valid_input_value,
9        visitor::{Visitor, VisitorContext},
10    },
11};
12
13pub struct DefaultValuesOfCorrectType;
14
15impl<'a> Visitor<'a> for DefaultValuesOfCorrectType {
16    fn enter_variable_definition(
17        &mut self,
18        ctx: &mut VisitorContext<'a>,
19        variable_definition: &'a Positioned<VariableDefinition>,
20    ) {
21        if let BaseType::Named(vtype_name) = &variable_definition.node.var_type.node.base
22            && !ctx.registry.types.contains_key(vtype_name.as_str())
23        {
24            ctx.report_error(
25                vec![variable_definition.pos],
26                format!(r#"Unknown type "{}""#, vtype_name),
27            );
28            return;
29        }
30
31        if let Some(value) = &variable_definition.node.default_value
32            && let Some(reason) = is_valid_input_value(
33                ctx.registry,
34                &variable_definition.node.var_type.to_string(),
35                &value.node,
36                QueryPathNode {
37                    parent: None,
38                    segment: QueryPathSegment::Name(&variable_definition.node.name.node),
39                },
40            )
41        {
42            ctx.report_error(
43                vec![variable_definition.pos],
44                format!("Invalid default value for argument: {}", reason),
45            )
46        }
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    pub fn factory() -> DefaultValuesOfCorrectType {
55        DefaultValuesOfCorrectType
56    }
57
58    #[test]
59    fn variables_with_no_default_values() {
60        expect_passes_rule!(
61            factory,
62            r#"
63          query NullableValues($a: Int, $b: String, $c: ComplexInput) {
64            dog { name }
65          }
66        "#,
67        );
68    }
69
70    #[test]
71    fn required_variables_without_default_values() {
72        expect_passes_rule!(
73            factory,
74            r#"
75          query RequiredValues($a: Int!, $b: String!) {
76            dog { name }
77          }
78        "#,
79        );
80    }
81
82    #[test]
83    fn variables_with_valid_default_values() {
84        expect_passes_rule!(
85            factory,
86            r#"
87          query WithDefaultValues(
88            $a: Int = 1,
89            $b: String = "ok",
90            $c: ComplexInput = { requiredField: true, intField: 3 }
91          ) {
92            dog { name }
93          }
94        "#,
95        );
96    }
97
98    #[test]
99    fn required_variables_with_default_values() {
100        expect_passes_rule!(
101            factory,
102            r#"
103          query UnreachableDefaultValues($a: Int! = 3, $b: String! = "default") {
104            dog { name }
105          }
106        "#,
107        );
108    }
109
110    #[test]
111    fn variables_with_invalid_default_values() {
112        expect_fails_rule!(
113            factory,
114            r#"
115          query InvalidDefaultValues(
116            $a: Int = "one",
117            $b: String = 4,
118            $c: ComplexInput = "notverycomplex"
119          ) {
120            dog { name }
121          }
122        "#,
123        );
124    }
125
126    #[test]
127    fn complex_variables_missing_required_field() {
128        expect_fails_rule!(
129            factory,
130            r#"
131          query MissingRequiredField($a: ComplexInput = {intField: 3}) {
132            dog { name }
133          }
134        "#,
135        );
136    }
137
138    #[test]
139    fn list_variables_with_invalid_item() {
140        expect_fails_rule!(
141            factory,
142            r#"
143          query InvalidItem($a: [String] = ["one", 2]) {
144            dog { name }
145          }
146        "#,
147        );
148    }
149}