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
use crate::executable::{ExecutableDocument, SelectionSet, VariableDefinitions};
use crate::{OperationType, VariableDirectives};

#[derive(Debug)]
pub enum OperationDefinition<
    E: ExplicitOperationDefinition,
    I: ImplicitOperationDefinition<SelectionSet = E::SelectionSet>,
> {
    Explicit(E),
    Implicit(I),
}

impl<
        E: ExplicitOperationDefinition,
        I: ImplicitOperationDefinition<SelectionSet = E::SelectionSet>,
    > OperationDefinition<E, I>
{
    pub fn operation_type(&self) -> OperationType {
        match self {
            Self::Explicit(eod) => eod.operation_type(),
            Self::Implicit(_) => OperationType::Query,
        }
    }

    pub fn name(&self) -> Option<&str> {
        match self {
            Self::Explicit(eod) => eod.name(),
            Self::Implicit(_) => None,
        }
    }

    pub fn variable_definitions(&self) -> Option<&E::VariableDefinitions> {
        match self {
            Self::Explicit(eod) => eod.variable_definitions(),
            Self::Implicit(_) => None,
        }
    }

    pub fn selection_set(&self) -> &E::SelectionSet {
        match self {
            Self::Explicit(eod) => eod.selection_set(),
            Self::Implicit(iod) => iod.selection_set(),
        }
    }
}

pub trait AbstractOperationDefinition: Into<OperationDefinition<Self::ExplicitOperationDefinition, Self::ImplicitOperationDefinition>>
    + AsRef<OperationDefinition<Self::ExplicitOperationDefinition, Self::ImplicitOperationDefinition>>
{
    type ExplicitOperationDefinition: ExplicitOperationDefinition;
    type ImplicitOperationDefinition: ImplicitOperationDefinition<SelectionSet=<Self::ExplicitOperationDefinition as ExplicitOperationDefinition>::SelectionSet>;
}

impl<
        E: ExplicitOperationDefinition,
        I: ImplicitOperationDefinition<SelectionSet = E::SelectionSet>,
    > AsRef<OperationDefinition<E, I>> for OperationDefinition<E, I>
{
    fn as_ref(&self) -> &OperationDefinition<E, I> {
        self
    }
}

impl<
        E: ExplicitOperationDefinition,
        I: ImplicitOperationDefinition<SelectionSet = E::SelectionSet>,
    > AbstractOperationDefinition for OperationDefinition<E, I>
{
    type ExplicitOperationDefinition = E;
    type ImplicitOperationDefinition = I;
}

pub type OperationDefinitionFromExecutableDocument<E> = OperationDefinition<
    <E as ExecutableDocument>::ExplicitOperationDefinition,
    <E as ExecutableDocument>::ImplicitOperationDefinition,
>;

pub trait ExplicitOperationDefinition: Sized {
    type VariableDefinitions: VariableDefinitions;
    type Directives: VariableDirectives;
    type SelectionSet: SelectionSet;

    fn operation_type(&self) -> OperationType;
    fn name(&self) -> Option<&str>;
    fn variable_definitions(&self) -> Option<&Self::VariableDefinitions>;
    fn directives(&self) -> &Self::Directives;
    fn selection_set(&self) -> &Self::SelectionSet;
}

pub trait ImplicitOperationDefinition: Sized {
    type SelectionSet: SelectionSet;

    fn selection_set(&self) -> &Self::SelectionSet;
}