graphql_federated_graph/federated_graph/
directive_definitions.rs

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use super::*;

pub type DirectiveDefinition<'a> = super::view::ViewNested<'a, DirectiveDefinitionId, DirectiveDefinitionRecord>;

#[derive(Debug, Clone)]
pub struct DirectiveDefinitionRecord {
    pub namespace: Option<StringId>,
    pub name: StringId,
    pub locations: DirectiveLocations,
    pub repeatable: bool,
}

#[derive(Debug, Clone)]
pub struct DirectiveDefinitionArgument {
    pub directive_definition_id: DirectiveDefinitionId,
    pub input_value_definition: InputValueDefinition,
}

impl FederatedGraph {
    pub fn iter_directive_definitions(&self) -> impl ExactSizeIterator<Item = DirectiveDefinition<'_>> {
        self.directive_definitions
            .iter()
            .enumerate()
            .map(move |(idx, record)| DirectiveDefinition {
                graph: self,
                view: View { id: idx.into(), record },
            })
    }

    pub fn push_directive_definition_argument(
        &mut self,
        directive_definition_id: DirectiveDefinitionId,
        argument: InputValueDefinition,
    ) {
        self.directive_definition_arguments.push(DirectiveDefinitionArgument {
            directive_definition_id,
            input_value_definition: argument,
        })
    }

    pub fn push_directive_definition(
        &mut self,
        directive_definitons: DirectiveDefinitionRecord,
    ) -> DirectiveDefinitionId {
        let id = self.directive_definitions.len().into();
        self.directive_definitions.push(directive_definitons);
        id
    }
}

bitflags::bitflags! {
    /// https://spec.graphql.org/October2021/#sec-The-__Directive-Type
    #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
    pub struct DirectiveLocations: u32 {
        const QUERY = 0b1 << 0;
        const MUTATION = 0b1 << 1;
        const SUBSCRIPTION = 0b1 << 2;
        const FIELD = 0b1 << 3;
        const FRAGMENT_DEFINITION = 0b1 << 4;
        const FRAGMENT_SPREAD = 0b1 << 5;
        const INLINE_FRAGMENT = 0b1 << 6;
        const VARIABLE_DEFINITION = 0b1 << 7;
        const SCHEMA = 0b1 << 8;
        const SCALAR = 0b1 << 9;
        const OBJECT = 0b1 << 10;
        const FIELD_DEFINITION = 0b1 << 11;
        const ARGUMENT_DEFINITION = 0b1 << 12;
        const INTERFACE = 0b1 << 13;
        const UNION = 0b1 << 14;
        const ENUM = 0b1 << 15;
        const ENUM_VALUE = 0b1 << 16;
        const INPUT_OBJECT = 0b1 << 17;
        const INPUT_FIELD_DEFINITION = 0b1 << 18;
    }
}

impl fmt::Display for DirectiveLocations {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut locations = self.iter().peekable();

        while let Some(location) = locations.next() {
            let name = match location {
                DirectiveLocations::QUERY => "QUERY",
                DirectiveLocations::MUTATION => "MUTATION",
                DirectiveLocations::SUBSCRIPTION => "SUBSCRIPTION",
                DirectiveLocations::FIELD => "FIELD",
                DirectiveLocations::FRAGMENT_DEFINITION => "FRAGMENT_DEFINITION",
                DirectiveLocations::FRAGMENT_SPREAD => "FRAGMENT_SPREAD",
                DirectiveLocations::INLINE_FRAGMENT => "INLINE_FRAGMENT",
                DirectiveLocations::VARIABLE_DEFINITION => "VARIABLE_DEFINITION",
                DirectiveLocations::SCHEMA => "SCHEMA",
                DirectiveLocations::SCALAR => "SCALAR",
                DirectiveLocations::OBJECT => "OBJECT",
                DirectiveLocations::FIELD_DEFINITION => "FIELD_DEFINITION",
                DirectiveLocations::ARGUMENT_DEFINITION => "ARGUMENT_DEFINITION",
                DirectiveLocations::INTERFACE => "INTERFACE",
                DirectiveLocations::UNION => "UNION",
                DirectiveLocations::ENUM => "ENUM",
                DirectiveLocations::ENUM_VALUE => "ENUM_VALUE",
                DirectiveLocations::INPUT_OBJECT => "INPUT_OBJECT",
                DirectiveLocations::INPUT_FIELD_DEFINITION => "INPUT_FIELD_DEFINITION",
                _ => unreachable!(),
            };

            f.write_str(name)?;

            if locations.peek().is_some() {
                f.write_str(" | ")?;
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn directive_definitions_display() {
        let all = DirectiveLocations::all().to_string();

        let expected = "QUERY | MUTATION | SUBSCRIPTION | FIELD | FRAGMENT_DEFINITION | FRAGMENT_SPREAD | INLINE_FRAGMENT | VARIABLE_DEFINITION | SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION";

        assert_eq!(all, expected);
    }
}