graphql 1.4.2 → 1.4.3
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.
- 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
|