graphql-schema_comparator 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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