graphql 1.4.2 → 1.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/define/defined_object_proxy.rb +3 -12
- data/lib/graphql/field.rb +5 -1
- data/lib/graphql/language/lexer.rb +2 -2
- data/lib/graphql/language/lexer.rl +2 -2
- data/lib/graphql/relay/mutation.rb +8 -8
- data/lib/graphql/relay/node.rb +21 -4
- data/lib/graphql/schema/validation.rb +3 -3
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/define/instance_definable_spec.rb +18 -0
- data/spec/graphql/relay/mutation_spec.rb +23 -0
- data/spec/graphql/relay/node_spec.rb +54 -1
- data/spec/support/star_wars/schema.rb +13 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cda98acc4cef5d2d8e4c9c77cd9ac5f5139cc38a
|
4
|
+
data.tar.gz: 184b72d444de078b443453bca6f0a4d64d8cf0b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf7c368fd8d9ef704580aa2956e2813db1e3efbd748f1d9836d58b17ae5afaca3df2d623750dd9546688e42ab1cb5c0be26f6bbe46ea3f7d837788c8fc00fe92
|
7
|
+
data.tar.gz: ce531eb4ad6cd87b947c9c5fbd68d5cd14fef266950a3448e02659d02e8bc7db10c7d9d206ea12751d059c01392ed952facf938c3cddfd53dfb21404b554d83f
|
@@ -16,22 +16,13 @@ module GraphQL
|
|
16
16
|
if definition
|
17
17
|
definition.call(@target, *args, &block)
|
18
18
|
else
|
19
|
-
|
20
|
-
|
19
|
+
msg = "#{@target.class.name} can't define '#{name}'"
|
20
|
+
raise NoMethodError, msg, caller
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
def respond_to_missing?(name, include_private = false)
|
25
|
-
|
26
|
-
super
|
27
|
-
end
|
28
|
-
|
29
|
-
def to_s
|
30
|
-
inspect
|
31
|
-
end
|
32
|
-
|
33
|
-
def inspect
|
34
|
-
"<DefinedObjectProxy #{@target} (#{@dictionary.keys})>"
|
25
|
+
@dictionary[name] || super
|
35
26
|
end
|
36
27
|
end
|
37
28
|
end
|
data/lib/graphql/field.rb
CHANGED
@@ -126,18 +126,22 @@ module GraphQL
|
|
126
126
|
:type, :arguments,
|
127
127
|
:property, :hash_key, :complexity, :mutation,
|
128
128
|
:relay_node_field,
|
129
|
+
:relay_nodes_field,
|
129
130
|
argument: GraphQL::Define::AssignArgument
|
130
131
|
|
131
132
|
ensure_defined(
|
132
133
|
:name, :deprecation_reason, :description, :description=, :property, :hash_key, :mutation, :arguments, :complexity,
|
133
134
|
:resolve, :resolve=, :lazy_resolve, :lazy_resolve=, :lazy_resolve_proc, :resolve_proc,
|
134
135
|
:type, :type=, :name=, :property=, :hash_key=,
|
135
|
-
:relay_node_field,
|
136
|
+
:relay_node_field, :relay_nodes_field,
|
136
137
|
)
|
137
138
|
|
138
139
|
# @return [Boolean] True if this is the Relay find-by-id field
|
139
140
|
attr_accessor :relay_node_field
|
140
141
|
|
142
|
+
# @return [Boolean] True if this is the Relay find-by-ids field
|
143
|
+
attr_accessor :relay_nodes_field
|
144
|
+
|
141
145
|
# @return [<#call(obj, args, ctx)>] A proc-like object which can be called to return the field's value
|
142
146
|
attr_reader :resolve_proc
|
143
147
|
|
@@ -990,7 +990,7 @@ end
|
|
990
990
|
def self.record_comment(ts, te, meta)
|
991
991
|
token = GraphQL::Language::Token.new(
|
992
992
|
name: :COMMENT,
|
993
|
-
value: meta[:data][ts...te].pack("c*"),
|
993
|
+
value: meta[:data][ts...te].pack("c*").force_encoding("UTF-8"),
|
994
994
|
line: meta[:line],
|
995
995
|
col: meta[:col],
|
996
996
|
prev_token: meta[:previous_token],
|
@@ -1004,7 +1004,7 @@ end
|
|
1004
1004
|
def self.emit(token_name, ts, te, meta)
|
1005
1005
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
1006
1006
|
name: token_name,
|
1007
|
-
value: meta[:data][ts...te].pack("c*"),
|
1007
|
+
value: meta[:data][ts...te].pack("c*").force_encoding("UTF-8"),
|
1008
1008
|
line: meta[:line],
|
1009
1009
|
col: meta[:col],
|
1010
1010
|
prev_token: meta[:previous_token],
|
@@ -145,7 +145,7 @@ module GraphQL
|
|
145
145
|
def self.record_comment(ts, te, meta)
|
146
146
|
token = GraphQL::Language::Token.new(
|
147
147
|
name: :COMMENT,
|
148
|
-
value: meta[:data][ts...te].pack("c*"),
|
148
|
+
value: meta[:data][ts...te].pack("c*").force_encoding("UTF-8"),
|
149
149
|
line: meta[:line],
|
150
150
|
col: meta[:col],
|
151
151
|
prev_token: meta[:previous_token],
|
@@ -159,7 +159,7 @@ module GraphQL
|
|
159
159
|
def self.emit(token_name, ts, te, meta)
|
160
160
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
161
161
|
name: token_name,
|
162
|
-
value: meta[:data][ts...te].pack("c*"),
|
162
|
+
value: meta[:data][ts...te].pack("c*").force_encoding("UTF-8"),
|
163
163
|
line: meta[:line],
|
164
164
|
col: meta[:col],
|
165
165
|
prev_token: meta[:previous_token],
|
@@ -177,23 +177,23 @@ module GraphQL
|
|
177
177
|
def call(obj, args, ctx)
|
178
178
|
mutation_result = @resolve.call(obj, args[:input], ctx)
|
179
179
|
|
180
|
-
if mutation_result.is_a?(GraphQL::ExecutionError)
|
181
|
-
ctx.add_error(mutation_result)
|
182
|
-
mutation_result = nil
|
183
|
-
end
|
184
|
-
|
185
180
|
if ctx.schema.lazy?(mutation_result)
|
186
181
|
@mutation.field.prepare_lazy(mutation_result, args, ctx).then { |inner_obj|
|
187
|
-
build_result(inner_obj, args)
|
182
|
+
build_result(inner_obj, args, ctx)
|
188
183
|
}
|
189
184
|
else
|
190
|
-
build_result(mutation_result, args)
|
185
|
+
build_result(mutation_result, args, ctx)
|
191
186
|
end
|
192
187
|
end
|
193
188
|
|
194
189
|
private
|
195
190
|
|
196
|
-
def build_result(mutation_result, args)
|
191
|
+
def build_result(mutation_result, args, ctx)
|
192
|
+
if mutation_result.is_a?(GraphQL::ExecutionError)
|
193
|
+
ctx.add_error(mutation_result)
|
194
|
+
mutation_result = nil
|
195
|
+
end
|
196
|
+
|
197
197
|
if @wrap_result
|
198
198
|
@mutation.result_class.new(client_mutation_id: args[:input][:clientMutationId], result: mutation_result)
|
199
199
|
else
|
data/lib/graphql/relay/node.rb
CHANGED
@@ -17,13 +17,30 @@ module GraphQL
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
def self.plural_field
|
21
|
+
GraphQL::Field.define do
|
22
|
+
type(!types[GraphQL::Relay::Node.interface])
|
23
|
+
description("Fetches a list of objects given a list of IDs.")
|
24
|
+
argument(:ids, !types[!types.ID], "IDs of the objects.")
|
25
|
+
resolve(GraphQL::Relay::Node::FindNodes)
|
26
|
+
relay_nodes_field(true)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
20
30
|
# @return [GraphQL::InterfaceType] The interface which all Relay types must implement
|
21
31
|
def self.interface
|
22
32
|
@interface ||= GraphQL::InterfaceType.define do
|
23
|
-
name
|
24
|
-
description
|
25
|
-
field
|
26
|
-
default_relay
|
33
|
+
name("Node")
|
34
|
+
description("An object with an ID.")
|
35
|
+
field(:id, !types.ID, "ID of the object.")
|
36
|
+
default_relay(true)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# A field resolve for finding objects by IDs
|
41
|
+
module FindNodes
|
42
|
+
def self.call(obj, args, ctx)
|
43
|
+
args[:ids].map { |id| ctx.query.schema.object_from_id(id, ctx) }
|
27
44
|
end
|
28
45
|
end
|
29
46
|
|
@@ -132,7 +132,7 @@ module GraphQL
|
|
132
132
|
|
133
133
|
SCHEMA_CAN_RESOLVE_TYPES = ->(schema) {
|
134
134
|
if schema.types.values.any? { |type| type.kind.resolves? } && schema.resolve_type_proc.nil?
|
135
|
-
"schema contains Interfaces or Unions, so you must define a `resolve_type (obj, ctx)
|
135
|
+
"schema contains Interfaces or Unions, so you must define a `resolve_type -> (obj, ctx) { ... }` function"
|
136
136
|
else
|
137
137
|
# :+1:
|
138
138
|
end
|
@@ -141,7 +141,7 @@ module GraphQL
|
|
141
141
|
SCHEMA_CAN_FETCH_IDS = ->(schema) {
|
142
142
|
has_node_field = schema.query && schema.query.all_fields.any?(&:relay_node_field)
|
143
143
|
if has_node_field && schema.object_from_id_proc.nil?
|
144
|
-
"schema contains `node(id:...)` field, so you must define a `object_from_id (id, ctx)
|
144
|
+
"schema contains `node(id:...)` field, so you must define a `object_from_id -> (id, ctx) { ... }` function"
|
145
145
|
else
|
146
146
|
# :rocket:
|
147
147
|
end
|
@@ -150,7 +150,7 @@ module GraphQL
|
|
150
150
|
SCHEMA_CAN_GENERATE_IDS = ->(schema) {
|
151
151
|
has_id_field = schema.types.values.any? { |t| t.kind.fields? && t.all_fields.any? { |f| f.resolve_proc.is_a?(GraphQL::Relay::GlobalIdResolve) } }
|
152
152
|
if has_id_field && schema.id_from_object_proc.nil?
|
153
|
-
"schema contains `global_id_field`, so you must define a `id_from_object (obj, type, ctx)
|
153
|
+
"schema contains `global_id_field`, so you must define a `id_from_object -> (obj, type, ctx) { ... }` function"
|
154
154
|
else
|
155
155
|
# :ok_hand:
|
156
156
|
end
|
data/lib/graphql/version.rb
CHANGED
@@ -115,4 +115,22 @@ describe GraphQL::Define::InstanceDefinable do
|
|
115
115
|
assert_equal :green, arugula.metadata[:color]
|
116
116
|
end
|
117
117
|
end
|
118
|
+
|
119
|
+
describe "typos" do
|
120
|
+
it "provides the right class name, method name and line number" do
|
121
|
+
err = assert_raises(NoMethodError) {
|
122
|
+
beet = Garden::Vegetable.define {
|
123
|
+
name "Beet"
|
124
|
+
nonsense :Blah
|
125
|
+
}
|
126
|
+
beet.name
|
127
|
+
}
|
128
|
+
assert_includes err.message, "Garden::Vegetable"
|
129
|
+
assert_includes err.message, "nonsense"
|
130
|
+
first_backtrace = err.backtrace.first
|
131
|
+
# This is the offset from the assertion to the `nonsense` call,
|
132
|
+
# it might change when this test changes:
|
133
|
+
assert_includes first_backtrace, "#{__LINE__ - 9}"
|
134
|
+
end
|
135
|
+
end
|
118
136
|
end
|
@@ -190,5 +190,28 @@ describe GraphQL::Relay::Mutation do
|
|
190
190
|
|
191
191
|
assert_equal(expected, result)
|
192
192
|
end
|
193
|
+
|
194
|
+
it "supports raising an error in a lazy callback" do
|
195
|
+
result = star_wars_query(query_string, "clientMutationId" => "5678", "shipName" => "Ebon Hawk")
|
196
|
+
|
197
|
+
expected = {
|
198
|
+
"data" => {
|
199
|
+
"introduceShip" => {
|
200
|
+
"clientMutationId" => "5678",
|
201
|
+
"shipEdge" => nil,
|
202
|
+
"faction" => nil,
|
203
|
+
}
|
204
|
+
},
|
205
|
+
"errors" => [
|
206
|
+
{
|
207
|
+
"message" => "💥",
|
208
|
+
"locations" => [ { "line" => 3 , "column" => 7}],
|
209
|
+
"path" => ["introduceShip"]
|
210
|
+
}
|
211
|
+
]
|
212
|
+
}
|
213
|
+
|
214
|
+
assert_equal(expected, result)
|
215
|
+
end
|
193
216
|
end
|
194
217
|
end
|
@@ -56,7 +56,6 @@ describe GraphQL::Relay::Node do
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
59
|
it 'finds objects by id' do
|
61
60
|
id = GraphQL::Schema::UniqueWithinType.encode("Faction", "1")
|
62
61
|
result = star_wars_query(%|{
|
@@ -91,4 +90,58 @@ describe GraphQL::Relay::Node do
|
|
91
90
|
assert_equal(expected, result)
|
92
91
|
end
|
93
92
|
end
|
93
|
+
|
94
|
+
describe ".plural_identifying_field" do
|
95
|
+
it 'finds objects by ids' do
|
96
|
+
id = GraphQL::Schema::UniqueWithinType.encode("Faction", "1")
|
97
|
+
id2 = GraphQL::Schema::UniqueWithinType.encode("Faction", "2")
|
98
|
+
|
99
|
+
result = star_wars_query(%|{
|
100
|
+
nodes(ids: ["#{id}", "#{id2}"]) {
|
101
|
+
id,
|
102
|
+
... on Faction {
|
103
|
+
name
|
104
|
+
ships(first: 1) {
|
105
|
+
edges {
|
106
|
+
node {
|
107
|
+
name
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}|)
|
114
|
+
|
115
|
+
expected = {
|
116
|
+
"data" => {
|
117
|
+
"nodes" => [{
|
118
|
+
"id"=>"RmFjdGlvbi0x",
|
119
|
+
"name"=>"Alliance to Restore the Republic",
|
120
|
+
"ships"=>{
|
121
|
+
"edges"=>[
|
122
|
+
{"node"=>{
|
123
|
+
"name" => "X-Wing"
|
124
|
+
}
|
125
|
+
}
|
126
|
+
]
|
127
|
+
}
|
128
|
+
}, {
|
129
|
+
"id" => "RmFjdGlvbi0y",
|
130
|
+
"name" => "Galactic Empire",
|
131
|
+
"ships" => {
|
132
|
+
"edges" => [
|
133
|
+
{ "node" => { "name" => "TIE Fighter" } }
|
134
|
+
]
|
135
|
+
}
|
136
|
+
}]
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
assert_equal(expected, result)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'is marked as relay_nodes_field' do
|
144
|
+
assert GraphQL::Relay::Node.plural_field.relay_nodes_field
|
145
|
+
end
|
146
|
+
end
|
94
147
|
end
|
@@ -161,7 +161,8 @@ module StarWars
|
|
161
161
|
faction_id = inputs["factionId"]
|
162
162
|
if inputs["shipName"] == 'Millennium Falcon'
|
163
163
|
GraphQL::ExecutionError.new("Sorry, Millennium Falcon ship is reserved")
|
164
|
-
|
164
|
+
elsif inputs["shipName"] == "Ebon Hawk"
|
165
|
+
LazyWrapper.new { raise GraphQL::ExecutionError.new("💥")}
|
165
166
|
else
|
166
167
|
ship = DATA.create_ship(inputs["shipName"], faction_id)
|
167
168
|
faction = DATA["Faction"][faction_id]
|
@@ -183,9 +184,16 @@ module StarWars
|
|
183
184
|
|
184
185
|
|
185
186
|
class LazyWrapper
|
186
|
-
|
187
|
-
|
188
|
-
|
187
|
+
def initialize(value = nil, &block)
|
188
|
+
if block_given?
|
189
|
+
@lazy_value = block
|
190
|
+
else
|
191
|
+
@value = value
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def value
|
196
|
+
@resolved_value = @value || @lazy_value.call
|
189
197
|
end
|
190
198
|
end
|
191
199
|
|
@@ -210,6 +218,7 @@ module StarWars
|
|
210
218
|
end
|
211
219
|
|
212
220
|
field :node, GraphQL::Relay::Node.field
|
221
|
+
field :nodes, GraphQL::Relay::Node.plural_field
|
213
222
|
end
|
214
223
|
|
215
224
|
MutationType = GraphQL::ObjectType.define do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: codeclimate-test-reporter
|