graphql-schema_comparator 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,44 @@
1
+ module GraphQL
2
+ module SchemaComparator
3
+ module Diff
4
+ class Argument
5
+ def initialize(type, field, old_arg, new_arg)
6
+ @type = type
7
+ @field = field
8
+
9
+ @old_arg = old_arg
10
+ @new_arg = new_arg
11
+ end
12
+
13
+ def diff
14
+ changes = []
15
+
16
+ if old_arg.description != new_arg.description
17
+ changes << Changes::FieldArgumentDescriptionChanged.new(type, field, old_arg, new_arg)
18
+ end
19
+
20
+ if old_arg.default_value != new_arg.default_value
21
+ changes << Changes::FieldArgumentDefaultChanged.new(type, field, old_arg, new_arg)
22
+ end
23
+
24
+ if old_arg.type != new_arg.type
25
+ changes << Changes::FieldArgumentTypeChanged.new(type, field, old_arg, new_arg)
26
+ end
27
+
28
+ # TODO directives
29
+
30
+ changes
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader(
36
+ :type,
37
+ :field,
38
+ :new_arg,
39
+ :old_arg
40
+ )
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,58 @@
1
+ module GraphQL
2
+ module SchemaComparator
3
+ module Diff
4
+ class Enum
5
+ def initialize(old_type, new_type)
6
+ @old_type = old_type
7
+ @new_type = new_type
8
+
9
+ @old_values = old_type.values
10
+ @new_values = new_type.values
11
+ end
12
+
13
+ def diff
14
+ changes = []
15
+
16
+ changes += removed_values.map { |value| Changes::EnumValueRemoved.new(old_type, value) }
17
+ changes += added_values.map { |value| Changes::EnumValueAdded.new(new_type, value) }
18
+
19
+ each_common_value do |old_value, new_value|
20
+ # TODO: Add Directive Stuff
21
+
22
+ if old_value.description != new_value.description
23
+ changes += Changes::EnumValueDescriptionChanged.new(old_value, new_value)
24
+ end
25
+
26
+ if old_value.deprecation_reason != new_value.deprecation_reason
27
+ changes += Changes::EnumValueDeprecated.new(old_value, new_value)
28
+ end
29
+ end
30
+
31
+ changes
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :old_type, :new_type, :old_values, :new_values
37
+
38
+ def each_common_value(&block)
39
+ intersection = old_values.keys & new_values.keys
40
+ intersection.each do |common_value|
41
+ old_value = old_type.values[common_value]
42
+ new_value = new_type.values[common_value]
43
+
44
+ block.call(old_value, new_value)
45
+ end
46
+ end
47
+
48
+ def removed_values
49
+ (old_values.keys - new_values.keys).map { |removed| old_type.values[removed] }
50
+ end
51
+
52
+ def added_values
53
+ (new_values.keys - old_values.keys).map { |added| new_type.values[added] }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,77 @@
1
+ module GraphQL
2
+ module SchemaComparator
3
+ module Diff
4
+ class Field
5
+ def initialize(old_type, new_type, old_field, new_field)
6
+ @old_type = old_type
7
+ @new_type = new_type
8
+
9
+ @old_field = old_field
10
+ @new_field = new_field
11
+
12
+ @old_arguments = old_field.arguments
13
+ @new_arguments = new_field.arguments
14
+ end
15
+
16
+ def diff
17
+ changes = []
18
+
19
+ if old_field.description != new_field.description
20
+ changes << Changes::FieldDescriptionChanged.new(new_type, old_field, new_field)
21
+ end
22
+
23
+ if old_field.deprecation_reason != new_field.deprecation_reason
24
+ changes << Changes::FieldDeprecationChanged.new(new_type, old_field, new_field)
25
+ end
26
+
27
+ if old_field.type != new_field.type
28
+ changes << Changes::FieldTypeChanged.new(new_type, old_field, new_field)
29
+ end
30
+
31
+ changes += arg_removals
32
+
33
+ changes += arg_additions
34
+
35
+ each_common_argument do |old_arg, new_arg|
36
+ changes += Diff::Argument.new(new_type, new_field, old_arg, new_arg).diff
37
+ end
38
+
39
+ # TODO: directives
40
+
41
+ changes
42
+ end
43
+
44
+ private
45
+
46
+ attr_reader(
47
+ :old_type,
48
+ :new_type,
49
+ :new_field,
50
+ :old_field,
51
+ :old_arguments,
52
+ :new_arguments
53
+ )
54
+
55
+ def arg_removals
56
+ removed = old_arguments.values.select { |arg| !new_arguments[arg.name] }
57
+ removed.map { |arg| Changes::FieldArgumentRemoved.new(new_type, old_field, arg) }
58
+ end
59
+
60
+ def arg_additions
61
+ removed = new_arguments.values.select { |arg| !old_arguments[arg.name] }
62
+ removed.map { |arg| Changes::FieldArgumentAdded.new(new_type, new_field, arg) }
63
+ end
64
+
65
+ def each_common_argument(&block)
66
+ intersection = old_arguments.keys & new_arguments.keys
67
+ intersection.each do |common_arg|
68
+ old_arg = old_field.arguments[common_arg]
69
+ new_arg = new_field.arguments[common_arg]
70
+
71
+ block.call(old_arg, new_arg)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,39 @@
1
+ module GraphQL
2
+ module SchemaComparator
3
+ module Diff
4
+ class InputField
5
+ def initialize(old_type, new_type, old_field, new_field)
6
+ @old_type = old_type
7
+ @new_type = new_type
8
+
9
+ @old_field = old_field
10
+ @new_field = new_field
11
+ end
12
+
13
+ def diff
14
+ changes = []
15
+
16
+ if old_field.description != new_field.description
17
+ changes << Changes::InputFieldDescriptionChanged.new(old_type, old_field, new_field)
18
+ end
19
+
20
+ if old_field.default_value != new_field.default_value
21
+ changes << Changes::InputFieldDefaultChanged.new(old_type, old_field, new_field)
22
+ end
23
+
24
+ if old_field.type != new_field.type
25
+ changes << Changes::InputFieldTypeChanged.new(old_type, old_field, new_field)
26
+ end
27
+
28
+ # TODO: directives
29
+
30
+ changes
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :old_type, :new_type, :new_field, :old_field
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,51 @@
1
+ module GraphQL
2
+ module SchemaComparator
3
+ module Diff
4
+ class InputObject
5
+ def initialize(old_type, new_type)
6
+ @old_type = old_type
7
+ @new_type = new_type
8
+
9
+ @old_fields = old_type.arguments
10
+ @new_fields = new_type.arguments
11
+ end
12
+
13
+ def diff
14
+ changes = []
15
+
16
+ changes += removed_fields.map { |field| Changes::InputFieldRemoved.new(old_type, field) }
17
+ changes += added_fields.map { |field| Changes::InputFieldAdded.new(new_type, field) }
18
+
19
+ each_common_field do |old_field, new_field|
20
+ # TODO: Add Directive Stuff
21
+ changes += InputField.new(old_type, new_type, old_field, new_field).diff
22
+ end
23
+
24
+ changes
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :old_type, :new_type, :old_fields, :new_fields
30
+
31
+ def each_common_field(&block)
32
+ intersection = old_fields.keys & new_fields.keys
33
+ intersection.each do |common_field|
34
+ old_field = old_type.arguments[common_field]
35
+ new_field = new_type.arguments[common_field]
36
+
37
+ block.call(old_field, new_field)
38
+ end
39
+ end
40
+
41
+ def removed_fields
42
+ old_fields.values.select { |field| !new_fields[field.name] }
43
+ end
44
+
45
+ def added_fields
46
+ new_fields.values.select { |field| !old_fields[field.name] }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,51 @@
1
+ module GraphQL
2
+ module SchemaComparator
3
+ module Diff
4
+ class Interface
5
+ def initialize(old_iface, new_iface)
6
+ @old_iface = old_iface
7
+ @new_iface = new_iface
8
+
9
+ @old_fields = old_iface.fields
10
+ @new_fields = new_iface.fields
11
+ end
12
+
13
+ def diff
14
+ changes = []
15
+ changes += field_removals
16
+ changes += field_additions
17
+
18
+ each_common_field do |old_field, new_field|
19
+ changes += Diff::Field.new(old_iface, new_iface, old_field, new_field).diff
20
+ end
21
+
22
+ changes
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :old_iface, :new_iface, :old_fields, :new_fields
28
+
29
+ def field_removals
30
+ removed = old_fields.values.select { |field| !new_fields[field.name] }
31
+ removed.map { |field| Changes::FieldRemoved.new(old_iface, field) }
32
+ end
33
+
34
+ def field_additions
35
+ added = new_fields.values.select { |field| !old_fields[field.name] }
36
+ added.map { |field| Changes::FieldAdded.new(new_iface, field) }
37
+ end
38
+
39
+ def each_common_field(&block)
40
+ intersection = old_fields.keys & new_fields.keys
41
+ intersection.each do |common_field|
42
+ old_field = old_iface.fields[common_field]
43
+ new_field = new_iface.fields[common_field]
44
+
45
+ block.call(old_field, new_field)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,74 @@
1
+ module GraphQL
2
+ module SchemaComparator
3
+ module Diff
4
+ class ObjectType
5
+ def initialize(old_type, new_type)
6
+ @old_type = old_type
7
+ @new_type = new_type
8
+
9
+ @old_fields = old_type.fields
10
+ @new_fields = new_type.fields
11
+
12
+ @old_interfaces = old_type.interfaces
13
+ @new_interfaces = new_type.interfaces
14
+ end
15
+
16
+ def diff
17
+ changes = []
18
+
19
+ changes += interface_additions
20
+ changes += interface_removals
21
+ changes += field_removals
22
+ changes += field_additions
23
+
24
+ each_common_field do |old_field, new_field|
25
+ changes += Diff::Field.new(old_type, new_type, old_field, new_field).diff
26
+ end
27
+
28
+ changes
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader(
34
+ :old_type,
35
+ :new_type,
36
+ :old_fields,
37
+ :new_fields,
38
+ :old_interfaces,
39
+ :new_interfaces
40
+ )
41
+
42
+ def interface_removals
43
+ removed = old_interfaces.select { |iface| !new_interfaces.include?(iface) }
44
+ removed.map { |iface| Changes::ObjectTypeInterfaceRemoved.new(iface, old_type) }
45
+ end
46
+
47
+ def interface_additions
48
+ added = new_interfaces.select { |iface| !old_interfaces.include?(iface) }
49
+ added.map { |iface| Changes::ObjectTypeInterfaceAdded.new(iface, new_type) }
50
+ end
51
+
52
+ def field_removals
53
+ removed = old_fields.values.select { |field| !new_fields[field.name] }
54
+ removed.map { |field| Changes::FieldRemoved.new(old_type, field) }
55
+ end
56
+
57
+ def field_additions
58
+ added = new_fields.values.select { |field| !old_fields[field.name] }
59
+ added.map { |field| Changes::FieldAdded.new(new_type, field) }
60
+ end
61
+
62
+ def each_common_field(&block)
63
+ intersection = old_fields.keys & new_fields.keys
64
+ intersection.each do |common_field|
65
+ old_field = old_type.fields[common_field]
66
+ new_field = new_type.fields[common_field]
67
+
68
+ block.call(old_field, new_field)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,117 @@
1
+ require "graphql/schema_comparator/diff/enum"
2
+ require "graphql/schema_comparator/diff/union"
3
+ require "graphql/schema_comparator/diff/input_object"
4
+ require "graphql/schema_comparator/diff/input_field"
5
+ require "graphql/schema_comparator/diff/object_type"
6
+ require "graphql/schema_comparator/diff/interface"
7
+ require "graphql/schema_comparator/diff/field"
8
+ require "graphql/schema_comparator/diff/argument"
9
+
10
+ module GraphQL
11
+ module SchemaComparator
12
+ module Diff
13
+ class Schema
14
+ def initialize(old_schema, new_schema)
15
+ @old_schema = old_schema
16
+ @new_schema = new_schema
17
+
18
+ @old_types = old_schema.types
19
+ @new_types = new_schema.types
20
+ end
21
+
22
+ def diff
23
+ changes = []
24
+
25
+ # Removed and Added Types
26
+ changes += removed_types.map { |type| Changes::TypeRemoved.new(type) }
27
+ changes += added_types.map { |type| Changes::TypeAdded.new(type) }
28
+
29
+ # Type Diff for common types
30
+ each_common_type do |old_type, new_type|
31
+ changes += changes_in_type(old_type, new_type)
32
+ end
33
+
34
+ # Diff Schemas
35
+ changes += changes_in_schema
36
+
37
+ # Diff Directives
38
+ changes += changes_in_directives
39
+
40
+ changes
41
+ end
42
+
43
+ def changes_in_type(old_type, new_type)
44
+ changes = []
45
+
46
+ if old_type.kind != new_type.kind
47
+ changes << Changes::TypeKindChanged.new(old_type, new_type)
48
+ else
49
+ case old_type
50
+ when GraphQL::EnumType
51
+ changes += Diff::Enum.new(old_type, new_type).diff
52
+ when GraphQL::UnionType
53
+ changes += Diff::Union.new(old_type, new_type).diff
54
+ when GraphQL::InputObjectType
55
+ changes += Diff::InputObject.new(old_type, new_type).diff
56
+ when GraphQL::ObjectType
57
+ changes += Diff::ObjectType.new(old_type, new_type).diff
58
+ when GraphQL::InterfaceType
59
+ changes += Diff::Interface.new(old_type, new_type).diff
60
+ end
61
+ end
62
+
63
+ if old_type.description != new_type.description
64
+ changes << Changes::TypeDescriptionChanged.new(old_type, new_type)
65
+ end
66
+
67
+ changes
68
+ end
69
+
70
+ def changes_in_schema
71
+ changes = []
72
+
73
+ if old_schema.query != new_schema.query
74
+ changes << Changes::SchemaQueryTypeChanged.new(old_schema, new_schema)
75
+ end
76
+
77
+ if old_schema.mutation != new_schema.mutation
78
+ changes << Changes::SchemaMutationTypeChanged.new(old_schema, new_schema)
79
+ end
80
+
81
+ if old_schema.subscription != new_schema.subscription
82
+ changes << Changes::SchemaSubscriptionTypeChanged.new(old_schema, new_schema)
83
+ end
84
+
85
+ changes
86
+ end
87
+
88
+ def changes_in_directives
89
+ # TODO
90
+ []
91
+ end
92
+
93
+ private
94
+
95
+ def each_common_type(&block)
96
+ intersection = old_types.keys & new_types.keys
97
+ intersection.each do |common_type_name|
98
+ old_type = old_schema.types[common_type_name]
99
+ new_type = new_schema.types[common_type_name]
100
+
101
+ block.call(old_type, new_type)
102
+ end
103
+ end
104
+
105
+ def removed_types
106
+ (old_types.keys - new_types.keys).map { |type_name| old_schema.types[type_name] }
107
+ end
108
+
109
+ def added_types
110
+ (new_types.keys - old_types.keys).map { |type_name| new_schema.types[type_name] }
111
+ end
112
+
113
+ attr_reader :old_schema, :new_schema, :old_types, :new_types
114
+ end
115
+ end
116
+ end
117
+ end