1use anyhow::Error;
2use quote::__private::TokenStream;
3use quote::{format_ident, quote};
4
5use crate::parser::{parse_file, parse_graphql_type};
6
7#[derive(Debug, Clone)]
8pub struct Schema {
9 pub types: Vec<TypeDefinition>,
10}
11
12impl Schema {
13 pub fn parse(input: &str) -> Result<Self, Error> {
14 let schema = parse_file(input)?;
15
16 Ok(schema)
17 }
18}
19
20#[derive(Debug, Clone)]
22pub struct TypeDefinition {
23 pub name: String,
24 pub fields: Vec<Field>,
25}
26
27impl TypeDefinition {
28 pub fn parse(input: &str) -> Result<Self, Error> {
30 parse_graphql_type(input)
31 }
32
33 pub fn snake_case_name(&self) -> String {
34 camel_to_snake_case(&self.name)
35 }
36}
37
38#[derive(Debug, Clone)]
40pub struct Field {
41 pub name: String,
42 pub field_type: GraphQlType,
43}
44
45impl Field {
46 pub fn snake_case_name(&self) -> String {
47 camel_to_snake_case(&self.name)
48 }
49
50 pub fn field_type(&self) -> &GraphQlType {
51 &self.field_type
52 }
53
54 pub fn name(&self) -> &str {
55 &self.name
56 }
57
58 pub fn is_id(&self) -> bool {
59 match self.field_type {
60 GraphQlType::Id => true,
61 _ => false,
62 }
63 }
64
65 pub fn required(&self) -> bool {
66 match self.field_type {
67 GraphQlType::Id
68 | GraphQlType::String { required: true, .. }
69 | GraphQlType::Bytes { required: true, .. }
70 | GraphQlType::Boolean { required: true, .. }
71 | GraphQlType::BigInt { required: true, .. }
72 | GraphQlType::Int { required: true, .. }
73 | GraphQlType::Relation { required: true, .. }
74 | GraphQlType::Array { required: true, .. } => true,
75 _ => false,
76 }
77 }
78
79 pub fn derived_from(&self) -> bool {
80 match self.field_type {
81 GraphQlType::String {
82 derived_from: true, ..
83 }
84 | GraphQlType::Bytes {
85 derived_from: true, ..
86 }
87 | GraphQlType::Boolean {
88 derived_from: true, ..
89 }
90 | GraphQlType::BigInt {
91 derived_from: true, ..
92 }
93 | GraphQlType::Int {
94 derived_from: true, ..
95 }
96 | GraphQlType::Relation {
97 derived_from: true, ..
98 }
99 | GraphQlType::Array {
100 derived_from: true, ..
101 } => true,
102 _ => false,
103 }
104 }
105
106 pub fn rust_type(&self) -> TokenStream {
107 match &self.field_type {
108 GraphQlType::Array { internal_type, .. } => {
109 let internal_type = format_ident!("{}", internal_type.rust_type());
110 quote! (
111 &Vec<#internal_type>
112 )
113 }
114 GraphQlType::Bytes { .. } => {
115 quote!(&Vec<u8>)
116 }
117 GraphQlType::Boolean { .. } => {
118 quote!(bool)
119 }
120 _ => {
121 let type_ident = format_ident!("{}", self.field_type.rust_type());
122 quote! (
123 &#type_ident
124 )
125 }
126 }
127 }
128}
129
130fn camel_to_snake_case(input: &str) -> String {
131 let mut result = String::new();
132 for (i, c) in input.chars().enumerate() {
133 if c.is_uppercase() {
134 if i != 0 {
135 result.push('_');
136 }
137 result.push(c.to_lowercase().next().unwrap());
138 } else {
139 result.push(c);
140 }
141 }
142 result
143}
144
145#[derive(Debug, Clone)]
147pub enum GraphQlType {
148 Id,
149 String {
150 required: bool,
151 derived_from: bool,
152 },
153 Bytes {
154 required: bool,
155 derived_from: bool,
156 },
157 Boolean {
158 required: bool,
159 derived_from: bool,
160 },
161 BigInt {
162 required: bool,
163 derived_from: bool,
164 },
165 Int {
166 required: bool,
167 derived_from: bool,
168 },
169 Array {
170 required: bool,
171 derived_from: bool,
172 internal_type: Box<GraphQlType>,
173 },
174 Relation {
176 required: bool,
177 derived_from: bool,
178 },
179}
180
181impl GraphQlType {
182 pub fn new(
183 required: bool,
184 derived_from: bool,
185 type_name: &str,
186 internal_type: Option<Box<GraphQlType>>,
187 ) -> Self {
188 match type_name {
189 "ID" => GraphQlType::Id,
190 "String" => GraphQlType::String {
191 required,
192 derived_from,
193 },
194 "Bytes" => GraphQlType::Bytes {
195 required,
196 derived_from,
197 },
198 "Boolean" => GraphQlType::Boolean {
199 required,
200 derived_from,
201 },
202 "BigInt" => GraphQlType::BigInt {
203 required,
204 derived_from,
205 },
206 "Int" => GraphQlType::Int {
207 required,
208 derived_from,
209 },
210 "Array" => GraphQlType::Array {
211 required,
212 derived_from,
213 internal_type: internal_type.unwrap(),
214 },
215 _ => GraphQlType::Relation {
216 required,
217 derived_from,
218 },
219 }
220 }
221
222 pub fn rust_type(&self) -> String {
223 match self {
224 GraphQlType::Id
225 | GraphQlType::String { .. }
226 | GraphQlType::BigInt { .. }
227 | GraphQlType::Relation { .. } => {
228 format!("String")
229 }
230 GraphQlType::Bytes { .. } => {
231 format!("Vec<u8>")
232 }
233 GraphQlType::Boolean { .. } => {
234 format!("bool")
235 }
236 GraphQlType::Int { .. } => {
237 format!("i32")
238 }
239 GraphQlType::Array { internal_type, .. } => {
240 let internal_type = internal_type.rust_type();
241 format!("Vec<{}>", internal_type)
242 }
243 }
244 }
245}