graphql-client 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/graphql/client.rb +20 -10
- data/lib/graphql/client/definition.rb +116 -23
- data/lib/graphql/client/deprecation.rb +2 -2
- data/lib/graphql/client/document_types.rb +3 -0
- data/lib/graphql/client/error.rb +3 -0
- data/lib/graphql/client/response.rb +2 -2
- data/lib/graphql/client/schema.rb +106 -0
- data/lib/graphql/client/schema/base_type.rb +39 -0
- data/lib/graphql/client/schema/enum_type.rb +56 -0
- data/lib/graphql/client/schema/include_directive.rb +44 -0
- data/lib/graphql/client/schema/interface_type.rb +31 -0
- data/lib/graphql/client/schema/list_type.rb +57 -0
- data/lib/graphql/client/schema/non_null_type.rb +52 -0
- data/lib/graphql/client/schema/object_type.rb +162 -0
- data/lib/graphql/client/schema/possible_types.rb +55 -0
- data/lib/graphql/client/schema/scalar_type.rb +47 -0
- data/lib/graphql/client/schema/skip_directive.rb +44 -0
- data/lib/graphql/client/schema/union_type.rb +31 -0
- metadata +14 -3
- data/lib/graphql/client/query_result.rb +0 -402
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "graphql/client/error"
|
4
|
+
require "graphql/client/schema/base_type"
|
5
|
+
|
6
|
+
module GraphQL
|
7
|
+
class Client
|
8
|
+
module Schema
|
9
|
+
class EnumType < Module
|
10
|
+
include BaseType
|
11
|
+
|
12
|
+
# Internal: Construct enum wrapper from another GraphQL::EnumType.
|
13
|
+
#
|
14
|
+
# type - GraphQL::EnumType instance
|
15
|
+
def initialize(type)
|
16
|
+
unless type.is_a?(GraphQL::EnumType)
|
17
|
+
raise "expected type to be a GraphQL::EnumType, but was #{type.class}"
|
18
|
+
end
|
19
|
+
|
20
|
+
@type = type
|
21
|
+
|
22
|
+
all_values = type.values.keys
|
23
|
+
|
24
|
+
all_values.each do |value|
|
25
|
+
str = value.dup
|
26
|
+
all_values.each do |v|
|
27
|
+
str.define_singleton_method("#{v.downcase}?") { false }
|
28
|
+
end
|
29
|
+
str.define_singleton_method("#{value.downcase}?") { true }
|
30
|
+
str.freeze
|
31
|
+
const_set(value, str)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def define_class(definition, irep_node)
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
# Internal: Cast JSON value to wrapped value.
|
40
|
+
#
|
41
|
+
# values - JSON value
|
42
|
+
# errors - Errors instance
|
43
|
+
#
|
44
|
+
# Returns String or nil.
|
45
|
+
def cast(value, _errors = nil)
|
46
|
+
case value
|
47
|
+
when String, NilClass
|
48
|
+
value
|
49
|
+
else
|
50
|
+
raise InvariantError, "expected value to be a String, but was #{value.class}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "graphql/client/schema/base_type"
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
class Client
|
7
|
+
module Schema
|
8
|
+
class IncludeDirective
|
9
|
+
include BaseType
|
10
|
+
|
11
|
+
# Internal: Construct list wrapper from other BaseType.
|
12
|
+
#
|
13
|
+
# of_klass - BaseType instance
|
14
|
+
def initialize(of_klass)
|
15
|
+
unless of_klass.is_a?(BaseType)
|
16
|
+
raise TypeError, "expected #{of_klass.inspect} to be a #{BaseType}"
|
17
|
+
end
|
18
|
+
|
19
|
+
@of_klass = of_klass
|
20
|
+
end
|
21
|
+
|
22
|
+
# Internal: Get wrapped klass.
|
23
|
+
#
|
24
|
+
# Returns BaseType instance.
|
25
|
+
attr_reader :of_klass
|
26
|
+
|
27
|
+
# Internal: Cast JSON value to wrapped value.
|
28
|
+
#
|
29
|
+
# values - JSON value
|
30
|
+
# errors - Errors instance
|
31
|
+
#
|
32
|
+
# Returns List instance or nil.
|
33
|
+
def cast(value, errors)
|
34
|
+
case value
|
35
|
+
when NilClass
|
36
|
+
nil
|
37
|
+
else
|
38
|
+
of_klass.cast(value, errors)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "graphql/client/schema/possible_types"
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
class Client
|
7
|
+
module Schema
|
8
|
+
class InterfaceType < Module
|
9
|
+
include BaseType
|
10
|
+
|
11
|
+
def initialize(type)
|
12
|
+
unless type.is_a?(GraphQL::InterfaceType)
|
13
|
+
raise "expected type to be a GraphQL::InterfaceType, but was #{type.class}"
|
14
|
+
end
|
15
|
+
|
16
|
+
@type = type
|
17
|
+
end
|
18
|
+
|
19
|
+
def new(types)
|
20
|
+
PossibleTypes.new(type, types)
|
21
|
+
end
|
22
|
+
|
23
|
+
def define_class(definition, irep_node)
|
24
|
+
new(irep_node.typed_children.keys.map { |ctype|
|
25
|
+
schema_module.const_get(ctype.name).define_class(definition, irep_node)
|
26
|
+
})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "graphql/client/error"
|
4
|
+
require "graphql/client/list"
|
5
|
+
require "graphql/client/schema/base_type"
|
6
|
+
|
7
|
+
module GraphQL
|
8
|
+
class Client
|
9
|
+
module Schema
|
10
|
+
class ListType
|
11
|
+
include BaseType
|
12
|
+
|
13
|
+
# Internal: Construct list wrapper from other BaseType.
|
14
|
+
#
|
15
|
+
# of_klass - BaseType instance
|
16
|
+
def initialize(of_klass)
|
17
|
+
unless of_klass.is_a?(BaseType)
|
18
|
+
raise TypeError, "expected #{of_klass.inspect} to be a #{BaseType}"
|
19
|
+
end
|
20
|
+
|
21
|
+
@of_klass = of_klass
|
22
|
+
end
|
23
|
+
|
24
|
+
# Internal: Get wrapped klass.
|
25
|
+
#
|
26
|
+
# Returns BaseType instance.
|
27
|
+
attr_reader :of_klass
|
28
|
+
|
29
|
+
# Internal: Cast JSON value to wrapped value.
|
30
|
+
#
|
31
|
+
# values - JSON value
|
32
|
+
# errors - Errors instance
|
33
|
+
#
|
34
|
+
# Returns List instance or nil.
|
35
|
+
def cast(values, errors)
|
36
|
+
case values
|
37
|
+
when Array
|
38
|
+
List.new(values.each_with_index.map { |e, idx|
|
39
|
+
of_klass.cast(e, errors.filter_by_path(idx))
|
40
|
+
}, errors)
|
41
|
+
when NilClass
|
42
|
+
nil
|
43
|
+
else
|
44
|
+
raise InvariantError, "expected value to be a list, but was #{values.class}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Internal: Get list wrapper of this type class.
|
49
|
+
#
|
50
|
+
# Returns ListType instance.
|
51
|
+
def to_list_type
|
52
|
+
self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "graphql/client/error"
|
4
|
+
require "graphql/client/schema/base_type"
|
5
|
+
|
6
|
+
module GraphQL
|
7
|
+
class Client
|
8
|
+
module Schema
|
9
|
+
class NonNullType
|
10
|
+
include BaseType
|
11
|
+
|
12
|
+
# Internal: Construct non-nullable wrapper from other BaseType.
|
13
|
+
#
|
14
|
+
# of_klass - BaseType instance
|
15
|
+
def initialize(of_klass)
|
16
|
+
unless of_klass.is_a?(BaseType)
|
17
|
+
raise TypeError, "expected #{of_klass.inspect} to be a #{BaseType}"
|
18
|
+
end
|
19
|
+
|
20
|
+
@of_klass = of_klass
|
21
|
+
end
|
22
|
+
|
23
|
+
# Internal: Get wrapped klass.
|
24
|
+
#
|
25
|
+
# Returns BaseType instance.
|
26
|
+
attr_reader :of_klass
|
27
|
+
|
28
|
+
# Internal: Cast JSON value to wrapped value.
|
29
|
+
#
|
30
|
+
# value - JSON value
|
31
|
+
# errors - Errors instance
|
32
|
+
#
|
33
|
+
# Returns BaseType instance.
|
34
|
+
def cast(value, errors)
|
35
|
+
case value
|
36
|
+
when NilClass
|
37
|
+
raise InvariantError, "expected value to be non-nullable, but was nil"
|
38
|
+
else
|
39
|
+
of_klass.cast(value, errors)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Internal: Get non-nullable wrapper of this type class.
|
44
|
+
#
|
45
|
+
# Returns NonNullType instance.
|
46
|
+
def to_non_null_type
|
47
|
+
self
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/inflector"
|
4
|
+
require "graphql/client/deprecation"
|
5
|
+
require "graphql/client/error"
|
6
|
+
require "graphql/client/errors"
|
7
|
+
require "graphql/client/schema/base_type"
|
8
|
+
require "graphql/client/schema/possible_types"
|
9
|
+
|
10
|
+
module GraphQL
|
11
|
+
class Client
|
12
|
+
module Schema
|
13
|
+
module ObjectType
|
14
|
+
def self.new(type, fields = {})
|
15
|
+
Class.new(ObjectClass) do
|
16
|
+
extend BaseType
|
17
|
+
extend ObjectType
|
18
|
+
|
19
|
+
define_singleton_method(:type) { type }
|
20
|
+
define_singleton_method(:fields) { fields }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def define_class(definition, irep_node)
|
25
|
+
fields = irep_node.typed_children[type].inject({}) { |h, (field_name, field_irep_node)|
|
26
|
+
if definition.indexes[:definitions][field_irep_node.ast_node] == definition.definition_node
|
27
|
+
h[field_name.to_sym] = schema_module.define_class(definition, field_irep_node, field_irep_node.definition.type)
|
28
|
+
end
|
29
|
+
h
|
30
|
+
}
|
31
|
+
|
32
|
+
Class.new(self) do
|
33
|
+
define_fields(fields)
|
34
|
+
|
35
|
+
if definition.client.enforce_collocated_callers
|
36
|
+
Client.enforce_collocated_callers(self, fields.keys, definition.source_location[0])
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
attr_reader :source_definition
|
41
|
+
attr_reader :_spreads
|
42
|
+
end
|
43
|
+
|
44
|
+
@source_definition = definition
|
45
|
+
@_spreads = definition.indexes[:spreads][irep_node.ast_node]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def define_fields(fields)
|
50
|
+
fields.each { |name, type| define_field(name, type) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def define_field(name, type)
|
54
|
+
name = name.to_s
|
55
|
+
method_name = ActiveSupport::Inflector.underscore(name)
|
56
|
+
|
57
|
+
define_method(method_name) do
|
58
|
+
@casted_data.fetch(name) do
|
59
|
+
@casted_data[name] = type.cast(@data[name], @errors.filter_by_path(name))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
define_method("#{method_name}?") do
|
64
|
+
@data[name] ? true : false
|
65
|
+
end
|
66
|
+
|
67
|
+
if name != method_name
|
68
|
+
define_method(name) do
|
69
|
+
@casted_data.fetch(name) do
|
70
|
+
@casted_data[name] = type.cast(@data[name], @errors.filter_by_path(name))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
Deprecation.deprecate_methods(self, name => "Use ##{method_name} instead")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def cast(value, errors)
|
78
|
+
case value
|
79
|
+
when Hash
|
80
|
+
new(value, errors)
|
81
|
+
when NilClass
|
82
|
+
nil
|
83
|
+
else
|
84
|
+
raise InvariantError, "expected value to be a Hash, but was #{value.class}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class ObjectClass
|
90
|
+
def initialize(data = {}, errors = Errors.new)
|
91
|
+
@data = data
|
92
|
+
@casted_data = {}
|
93
|
+
@errors = errors
|
94
|
+
end
|
95
|
+
|
96
|
+
# Public: Returns the raw response data
|
97
|
+
#
|
98
|
+
# Returns Hash
|
99
|
+
def to_h
|
100
|
+
@data
|
101
|
+
end
|
102
|
+
|
103
|
+
# Public: Return errors associated with data.
|
104
|
+
#
|
105
|
+
# Returns Errors collection.
|
106
|
+
attr_reader :errors
|
107
|
+
|
108
|
+
def method_missing(*args)
|
109
|
+
super
|
110
|
+
rescue NoMethodError => e
|
111
|
+
type = self.class.type
|
112
|
+
|
113
|
+
field = type.all_fields.find do |f|
|
114
|
+
f.name == e.name.to_s || ActiveSupport::Inflector.underscore(f.name) == e.name.to_s
|
115
|
+
end
|
116
|
+
|
117
|
+
unless field
|
118
|
+
raise UnimplementedFieldError, "undefined field `#{e.name}' on #{type} type. https://git.io/v1y3m"
|
119
|
+
end
|
120
|
+
|
121
|
+
if @data.key?(field.name)
|
122
|
+
error_class = ImplicitlyFetchedFieldError
|
123
|
+
message = "implicitly fetched field `#{field.name}' on #{type} type. https://git.io/v1yGL"
|
124
|
+
else
|
125
|
+
error_class = UnfetchedFieldError
|
126
|
+
message = "unfetched field `#{field.name}' on #{type} type. https://git.io/v1y3U"
|
127
|
+
end
|
128
|
+
|
129
|
+
raise error_class, message
|
130
|
+
end
|
131
|
+
|
132
|
+
def inspect
|
133
|
+
parent = self.class.ancestors.select { |m| m.is_a?(ObjectType) }.last
|
134
|
+
|
135
|
+
ivars = @data.map { |key, value|
|
136
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
137
|
+
"#{key}=..."
|
138
|
+
else
|
139
|
+
"#{key}=#{value.inspect}"
|
140
|
+
end
|
141
|
+
}
|
142
|
+
|
143
|
+
buf = "#<#{parent.name}".dup
|
144
|
+
buf << " " << ivars.join(" ") if ivars.any?
|
145
|
+
buf << ">"
|
146
|
+
buf
|
147
|
+
end
|
148
|
+
|
149
|
+
def typename
|
150
|
+
Deprecation.deprecation_warning("typename", "Use #class.type.name instead")
|
151
|
+
self.class.type.name
|
152
|
+
end
|
153
|
+
|
154
|
+
def type_of?(*types)
|
155
|
+
Deprecation.deprecation_warning("type_of?", "Use #is_a? instead")
|
156
|
+
names = ([self.class.type] + self.class.ancestors.select { |m| m.is_a?(InterfaceType) || m.is_a?(UnionType) }.map(&:type)).map(&:name)
|
157
|
+
types.any? { |type| names.include?(type.to_s) }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "graphql/client/error"
|
4
|
+
require "graphql/client/schema/base_type"
|
5
|
+
require "graphql/client/schema/object_type"
|
6
|
+
|
7
|
+
module GraphQL
|
8
|
+
class Client
|
9
|
+
module Schema
|
10
|
+
class PossibleTypes
|
11
|
+
include BaseType
|
12
|
+
|
13
|
+
def initialize(type, types)
|
14
|
+
@type = type
|
15
|
+
|
16
|
+
unless types.is_a?(Enumerable)
|
17
|
+
raise TypeError, "expected types to be Enumerable, but was #{types.class}"
|
18
|
+
end
|
19
|
+
|
20
|
+
@possible_types = {}
|
21
|
+
types.each do |klass|
|
22
|
+
unless klass.is_a?(ObjectType)
|
23
|
+
raise TypeError, "expected type to be #{ObjectType}, but was #{type.class}"
|
24
|
+
end
|
25
|
+
@possible_types[klass.type.name] = klass
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :possible_types
|
30
|
+
|
31
|
+
# Internal: Cast JSON value to wrapped value.
|
32
|
+
#
|
33
|
+
# value - JSON value
|
34
|
+
# errors - Errors instance
|
35
|
+
#
|
36
|
+
# Returns BaseType instance.
|
37
|
+
def cast(value, errors)
|
38
|
+
case value
|
39
|
+
when Hash
|
40
|
+
typename = value["__typename"]
|
41
|
+
if type = possible_types[typename]
|
42
|
+
type.cast(value, errors)
|
43
|
+
else
|
44
|
+
raise InvariantError, "expected value to be one of (#{possible_types.keys.join(", ")}), but was #{typename}"
|
45
|
+
end
|
46
|
+
when NilClass
|
47
|
+
nil
|
48
|
+
else
|
49
|
+
raise InvariantError, "expected value to be a Hash, but was #{value.class}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|