Skip to main content

oxirs_gql/
types.rs

1//! GraphQL type system implementation
2//!
3//! This module provides the GraphQL type system including scalar types,
4//! object types, interfaces, unions, and enums.
5
6use crate::ast::Value;
7use anyhow::{anyhow, Result};
8use std::collections::HashMap;
9use std::fmt;
10
11/// GraphQL type information
12#[derive(Debug, Clone, PartialEq)]
13pub enum GraphQLType {
14    Scalar(ScalarType),
15    Object(ObjectType),
16    Interface(InterfaceType),
17    Union(UnionType),
18    Enum(EnumType),
19    InputObject(InputObjectType),
20    List(Box<GraphQLType>),
21    NonNull(Box<GraphQLType>),
22}
23
24impl GraphQLType {
25    pub fn name(&self) -> &str {
26        match self {
27            GraphQLType::Scalar(s) => &s.name,
28            GraphQLType::Object(o) => &o.name,
29            GraphQLType::Interface(i) => &i.name,
30            GraphQLType::Union(u) => &u.name,
31            GraphQLType::Enum(e) => &e.name,
32            GraphQLType::InputObject(io) => &io.name,
33            GraphQLType::List(inner) => inner.name(),
34            GraphQLType::NonNull(inner) => inner.name(),
35        }
36    }
37
38    pub fn is_nullable(&self) -> bool {
39        !matches!(self, GraphQLType::NonNull(_))
40    }
41
42    pub fn is_list(&self) -> bool {
43        matches!(self, GraphQLType::List(_))
44    }
45
46    pub fn is_scalar(&self) -> bool {
47        matches!(self, GraphQLType::Scalar(_))
48    }
49
50    pub fn is_object(&self) -> bool {
51        matches!(self, GraphQLType::Object(_))
52    }
53}
54
55impl fmt::Display for GraphQLType {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        match self {
58            GraphQLType::Scalar(s) => write!(f, "{}", s.name),
59            GraphQLType::Object(o) => write!(f, "{}", o.name),
60            GraphQLType::Interface(i) => write!(f, "{}", i.name),
61            GraphQLType::Union(u) => write!(f, "{}", u.name),
62            GraphQLType::Enum(e) => write!(f, "{}", e.name),
63            GraphQLType::InputObject(io) => write!(f, "{}", io.name),
64            GraphQLType::List(inner) => write!(f, "[{inner}]"),
65            GraphQLType::NonNull(inner) => write!(f, "{inner}!"),
66        }
67    }
68}
69
70/// Scalar type definition
71#[derive(Debug, Clone)]
72pub struct ScalarType {
73    pub name: String,
74    pub description: Option<String>,
75    pub serialize: fn(&Value) -> Result<Value>,
76    pub parse_value: fn(&Value) -> Result<Value>,
77    pub parse_literal: fn(&Value) -> Result<Value>,
78}
79
80impl PartialEq for ScalarType {
81    fn eq(&self, other: &Self) -> bool {
82        self.name == other.name && self.description == other.description
83        // Note: Function pointers are not compared as they cannot be reliably compared
84    }
85}
86
87impl ScalarType {
88    pub fn new(name: String) -> Self {
89        Self {
90            name,
91            description: None,
92            serialize: |v| Ok(v.clone()),
93            parse_value: |v| Ok(v.clone()),
94            parse_literal: |v| Ok(v.clone()),
95        }
96    }
97
98    pub fn with_description(mut self, description: String) -> Self {
99        self.description = Some(description);
100        self
101    }
102
103    pub fn with_serializer(mut self, serialize: fn(&Value) -> Result<Value>) -> Self {
104        self.serialize = serialize;
105        self
106    }
107
108    pub fn with_value_parser(mut self, parse_value: fn(&Value) -> Result<Value>) -> Self {
109        self.parse_value = parse_value;
110        self
111    }
112
113    pub fn with_literal_parser(mut self, parse_literal: fn(&Value) -> Result<Value>) -> Self {
114        self.parse_literal = parse_literal;
115        self
116    }
117}
118
119/// Object type definition
120#[derive(Debug, Clone, PartialEq)]
121pub struct ObjectType {
122    pub name: String,
123    pub description: Option<String>,
124    pub fields: HashMap<String, FieldType>,
125    pub interfaces: Vec<String>,
126}
127
128impl ObjectType {
129    pub fn new(name: String) -> Self {
130        Self {
131            name,
132            description: None,
133            fields: HashMap::new(),
134            interfaces: Vec::new(),
135        }
136    }
137
138    pub fn with_description(mut self, description: String) -> Self {
139        self.description = Some(description);
140        self
141    }
142
143    pub fn with_field(mut self, name: String, field: FieldType) -> Self {
144        self.fields.insert(name, field);
145        self
146    }
147
148    pub fn with_interface(mut self, interface: String) -> Self {
149        self.interfaces.push(interface);
150        self
151    }
152}
153
154/// Field type definition
155#[derive(Debug, Clone, PartialEq)]
156pub struct FieldType {
157    pub name: String,
158    pub description: Option<String>,
159    pub field_type: GraphQLType,
160    pub arguments: HashMap<String, ArgumentType>,
161}
162
163impl FieldType {
164    pub fn new(name: String, field_type: GraphQLType) -> Self {
165        Self {
166            name,
167            description: None,
168            field_type,
169            arguments: HashMap::new(),
170        }
171    }
172
173    pub fn with_description(mut self, description: String) -> Self {
174        self.description = Some(description);
175        self
176    }
177
178    pub fn with_argument(mut self, name: String, argument: ArgumentType) -> Self {
179        self.arguments.insert(name, argument);
180        self
181    }
182}
183
184/// Argument type definition
185#[derive(Debug, Clone, PartialEq)]
186pub struct ArgumentType {
187    pub name: String,
188    pub description: Option<String>,
189    pub argument_type: GraphQLType,
190    pub default_value: Option<Value>,
191}
192
193impl ArgumentType {
194    pub fn new(name: String, argument_type: GraphQLType) -> Self {
195        Self {
196            name,
197            description: None,
198            argument_type,
199            default_value: None,
200        }
201    }
202
203    pub fn with_description(mut self, description: String) -> Self {
204        self.description = Some(description);
205        self
206    }
207
208    pub fn with_default_value(mut self, default_value: Value) -> Self {
209        self.default_value = Some(default_value);
210        self
211    }
212}
213
214/// Interface type definition
215#[derive(Debug, Clone, PartialEq)]
216pub struct InterfaceType {
217    pub name: String,
218    pub description: Option<String>,
219    pub fields: HashMap<String, FieldType>,
220    pub interfaces: Vec<String>,
221}
222
223impl InterfaceType {
224    pub fn new(name: String) -> Self {
225        Self {
226            name,
227            description: None,
228            fields: HashMap::new(),
229            interfaces: Vec::new(),
230        }
231    }
232
233    pub fn with_description(mut self, description: String) -> Self {
234        self.description = Some(description);
235        self
236    }
237
238    pub fn with_field(mut self, name: String, field: FieldType) -> Self {
239        self.fields.insert(name, field);
240        self
241    }
242}
243
244/// Union type definition
245#[derive(Debug, Clone, PartialEq)]
246pub struct UnionType {
247    pub name: String,
248    pub description: Option<String>,
249    pub types: Vec<String>,
250}
251
252impl UnionType {
253    pub fn new(name: String) -> Self {
254        Self {
255            name,
256            description: None,
257            types: Vec::new(),
258        }
259    }
260
261    pub fn with_description(mut self, description: String) -> Self {
262        self.description = Some(description);
263        self
264    }
265
266    pub fn with_type(mut self, type_name: String) -> Self {
267        self.types.push(type_name);
268        self
269    }
270}
271
272/// Enum type definition
273#[derive(Debug, Clone, PartialEq)]
274pub struct EnumType {
275    pub name: String,
276    pub description: Option<String>,
277    pub values: HashMap<String, EnumValue>,
278}
279
280impl EnumType {
281    pub fn new(name: String) -> Self {
282        Self {
283            name,
284            description: None,
285            values: HashMap::new(),
286        }
287    }
288
289    pub fn with_description(mut self, description: String) -> Self {
290        self.description = Some(description);
291        self
292    }
293
294    pub fn with_value(mut self, name: String, value: EnumValue) -> Self {
295        self.values.insert(name, value);
296        self
297    }
298}
299
300/// Enum value definition
301#[derive(Debug, Clone, PartialEq)]
302pub struct EnumValue {
303    pub name: String,
304    pub description: Option<String>,
305    pub value: Value,
306    pub deprecated: Option<String>,
307}
308
309impl EnumValue {
310    pub fn new(name: String, value: Value) -> Self {
311        Self {
312            name,
313            description: None,
314            value,
315            deprecated: None,
316        }
317    }
318
319    pub fn with_description(mut self, description: String) -> Self {
320        self.description = Some(description);
321        self
322    }
323
324    pub fn with_deprecation(mut self, reason: String) -> Self {
325        self.deprecated = Some(reason);
326        self
327    }
328}
329
330/// Input object type definition
331#[derive(Debug, Clone, PartialEq)]
332pub struct InputObjectType {
333    pub name: String,
334    pub description: Option<String>,
335    pub fields: HashMap<String, InputFieldType>,
336}
337
338impl InputObjectType {
339    pub fn new(name: String) -> Self {
340        Self {
341            name,
342            description: None,
343            fields: HashMap::new(),
344        }
345    }
346
347    pub fn with_description(mut self, description: String) -> Self {
348        self.description = Some(description);
349        self
350    }
351
352    pub fn with_field(mut self, name: String, field: InputFieldType) -> Self {
353        self.fields.insert(name, field);
354        self
355    }
356}
357
358/// Input field type definition
359#[derive(Debug, Clone, PartialEq)]
360pub struct InputFieldType {
361    pub name: String,
362    pub description: Option<String>,
363    pub field_type: GraphQLType,
364    pub default_value: Option<Value>,
365}
366
367impl InputFieldType {
368    pub fn new(name: String, field_type: GraphQLType) -> Self {
369        Self {
370            name,
371            description: None,
372            field_type,
373            default_value: None,
374        }
375    }
376
377    pub fn with_description(mut self, description: String) -> Self {
378        self.description = Some(description);
379        self
380    }
381
382    pub fn with_default_value(mut self, default_value: Value) -> Self {
383        self.default_value = Some(default_value);
384        self
385    }
386}
387
388/// Built-in scalar types
389pub struct BuiltinScalars;
390
391impl BuiltinScalars {
392    pub fn string() -> ScalarType {
393        ScalarType::new("String".to_string())
394            .with_description("The `String` scalar type represents textual data, represented as UTF-8 character sequences.".to_string())
395            .with_serializer(|v| match v {
396                Value::StringValue(s) => Ok(Value::StringValue(s.clone())),
397                _ => Err(anyhow!("Cannot serialize {:?} as String", v)),
398            })
399            .with_value_parser(|v| match v {
400                Value::StringValue(_) => Ok(v.clone()),
401                _ => Err(anyhow!("Cannot parse {:?} as String", v)),
402            })
403            .with_literal_parser(|v| match v {
404                Value::StringValue(_) => Ok(v.clone()),
405                _ => Err(anyhow!("Cannot parse literal {:?} as String", v)),
406            })
407    }
408
409    pub fn int() -> ScalarType {
410        ScalarType::new("Int".to_string())
411            .with_description(
412                "The `Int` scalar type represents non-fractional signed whole numeric values."
413                    .to_string(),
414            )
415            .with_serializer(|v| match v {
416                Value::IntValue(i) => Ok(Value::IntValue(*i)),
417                _ => Err(anyhow!("Cannot serialize {:?} as Int", v)),
418            })
419            .with_value_parser(|v| match v {
420                Value::IntValue(_) => Ok(v.clone()),
421                _ => Err(anyhow!("Cannot parse {:?} as Int", v)),
422            })
423            .with_literal_parser(|v| match v {
424                Value::IntValue(_) => Ok(v.clone()),
425                _ => Err(anyhow!("Cannot parse literal {:?} as Int", v)),
426            })
427    }
428
429    pub fn float() -> ScalarType {
430        ScalarType::new("Float".to_string())
431            .with_description(
432                "The `Float` scalar type represents signed double-precision fractional values."
433                    .to_string(),
434            )
435            .with_serializer(|v| match v {
436                Value::FloatValue(f) => Ok(Value::FloatValue(*f)),
437                Value::IntValue(i) => Ok(Value::FloatValue(*i as f64)),
438                _ => Err(anyhow!("Cannot serialize {:?} as Float", v)),
439            })
440            .with_value_parser(|v| match v {
441                Value::FloatValue(_) => Ok(v.clone()),
442                Value::IntValue(i) => Ok(Value::FloatValue(*i as f64)),
443                _ => Err(anyhow!("Cannot parse {:?} as Float", v)),
444            })
445            .with_literal_parser(|v| match v {
446                Value::FloatValue(_) => Ok(v.clone()),
447                Value::IntValue(i) => Ok(Value::FloatValue(*i as f64)),
448                _ => Err(anyhow!("Cannot parse literal {:?} as Float", v)),
449            })
450    }
451
452    pub fn boolean() -> ScalarType {
453        ScalarType::new("Boolean".to_string())
454            .with_description("The `Boolean` scalar type represents `true` or `false`.".to_string())
455            .with_serializer(|v| match v {
456                Value::BooleanValue(b) => Ok(Value::BooleanValue(*b)),
457                _ => Err(anyhow!("Cannot serialize {:?} as Boolean", v)),
458            })
459            .with_value_parser(|v| match v {
460                Value::BooleanValue(_) => Ok(v.clone()),
461                _ => Err(anyhow!("Cannot parse {:?} as Boolean", v)),
462            })
463            .with_literal_parser(|v| match v {
464                Value::BooleanValue(_) => Ok(v.clone()),
465                _ => Err(anyhow!("Cannot parse literal {:?} as Boolean", v)),
466            })
467    }
468
469    pub fn id() -> ScalarType {
470        ScalarType::new("ID".to_string())
471            .with_description("The `ID` scalar type represents a unique identifier.".to_string())
472            .with_serializer(|v| match v {
473                Value::StringValue(s) => Ok(Value::StringValue(s.clone())),
474                Value::IntValue(i) => Ok(Value::StringValue(i.to_string())),
475                _ => Err(anyhow!("Cannot serialize {:?} as ID", v)),
476            })
477            .with_value_parser(|v| match v {
478                Value::StringValue(_) => Ok(v.clone()),
479                Value::IntValue(i) => Ok(Value::StringValue(i.to_string())),
480                _ => Err(anyhow!("Cannot parse {:?} as ID", v)),
481            })
482            .with_literal_parser(|v| match v {
483                Value::StringValue(_) => Ok(v.clone()),
484                Value::IntValue(i) => Ok(Value::StringValue(i.to_string())),
485                _ => Err(anyhow!("Cannot parse literal {:?} as ID", v)),
486            })
487    }
488}
489
490/// Schema containing all types
491#[derive(Debug, Clone)]
492pub struct Schema {
493    pub query_type: Option<String>,
494    pub mutation_type: Option<String>,
495    pub subscription_type: Option<String>,
496    pub types: HashMap<String, GraphQLType>,
497    pub directives: HashMap<String, DirectiveType>,
498}
499
500impl Schema {
501    pub fn new() -> Self {
502        let mut schema = Self {
503            query_type: None,
504            mutation_type: None,
505            subscription_type: None,
506            types: HashMap::new(),
507            directives: HashMap::new(),
508        };
509
510        // Add built-in scalar types
511        schema.add_type(GraphQLType::Scalar(BuiltinScalars::string()));
512        schema.add_type(GraphQLType::Scalar(BuiltinScalars::int()));
513        schema.add_type(GraphQLType::Scalar(BuiltinScalars::float()));
514        schema.add_type(GraphQLType::Scalar(BuiltinScalars::boolean()));
515        schema.add_type(GraphQLType::Scalar(BuiltinScalars::id()));
516
517        schema
518    }
519
520    pub fn add_type(&mut self, graphql_type: GraphQLType) {
521        let name = graphql_type.name().to_string();
522        self.types.insert(name, graphql_type);
523    }
524
525    pub fn get_type(&self, name: &str) -> Option<&GraphQLType> {
526        self.types.get(name)
527    }
528
529    pub fn set_query_type(&mut self, type_name: String) {
530        self.query_type = Some(type_name);
531    }
532
533    pub fn set_mutation_type(&mut self, type_name: String) {
534        self.mutation_type = Some(type_name);
535    }
536
537    pub fn set_subscription_type(&mut self, type_name: String) {
538        self.subscription_type = Some(type_name);
539    }
540}
541
542impl Default for Schema {
543    fn default() -> Self {
544        Self::new()
545    }
546}
547
548/// Directive type definition
549#[derive(Debug, Clone, PartialEq)]
550pub struct DirectiveType {
551    pub name: String,
552    pub description: Option<String>,
553    pub locations: Vec<DirectiveLocation>,
554    pub arguments: HashMap<String, ArgumentType>,
555    pub repeatable: bool,
556}
557
558/// Directive locations
559#[derive(Debug, Clone, PartialEq)]
560pub enum DirectiveLocation {
561    Query,
562    Mutation,
563    Subscription,
564    Field,
565    FragmentDefinition,
566    FragmentSpread,
567    InlineFragment,
568    VariableDefinition,
569    Schema,
570    Scalar,
571    Object,
572    FieldDefinition,
573    ArgumentDefinition,
574    Interface,
575    Union,
576    Enum,
577    EnumValue,
578    InputObject,
579    InputFieldDefinition,
580}