graphgate_planner/
plan.rs

1use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
2use std::ops::{Deref, DerefMut};
3
4use indexmap::IndexMap;
5use serde::{Serialize, Serializer};
6use value::{ConstValue, Name, Variables};
7
8use crate::types::{FetchQuery, VariablesRef};
9use crate::Request;
10
11#[derive(Debug, Serialize)]
12#[serde(tag = "type", rename_all = "lowercase")]
13pub enum PlanNode<'a> {
14    Sequence(SequenceNode<'a>),
15    Parallel(ParallelNode<'a>),
16    Introspection(IntrospectionNode),
17    Fetch(FetchNode<'a>),
18    Flatten(FlattenNode<'a>),
19}
20
21impl<'a> PlanNode<'a> {
22    pub(crate) fn flatten(self) -> Self {
23        match self {
24            PlanNode::Sequence(mut node) if node.nodes.len() == 1 => node.nodes.remove(0),
25            PlanNode::Parallel(mut node) if node.nodes.len() == 1 => node.nodes.remove(0),
26            _ => self,
27        }
28    }
29}
30
31#[derive(Debug, Clone, Hash, Eq, PartialEq)]
32pub struct PathSegment<'a> {
33    pub name: &'a str,
34    pub is_list: bool,
35    pub possible_type: Option<&'a str>,
36}
37
38#[derive(Clone, Default, Hash, Eq, PartialEq)]
39pub struct ResponsePath<'a>(Vec<PathSegment<'a>>);
40
41impl<'a> Debug for ResponsePath<'a> {
42    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
43        for (idx, segment) in self.0.iter().enumerate() {
44            if idx > 0 {
45                write!(f, ".")?;
46            }
47            if segment.is_list {
48                write!(f, "[{}]", segment.name)?;
49            } else {
50                write!(f, "{}", segment.name)?;
51            }
52            if let Some(possible_type) = segment.possible_type {
53                write!(f, "({})", possible_type)?;
54            }
55        }
56        Ok(())
57    }
58}
59
60impl<'a> Display for ResponsePath<'a> {
61    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
62        Debug::fmt(self, f)
63    }
64}
65
66impl<'a> Serialize for ResponsePath<'a> {
67    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68    where
69        S: Serializer,
70    {
71        serializer.serialize_str(&self.to_string())
72    }
73}
74
75impl<'a> Deref for ResponsePath<'a> {
76    type Target = Vec<PathSegment<'a>>;
77
78    fn deref(&self) -> &Self::Target {
79        &self.0
80    }
81}
82
83impl<'a> DerefMut for ResponsePath<'a> {
84    fn deref_mut(&mut self) -> &mut Self::Target {
85        &mut self.0
86    }
87}
88
89#[derive(Default, Debug, Serialize)]
90pub struct SequenceNode<'a> {
91    pub nodes: Vec<PlanNode<'a>>,
92}
93
94#[derive(Default, Debug, Serialize)]
95pub struct ParallelNode<'a> {
96    pub nodes: Vec<PlanNode<'a>>,
97}
98
99#[derive(Debug, Serialize)]
100pub struct IntrospectionDirective {
101    pub name: Name,
102
103    #[serde(skip_serializing_if = "IndexMap::is_empty")]
104    pub arguments: IndexMap<Name, ConstValue>,
105}
106
107#[derive(Debug, Serialize)]
108pub struct IntrospectionField {
109    pub name: Name,
110
111    #[serde(skip_serializing_if = "Option::is_none")]
112    pub alias: Option<Name>,
113
114    #[serde(skip_serializing_if = "IndexMap::is_empty")]
115    pub arguments: IndexMap<Name, ConstValue>,
116
117    #[serde(skip_serializing_if = "Vec::is_empty")]
118    pub directives: Vec<IntrospectionDirective>,
119
120    pub selection_set: IntrospectionSelectionSet,
121}
122
123#[derive(Debug, Default, Serialize)]
124#[serde(transparent)]
125pub struct IntrospectionSelectionSet(pub Vec<IntrospectionField>);
126
127#[derive(Debug, Serialize)]
128#[serde(transparent)]
129pub struct IntrospectionNode {
130    pub selection_set: IntrospectionSelectionSet,
131}
132
133#[derive(Debug, Serialize)]
134#[serde(rename_all = "camelCase")]
135pub struct FetchNode<'a> {
136    pub service: &'a str,
137    #[serde(skip_serializing_if = "VariablesRef::is_empty")]
138    pub variables: VariablesRef<'a>,
139    pub query: FetchQuery<'a>,
140}
141
142impl<'a> FetchNode<'a> {
143    pub fn to_request(&self) -> Request {
144        Request::new(self.query.to_string()).variables(self.variables.to_variables())
145    }
146}
147
148#[derive(Debug, Serialize)]
149#[serde(rename_all = "camelCase")]
150pub struct FlattenNode<'a> {
151    pub path: ResponsePath<'a>,
152    pub prefix: usize,
153    pub service: &'a str,
154    #[serde(skip_serializing_if = "VariablesRef::is_empty")]
155    pub variables: VariablesRef<'a>,
156    pub query: FetchQuery<'a>,
157}
158
159impl<'a> FlattenNode<'a> {
160    pub fn to_request(&self, representations: Variables) -> Request {
161        Request::new(self.query.to_string())
162            .variables(representations)
163            .extend_variables(self.variables.to_variables())
164    }
165}
166
167#[derive(Debug, Serialize)]
168#[serde(rename_all = "camelCase")]
169pub struct SubscribeNode<'a> {
170    pub subscribe_nodes: Vec<FetchNode<'a>>,
171    #[serde(skip_serializing_if = "Option::is_none")]
172    pub flatten_node: Option<PlanNode<'a>>,
173}
174
175#[derive(Debug, Serialize)]
176#[serde(tag = "type", rename_all = "lowercase")]
177pub enum RootNode<'a> {
178    Subscribe(SubscribeNode<'a>),
179    Query(PlanNode<'a>),
180}