graphql 1.7.8 → 1.7.9
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/base_type.rb +6 -5
- data/lib/graphql/compatibility/query_parser_specification.rb +7 -0
- data/lib/graphql/field.rb +3 -3
- data/lib/graphql/internal_representation/node.rb +32 -13
- data/lib/graphql/internal_representation/visit.rb +3 -6
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/language/block_string.rb +47 -0
- data/lib/graphql/language/lexer.rb +129 -68
- data/lib/graphql/language/lexer.rl +13 -4
- data/lib/graphql/language/nodes.rb +6 -3
- data/lib/graphql/language/printer.rb +1 -1
- data/lib/graphql/language/token.rb +1 -1
- data/lib/graphql/query.rb +1 -1
- data/lib/graphql/schema/build_from_definition.rb +2 -0
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +15 -8
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +11 -1
- data/lib/graphql/tracing/data_dog_tracing.rb +13 -9
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/backtrace_spec.rb +10 -0
- data/spec/graphql/directive_spec.rb +3 -1
- data/spec/graphql/language/block_string_spec.rb +70 -0
- data/spec/graphql/language/lexer_spec.rb +9 -0
- data/spec/graphql/query_spec.rb +1 -1
- data/spec/graphql/schema/printer_spec.rb +48 -5
- metadata +19 -2
@@ -34,6 +34,9 @@
|
|
34
34
|
RBRACKET = ']';
|
35
35
|
COLON = ':';
|
36
36
|
QUOTE = '"';
|
37
|
+
BLOCK_QUOTE = '"""';
|
38
|
+
ESCAPED_BLOCK_QUOTE = '\\"""';
|
39
|
+
BLOCK_STRING_CHAR = (ESCAPED_BLOCK_QUOTE | ^'"""');
|
37
40
|
ESCAPED_QUOTE = '\\"';
|
38
41
|
STRING_CHAR = (ESCAPED_QUOTE | ^'"');
|
39
42
|
VAR_SIGN = '$';
|
@@ -44,7 +47,7 @@
|
|
44
47
|
PIPE = '|';
|
45
48
|
|
46
49
|
QUOTED_STRING = QUOTE STRING_CHAR* QUOTE;
|
47
|
-
|
50
|
+
BLOCK_STRING = BLOCK_QUOTE BLOCK_STRING_CHAR* BLOCK_QUOTE;
|
48
51
|
# catch-all for anything else. must be at the bottom for precedence.
|
49
52
|
UNKNOWN_CHAR = /./;
|
50
53
|
|
@@ -75,7 +78,8 @@
|
|
75
78
|
RBRACKET => { emit(:RBRACKET, ts, te, meta) };
|
76
79
|
LBRACKET => { emit(:LBRACKET, ts, te, meta) };
|
77
80
|
COLON => { emit(:COLON, ts, te, meta) };
|
78
|
-
QUOTED_STRING => { emit_string(ts
|
81
|
+
QUOTED_STRING => { emit_string(ts, te, meta, block: false) };
|
82
|
+
BLOCK_STRING => { emit_string(ts, te, meta, block: true) };
|
79
83
|
VAR_SIGN => { emit(:VAR_SIGN, ts, te, meta) };
|
80
84
|
DIR_SIGN => { emit(:DIR_SIGN, ts, te, meta) };
|
81
85
|
ELLIPSIS => { emit(:ELLIPSIS, ts, te, meta) };
|
@@ -188,8 +192,13 @@ module GraphQL
|
|
188
192
|
PACK_DIRECTIVE = "c*"
|
189
193
|
UTF_8_ENCODING = "UTF-8"
|
190
194
|
|
191
|
-
def self.emit_string(ts, te, meta)
|
192
|
-
|
195
|
+
def self.emit_string(ts, te, meta, block:)
|
196
|
+
quotes_length = block ? 3 : 1
|
197
|
+
ts += quotes_length
|
198
|
+
value = meta[:data][ts...te - quotes_length].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING)
|
199
|
+
if block
|
200
|
+
value = GraphQL::Language::BlockString.trim_whitespace(value)
|
201
|
+
end
|
193
202
|
if value !~ VALID_STRING
|
194
203
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
195
204
|
name: :BAD_UNICODE_ESCAPE,
|
@@ -288,13 +288,16 @@ module GraphQL
|
|
288
288
|
private
|
289
289
|
|
290
290
|
def serialize_value_for_hash(value)
|
291
|
-
|
291
|
+
case value
|
292
|
+
when InputObject
|
292
293
|
value.to_h
|
293
|
-
|
294
|
+
when Array
|
294
295
|
value.map do |v|
|
295
296
|
serialize_value_for_hash v
|
296
297
|
end
|
297
|
-
|
298
|
+
when Enum
|
299
|
+
value.name
|
300
|
+
when NullValue
|
298
301
|
nil
|
299
302
|
else
|
300
303
|
value
|
data/lib/graphql/query.rb
CHANGED
@@ -157,7 +157,7 @@ module GraphQL
|
|
157
157
|
def result
|
158
158
|
if !@executed
|
159
159
|
with_prepared_ast {
|
160
|
-
Execution::Multiplex.run_queries(@schema, [self])
|
160
|
+
Execution::Multiplex.run_queries(@schema, [self], context: @context)
|
161
161
|
}
|
162
162
|
end
|
163
163
|
@result ||= Query::Result.new(query: self, values: @result_values)
|
@@ -2,6 +2,9 @@
|
|
2
2
|
module GraphQL
|
3
3
|
module StaticValidation
|
4
4
|
class FieldsWillMerge
|
5
|
+
# Special handling for fields without arguments
|
6
|
+
NO_ARGS = {}.freeze
|
7
|
+
|
5
8
|
def validate(context)
|
6
9
|
context.each_irep_node do |node|
|
7
10
|
if node.ast_nodes.size > 1
|
@@ -16,15 +19,19 @@ module GraphQL
|
|
16
19
|
|
17
20
|
# Check for incompatible / non-identical arguments on this node:
|
18
21
|
args = node.ast_nodes.map do |n|
|
19
|
-
n.arguments.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
if n.arguments.any?
|
23
|
+
n.arguments.reduce({}) do |memo, a|
|
24
|
+
arg_value = a.value
|
25
|
+
memo[a.name] = case arg_value
|
26
|
+
when GraphQL::Language::Nodes::AbstractNode
|
27
|
+
arg_value.to_query_string
|
28
|
+
else
|
29
|
+
GraphQL::Language.serialize(arg_value)
|
30
|
+
end
|
31
|
+
memo
|
26
32
|
end
|
27
|
-
|
33
|
+
else
|
34
|
+
NO_ARGS
|
28
35
|
end
|
29
36
|
end
|
30
37
|
args.uniq!
|
@@ -102,7 +102,17 @@ module GraphQL
|
|
102
102
|
def follow_spreads(node, parent_variables, spreads_for_context, fragment_definitions, visited_fragments)
|
103
103
|
spreads = spreads_for_context[node] - visited_fragments
|
104
104
|
spreads.each do |spread_name|
|
105
|
-
def_node
|
105
|
+
def_node = nil
|
106
|
+
variables = nil
|
107
|
+
# Implement `.find` by hand to avoid Ruby's internal allocations
|
108
|
+
fragment_definitions.each do |frag_def_node, vars|
|
109
|
+
if frag_def_node.name == spread_name
|
110
|
+
def_node = frag_def_node
|
111
|
+
variables = vars
|
112
|
+
break
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
106
116
|
next if !def_node
|
107
117
|
visited_fragments << spread_name
|
108
118
|
variables.each do |name, child_usage|
|
@@ -15,17 +15,12 @@ module GraphQL
|
|
15
15
|
}
|
16
16
|
|
17
17
|
def platform_trace(platform_key, key, data)
|
18
|
-
|
18
|
+
tracer.trace(platform_key, service: service_name) do |span|
|
19
|
+
span.span_type = 'custom'
|
19
20
|
|
20
|
-
pin = Datadog::Pin.get_from(self)
|
21
|
-
unless pin
|
22
|
-
pin = Datadog::Pin.new(service)
|
23
|
-
pin.onto(self)
|
24
|
-
end
|
25
|
-
|
26
|
-
pin.tracer.trace(platform_key, service: pin.service) do |span|
|
27
21
|
if key == 'execute_multiplex'
|
28
|
-
|
22
|
+
operations = data[:multiplex].queries.map(&:selected_operation_name).join(', ')
|
23
|
+
span.resource = operations unless operations.empty?
|
29
24
|
end
|
30
25
|
|
31
26
|
if key == 'execute_query'
|
@@ -33,10 +28,19 @@ module GraphQL
|
|
33
28
|
span.set_tag(:selected_operation_type, data[:query].selected_operation.operation_type)
|
34
29
|
span.set_tag(:query_string, data[:query].query_string)
|
35
30
|
end
|
31
|
+
|
36
32
|
yield
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
36
|
+
def service_name
|
37
|
+
options.fetch(:service, 'ruby-graphql')
|
38
|
+
end
|
39
|
+
|
40
|
+
def tracer
|
41
|
+
options.fetch(:tracer, Datadog.tracer)
|
42
|
+
end
|
43
|
+
|
40
44
|
def platform_field_key(type, field)
|
41
45
|
"#{type.name}.#{field.name}"
|
42
46
|
end
|
data/lib/graphql/version.rb
CHANGED
@@ -126,6 +126,16 @@ describe GraphQL::Backtrace do
|
|
126
126
|
assert_includes err.message, "more lines"
|
127
127
|
end
|
128
128
|
|
129
|
+
it "annotates errors from Query#result" do
|
130
|
+
query_str = "query StrField { field2 { strField } __typename }"
|
131
|
+
context = { backtrace: true }
|
132
|
+
query = GraphQL::Query.new(schema, query_str, context: context)
|
133
|
+
err = assert_raises(GraphQL::Backtrace::TracedError) {
|
134
|
+
query.result
|
135
|
+
}
|
136
|
+
assert_instance_of RuntimeError, err.cause
|
137
|
+
end
|
138
|
+
|
129
139
|
it "annotates errors inside lazy resolution" do
|
130
140
|
# Test context-based flag
|
131
141
|
err = assert_raises(GraphQL::Backtrace::TracedError) {
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe GraphQL::Language::BlockString do
|
5
|
+
describe "trimming whitespace" do
|
6
|
+
def trim_whitespace(str)
|
7
|
+
GraphQL::Language::BlockString.trim_whitespace(str)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "matches the examples in graphql-js" do
|
11
|
+
# these are taken from:
|
12
|
+
# https://github.com/graphql/graphql-js/blob/36ec0e9d34666362ff0e2b2b18edeb98e3c9abee/src/language/__tests__/blockStringValue-test.js#L12
|
13
|
+
# A set of [before, after] pairs:
|
14
|
+
examples = [
|
15
|
+
[
|
16
|
+
# Removes common whitespace:
|
17
|
+
"
|
18
|
+
Hello,
|
19
|
+
World!
|
20
|
+
|
21
|
+
Yours,
|
22
|
+
GraphQL.
|
23
|
+
",
|
24
|
+
"Hello,\n World!\n\nYours,\n GraphQL."
|
25
|
+
],
|
26
|
+
[
|
27
|
+
# Removes leading and trailing newlines:
|
28
|
+
"
|
29
|
+
|
30
|
+
Hello,
|
31
|
+
World!
|
32
|
+
|
33
|
+
Yours,
|
34
|
+
GraphQL.
|
35
|
+
|
36
|
+
",
|
37
|
+
"Hello,\n World!\n\nYours,\n GraphQL."
|
38
|
+
],
|
39
|
+
[
|
40
|
+
# Removes blank lines (with whitespace _and_ newlines:)
|
41
|
+
"\n \n
|
42
|
+
Hello,
|
43
|
+
World!
|
44
|
+
|
45
|
+
Yours,
|
46
|
+
GraphQL.
|
47
|
+
|
48
|
+
\n \n",
|
49
|
+
"Hello,\n World!\n\nYours,\n GraphQL."
|
50
|
+
],
|
51
|
+
[
|
52
|
+
# Retains indentation from the first line
|
53
|
+
" Hello,\n World!\n\n Yours,\n GraphQL.",
|
54
|
+
" Hello,\n World!\n\nYours,\n GraphQL.",
|
55
|
+
],
|
56
|
+
[
|
57
|
+
# Doesn't alter trailing spaces
|
58
|
+
"\n \n Hello, \n World! \n\n Yours, \n GraphQL. ",
|
59
|
+
"Hello, \n World! \n\nYours, \n GraphQL. ",
|
60
|
+
|
61
|
+
],
|
62
|
+
]
|
63
|
+
|
64
|
+
examples.each_with_index do |(before, after), idx|
|
65
|
+
transformed_str = trim_whitespace(before)
|
66
|
+
assert_equal(after, transformed_str, "Example ##{idx + 1}")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -26,6 +26,15 @@ describe GraphQL::Language::Lexer do
|
|
26
26
|
assert_equal tokens[0], tokens[1].prev_token
|
27
27
|
end
|
28
28
|
|
29
|
+
describe "block strings" do
|
30
|
+
let(:query_string) { %|{ a(b: """\nc\n d\n""")}|}
|
31
|
+
|
32
|
+
it "tokenizes them" do
|
33
|
+
str_token = tokens[5]
|
34
|
+
assert_equal "c\n d", str_token.value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
29
38
|
it "unescapes escaped characters" do
|
30
39
|
assert_equal "\" \\ / \b \f \n \r \t", subject.tokenize('"\\" \\\\ \\/ \\b \\f \\n \\r \\t"').first.to_s
|
31
40
|
end
|
data/spec/graphql/query_spec.rb
CHANGED
@@ -85,7 +85,7 @@ describe GraphQL::Query do
|
|
85
85
|
operation_name: operation_name,
|
86
86
|
max_depth: max_depth,
|
87
87
|
)
|
88
|
-
query.query_string = '{ __type(name: "Cheese") { name } }'
|
88
|
+
query.query_string = '{ __type(name: """Cheese""") { name } }'
|
89
89
|
assert_equal "Cheese", query.result["data"] ["__type"]["name"]
|
90
90
|
end
|
91
91
|
end
|
@@ -14,7 +14,11 @@ describe GraphQL::Schema::Printer do
|
|
14
14
|
|
15
15
|
value "FOO", value: :foo
|
16
16
|
value "BAR", value: :bar
|
17
|
-
value "BAZ", deprecation_reason:
|
17
|
+
value "BAZ", deprecation_reason: <<-REASON
|
18
|
+
Use "BAR" instead.
|
19
|
+
|
20
|
+
It's the replacement for this value.
|
21
|
+
REASON
|
18
22
|
value "WOZ", deprecation_reason: GraphQL::Directive::DEFAULT_DEPRECATION_REASON
|
19
23
|
end
|
20
24
|
|
@@ -352,7 +356,6 @@ SCHEMA
|
|
352
356
|
custom_mutation = schema.mutation.redefine(name: "MyMutationRoot")
|
353
357
|
custom_schema = schema.redefine(mutation: custom_mutation)
|
354
358
|
|
355
|
-
|
356
359
|
expected = <<SCHEMA
|
357
360
|
schema {
|
358
361
|
query: Query
|
@@ -389,7 +392,7 @@ type Audio {
|
|
389
392
|
|
390
393
|
enum Choice {
|
391
394
|
BAR
|
392
|
-
BAZ @deprecated(reason: "Use "BAR"
|
395
|
+
BAZ @deprecated(reason: "Use \\\"BAR\\\" instead.\\n\\nIt's the replacement for this value.\\n")
|
393
396
|
FOO
|
394
397
|
WOZ @deprecated
|
395
398
|
}
|
@@ -438,7 +441,7 @@ interface Node {
|
|
438
441
|
type Post {
|
439
442
|
body: String!
|
440
443
|
comments: [Comment!]
|
441
|
-
comments_count: Int! @deprecated(reason: "Use "comments".")
|
444
|
+
comments_count: Int! @deprecated(reason: "Use \\\"comments\\\".")
|
442
445
|
id: ID!
|
443
446
|
title: String!
|
444
447
|
}
|
@@ -600,7 +603,7 @@ SCHEMA
|
|
600
603
|
type Post {
|
601
604
|
body: String!
|
602
605
|
comments: [Comment!]
|
603
|
-
comments_count: Int! @deprecated(reason: "Use "comments".")
|
606
|
+
comments_count: Int! @deprecated(reason: "Use \\\"comments\\\".")
|
604
607
|
id: ID!
|
605
608
|
title: String!
|
606
609
|
}
|
@@ -608,4 +611,44 @@ SCHEMA
|
|
608
611
|
assert_equal expected.chomp, GraphQL::Schema::Printer.new(schema).print_type(schema.types['Post'])
|
609
612
|
end
|
610
613
|
end
|
614
|
+
|
615
|
+
describe "#print_directive" do
|
616
|
+
it "prints the deprecation reason in a single line escaped string including line breaks" do
|
617
|
+
expected = <<SCHEMA
|
618
|
+
enum Choice {
|
619
|
+
BAR
|
620
|
+
BAZ @deprecated(reason: "Use \\\"BAR\\\" instead.\\n\\nIt's the replacement for this value.\\n")
|
621
|
+
FOO
|
622
|
+
WOZ @deprecated
|
623
|
+
}
|
624
|
+
|
625
|
+
type Subscription {
|
626
|
+
}
|
627
|
+
|
628
|
+
input Varied {
|
629
|
+
bool: Boolean
|
630
|
+
enum: Choice = FOO
|
631
|
+
float: Float
|
632
|
+
int: Int
|
633
|
+
}
|
634
|
+
SCHEMA
|
635
|
+
|
636
|
+
only_filter = ->(member, ctx) {
|
637
|
+
case member
|
638
|
+
when GraphQL::ScalarType
|
639
|
+
true
|
640
|
+
when GraphQL::BaseType
|
641
|
+
ctx[:names].include?(member.name)
|
642
|
+
when GraphQL::Argument
|
643
|
+
member.name != "id"
|
644
|
+
else
|
645
|
+
true
|
646
|
+
end
|
647
|
+
}
|
648
|
+
|
649
|
+
context = { names: ["Varied", "Choice", "Subscription"] }
|
650
|
+
|
651
|
+
assert_equal expected.chomp, GraphQL::Schema::Printer.new(schema, context: context, only: only_filter).print_schema
|
652
|
+
end
|
653
|
+
end
|
611
654
|
end
|
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.7.
|
4
|
+
version: 1.7.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-01
|
11
|
+
date: 2018-02-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 3.0.0
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: memory_profiler
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
139
153
|
- !ruby/object:Gem::Dependency
|
140
154
|
name: minitest
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -417,6 +431,7 @@ files:
|
|
417
431
|
- lib/graphql/invalid_name_error.rb
|
418
432
|
- lib/graphql/invalid_null_error.rb
|
419
433
|
- lib/graphql/language.rb
|
434
|
+
- lib/graphql/language/block_string.rb
|
420
435
|
- lib/graphql/language/comments.rb
|
421
436
|
- lib/graphql/language/definition_slice.rb
|
422
437
|
- lib/graphql/language/document_from_schema_definition.rb
|
@@ -899,6 +914,7 @@ files:
|
|
899
914
|
- spec/graphql/introspection/schema_type_spec.rb
|
900
915
|
- spec/graphql/introspection/type_by_name_field_spec.rb
|
901
916
|
- spec/graphql/introspection/type_type_spec.rb
|
917
|
+
- spec/graphql/language/block_string_spec.rb
|
902
918
|
- spec/graphql/language/definition_slice_spec.rb
|
903
919
|
- spec/graphql/language/document_from_schema_definition_spec.rb
|
904
920
|
- spec/graphql/language/equality_spec.rb
|
@@ -1370,6 +1386,7 @@ test_files:
|
|
1370
1386
|
- spec/graphql/introspection/schema_type_spec.rb
|
1371
1387
|
- spec/graphql/introspection/type_by_name_field_spec.rb
|
1372
1388
|
- spec/graphql/introspection/type_type_spec.rb
|
1389
|
+
- spec/graphql/language/block_string_spec.rb
|
1373
1390
|
- spec/graphql/language/definition_slice_spec.rb
|
1374
1391
|
- spec/graphql/language/document_from_schema_definition_spec.rb
|
1375
1392
|
- spec/graphql/language/equality_spec.rb
|