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    /// - [ChangeDescription]: the new description, or empty if the description was removed
29    pub span: Span,
30}
31
32#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
33#[allow(missing_docs)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35#[repr(u8)]
36pub enum ChangeKind {
37    // /!\ The order of variants matters for the PartialOrd derive /!\
38    ChangeQueryType,
39    ChangeMutationType,
40    ChangeSubscriptionType,
41    RemoveObjectType,
42    AddObjectType,
43    AddInterfaceImplementation,
44    RemoveInterfaceImplementation,
45    ChangeFieldType,
46    RemoveField,
47    AddField,
48    AddUnion,
49    RemoveUnion,
50    AddUnionMember,
51    RemoveUnionMember,
52    AddEnum,
53    RemoveEnum,
54    AddEnumValue,
55    RemoveEnumValue,
56    AddScalar,
57    RemoveScalar,
58    AddInterface,
59    RemoveInterface,
60    AddDirectiveDefinition,
61    RemoveDirectiveDefinition,
62    AddSchemaDefinition,
63    RemoveSchemaDefinition,
64    AddSchemaExtension,
65    RemoveSchemaExtension,
66    AddInputObject,
67    RemoveInputObject,
68    AddFieldArgument,
69    RemoveFieldArgument,
70    AddFieldArgumentDefault,
71    RemoveFieldArgumentDefault,
72    ChangeFieldArgumentDefault,
73    ChangeFieldArgumentType,
74    AddDirective,
75    RemoveDirective,
76    ChangeDescription,
77}
78
79impl ChangeKind {
80    /// The change kind as a string.
81    pub fn as_str(&self) -> &'static str {
82        use ChangeKind::*;
83
84        match self {
85            ChangeQueryType => "ChangeQueryType",
86            ChangeMutationType => "ChangeMutationType",
87            ChangeSubscriptionType => "ChangeSubscriptionType",
88            RemoveObjectType => "RemoveObjectType",
89            AddObjectType => "AddObjectType",
90            AddInterfaceImplementation => "AddInterfaceImplementation",
91            RemoveInterfaceImplementation => "RemoveInterfaceImplementation",
92            ChangeFieldType => "ChangeFieldType",
93            RemoveField => "RemoveField",
94            AddField => "AddField",
95            AddUnion => "AddUnion",
96            RemoveUnion => "RemoveUnion",
97            AddUnionMember => "AddUnionMember",
98            RemoveUnionMember => "RemoveUnionMember",
99            AddEnum => "AddEnum",
100            RemoveEnum => "RemoveEnum",
101            AddEnumValue => "AddEnumValue",
102            RemoveEnumValue => "RemoveEnumValue",
103            AddScalar => "AddScalar",
104            RemoveScalar => "RemoveScalar",
105            AddInterface => "AddInterface",
106            RemoveInterface => "RemoveInterface",
107            AddDirectiveDefinition => "AddDirectiveDefinition",
108            RemoveDirectiveDefinition => "RemoveDirectiveDefinition",
109            AddSchemaDefinition => "AddSchemaDefinition",
110            AddSchemaExtension => "AddSchemaExtension",
111            RemoveSchemaDefinition => "RemoveSchemaDefinition",
112            RemoveSchemaExtension => "RemoveSchemaExtension",
113            AddInputObject => "AddInputObject",
114            RemoveInputObject => "RemoveInputObject",
115            AddFieldArgument => "AddFieldArgument",
116            RemoveFieldArgument => "RemoveFieldArgument",
117            AddFieldArgumentDefault => "AddFieldArgumentDefault",
118            RemoveFieldArgumentDefault => "RemoveFieldArgumentDefault",
119            ChangeFieldArgumentDefault => "ChangeFieldArgumentDefault",
120            ChangeFieldArgumentType => "ChangeFieldArgumentType",
121            AddDirective => "AddDirective",
122            RemoveDirective => "RemoveDirective",
123            ChangeDescription => "ChangeDescription",
124        }
125    }
126}
127
128impl std::str::FromStr for ChangeKind {
129    type Err = ();
130
131    fn from_str(s: &str) -> Result<Self, Self::Err> {
132        Ok(match s {
133            "ChangeQueryType" => Self::ChangeQueryType,
134            "ChangeMutationType" => Self::ChangeMutationType,
135            "ChangeSubscriptionType" => Self::ChangeSubscriptionType,
136            "RemoveObjectType" => Self::RemoveObjectType,
137            "AddObjectType" => Self::AddObjectType,
138            "AddInterfaceImplementation" => Self::AddInterfaceImplementation,
139            "RemoveInterfaceImplementation" => Self::RemoveInterfaceImplementation,
140            "ChangeFieldType" => Self::ChangeFieldType,
141            "RemoveField" => Self::RemoveField,
142            "AddField" => Self::AddField,
143            "AddUnion" => Self::AddUnion,
144            "RemoveUnion" => Self::RemoveUnion,
145            "AddUnionMember" => Self::AddUnionMember,
146            "RemoveUnionMember" => Self::RemoveUnionMember,
147            "AddEnum" => Self::AddEnum,
148            "RemoveEnum" => Self::RemoveEnum,
149            "AddEnumValue" => Self::AddEnumValue,
150            "RemoveEnumValue" => Self::RemoveEnumValue,
151            "AddScalar" => Self::AddScalar,
152            "RemoveScalar" => Self::RemoveScalar,
153            "AddInterface" => Self::AddInterface,
154            "RemoveInterface" => Self::RemoveInterface,
155            "AddDirectiveDefinition" => Self::AddDirectiveDefinition,
156            "RemoveDirectiveDefinition" => Self::RemoveDirectiveDefinition,
157            "AddSchemaDefinition" => Self::AddSchemaDefinition,
158            "RemoveSchemaDefinition" => Self::RemoveSchemaDefinition,
159            "AddSchemaExtension" => Self::AddSchemaExtension,
160            "RemoveSchemaExtension" => Self::RemoveSchemaExtension,
161            "AddInputObject" => Self::AddInputObject,
162            "RemoveInputObject" => Self::RemoveInputObject,
163            "AddFieldArgument" => Self::AddFieldArgument,
164            "RemoveFieldArgument" => Self::RemoveFieldArgument,
165            "AddFieldArgumentDefault" => Self::AddFieldArgumentDefault,
166            "RemoveFieldArgumentDefault" => Self::RemoveFieldArgumentDefault,
167            "ChangeFieldArgumentDefault" => Self::ChangeFieldArgumentDefault,
168            "ChangeFieldArgumentType" => Self::ChangeFieldArgumentType,
169            "AddDirective" => Self::AddDirective,
170            "RemoveDirective" => Self::RemoveDirective,
171            "ChangeDescription" => Self::ChangeDescription,
172            _ => return Err(()),
173        })
174    }
175}
176
177/// A span in a source file.
178#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Copy)]
179#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
180pub struct Span {
181    /// The byte offset where the span starts.
182    pub start: usize,
183    /// The byte offset where the span stops (exclusive).
184    pub end: usize,
185}
186
187impl Span {
188    /// Create a span from start and end.
189    pub fn new(start: usize, end: usize) -> Self {
190        Span { start, end }
191    }
192
193    pub(crate) const fn empty() -> Span {
194        Span { start: 0, end: 0 }
195    }
196}
197
198impl From<cynic_parser::Span> for Span {
199    fn from(cynic_parser::Span { start, end }: cynic_parser::Span) -> Self {
200        Span { start, end }
201    }
202}
203
204impl std::ops::Index<Span> for str {
205    type Output = str;
206
207    fn index(&self, Span { start, end }: Span) -> &Self::Output {
208        &self[start..end]
209    }
210}