1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Serialize, Deserialize)]
4pub struct GraphQLResponse {
5 pub data: Data,
6}
7
8#[derive(Debug, Serialize, Deserialize)]
9pub struct Data {
10 #[serde(rename = "__schema")]
11 pub schema: Schema,
12}
13
14#[derive(Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
15#[serde(rename_all = "camelCase")]
16pub struct Schema {
17 pub query_type: Option<RootTypeRef>,
18 pub mutation_type: Option<RootTypeRef>,
19 pub types: Vec<FullType>,
20}
21
22impl Schema {
23 pub fn _find_type(&self, type_ref: &TypeRef) -> Option<&FullType> {
24 let type_ref_name = type_ref.name.as_ref()?;
25
26 for typ in &self.types {
27 if &typ.name == type_ref_name {
28 return Some(typ);
29 }
30 }
31
32 None
33 }
34}
35
36#[derive(Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
37#[serde(rename_all = "camelCase")]
38pub struct RootTypeRef {
39 pub name: String,
40}
41
42#[derive(Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
43#[serde(rename_all = "camelCase")]
44pub struct TypeRef {
45 pub kind: Kind,
46 pub name: Option<String>,
47 pub of_type: Option<Box<TypeRef>>,
48}
49
50#[derive(Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
51#[serde(rename_all = "camelCase")]
52pub struct FullType {
53 pub kind: Kind,
54 pub name: String,
55 pub description: Option<String>,
56 pub fields: Option<Vec<Field>>,
57 pub input_fields: Option<Vec<InputValue>>,
58 pub interfaces: Option<Vec<TypeRef>>,
59 pub enum_values: Option<Vec<EnumValue>>,
60 pub possible_types: Option<Vec<TypeRef>>,
61}
62
63#[derive(Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
64#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
65pub enum Kind {
66 NonNull,
67 List,
68 Object,
69 InputObject,
70 Union,
71 Enum,
72 Scalar,
73 Interface,
74}
75
76impl Kind {
77 pub fn prefix(&self) -> &str {
78 match self {
79 Self::NonNull => "non_null",
80 Self::List => "list",
81 Self::Object => "object",
82 Self::InputObject => "input_object",
83 Self::Union => "union",
84 Self::Enum => "enum",
85 Self::Scalar => "scalar",
86 Self::Interface => "interface",
87 }
88 }
89}
90
91#[derive(Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
92#[serde(rename_all = "camelCase")]
93pub struct Field {
94 pub name: String,
95 pub description: Option<String>,
96 pub args: Vec<InputValue>,
97 #[serde(rename = "type")]
98 pub typ: TypeRef,
99 pub is_deprecated: bool,
100 pub deprecation_reason: Option<String>,
101}
102
103#[derive(Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
104#[serde(rename_all = "camelCase")]
105pub struct InputValue {
106 pub name: String,
107 pub description: Option<String>,
108 #[serde(rename = "type")]
109 pub typ: TypeRef,
110 pub default_value: Option<String>,
111}
112
113#[derive(Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
114#[serde(rename_all = "camelCase")]
115pub struct EnumValue {
116 pub name: String,
117 pub description: Option<String>,
118 pub is_deprecated: bool,
119 pub deprecation_reason: Option<String>,
120}
121
122impl Schema {
123 pub fn find_uses(&self, full_type: &FullType) -> Vec<TypeUse> {
124 let mut uses = Vec::new();
125
126 for typ in &self.types {
127 if let Some(ref fields) = typ.fields {
128 for field in fields {
129 if self.is_use(full_type, &field.typ) {
130 uses.push(TypeUse::Field { typ, field: &field });
131 } else {
132 for arg in &field.args {
133 if self.is_use(full_type, &arg.typ) {
134 uses.push(TypeUse::Field { typ, field });
135 break;
136 }
137 }
138 }
139 }
140 }
141 if let Some(ref input_fields) = typ.input_fields {
142 for input_field in input_fields {
143 if self.is_use(full_type, &input_field.typ) {
144 uses.push(TypeUse::InputField {
145 typ,
146 input_field: &input_field,
147 });
148 }
149 }
150 }
151 if let Some(ref possible_types) = typ.possible_types {
152 for possible_type in possible_types {
153 if self.is_use(full_type, &possible_type) {
154 uses.push(TypeUse::PossibleType { typ });
155 }
156 }
157 }
158 }
159
160 uses.sort();
161 uses
162 }
163
164 fn is_use(&self, full_type: &FullType, type_ref: &TypeRef) -> bool {
165 if Some(&full_type.name) == type_ref.name.as_ref() {
166 return true;
167 }
168
169 if let Some(ref of_type) = type_ref.of_type {
170 match type_ref.kind {
171 Kind::NonNull | Kind::List => self.is_use(full_type, of_type),
172 _ => false,
173 }
174 } else {
175 false
176 }
177 }
178}
179
180#[derive(Debug, Serialize, Eq, Ord, PartialEq, PartialOrd)]
181#[serde(tag = "use_type")]
182pub enum TypeUse<'a> {
183 Field {
185 #[serde(rename = "type")]
186 typ: &'a FullType,
187 field: &'a Field,
188 },
189 InputField {
191 #[serde(rename = "type")]
192 typ: &'a FullType,
193 input_field: &'a InputValue,
194 },
195 PossibleType {
197 #[serde(rename = "type")]
198 typ: &'a FullType,
199 },
200}