1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use arbitrary::{Arbitrary, Result};

use crate::{
    directive::Directive, name::Name, selection_set::SelectionSet, variable::VariableDef,
    DocumentBuilder,
};

/// The __operationDef type represents an operation definition
///
/// *OperationDefinition*:
///     OperationType Name? VariableDefinitions? Directives? SelectionSet
///
/// Detailed documentation can be found in [GraphQL spec](https://spec.graphql.org/October2021/#sec-Language.Operations).
#[derive(Debug)]
pub struct OperationDef {
    pub(crate) operation_type: OperationType,
    pub(crate) name: Option<Name>,
    pub(crate) variable_definitions: Vec<VariableDef>,
    pub(crate) directives: Vec<Directive>,
    pub(crate) selection_set: SelectionSet,
    pub(crate) shorthand: bool,
}

impl From<OperationDef> for apollo_encoder::OperationDefinition {
    fn from(op_def: OperationDef) -> Self {
        let mut new_op_def = Self::new(op_def.operation_type.into(), op_def.selection_set.into());
        new_op_def.name(op_def.name.map(String::from));
        op_def
            .variable_definitions
            .into_iter()
            .for_each(|var_def| new_op_def.variable_definition(var_def.into()));
        op_def.shorthand.then(|| new_op_def.shorthand());
        op_def
            .directives
            .into_iter()
            .for_each(|directive| new_op_def.directive(directive.into()));

        new_op_def
    }
}

/// The __operationType type represents the kind of operation
///
/// *OperationType*:
///     query | mutation | subscription
///
/// Detailed documentation can be found in [GraphQL spec](https://spec.graphql.org/October2021/#OperationType).
#[derive(Debug, Arbitrary)]
pub enum OperationType {
    Query,
    Mutation,
    Subscription,
}

impl From<OperationType> for apollo_encoder::OperationType {
    fn from(op_type: OperationType) -> Self {
        match op_type {
            OperationType::Query => Self::Query,
            OperationType::Mutation => Self::Mutation,
            OperationType::Subscription => Self::Subscription,
        }
    }
}

impl<'a> DocumentBuilder<'a> {
    /// Create an arbitrary `OperationDef`
    pub fn operation_definition(&mut self) -> Result<OperationDef> {
        let name = self
            .u
            .arbitrary()
            .unwrap_or(false)
            .then(|| self.type_name())
            .transpose()?;
        let operation_type = self.u.arbitrary()?;
        let directives = self.directives()?;
        let selection_set = self.selection_set()?;
        let variable_definitions = self.variable_definitions()?;
        let shorthand = self.operation_defs.is_empty() && self.u.arbitrary().unwrap_or(false);

        Ok(OperationDef {
            operation_type,
            name,
            variable_definitions,
            directives,
            selection_set,
            shorthand,
        })
    }
}