Skip to main content

graphql_schema_diff/
change.rs

1/// A change that represents a meaningful difference between the two schemas. Changes have a
2/// direction: from source to target. For example, if `kind` is `AddField`, it means the field does
3/// not exist in the `source` schema but it does exist in the `target` schema.
4#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub struct Change {
7    // /!\ The order of fields matters for the PartialOrd derive /!\
8    /// Where the change happened in the schema. It is dot separated where relevant. For example if
9    /// the change happened in a field argument, the path will be something like
10    /// `ParentTypeName.fieldName.argumentName`.
11    ///
12    /// See [crate::path::Path] for the full documentation.
13    pub path: String,
14    /// The nature of the change.
15    pub kind: ChangeKind,
16    /// Contents depend on the change kind:
17    ///
18    /// - [ChangeQueryType]/[ChangeMutationType]/[ChangeSubscriptionType]: the new type
19    /// - [AddObjectType]/[AddUnion]/[AddEnum]/[AddScalar]/[AddInterface]/[AddInputObject]/[AddSchemaDefinition]/[AddDirectiveDefinition]: the whole definition.
20    /// - [AddInterfaceImplementation]/[RemoveInterfaceImplementation]: empty
21    /// - [ChangeFieldType]/[ChangeFieldArgumentType]: the new type
22    /// - [RemoveObjectType]/[RemoveField]/[RemoveUnion]/[RemoveUnionMember]/[RemoveEnum]/[RemoveScalar]/[RemoveInterface]/[RemoveDirectiveDefinition]/[RemoveSchemaDefinition]/[RemoveInputObject]/[RemoveFieldArgument]/[RemoveFieldArgumentDefault]: empty
23    /// - [AddField]: the whole field definition
24    /// - [AddUnionMember]: the union member added
25    /// - [AddEnumValue]/[RemoveEnumValue]: empty
26    /// - [AddFieldArgument]: the value of the argument, potentially with the default
27    /// - [AddFieldArgumentDefault]/[ChangeFieldArgumentDefault]: the default value of the argument
28    pub span: Span,
29}
30
31#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
32#[allow(missing_docs)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34#[repr(u8)]
35pub enum ChangeKind {
36    // /!\ The order of variants matters for the PartialOrd derive /!\
37    ChangeQueryType,
38    ChangeMutationType,
39    ChangeSubscriptionType,
40    RemoveObjectType,
41    AddObjectType,
42    AddInterfaceImplementation,
43    RemoveInterfaceImplementation,
44    ChangeFieldType,
45    RemoveField,
46    AddField,
47    AddUnion,
48    RemoveUnion,
49    AddUnionMember,
50    RemoveUnionMember,
51    AddEnum,
52    RemoveEnum,
53    AddEnumValue,
54    RemoveEnumValue,
55    AddScalar,
56    RemoveScalar,
57    AddInterface,
58    RemoveInterface,
59    AddDirectiveDefinition,
60    RemoveDirectiveDefinition,
61    AddSchemaDefinition,
62    RemoveSchemaDefinition,
63    AddSchemaExtension,
64    RemoveSchemaExtension,
65    AddInputObject,
66    RemoveInputObject,
67    AddFieldArgument,
68    RemoveFieldArgument,
69    AddFieldArgumentDefault,
70    RemoveFieldArgumentDefault,
71    ChangeFieldArgumentDefault,
72    ChangeFieldArgumentType,
73    AddDirective,
74    RemoveDirective,
75}
76
77impl ChangeKind {
78    /// The change kind as a string.
79    pub fn as_str(&self) -> &'static str {
80        use ChangeKind::*;
81
82        match self {
83            ChangeQueryType => "ChangeQueryType",
84            ChangeMutationType => "ChangeMutationType",
85            ChangeSubscriptionType => "ChangeSubscriptionType",
86            RemoveObjectType => "RemoveObjectType",
87            AddObjectType => "AddObjectType",
88            AddInterfaceImplementation => "AddInterfaceImplementation",
89            RemoveInterfaceImplementation => "RemoveInterfaceImplementation",
90            ChangeFieldType => "ChangeFieldType",
91            RemoveField => "RemoveField",
92            AddField => "AddField",
93            AddUnion => "AddUnion",
94            RemoveUnion => "RemoveUnion",
95            AddUnionMember => "AddUnionMember",
96            RemoveUnionMember => "RemoveUnionMember",
97            AddEnum => "AddEnum",
98            RemoveEnum => "RemoveEnum",
99            AddEnumValue => "AddEnumValue",
100            RemoveEnumValue => "RemoveEnumValue",
101            AddScalar => "AddScalar",
102            RemoveScalar => "RemoveScalar",
103            AddInterface => "AddInterface",
104            RemoveInterface => "RemoveInterface",
105            AddDirectiveDefinition => "AddDirectiveDefinition",
106            RemoveDirectiveDefinition => "RemoveDirectiveDefinition",
107            AddSchemaDefinition => "AddSchemaDefinition",
108            AddSchemaExtension => "AddSchemaExtension",
109            RemoveSchemaDefinition => "RemoveSchemaDefinition",
110            RemoveSchemaExtension => "RemoveSchemaExtension",
111            AddInputObject => "AddInputObject",
112            RemoveInputObject => "RemoveInputObject",
113            AddFieldArgument => "AddFieldArgument",
114            RemoveFieldArgument => "RemoveFieldArgument",
115            AddFieldArgumentDefault => "AddFieldArgumentDefault",
116            RemoveFieldArgumentDefault => "RemoveFieldArgumentDefault",
117            ChangeFieldArgumentDefault => "ChangeFieldArgumentDefault",
118            ChangeFieldArgumentType => "ChangeFieldArgumentType",
119            AddDirective => "AddDirective",
120            RemoveDirective => "RemoveDirective",
121        }
122    }
123}
124
125impl std::str::FromStr for ChangeKind {
126    type Err = ();
127
128    fn from_str(s: &str) -> Result<Self, Self::Err> {
129        Ok(match s {
130            "ChangeQueryType" => Self::ChangeQueryType,
131            "ChangeMutationType" => Self::ChangeMutationType,
132            "ChangeSubscriptionType" => Self::ChangeSubscriptionType,
133            "RemoveObjectType" => Self::RemoveObjectType,
134            "AddObjectType" => Self::AddObjectType,
135            "AddInterfaceImplementation" => Self::AddInterfaceImplementation,
136            "RemoveInterfaceImplementation" => Self::RemoveInterfaceImplementation,
137            "ChangeFieldType" => Self::ChangeFieldType,
138            "RemoveField" => Self::RemoveField,
139            "AddField" => Self::AddField,
140            "AddUnion" => Self::AddUnion,
141            "RemoveUnion" => Self::RemoveUnion,
142            "AddUnionMember" => Self::AddUnionMember,
143            "RemoveUnionMember" => Self::RemoveUnionMember,
144            "AddEnum" => Self::AddEnum,
145            "RemoveEnum" => Self::RemoveEnum,
146            "AddEnumValue" => Self::AddEnumValue,
147            "RemoveEnumValue" => Self::RemoveEnumValue,
148            "AddScalar" => Self::AddScalar,
149            "RemoveScalar" => Self::RemoveScalar,
150            "AddInterface" => Self::AddInterface,
151            "RemoveInterface" => Self::RemoveInterface,
152            "AddDirectiveDefinition" => Self::AddDirectiveDefinition,
153            "RemoveDirectiveDefinition" => Self::RemoveDirectiveDefinition,
154            "AddSchemaDefinition" => Self::AddSchemaDefinition,
155            "RemoveSchemaDefinition" => Self::RemoveSchemaDefinition,
156            "AddSchemaExtension" => Self::AddSchemaExtension,
157            "RemoveSchemaExtension" => Self::RemoveSchemaExtension,
158            "AddInputObject" => Self::AddInputObject,
159            "RemoveInputObject" => Self::RemoveInputObject,
160            "AddFieldArgument" => Self::AddFieldArgument,
161            "RemoveFieldArgument" => Self::RemoveFieldArgument,
162            "AddFieldArgumentDefault" => Self::AddFieldArgumentDefault,
163            "RemoveFieldArgumentDefault" => Self::RemoveFieldArgumentDefault,
164            "ChangeFieldArgumentDefault" => Self::ChangeFieldArgumentDefault,
165            "ChangeFieldArgumentType" => Self::ChangeFieldArgumentType,
166            "AddDirective" => Self::AddDirective,
167            "RemoveDirective" => Self::RemoveDirective,
168            _ => return Err(()),
169        })
170    }
171}
172
173/// A span in a source file.
174#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug, serde::Serialize, serde::Deserialize, Copy)]
175pub struct Span {
176    /// The byte offset where the span starts.
177    pub start: usize,
178    /// The byte offset where the span stops (exclusive).
179    pub end: usize,
180}
181
182impl Span {
183    /// Create a span from start and end.
184    pub fn new(start: usize, end: usize) -> Self {
185        Span { start, end }
186    }
187
188    pub(crate) const fn empty() -> Span {
189        Span { start: 0, end: 0 }
190    }
191}
192
193impl From<cynic_parser::Span> for Span {
194    fn from(cynic_parser::Span { start, end }: cynic_parser::Span) -> Self {
195        Span { start, end }
196    }
197}
198
199impl std::ops::Index<Span> for str {
200    type Output = str;
201
202    fn index(&self, Span { start, end }: Span) -> &Self::Output {
203        &self[start..end]
204    }
205}