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
use crate::executable::{SelectionSet, VariableDefinitions};
use crate::{OperationType, VariableDirectives};
use std::cmp::{Eq, Ord};
use std::hash::Hash;

#[derive(Debug)]
pub enum OperationDefinitionReference<'a, O: OperationDefinition> {
    Explicit(&'a O::ExplicitOperationDefinition),
    Implicit(&'a O::ImplicitOperationDefinition),
}

impl<'a, O: OperationDefinition> OperationDefinitionReference<'a, O> {
    pub fn operation_type(&self) -> OperationType {
        match self {
            Self::Explicit(eod) => eod.operation_type(),
            Self::Implicit(_) => OperationType::Query,
        }
    }

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

    pub fn variable_definitions(&self) -> Option<&'a <<O as OperationDefinition>::ExplicitOperationDefinition as ExplicitOperationDefinition>::VariableDefinitions>{
        match self {
            Self::Explicit(eod) => eod.variable_definitions(),
            Self::Implicit(_) => None,
        }
    }

    pub fn selection_set(&self) -> &'a <<O as OperationDefinition>::ExplicitOperationDefinition as ExplicitOperationDefinition>::SelectionSet{
        match self {
            Self::Explicit(eod) => eod.selection_set(),
            Self::Implicit(iod) => iod.selection_set(),
        }
    }

    pub fn directives(&self) -> Option<&'a <<O as OperationDefinition>::ExplicitOperationDefinition as ExplicitOperationDefinition>::Directives>{
        match self {
            Self::Explicit(eod) => Some(eod.directives()),
            Self::Implicit(_) => None,
        }
    }
}

pub trait OperationDefinition: Eq + Hash + Ord + Sized {
    type ExplicitOperationDefinition: ExplicitOperationDefinition;
    type ImplicitOperationDefinition: ImplicitOperationDefinition<SelectionSet=<Self::ExplicitOperationDefinition as ExplicitOperationDefinition>::SelectionSet>;

    fn as_ref(&self) -> OperationDefinitionReference<'_, Self>;
}

pub trait ExplicitOperationDefinition {
    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 {
    type SelectionSet: SelectionSet;

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