Skip to main content

cynic_parser/schema_coordinates/
mod.rs

1use std::fmt;
2
3use crate::{Error, Span};
4
5mod lexer;
6mod ty;
7
8mod argument;
9mod directive;
10mod directive_argument;
11mod member;
12#[allow(unused_braces)]
13mod parser;
14
15pub use self::{
16    argument::ArgumentCoordinate, directive::DirectiveCoordinate,
17    directive_argument::DirectiveArgumentCoordinate, member::MemberCoordinate, ty::TypeCoordinate,
18};
19
20pub fn parse_schema_coordinate(input: &str) -> Result<SchemaCoordinate, Error> {
21    if input.trim().is_empty() {
22        return Err(Error::EmptySchemaCoordinate);
23    }
24
25    let lexer = lexer::Lexer::new(input);
26
27    Ok(parser::SchemaCoordinateParser::new().parse(input, lexer)?)
28}
29
30/// A GraphQL [Schema Coordinate][1]
31///
32/// [1]: https://spec.graphql.org/September2025/#sec-Schema-Coordinates
33#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
34pub enum SchemaCoordinate {
35    Type(TypeCoordinate),
36    Member(MemberCoordinate),
37    Argument(ArgumentCoordinate),
38    Directive(DirectiveCoordinate),
39    DirectiveArgument(DirectiveArgumentCoordinate),
40}
41
42impl SchemaCoordinate {
43    pub fn ty(name: impl Into<String>) -> Self {
44        SchemaCoordinate::Type(TypeCoordinate::new(name))
45    }
46
47    pub fn member(ty: impl Into<String>, field: impl Into<String>) -> Self {
48        SchemaCoordinate::Member(MemberCoordinate::new(ty, field))
49    }
50
51    pub fn argument(
52        ty: impl Into<String>,
53        field: impl Into<String>,
54        argument: impl Into<String>,
55    ) -> Self {
56        SchemaCoordinate::Argument(ArgumentCoordinate::new(ty, field, argument))
57    }
58
59    pub fn directive(name: impl Into<String>) -> Self {
60        SchemaCoordinate::Directive(DirectiveCoordinate::new(name))
61    }
62
63    pub fn directive_argument(name: impl Into<String>, argument: impl Into<String>) -> Self {
64        SchemaCoordinate::DirectiveArgument(DirectiveArgumentCoordinate::new(name, argument))
65    }
66
67    pub fn as_ty(&self) -> Option<&TypeCoordinate> {
68        match self {
69            SchemaCoordinate::Type(inner) => Some(inner),
70            _ => None,
71        }
72    }
73
74    pub fn is_ty(&self) -> bool {
75        matches!(self, SchemaCoordinate::Type(_))
76    }
77
78    pub fn as_member(&self) -> Option<&MemberCoordinate> {
79        match self {
80            SchemaCoordinate::Member(inner) => Some(inner),
81            _ => None,
82        }
83    }
84
85    pub fn is_member(&self) -> bool {
86        matches!(self, SchemaCoordinate::Member(_))
87    }
88
89    pub fn as_argument(&self) -> Option<&ArgumentCoordinate> {
90        match self {
91            SchemaCoordinate::Argument(inner) => Some(inner),
92            _ => None,
93        }
94    }
95
96    pub fn is_argument(&self) -> bool {
97        matches!(self, SchemaCoordinate::Argument(_))
98    }
99
100    pub fn as_directive(&self) -> Option<&DirectiveCoordinate> {
101        match self {
102            SchemaCoordinate::Directive(inner) => Some(inner),
103            _ => None,
104        }
105    }
106
107    pub fn is_directive(&self) -> bool {
108        matches!(self, SchemaCoordinate::Directive(_))
109    }
110
111    pub fn as_directive_argument(&self) -> Option<&DirectiveArgumentCoordinate> {
112        match self {
113            SchemaCoordinate::DirectiveArgument(inner) => Some(inner),
114            _ => None,
115        }
116    }
117
118    pub fn is_directive_argument(&self) -> bool {
119        matches!(self, SchemaCoordinate::DirectiveArgument(_))
120    }
121}
122
123impl fmt::Display for SchemaCoordinate {
124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        match self {
126            SchemaCoordinate::Type(inner) => write!(f, "{inner}"),
127            SchemaCoordinate::Member(inner) => write!(f, "{inner}"),
128            SchemaCoordinate::Argument(inner) => write!(f, "{inner}"),
129            SchemaCoordinate::Directive(inner) => write!(f, "{inner}"),
130            SchemaCoordinate::DirectiveArgument(inner) => write!(f, "{inner}"),
131        }
132    }
133}
134
135#[derive(Clone, Debug, Eq)]
136pub struct Name {
137    span: Span,
138    value: Box<str>,
139}
140
141impl Name {
142    fn new(value: String) -> Self {
143        Name {
144            span: Span::default(),
145            value: value.into(),
146        }
147    }
148}
149
150impl PartialEq for Name {
151    fn eq(&self, other: &Self) -> bool {
152        self.value == other.value
153    }
154}
155
156impl PartialOrd for Name {
157    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
158        Some(self.cmp(other))
159    }
160}
161
162impl Ord for Name {
163    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
164        self.value.cmp(&other.value)
165    }
166}
167
168impl std::hash::Hash for Name {
169    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
170        self.value.hash(state);
171    }
172}