graphql 1.5.13 → 1.5.14
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/instance_definable.rb +1 -1
- data/lib/graphql/enum_type.rb +1 -1
- data/lib/graphql/language/lexer.rb +1242 -973
- data/lib/graphql/language/lexer.rl +37 -38
- data/lib/graphql/relay/connection_instrumentation.rb +2 -2
- data/lib/graphql/relay/connection_resolve.rb +25 -3
- data/lib/graphql/schema.rb +1 -0
- data/lib/graphql/schema/unique_within_type.rb +3 -3
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/define/instance_definable_spec.rb +9 -1
- data/spec/graphql/relay/connection_resolve_spec.rb +10 -0
- data/spec/graphql/schema/unique_within_type_spec.rb +10 -3
- data/spec/support/star_wars/data.rb +13 -2
- data/spec/support/star_wars/schema.rb +12 -2
- metadata +2 -2
@@ -49,40 +49,40 @@
|
|
49
49
|
UNKNOWN_CHAR = /./;
|
50
50
|
|
51
51
|
main := |*
|
52
|
-
INT => {
|
53
|
-
FLOAT => {
|
54
|
-
ON => {
|
55
|
-
FRAGMENT => {
|
56
|
-
TRUE => {
|
57
|
-
FALSE => {
|
58
|
-
NULL => {
|
59
|
-
QUERY => {
|
60
|
-
MUTATION => {
|
61
|
-
SUBSCRIPTION => {
|
62
|
-
SCHEMA => {
|
63
|
-
SCALAR => {
|
64
|
-
TYPE => {
|
65
|
-
IMPLEMENTS => {
|
66
|
-
INTERFACE => {
|
67
|
-
UNION => {
|
68
|
-
ENUM => {
|
69
|
-
INPUT => {
|
70
|
-
DIRECTIVE => {
|
71
|
-
RCURLY => {
|
72
|
-
LCURLY => {
|
73
|
-
RPAREN => {
|
74
|
-
LPAREN => {
|
75
|
-
RBRACKET => {
|
76
|
-
LBRACKET => {
|
77
|
-
COLON => {
|
52
|
+
INT => { emit(:INT, ts, te, meta) };
|
53
|
+
FLOAT => { emit(:FLOAT, ts, te, meta) };
|
54
|
+
ON => { emit(:ON, ts, te, meta) };
|
55
|
+
FRAGMENT => { emit(:FRAGMENT, ts, te, meta) };
|
56
|
+
TRUE => { emit(:TRUE, ts, te, meta) };
|
57
|
+
FALSE => { emit(:FALSE, ts, te, meta) };
|
58
|
+
NULL => { emit(:NULL, ts, te, meta) };
|
59
|
+
QUERY => { emit(:QUERY, ts, te, meta) };
|
60
|
+
MUTATION => { emit(:MUTATION, ts, te, meta) };
|
61
|
+
SUBSCRIPTION => { emit(:SUBSCRIPTION, ts, te, meta) };
|
62
|
+
SCHEMA => { emit(:SCHEMA, ts, te, meta) };
|
63
|
+
SCALAR => { emit(:SCALAR, ts, te, meta) };
|
64
|
+
TYPE => { emit(:TYPE, ts, te, meta) };
|
65
|
+
IMPLEMENTS => { emit(:IMPLEMENTS, ts, te, meta) };
|
66
|
+
INTERFACE => { emit(:INTERFACE, ts, te, meta) };
|
67
|
+
UNION => { emit(:UNION, ts, te, meta) };
|
68
|
+
ENUM => { emit(:ENUM, ts, te, meta) };
|
69
|
+
INPUT => { emit(:INPUT, ts, te, meta) };
|
70
|
+
DIRECTIVE => { emit(:DIRECTIVE, ts, te, meta) };
|
71
|
+
RCURLY => { emit(:RCURLY, ts, te, meta) };
|
72
|
+
LCURLY => { emit(:LCURLY, ts, te, meta) };
|
73
|
+
RPAREN => { emit(:RPAREN, ts, te, meta) };
|
74
|
+
LPAREN => { emit(:LPAREN, ts, te, meta) };
|
75
|
+
RBRACKET => { emit(:RBRACKET, ts, te, meta) };
|
76
|
+
LBRACKET => { emit(:LBRACKET, ts, te, meta) };
|
77
|
+
COLON => { emit(:COLON, ts, te, meta) };
|
78
78
|
QUOTED_STRING => { emit_string(ts + 1, te - 1, meta) };
|
79
|
-
VAR_SIGN => {
|
80
|
-
DIR_SIGN => {
|
81
|
-
ELLIPSIS => {
|
82
|
-
EQUALS => {
|
83
|
-
BANG => {
|
84
|
-
PIPE => {
|
85
|
-
IDENTIFIER => {
|
79
|
+
VAR_SIGN => { emit(:VAR_SIGN, ts, te, meta) };
|
80
|
+
DIR_SIGN => { emit(:DIR_SIGN, ts, te, meta) };
|
81
|
+
ELLIPSIS => { emit(:ELLIPSIS, ts, te, meta) };
|
82
|
+
EQUALS => { emit(:EQUALS, ts, te, meta) };
|
83
|
+
BANG => { emit(:BANG, ts, te, meta) };
|
84
|
+
PIPE => { emit(:PIPE, ts, te, meta) };
|
85
|
+
IDENTIFIER => { emit(:IDENTIFIER, ts, te, meta) };
|
86
86
|
COMMENT => { record_comment(ts, te, meta) };
|
87
87
|
|
88
88
|
NEWLINE => {
|
@@ -92,7 +92,7 @@
|
|
92
92
|
|
93
93
|
BLANK => { meta[:col] += te - ts };
|
94
94
|
|
95
|
-
UNKNOWN_CHAR => {
|
95
|
+
UNKNOWN_CHAR => { emit(:UNKNOWN_CHAR, ts, te, meta) };
|
96
96
|
|
97
97
|
*|;
|
98
98
|
}%%
|
@@ -131,11 +131,10 @@ module GraphQL
|
|
131
131
|
previous_token: nil,
|
132
132
|
}
|
133
133
|
|
134
|
-
|
134
|
+
p ||= 0
|
135
|
+
pe ||= data.length
|
135
136
|
|
136
|
-
|
137
|
-
emit(name, ts, te, meta)
|
138
|
-
}
|
137
|
+
%% write init;
|
139
138
|
|
140
139
|
%% write exec;
|
141
140
|
|
@@ -32,8 +32,8 @@ module GraphQL
|
|
32
32
|
connection_arguments = DEFAULT_ARGUMENTS.merge(field.arguments)
|
33
33
|
original_resolve = field.resolve_proc
|
34
34
|
original_lazy_resolve = field.lazy_resolve_proc
|
35
|
-
connection_resolve = GraphQL::Relay::ConnectionResolve.new(field, original_resolve)
|
36
|
-
connection_lazy_resolve = GraphQL::Relay::ConnectionResolve.new(field, original_lazy_resolve)
|
35
|
+
connection_resolve = GraphQL::Relay::ConnectionResolve.new(field, original_resolve, lazy: false)
|
36
|
+
connection_lazy_resolve = GraphQL::Relay::ConnectionResolve.new(field, original_lazy_resolve, lazy: true)
|
37
37
|
field.redefine(
|
38
38
|
resolve: connection_resolve,
|
39
39
|
lazy_resolve: connection_lazy_resolve,
|
@@ -2,21 +2,33 @@
|
|
2
2
|
module GraphQL
|
3
3
|
module Relay
|
4
4
|
class ConnectionResolve
|
5
|
-
def initialize(field, underlying_resolve)
|
5
|
+
def initialize(field, underlying_resolve, lazy:)
|
6
6
|
@field = field
|
7
7
|
@underlying_resolve = underlying_resolve
|
8
8
|
@max_page_size = field.connection_max_page_size
|
9
|
+
@lazy = lazy
|
9
10
|
end
|
10
11
|
|
11
12
|
def call(obj, args, ctx)
|
13
|
+
if @lazy && obj.is_a?(LazyNodesWrapper)
|
14
|
+
parent = obj.parent
|
15
|
+
obj = obj.lazy_object
|
16
|
+
else
|
17
|
+
parent = obj
|
18
|
+
end
|
19
|
+
|
12
20
|
nodes = @underlying_resolve.call(obj, args, ctx)
|
13
21
|
|
14
22
|
if nodes.nil?
|
15
23
|
nil
|
16
24
|
elsif ctx.schema.lazy?(nodes)
|
17
|
-
|
25
|
+
if !@lazy
|
26
|
+
LazyNodesWrapper.new(obj, nodes)
|
27
|
+
else
|
28
|
+
nodes
|
29
|
+
end
|
18
30
|
else
|
19
|
-
build_connection(nodes, args,
|
31
|
+
build_connection(nodes, args, parent, ctx)
|
20
32
|
end
|
21
33
|
end
|
22
34
|
|
@@ -31,6 +43,16 @@ module GraphQL
|
|
31
43
|
connection_class.new(nodes, args, field: @field, max_page_size: @max_page_size, parent: parent, context: ctx)
|
32
44
|
end
|
33
45
|
end
|
46
|
+
|
47
|
+
# A container for the proper `parent` of connection nodes.
|
48
|
+
# Without this wrapper, the lazy object _itself_ is passed into `build_connection`
|
49
|
+
# and it becomes the parent, which is wrong.
|
50
|
+
#
|
51
|
+
# We can get away with it because we know that this instrumentation will be applied last.
|
52
|
+
# That means its code after `underlying_resolve` will be _last_ on the way in.
|
53
|
+
# And, its code before `underlying_resolve` will be _first_ during lazy resolution.
|
54
|
+
# @api private
|
55
|
+
LazyNodesWrapper = Struct.new(:parent, :lazy_object)
|
34
56
|
end
|
35
57
|
end
|
36
58
|
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -111,6 +111,7 @@ module GraphQL
|
|
111
111
|
@parse_error_proc = DefaultParseError
|
112
112
|
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
113
113
|
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
114
|
+
@lazy_methods.set(GraphQL::Relay::ConnectionResolve::LazyNodesWrapper, :never_called)
|
114
115
|
@cursor_encoder = Base64Encoder
|
115
116
|
# Default to the built-in execution strategy:
|
116
117
|
@query_execution_strategy = self.class.default_execution_strategy
|
@@ -15,8 +15,8 @@ module GraphQL
|
|
15
15
|
def encode(type_name, object_value, separator: self.default_id_separator)
|
16
16
|
object_value_str = object_value.to_s
|
17
17
|
|
18
|
-
if type_name.include?(separator)
|
19
|
-
raise "encode(#{type_name}, #{object_value_str}) contains reserved characters `#{separator}`"
|
18
|
+
if type_name.include?(separator)
|
19
|
+
raise "encode(#{type_name}, #{object_value_str}) contains reserved characters `#{separator}` in the type name"
|
20
20
|
end
|
21
21
|
|
22
22
|
Base64.strict_encode64([type_name, object_value_str].join(separator))
|
@@ -25,7 +25,7 @@ module GraphQL
|
|
25
25
|
# @param node_id [String] A unique ID generated by {.encode}
|
26
26
|
# @return [Array<(String, String)>] The type name & value passed to {.encode}
|
27
27
|
def decode(node_id, separator: self.default_id_separator)
|
28
|
-
Base64.decode64(node_id).split(separator)
|
28
|
+
Base64.decode64(node_id).split(separator, 2)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
data/lib/graphql/version.rb
CHANGED
@@ -14,7 +14,7 @@ module Garden
|
|
14
14
|
include GraphQL::Define::InstanceDefinable
|
15
15
|
attr_accessor :name, :start_planting_on, :end_planting_on
|
16
16
|
ensure_defined(:name, :start_planting_on, :end_planting_on)
|
17
|
-
accepts_definitions :name, plant_between: DefinePlantBetween, color: GraphQL::Define.assign_metadata_key(:color)
|
17
|
+
accepts_definitions :name, plant_between: DefinePlantBetween, has_leaves: GraphQL::Define.assign_metadata_key(:has_leaves), color: GraphQL::Define.assign_metadata_key(:color)
|
18
18
|
|
19
19
|
# definition added later:
|
20
20
|
attr_accessor :height
|
@@ -58,6 +58,14 @@ describe GraphQL::Define::InstanceDefinable do
|
|
58
58
|
assert_equal Date.new(2000, 4, 20), tomato.start_planting_on
|
59
59
|
assert_equal Date.new(2000, 6, 1), tomato.end_planting_on
|
60
60
|
end
|
61
|
+
|
62
|
+
it "accepts bare definitions" do
|
63
|
+
radish = Garden::Vegetable.define do
|
64
|
+
name "Radish"
|
65
|
+
has_leaves
|
66
|
+
end
|
67
|
+
assert_equal true, radish.metadata[:has_leaves]
|
68
|
+
end
|
61
69
|
end
|
62
70
|
|
63
71
|
describe ".define with keywords" do
|
@@ -11,6 +11,7 @@ describe GraphQL::Relay::ConnectionResolve do
|
|
11
11
|
name
|
12
12
|
}
|
13
13
|
}
|
14
|
+
parentClassName
|
14
15
|
}
|
15
16
|
}
|
16
17
|
}
|
@@ -43,6 +44,15 @@ describe GraphQL::Relay::ConnectionResolve do
|
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
47
|
+
|
48
|
+
describe "when a lazy object is returned" do
|
49
|
+
it "returns the items with the correct parent" do
|
50
|
+
result = star_wars_query(query_string, { "name" => "lazyObject"})
|
51
|
+
assert_equal 5, result["data"]["rebels"]["ships"]["edges"].length
|
52
|
+
assert_equal "StarWars::FactionRecord", result["data"]["rebels"]["ships"]["parentClassName"]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
46
56
|
describe "when nil is returned" do
|
47
57
|
it "becomes null" do
|
48
58
|
result = star_wars_query(query_string, { "name" => "null" })
|
@@ -27,11 +27,18 @@ describe GraphQL::Schema::UniqueWithinType do
|
|
27
27
|
assert_equal("250cda0e-a89d-41cf-99e1-2872d89f1100", id)
|
28
28
|
end
|
29
29
|
|
30
|
-
it "
|
30
|
+
it "allows using the separator in the ID" do
|
31
|
+
global_id = GraphQL::Schema::UniqueWithinType.encode("SomeUUIDType", "250cda0e-a89d-41cf-99e1-2872d89f1100")
|
32
|
+
type_name, id = GraphQL::Schema::UniqueWithinType.decode(global_id)
|
33
|
+
assert_equal("SomeUUIDType", type_name)
|
34
|
+
assert_equal("250cda0e-a89d-41cf-99e1-2872d89f1100", id)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "raises an error if you try and use a reserved character in the typename" do
|
31
38
|
err = assert_raises(RuntimeError) {
|
32
|
-
GraphQL::Schema::UniqueWithinType.encode("Best-Thing", "234")
|
39
|
+
GraphQL::Schema::UniqueWithinType.encode("Best-Thing", "234-567")
|
33
40
|
}
|
34
|
-
assert_includes err.message, "encode(Best-Thing, 234) contains reserved characters `-`"
|
41
|
+
assert_includes err.message, "encode(Best-Thing, 234-567) contains reserved characters `-` in the type name"
|
35
42
|
end
|
36
43
|
end
|
37
44
|
end
|
@@ -55,7 +55,18 @@ module StarWars
|
|
55
55
|
class SequelBase < Sequel::Model(:bases)
|
56
56
|
end
|
57
57
|
|
58
|
-
|
58
|
+
class FactionRecord
|
59
|
+
attr_reader :id, :name, :ships, :bases, :basesClone
|
60
|
+
def initialize(id:, name:, ships:, bases:, basesClone:)
|
61
|
+
@id = id
|
62
|
+
@name = name
|
63
|
+
@ships = ships
|
64
|
+
@bases = bases
|
65
|
+
@basesClone = basesClone
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
rebels = FactionRecord.new({
|
59
70
|
id: '1',
|
60
71
|
name: 'Alliance to Restore the Republic',
|
61
72
|
ships: ['1', '2', '3', '4', '5'],
|
@@ -64,7 +75,7 @@ module StarWars
|
|
64
75
|
})
|
65
76
|
|
66
77
|
|
67
|
-
empire =
|
78
|
+
empire = FactionRecord.new({
|
68
79
|
id: '2',
|
69
80
|
name: 'Galactic Empire',
|
70
81
|
ships: ['6', '7', '8'],
|
@@ -83,13 +83,20 @@ module StarWars
|
|
83
83
|
type Ship.connection_type
|
84
84
|
end
|
85
85
|
|
86
|
+
ShipConnectionWithParentType = Ship.define_connection do
|
87
|
+
name "ShipConnectionWithParent"
|
88
|
+
field :parentClassName, !types.String do
|
89
|
+
resolve ->(o, a, c) { o.parent.class.name }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
86
93
|
Faction = GraphQL::ObjectType.define do
|
87
94
|
name "Faction"
|
88
95
|
interfaces [GraphQL::Relay::Node.interface]
|
89
96
|
|
90
97
|
field :id, !types.ID, resolve: GraphQL::Relay::GlobalIdResolve.new(type: Faction)
|
91
98
|
field :name, types.String
|
92
|
-
connection :ships,
|
99
|
+
connection :ships, ShipConnectionWithParentType do
|
93
100
|
resolve ->(obj, args, ctx) {
|
94
101
|
all_ships = obj.ships.map {|ship_id| StarWars::DATA["Ship"][ship_id] }
|
95
102
|
if args[:nameIncludes]
|
@@ -104,6 +111,9 @@ module StarWars
|
|
104
111
|
all_ships = LazyWrapper.new { raise GraphQL::ExecutionError.new("lazy raised error from within connection") }
|
105
112
|
when "null"
|
106
113
|
all_ships = nil
|
114
|
+
when "lazyObject"
|
115
|
+
prev_all_ships = all_ships
|
116
|
+
all_ships = LazyWrapper.new { prev_all_ships }
|
107
117
|
else
|
108
118
|
all_ships = all_ships.select { |ship| ship.name.include?(args[:nameIncludes])}
|
109
119
|
end
|
@@ -154,7 +164,7 @@ module StarWars
|
|
154
164
|
resolve ->(obj, args, ctx) {
|
155
165
|
all_bases = SequelBase.where(faction_id: obj.id)
|
156
166
|
if args[:nameIncludes]
|
157
|
-
all_bases = all_bases.where(
|
167
|
+
all_bases = all_bases.where(Sequel.like(:name, "%#{args[:nameIncludes]}%"))
|
158
168
|
end
|
159
169
|
all_bases
|
160
170
|
}
|
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.5.
|
4
|
+
version: 1.5.14
|
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-05-
|
11
|
+
date: 2017-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|