graphql 1.9.14 → 1.9.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/graphql/templates/base_field.erb +0 -4
- data/lib/generators/graphql/templates/graphql_controller.erb +1 -1
- data/lib/generators/graphql/templates/schema.erb +1 -1
- data/lib/graphql.rb +3 -0
- data/lib/graphql/analysis/ast/analyzer.rb +1 -1
- data/lib/graphql/base_type.rb +1 -1
- data/lib/graphql/function.rb +1 -1
- data/lib/graphql/input_object_type.rb +2 -1
- data/lib/graphql/language/document_from_schema_definition.rb +1 -1
- data/lib/graphql/language/lexer.rb +49 -48
- data/lib/graphql/language/lexer.rl +49 -48
- data/lib/graphql/language/nodes.rb +11 -8
- data/lib/graphql/language/parser.rb +4 -1
- data/lib/graphql/language/parser.y +4 -1
- data/lib/graphql/language/token.rb +1 -1
- data/lib/graphql/query/arguments.rb +6 -1
- data/lib/graphql/query/literal_input.rb +2 -1
- data/lib/graphql/relay/base_connection.rb +3 -3
- data/lib/graphql/relay/relation_connection.rb +9 -5
- data/lib/graphql/schema.rb +8 -8
- data/lib/graphql/schema/argument.rb +1 -11
- data/lib/graphql/schema/build_from_definition.rb +1 -1
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/field.rb +19 -2
- data/lib/graphql/schema/input_object.rb +4 -0
- data/lib/graphql/schema/loader.rb +3 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +2 -2
- data/lib/graphql/schema/member/has_fields.rb +15 -6
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/resolver.rb +14 -1
- data/lib/graphql/schema/wrapper.rb +1 -1
- data/lib/graphql/static_validation/definition_dependencies.rb +21 -12
- data/lib/graphql/subscriptions.rb +5 -5
- data/lib/graphql/upgrader/member.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f0505024fefcdebc975dad9259c3f3470f883b4251380e759de60ba380b3314
|
4
|
+
data.tar.gz: d92149e0da6aa4e110525a38badaf2163bf887205e2c6dd75c327302e0cfabb4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47b920de6ba95b4c15ebc4aace97d74931cc24efee8c3fb6a6291ea68a13b3ef46b9c613658306e1ff100d0917433431c129baba12553a94dc96a4184cbc5435
|
7
|
+
data.tar.gz: 0e9c03e45fd3b3cb40a9b6b948ee1f71952f618511254acb3840195ff9c054036308636c7b2a42858096e70d1764e38458b88b0f2f369f699c7f71cdd0afd415
|
@@ -2,7 +2,7 @@ class GraphqlController < ApplicationController
|
|
2
2
|
# If accessing from outside this domain, nullify the session
|
3
3
|
# This allows for outside API access while preventing CSRF attacks,
|
4
4
|
# but you'll have to authenticate your user separately
|
5
|
-
protect_from_forgery with: :null_session
|
5
|
+
# protect_from_forgery with: :null_session
|
6
6
|
|
7
7
|
def execute
|
8
8
|
variables = ensure_hash(params[:variables])
|
@@ -24,7 +24,7 @@ class <%= schema_name %> < GraphQL::Schema
|
|
24
24
|
def self.resolve_type(type, obj, ctx)
|
25
25
|
# TODO: Implement this function
|
26
26
|
# to return the correct type for `obj`
|
27
|
-
raise(
|
27
|
+
raise(GraphQL::RequiredImplementationMissingError)
|
28
28
|
end
|
29
29
|
<% end %><% if options[:batch] %>
|
30
30
|
# GraphQL::Batch setup:
|
data/lib/graphql.rb
CHANGED
@@ -10,6 +10,9 @@ module GraphQL
|
|
10
10
|
class Error < StandardError
|
11
11
|
end
|
12
12
|
|
13
|
+
class RequiredImplementationMissingError < Error
|
14
|
+
end
|
15
|
+
|
13
16
|
# Turn a query string or schema definition into an AST
|
14
17
|
# @param graphql_string [String] a GraphQL query string or schema definition
|
15
18
|
# @return [GraphQL::Language::Nodes::Document]
|
data/lib/graphql/base_type.rb
CHANGED
data/lib/graphql/function.rb
CHANGED
@@ -99,7 +99,8 @@ module GraphQL
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
|
-
arguments_class.new(input_values, context: ctx, defaults_used: defaults_used)
|
102
|
+
result = arguments_class.new(input_values, context: ctx, defaults_used: defaults_used)
|
103
|
+
result.prepare
|
103
104
|
end
|
104
105
|
|
105
106
|
# @api private
|
@@ -207,7 +207,7 @@ module GraphQL
|
|
207
207
|
when ListType
|
208
208
|
default_value.to_a.map { |v| build_default_value(v, type.of_type) }
|
209
209
|
else
|
210
|
-
raise
|
210
|
+
raise GraphQL::RequiredImplementationMissingError, "Unexpected default value type #{type.inspect}"
|
211
211
|
end
|
212
212
|
end
|
213
213
|
|
@@ -314,7 +314,7 @@ def self.run_lexer(query_string)
|
|
314
314
|
begin
|
315
315
|
te = p+1;
|
316
316
|
begin
|
317
|
-
emit(:RCURLY, ts, te, meta)
|
317
|
+
emit(:RCURLY, ts, te, meta, "}")
|
318
318
|
end
|
319
319
|
|
320
320
|
end
|
@@ -328,7 +328,7 @@ def self.run_lexer(query_string)
|
|
328
328
|
begin
|
329
329
|
te = p+1;
|
330
330
|
begin
|
331
|
-
emit(:LCURLY, ts, te, meta)
|
331
|
+
emit(:LCURLY, ts, te, meta, "{")
|
332
332
|
end
|
333
333
|
|
334
334
|
end
|
@@ -342,7 +342,7 @@ def self.run_lexer(query_string)
|
|
342
342
|
begin
|
343
343
|
te = p+1;
|
344
344
|
begin
|
345
|
-
emit(:RPAREN, ts, te, meta)
|
345
|
+
emit(:RPAREN, ts, te, meta, ")")
|
346
346
|
end
|
347
347
|
|
348
348
|
end
|
@@ -356,7 +356,7 @@ def self.run_lexer(query_string)
|
|
356
356
|
begin
|
357
357
|
te = p+1;
|
358
358
|
begin
|
359
|
-
emit(:LPAREN, ts, te, meta)
|
359
|
+
emit(:LPAREN, ts, te, meta, "(")
|
360
360
|
end
|
361
361
|
|
362
362
|
end
|
@@ -370,7 +370,7 @@ def self.run_lexer(query_string)
|
|
370
370
|
begin
|
371
371
|
te = p+1;
|
372
372
|
begin
|
373
|
-
emit(:RBRACKET, ts, te, meta)
|
373
|
+
emit(:RBRACKET, ts, te, meta, "]")
|
374
374
|
end
|
375
375
|
|
376
376
|
end
|
@@ -384,7 +384,7 @@ def self.run_lexer(query_string)
|
|
384
384
|
begin
|
385
385
|
te = p+1;
|
386
386
|
begin
|
387
|
-
emit(:LBRACKET, ts, te, meta)
|
387
|
+
emit(:LBRACKET, ts, te, meta, "[")
|
388
388
|
end
|
389
389
|
|
390
390
|
end
|
@@ -398,7 +398,7 @@ def self.run_lexer(query_string)
|
|
398
398
|
begin
|
399
399
|
te = p+1;
|
400
400
|
begin
|
401
|
-
emit(:COLON, ts, te, meta)
|
401
|
+
emit(:COLON, ts, te, meta, ":")
|
402
402
|
end
|
403
403
|
|
404
404
|
end
|
@@ -440,7 +440,7 @@ def self.run_lexer(query_string)
|
|
440
440
|
begin
|
441
441
|
te = p+1;
|
442
442
|
begin
|
443
|
-
emit(:VAR_SIGN, ts, te, meta)
|
443
|
+
emit(:VAR_SIGN, ts, te, meta, "$")
|
444
444
|
end
|
445
445
|
|
446
446
|
end
|
@@ -454,7 +454,7 @@ def self.run_lexer(query_string)
|
|
454
454
|
begin
|
455
455
|
te = p+1;
|
456
456
|
begin
|
457
|
-
emit(:DIR_SIGN, ts, te, meta)
|
457
|
+
emit(:DIR_SIGN, ts, te, meta, "@")
|
458
458
|
end
|
459
459
|
|
460
460
|
end
|
@@ -468,7 +468,7 @@ def self.run_lexer(query_string)
|
|
468
468
|
begin
|
469
469
|
te = p+1;
|
470
470
|
begin
|
471
|
-
emit(:ELLIPSIS, ts, te, meta)
|
471
|
+
emit(:ELLIPSIS, ts, te, meta, "...")
|
472
472
|
end
|
473
473
|
|
474
474
|
end
|
@@ -482,7 +482,7 @@ def self.run_lexer(query_string)
|
|
482
482
|
begin
|
483
483
|
te = p+1;
|
484
484
|
begin
|
485
|
-
emit(:EQUALS, ts, te, meta)
|
485
|
+
emit(:EQUALS, ts, te, meta, "=")
|
486
486
|
end
|
487
487
|
|
488
488
|
end
|
@@ -496,7 +496,7 @@ def self.run_lexer(query_string)
|
|
496
496
|
begin
|
497
497
|
te = p+1;
|
498
498
|
begin
|
499
|
-
emit(:BANG, ts, te, meta)
|
499
|
+
emit(:BANG, ts, te, meta, "!")
|
500
500
|
end
|
501
501
|
|
502
502
|
end
|
@@ -510,7 +510,7 @@ def self.run_lexer(query_string)
|
|
510
510
|
begin
|
511
511
|
te = p+1;
|
512
512
|
begin
|
513
|
-
emit(:PIPE, ts, te, meta)
|
513
|
+
emit(:PIPE, ts, te, meta, "|")
|
514
514
|
end
|
515
515
|
|
516
516
|
end
|
@@ -524,7 +524,7 @@ def self.run_lexer(query_string)
|
|
524
524
|
begin
|
525
525
|
te = p+1;
|
526
526
|
begin
|
527
|
-
emit(:AMP, ts, te, meta)
|
527
|
+
emit(:AMP, ts, te, meta, "&")
|
528
528
|
end
|
529
529
|
|
530
530
|
end
|
@@ -738,7 +738,7 @@ def self.run_lexer(query_string)
|
|
738
738
|
begin
|
739
739
|
p = ((te))-1;
|
740
740
|
begin
|
741
|
-
emit(:ON, ts, te, meta)
|
741
|
+
emit(:ON, ts, te, meta, "on")
|
742
742
|
end
|
743
743
|
|
744
744
|
end
|
@@ -746,7 +746,7 @@ def self.run_lexer(query_string)
|
|
746
746
|
begin
|
747
747
|
p = ((te))-1;
|
748
748
|
begin
|
749
|
-
emit(:FRAGMENT, ts, te, meta)
|
749
|
+
emit(:FRAGMENT, ts, te, meta, "fragment")
|
750
750
|
end
|
751
751
|
|
752
752
|
end
|
@@ -754,7 +754,7 @@ def self.run_lexer(query_string)
|
|
754
754
|
begin
|
755
755
|
p = ((te))-1;
|
756
756
|
begin
|
757
|
-
emit(:TRUE, ts, te, meta)
|
757
|
+
emit(:TRUE, ts, te, meta, "true")
|
758
758
|
end
|
759
759
|
|
760
760
|
end
|
@@ -762,7 +762,7 @@ def self.run_lexer(query_string)
|
|
762
762
|
begin
|
763
763
|
p = ((te))-1;
|
764
764
|
begin
|
765
|
-
emit(:FALSE, ts, te, meta)
|
765
|
+
emit(:FALSE, ts, te, meta, "false")
|
766
766
|
end
|
767
767
|
|
768
768
|
end
|
@@ -770,7 +770,7 @@ def self.run_lexer(query_string)
|
|
770
770
|
begin
|
771
771
|
p = ((te))-1;
|
772
772
|
begin
|
773
|
-
emit(:NULL, ts, te, meta)
|
773
|
+
emit(:NULL, ts, te, meta, "null")
|
774
774
|
end
|
775
775
|
|
776
776
|
end
|
@@ -778,7 +778,7 @@ def self.run_lexer(query_string)
|
|
778
778
|
begin
|
779
779
|
p = ((te))-1;
|
780
780
|
begin
|
781
|
-
emit(:QUERY, ts, te, meta)
|
781
|
+
emit(:QUERY, ts, te, meta, "query")
|
782
782
|
end
|
783
783
|
|
784
784
|
end
|
@@ -786,7 +786,7 @@ def self.run_lexer(query_string)
|
|
786
786
|
begin
|
787
787
|
p = ((te))-1;
|
788
788
|
begin
|
789
|
-
emit(:MUTATION, ts, te, meta)
|
789
|
+
emit(:MUTATION, ts, te, meta, "mutation")
|
790
790
|
end
|
791
791
|
|
792
792
|
end
|
@@ -794,7 +794,7 @@ def self.run_lexer(query_string)
|
|
794
794
|
begin
|
795
795
|
p = ((te))-1;
|
796
796
|
begin
|
797
|
-
emit(:SUBSCRIPTION, ts, te, meta)
|
797
|
+
emit(:SUBSCRIPTION, ts, te, meta, "subscription")
|
798
798
|
end
|
799
799
|
|
800
800
|
end
|
@@ -1371,11 +1371,11 @@ end
|
|
1371
1371
|
|
1372
1372
|
def self.record_comment(ts, te, meta)
|
1373
1373
|
token = GraphQL::Language::Token.new(
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1374
|
+
:COMMENT,
|
1375
|
+
meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
|
1376
|
+
meta[:line],
|
1377
|
+
meta[:col],
|
1378
|
+
meta[:previous_token],
|
1379
1379
|
)
|
1380
1380
|
|
1381
1381
|
meta[:previous_token] = token
|
@@ -1383,13 +1383,14 @@ meta[:previous_token] = token
|
|
1383
1383
|
meta[:col] += te - ts
|
1384
1384
|
end
|
1385
1385
|
|
1386
|
-
def self.emit(token_name, ts, te, meta)
|
1386
|
+
def self.emit(token_name, ts, te, meta, token_value = nil)
|
1387
|
+
token_value ||= meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING)
|
1387
1388
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1389
|
+
token_name,
|
1390
|
+
token_value,
|
1391
|
+
meta[:line],
|
1392
|
+
meta[:col],
|
1393
|
+
meta[:previous_token],
|
1393
1394
|
)
|
1394
1395
|
meta[:previous_token] = token
|
1395
1396
|
# Bump the column counter for the next token
|
@@ -1428,30 +1429,30 @@ end
|
|
1428
1429
|
# (It's faster: https://bugs.ruby-lang.org/issues/8110)
|
1429
1430
|
if !value.valid_encoding? || value !~ VALID_STRING
|
1430
1431
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
1431
|
-
|
1432
|
-
value
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1432
|
+
:BAD_UNICODE_ESCAPE,
|
1433
|
+
value,
|
1434
|
+
meta[:line],
|
1435
|
+
meta[:col],
|
1436
|
+
meta[:previous_token],
|
1436
1437
|
)
|
1437
1438
|
else
|
1438
1439
|
replace_escaped_characters_in_place(value)
|
1439
1440
|
|
1440
1441
|
if !value.valid_encoding?
|
1441
1442
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
1442
|
-
|
1443
|
-
value
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1443
|
+
:BAD_UNICODE_ESCAPE,
|
1444
|
+
value,
|
1445
|
+
meta[:line],
|
1446
|
+
meta[:col],
|
1447
|
+
meta[:previous_token],
|
1447
1448
|
)
|
1448
1449
|
else
|
1449
1450
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
1450
|
-
|
1451
|
-
value
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1451
|
+
:STRING,
|
1452
|
+
value,
|
1453
|
+
meta[:line],
|
1454
|
+
meta[:col],
|
1455
|
+
meta[:previous_token],
|
1455
1456
|
)
|
1456
1457
|
end
|
1457
1458
|
end
|
@@ -67,14 +67,14 @@
|
|
67
67
|
main := |*
|
68
68
|
INT => { emit(:INT, ts, te, meta) };
|
69
69
|
FLOAT => { emit(:FLOAT, ts, te, meta) };
|
70
|
-
ON => { emit(:ON, ts, te, meta) };
|
71
|
-
FRAGMENT => { emit(:FRAGMENT, ts, te, meta) };
|
72
|
-
TRUE => { emit(:TRUE, ts, te, meta) };
|
73
|
-
FALSE => { emit(:FALSE, ts, te, meta) };
|
74
|
-
NULL => { emit(:NULL, ts, te, meta) };
|
75
|
-
QUERY => { emit(:QUERY, ts, te, meta) };
|
76
|
-
MUTATION => { emit(:MUTATION, ts, te, meta) };
|
77
|
-
SUBSCRIPTION => { emit(:SUBSCRIPTION, ts, te, meta) };
|
70
|
+
ON => { emit(:ON, ts, te, meta, "on") };
|
71
|
+
FRAGMENT => { emit(:FRAGMENT, ts, te, meta, "fragment") };
|
72
|
+
TRUE => { emit(:TRUE, ts, te, meta, "true") };
|
73
|
+
FALSE => { emit(:FALSE, ts, te, meta, "false") };
|
74
|
+
NULL => { emit(:NULL, ts, te, meta, "null") };
|
75
|
+
QUERY => { emit(:QUERY, ts, te, meta, "query") };
|
76
|
+
MUTATION => { emit(:MUTATION, ts, te, meta, "mutation") };
|
77
|
+
SUBSCRIPTION => { emit(:SUBSCRIPTION, ts, te, meta, "subscription") };
|
78
78
|
SCHEMA => { emit(:SCHEMA, ts, te, meta) };
|
79
79
|
SCALAR => { emit(:SCALAR, ts, te, meta) };
|
80
80
|
TYPE => { emit(:TYPE, ts, te, meta) };
|
@@ -85,22 +85,22 @@
|
|
85
85
|
ENUM => { emit(:ENUM, ts, te, meta) };
|
86
86
|
INPUT => { emit(:INPUT, ts, te, meta) };
|
87
87
|
DIRECTIVE => { emit(:DIRECTIVE, ts, te, meta) };
|
88
|
-
RCURLY => { emit(:RCURLY, ts, te, meta) };
|
89
|
-
LCURLY => { emit(:LCURLY, ts, te, meta) };
|
90
|
-
RPAREN => { emit(:RPAREN, ts, te, meta) };
|
91
|
-
LPAREN => { emit(:LPAREN, ts, te, meta)
|
92
|
-
RBRACKET => { emit(:RBRACKET, ts, te, meta) };
|
93
|
-
LBRACKET => { emit(:LBRACKET, ts, te, meta) };
|
94
|
-
COLON => { emit(:COLON, ts, te, meta) };
|
88
|
+
RCURLY => { emit(:RCURLY, ts, te, meta, "}") };
|
89
|
+
LCURLY => { emit(:LCURLY, ts, te, meta, "{") };
|
90
|
+
RPAREN => { emit(:RPAREN, ts, te, meta, ")") };
|
91
|
+
LPAREN => { emit(:LPAREN, ts, te, meta, "(")};
|
92
|
+
RBRACKET => { emit(:RBRACKET, ts, te, meta, "]") };
|
93
|
+
LBRACKET => { emit(:LBRACKET, ts, te, meta, "[") };
|
94
|
+
COLON => { emit(:COLON, ts, te, meta, ":") };
|
95
95
|
QUOTED_STRING => { emit_string(ts, te, meta, block: false) };
|
96
96
|
BLOCK_STRING => { emit_string(ts, te, meta, block: true) };
|
97
|
-
VAR_SIGN => { emit(:VAR_SIGN, ts, te, meta) };
|
98
|
-
DIR_SIGN => { emit(:DIR_SIGN, ts, te, meta) };
|
99
|
-
ELLIPSIS => { emit(:ELLIPSIS, ts, te, meta) };
|
100
|
-
EQUALS => { emit(:EQUALS, ts, te, meta) };
|
101
|
-
BANG => { emit(:BANG, ts, te, meta) };
|
102
|
-
PIPE => { emit(:PIPE, ts, te, meta) };
|
103
|
-
AMP => { emit(:AMP, ts, te, meta) };
|
97
|
+
VAR_SIGN => { emit(:VAR_SIGN, ts, te, meta, "$") };
|
98
|
+
DIR_SIGN => { emit(:DIR_SIGN, ts, te, meta, "@") };
|
99
|
+
ELLIPSIS => { emit(:ELLIPSIS, ts, te, meta, "...") };
|
100
|
+
EQUALS => { emit(:EQUALS, ts, te, meta, "=") };
|
101
|
+
BANG => { emit(:BANG, ts, te, meta, "!") };
|
102
|
+
PIPE => { emit(:PIPE, ts, te, meta, "|") };
|
103
|
+
AMP => { emit(:AMP, ts, te, meta, "&") };
|
104
104
|
IDENTIFIER => { emit(:IDENTIFIER, ts, te, meta) };
|
105
105
|
COMMENT => { record_comment(ts, te, meta) };
|
106
106
|
|
@@ -163,11 +163,11 @@ module GraphQL
|
|
163
163
|
|
164
164
|
def self.record_comment(ts, te, meta)
|
165
165
|
token = GraphQL::Language::Token.new(
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
166
|
+
:COMMENT,
|
167
|
+
meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
|
168
|
+
meta[:line],
|
169
|
+
meta[:col],
|
170
|
+
meta[:previous_token],
|
171
171
|
)
|
172
172
|
|
173
173
|
meta[:previous_token] = token
|
@@ -175,13 +175,14 @@ module GraphQL
|
|
175
175
|
meta[:col] += te - ts
|
176
176
|
end
|
177
177
|
|
178
|
-
def self.emit(token_name, ts, te, meta)
|
178
|
+
def self.emit(token_name, ts, te, meta, token_value = nil)
|
179
|
+
token_value ||= meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING)
|
179
180
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
181
|
+
token_name,
|
182
|
+
token_value,
|
183
|
+
meta[:line],
|
184
|
+
meta[:col],
|
185
|
+
meta[:previous_token],
|
185
186
|
)
|
186
187
|
meta[:previous_token] = token
|
187
188
|
# Bump the column counter for the next token
|
@@ -220,30 +221,30 @@ module GraphQL
|
|
220
221
|
# (It's faster: https://bugs.ruby-lang.org/issues/8110)
|
221
222
|
if !value.valid_encoding? || value !~ VALID_STRING
|
222
223
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
223
|
-
|
224
|
-
value
|
225
|
-
|
226
|
-
|
227
|
-
|
224
|
+
:BAD_UNICODE_ESCAPE,
|
225
|
+
value,
|
226
|
+
meta[:line],
|
227
|
+
meta[:col],
|
228
|
+
meta[:previous_token],
|
228
229
|
)
|
229
230
|
else
|
230
231
|
replace_escaped_characters_in_place(value)
|
231
232
|
|
232
233
|
if !value.valid_encoding?
|
233
234
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
234
|
-
|
235
|
-
value
|
236
|
-
|
237
|
-
|
238
|
-
|
235
|
+
:BAD_UNICODE_ESCAPE,
|
236
|
+
value,
|
237
|
+
meta[:line],
|
238
|
+
meta[:col],
|
239
|
+
meta[:previous_token],
|
239
240
|
)
|
240
241
|
else
|
241
242
|
meta[:tokens] << token = GraphQL::Language::Token.new(
|
242
|
-
|
243
|
-
value
|
244
|
-
|
245
|
-
|
246
|
-
|
243
|
+
:STRING,
|
244
|
+
value,
|
245
|
+
meta[:line],
|
246
|
+
meta[:col],
|
247
|
+
meta[:previous_token],
|
247
248
|
)
|
248
249
|
end
|
249
250
|
end
|
@@ -28,7 +28,8 @@ module GraphQL
|
|
28
28
|
def initialize(options={})
|
29
29
|
if options.key?(:position_source)
|
30
30
|
position_source = options.delete(:position_source)
|
31
|
-
@line
|
31
|
+
@line = position_source.line
|
32
|
+
@col = position_source.col
|
32
33
|
end
|
33
34
|
|
34
35
|
@filename = options.delete(:filename)
|
@@ -66,7 +67,7 @@ module GraphQL
|
|
66
67
|
|
67
68
|
# @return [Symbol] the method to call on {Language::Visitor} for this node
|
68
69
|
def visit_method
|
69
|
-
raise
|
70
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.class.name}#visit_method shold return a symbol"
|
70
71
|
end
|
71
72
|
|
72
73
|
def position
|
@@ -350,6 +351,8 @@ module GraphQL
|
|
350
351
|
|
351
352
|
# A single selection in a GraphQL query.
|
352
353
|
class Field < AbstractNode
|
354
|
+
NONE = [].freeze
|
355
|
+
|
353
356
|
scalar_methods :name, :alias
|
354
357
|
children_methods({
|
355
358
|
arguments: GraphQL::Language::Nodes::Argument,
|
@@ -360,13 +363,13 @@ module GraphQL
|
|
360
363
|
# @!attribute selections
|
361
364
|
# @return [Array<Nodes::Field>] Selections on this object (or empty array if this is a scalar field)
|
362
365
|
|
363
|
-
def initialize_node(
|
364
|
-
@name = name
|
365
|
-
@arguments = arguments
|
366
|
-
@directives = directives
|
367
|
-
@selections = selections
|
366
|
+
def initialize_node(attributes)
|
367
|
+
@name = attributes[:name]
|
368
|
+
@arguments = attributes[:arguments] || NONE
|
369
|
+
@directives = attributes[:directives] || NONE
|
370
|
+
@selections = attributes[:selections] || NONE
|
368
371
|
# oops, alias is a keyword:
|
369
|
-
@alias =
|
372
|
+
@alias = attributes[:alias]
|
370
373
|
end
|
371
374
|
|
372
375
|
# Override this because default is `:fields`
|
@@ -21,6 +21,7 @@ def initialize(query_string, filename:, tracer: Tracing::NullTracer)
|
|
21
21
|
@query_string = query_string
|
22
22
|
@filename = filename
|
23
23
|
@tracer = tracer
|
24
|
+
@reused_next_token = [nil, nil]
|
24
25
|
end
|
25
26
|
|
26
27
|
def parse_document
|
@@ -51,7 +52,9 @@ def next_token
|
|
51
52
|
if lexer_token.nil?
|
52
53
|
nil
|
53
54
|
else
|
54
|
-
[lexer_token.name
|
55
|
+
@reused_next_token[0] = lexer_token.name
|
56
|
+
@reused_next_token[1] = lexer_token
|
57
|
+
@reused_next_token
|
55
58
|
end
|
56
59
|
end
|
57
60
|
|
@@ -440,6 +440,7 @@ def initialize(query_string, filename:, tracer: Tracing::NullTracer)
|
|
440
440
|
@query_string = query_string
|
441
441
|
@filename = filename
|
442
442
|
@tracer = tracer
|
443
|
+
@reused_next_token = [nil, nil]
|
443
444
|
end
|
444
445
|
|
445
446
|
def parse_document
|
@@ -470,7 +471,9 @@ def next_token
|
|
470
471
|
if lexer_token.nil?
|
471
472
|
nil
|
472
473
|
else
|
473
|
-
[lexer_token.name
|
474
|
+
@reused_next_token[0] = lexer_token.name
|
475
|
+
@reused_next_token[1] = lexer_token
|
476
|
+
@reused_next_token
|
474
477
|
end
|
475
478
|
end
|
476
479
|
|
@@ -87,6 +87,10 @@ module GraphQL
|
|
87
87
|
|
88
88
|
def_delegators :to_h, :keys, :values, :each, :any?
|
89
89
|
|
90
|
+
def prepare
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
90
94
|
# Access each key, value and type for the arguments in this set.
|
91
95
|
# @yield [argument_value] The {ArgumentValue} for each argument
|
92
96
|
# @yieldparam argument_value [ArgumentValue]
|
@@ -152,7 +156,8 @@ module GraphQL
|
|
152
156
|
wrap_value(value, arg_defn_type.of_type, context)
|
153
157
|
when GraphQL::InputObjectType
|
154
158
|
if value.is_a?(Hash)
|
155
|
-
arg_defn_type.arguments_class.new(value, context: context, defaults_used: Set.new)
|
159
|
+
result = arg_defn_type.arguments_class.new(value, context: context, defaults_used: Set.new)
|
160
|
+
result.prepare
|
156
161
|
else
|
157
162
|
value
|
158
163
|
end
|
@@ -108,7 +108,8 @@ module GraphQL
|
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
|
-
argument_owner.arguments_class.new(values_hash, context: context, defaults_used: defaults_used)
|
111
|
+
result = argument_owner.arguments_class.new(values_hash, context: context, defaults_used: defaults_used)
|
112
|
+
result.prepare
|
112
113
|
end
|
113
114
|
end
|
114
115
|
end
|
@@ -139,7 +139,7 @@ module GraphQL
|
|
139
139
|
|
140
140
|
# An opaque operation which returns a connection-specific cursor.
|
141
141
|
def cursor_from_node(object)
|
142
|
-
raise
|
142
|
+
raise GraphQL::RequiredImplementationMissingError, "must return a cursor for this object/connection pair"
|
143
143
|
end
|
144
144
|
|
145
145
|
def inspect
|
@@ -161,11 +161,11 @@ module GraphQL
|
|
161
161
|
end
|
162
162
|
|
163
163
|
def paged_nodes
|
164
|
-
raise
|
164
|
+
raise GraphQL::RequiredImplementationMissingError, "must return nodes for this connection after paging"
|
165
165
|
end
|
166
166
|
|
167
167
|
def sliced_nodes
|
168
|
-
raise
|
168
|
+
raise GraphQL::RequiredImplementationMissingError, "must return all nodes for this connection after chopping off first and last"
|
169
169
|
end
|
170
170
|
end
|
171
171
|
end
|
@@ -25,12 +25,16 @@ module GraphQL
|
|
25
25
|
|
26
26
|
def has_next_page
|
27
27
|
if first
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
if defined?(ActiveRecord::Relation) && nodes.is_a?(ActiveRecord::Relation)
|
29
|
+
initial_offset = after ? offset_from_cursor(after) : 0
|
30
|
+
return paged_nodes.length >= first && nodes.offset(first + initial_offset).exists?
|
31
|
+
end
|
32
|
+
return paged_nodes.length >= first && sliced_nodes_count > first
|
33
|
+
end
|
34
|
+
if GraphQL::Relay::ConnectionType.bidirectional_pagination && last
|
35
|
+
return sliced_nodes_count >= last
|
33
36
|
end
|
37
|
+
false
|
34
38
|
end
|
35
39
|
|
36
40
|
def has_previous_page
|
data/lib/graphql/schema.rb
CHANGED
@@ -281,13 +281,13 @@ module GraphQL
|
|
281
281
|
ensure_defined
|
282
282
|
# Assert that all necessary configs are present:
|
283
283
|
validation_error = Validation.validate(self)
|
284
|
-
validation_error && raise(
|
284
|
+
validation_error && raise(GraphQL::RequiredImplementationMissingError, validation_error)
|
285
285
|
rebuild_artifacts
|
286
286
|
|
287
287
|
@definition_error = nil
|
288
288
|
nil
|
289
289
|
rescue StandardError => err
|
290
|
-
if @raise_definition_error || err.is_a?(CyclicalDefinitionError)
|
290
|
+
if @raise_definition_error || err.is_a?(CyclicalDefinitionError) || err.is_a?(GraphQL::RequiredImplementationMissingError)
|
291
291
|
raise
|
292
292
|
else
|
293
293
|
# Raise this error _later_ to avoid messing with Rails constant loading
|
@@ -492,7 +492,7 @@ module GraphQL
|
|
492
492
|
def resolve_type(type, object, ctx = :__undefined__)
|
493
493
|
check_resolved_type(type, object, ctx) do |ok_type, ok_object, ok_ctx|
|
494
494
|
if @resolve_type_proc.nil?
|
495
|
-
raise(
|
495
|
+
raise(GraphQL::RequiredImplementationMissingError, "Can't determine GraphQL type for: #{ok_object.inspect}, define `resolve_type (type, obj, ctx) -> { ... }` inside `Schema.define`.")
|
496
496
|
end
|
497
497
|
@resolve_type_proc.call(ok_type, ok_object, ok_ctx)
|
498
498
|
end
|
@@ -553,7 +553,7 @@ module GraphQL
|
|
553
553
|
# @return [Any] The application object identified by `id`
|
554
554
|
def object_from_id(id, ctx)
|
555
555
|
if @object_from_id_proc.nil?
|
556
|
-
raise(
|
556
|
+
raise(GraphQL::RequiredImplementationMissingError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
|
557
557
|
else
|
558
558
|
@object_from_id_proc.call(id, ctx)
|
559
559
|
end
|
@@ -620,7 +620,7 @@ module GraphQL
|
|
620
620
|
# @return [String] a unique identifier for `object` which clients can use to refetch it
|
621
621
|
def id_from_object(object, type, ctx)
|
622
622
|
if @id_from_object_proc.nil?
|
623
|
-
raise(
|
623
|
+
raise(GraphQL::RequiredImplementationMissingError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
|
624
624
|
else
|
625
625
|
@id_from_object_proc.call(object, type, ctx)
|
626
626
|
end
|
@@ -956,16 +956,16 @@ module GraphQL
|
|
956
956
|
if type.kind.object?
|
957
957
|
type
|
958
958
|
else
|
959
|
-
raise
|
959
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types or Interface types (tried to resolve: #{type.name})"
|
960
960
|
end
|
961
961
|
end
|
962
962
|
|
963
963
|
def object_from_id(node_id, ctx)
|
964
|
-
raise
|
964
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(node_id, ctx) must be implemented to load by ID (tried to load from id `#{node_id}`)"
|
965
965
|
end
|
966
966
|
|
967
967
|
def id_from_object(object, type, ctx)
|
968
|
-
raise
|
968
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.id_from_object(object, type, ctx) must be implemented to create global ids (tried to create an id for `#{object.inspect}`)"
|
969
969
|
end
|
970
970
|
|
971
971
|
def visible?(member, context)
|
@@ -94,17 +94,7 @@ module GraphQL
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def authorized?(obj, ctx)
|
97
|
-
|
98
|
-
if arg_type.kind.input_object? && arg_type != @owner
|
99
|
-
arg_type.arguments.each do |_name, input_obj_arg|
|
100
|
-
if !input_obj_arg.authorized?(obj, ctx)
|
101
|
-
return false
|
102
|
-
end
|
103
|
-
end
|
104
|
-
true
|
105
|
-
else
|
106
|
-
true
|
107
|
-
end
|
97
|
+
true
|
108
98
|
end
|
109
99
|
|
110
100
|
def to_graphql
|
@@ -111,7 +111,7 @@ module GraphQL
|
|
111
111
|
end
|
112
112
|
|
113
113
|
NullResolveType = ->(type, obj, ctx) {
|
114
|
-
raise(
|
114
|
+
raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
|
115
115
|
}
|
116
116
|
|
117
117
|
NullScalarCoerce = ->(val, _ctx) { val }
|
@@ -58,7 +58,7 @@ module GraphQL
|
|
58
58
|
# @param context [GraphQL::Query::Context]
|
59
59
|
# @return [Boolean] If truthy, execution will continue
|
60
60
|
def self.enabled?(flag_name, object, context)
|
61
|
-
raise
|
61
|
+
raise GraphQL::RequiredImplementationMissingError, "Implement `.enabled?(flag_name, object, context)` to return true or false for the feature flag (#{flag_name.inspect})"
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -14,6 +14,7 @@ module GraphQL
|
|
14
14
|
include GraphQL::Schema::Member::AcceptsDefinition
|
15
15
|
include GraphQL::Schema::Member::HasArguments
|
16
16
|
include GraphQL::Schema::Member::HasPath
|
17
|
+
extend GraphQL::Schema::FindInheritedValue
|
17
18
|
|
18
19
|
# @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
|
19
20
|
attr_reader :name
|
@@ -135,6 +136,22 @@ module GraphQL
|
|
135
136
|
end
|
136
137
|
end
|
137
138
|
|
139
|
+
# This extension is applied to fields when {#connection?} is true.
|
140
|
+
#
|
141
|
+
# You can override it in your base field definition.
|
142
|
+
# @return [Class] A {FieldExtension} subclass for implementing pagination behavior.
|
143
|
+
# @example Configuring a custom extension
|
144
|
+
# class Types::BaseField < GraphQL::Schema::Field
|
145
|
+
# connection_extension(MyCustomExtension)
|
146
|
+
# end
|
147
|
+
def self.connection_extension(new_extension_class = nil)
|
148
|
+
if new_extension_class
|
149
|
+
@connection_extension = new_extension_class
|
150
|
+
else
|
151
|
+
@connection_extension ||= find_inherited_value(:connection_extension, ConnectionExtension)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
138
155
|
# @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
|
139
156
|
# @param type [Class, GraphQL::BaseType, Array] The return type of this field
|
140
157
|
# @param owner [Class] The type that this field belongs to
|
@@ -246,7 +263,7 @@ module GraphQL
|
|
246
263
|
# The problem with putting this after the definition_block
|
247
264
|
# is that it would override arguments
|
248
265
|
if connection?
|
249
|
-
self.extension(
|
266
|
+
self.extension(self.class.connection_extension)
|
250
267
|
end
|
251
268
|
|
252
269
|
if definition_block
|
@@ -582,7 +599,7 @@ module GraphQL
|
|
582
599
|
elsif ctx.respond_to?(extra_name)
|
583
600
|
ctx.public_send(extra_name)
|
584
601
|
else
|
585
|
-
raise
|
602
|
+
raise GraphQL::RequiredImplementationMissingError, "Unknown field extra for #{self.path}: #{extra_name.inspect}"
|
586
603
|
end
|
587
604
|
end
|
588
605
|
|
@@ -34,7 +34,7 @@ module GraphQL
|
|
34
34
|
end
|
35
35
|
|
36
36
|
NullResolveType = ->(type, obj, ctx) {
|
37
|
-
raise(
|
37
|
+
raise(GraphQL::RequiredImplementationMissingError, "This schema was loaded from string, so it can't resolve types for objects")
|
38
38
|
}
|
39
39
|
|
40
40
|
NullScalarCoerce = ->(val, _ctx) { val }
|
@@ -51,7 +51,7 @@ module GraphQL
|
|
51
51
|
when "NON_NULL"
|
52
52
|
NonNullType.new(of_type: resolve_type(types, type.fetch("ofType")))
|
53
53
|
else
|
54
|
-
fail
|
54
|
+
fail GraphQL::RequiredImplementationMissingError, "#{kind} not implemented"
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -171,7 +171,7 @@ module GraphQL
|
|
171
171
|
}
|
172
172
|
)
|
173
173
|
else
|
174
|
-
fail
|
174
|
+
fail GraphQL::RequiredImplementationMissingError, "#{type["kind"]} not implemented"
|
175
175
|
end
|
176
176
|
end
|
177
177
|
end
|
@@ -74,7 +74,7 @@ module GraphQL
|
|
74
74
|
|
75
75
|
# @return [GraphQL::BaseType] Convert this type to a legacy-style object.
|
76
76
|
def to_graphql
|
77
|
-
raise
|
77
|
+
raise GraphQL::RequiredImplementationMissingError
|
78
78
|
end
|
79
79
|
|
80
80
|
alias :unwrap :itself
|
@@ -88,7 +88,7 @@ module GraphQL
|
|
88
88
|
# without any namespaces and with any `-Type` suffix removed
|
89
89
|
def default_graphql_name
|
90
90
|
@default_graphql_name ||= begin
|
91
|
-
raise
|
91
|
+
raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
|
92
92
|
|
93
93
|
name.split("::").last.sub(/Type\Z/, "")
|
94
94
|
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require 'irb/ruby-token'
|
3
|
+
|
2
4
|
module GraphQL
|
3
5
|
class Schema
|
4
6
|
class Member
|
@@ -38,16 +40,23 @@ module GraphQL
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
43
|
+
# A list of Ruby keywords.
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
RUBY_KEYWORDS = RubyToken::TokenDefinitions.select { |definition| definition[1] == RubyToken::TkId }
|
47
|
+
.map { |definition| definition[2] }
|
48
|
+
.compact
|
49
|
+
|
50
|
+
# A list of GraphQL-Ruby keywords.
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
GRAPHQL_RUBY_KEYWORDS = [:context, :object, :method]
|
54
|
+
|
41
55
|
# A list of field names that we should advise users to pick a different
|
42
56
|
# resolve method name.
|
43
57
|
#
|
44
58
|
# @api private
|
45
|
-
CONFLICT_FIELD_NAMES = Set.new(
|
46
|
-
# GraphQL-Ruby conflicts
|
47
|
-
:context, :object,
|
48
|
-
# Ruby built-ins conflicts
|
49
|
-
:method, :class
|
50
|
-
])
|
59
|
+
CONFLICT_FIELD_NAMES = Set.new(GRAPHQL_RUBY_KEYWORDS + RUBY_KEYWORDS)
|
51
60
|
|
52
61
|
# Register this field with the class, overriding a previous one if needed.
|
53
62
|
# @param field_defn [GraphQL::Schema::Field]
|
@@ -103,7 +103,7 @@ module GraphQL
|
|
103
103
|
# Do the work. Everything happens here.
|
104
104
|
# @return [Object] An object corresponding to the return type
|
105
105
|
def resolve(**args)
|
106
|
-
raise
|
106
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.class.name}#resolve should execute the field's logic"
|
107
107
|
end
|
108
108
|
|
109
109
|
# Called before arguments are prepared.
|
@@ -267,6 +267,7 @@ module GraphQL
|
|
267
267
|
arguments: arguments,
|
268
268
|
null: null,
|
269
269
|
complexity: complexity,
|
270
|
+
extensions: extensions,
|
270
271
|
}
|
271
272
|
end
|
272
273
|
|
@@ -320,6 +321,18 @@ module GraphQL
|
|
320
321
|
inherited_lookups.merge(own_arguments_loads_as_type)
|
321
322
|
end
|
322
323
|
|
324
|
+
# Registers new extension
|
325
|
+
# @param extension [Class] Extension class
|
326
|
+
# @param options [Hash] Optional extension options
|
327
|
+
def extension(extension, **options)
|
328
|
+
extensions << {extension => options}
|
329
|
+
end
|
330
|
+
|
331
|
+
# @api private
|
332
|
+
def extensions
|
333
|
+
@extensions ||= []
|
334
|
+
end
|
335
|
+
|
323
336
|
private
|
324
337
|
|
325
338
|
def own_arguments_loads_as_type
|
@@ -11,11 +11,11 @@ module GraphQL
|
|
11
11
|
super
|
12
12
|
@defdep_node_paths = {}
|
13
13
|
|
14
|
-
# { name => node } pairs for fragments
|
15
|
-
@defdep_fragment_definitions = {}
|
14
|
+
# { name => [node, ...] } pairs for fragments (although duplicate-named fragments are _invalid_, they are _possible_)
|
15
|
+
@defdep_fragment_definitions = Hash.new{ |h, k| h[k] = [] }
|
16
16
|
|
17
17
|
# This tracks dependencies from fragment to Node where it was used
|
18
|
-
# {
|
18
|
+
# { fragment_definition_name => [dependent_node, dependent_node]}
|
19
19
|
@defdep_dependent_definitions = Hash.new { |h, k| h[k] = Set.new }
|
20
20
|
|
21
21
|
# First-level usages of spreads within definitions
|
@@ -32,7 +32,7 @@ module GraphQL
|
|
32
32
|
def on_document(node, parent)
|
33
33
|
node.definitions.each do |definition|
|
34
34
|
if definition.is_a? GraphQL::Language::Nodes::FragmentDefinition
|
35
|
-
@defdep_fragment_definitions[definition.name]
|
35
|
+
@defdep_fragment_definitions[definition.name] << definition
|
36
36
|
end
|
37
37
|
end
|
38
38
|
super
|
@@ -42,7 +42,7 @@ module GraphQL
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def on_operation_definition(node, prev_node)
|
45
|
-
@defdep_node_paths[node] = NodeWithPath.new(node, context.path)
|
45
|
+
@defdep_node_paths[node.name] = NodeWithPath.new(node, context.path)
|
46
46
|
@defdep_current_parent = node
|
47
47
|
super
|
48
48
|
@defdep_current_parent = nil
|
@@ -59,7 +59,7 @@ module GraphQL
|
|
59
59
|
@defdep_node_paths[node] = NodeWithPath.new(node, context.path)
|
60
60
|
|
61
61
|
# Track both sides of the dependency
|
62
|
-
@defdep_dependent_definitions[
|
62
|
+
@defdep_dependent_definitions[node.name] << @defdep_current_parent
|
63
63
|
@defdep_immediate_dependencies[@defdep_current_parent] << node
|
64
64
|
super
|
65
65
|
end
|
@@ -116,24 +116,28 @@ module GraphQL
|
|
116
116
|
dependency_map = DependencyMap.new
|
117
117
|
# Don't allow the loop to run more times
|
118
118
|
# than the number of fragments in the document
|
119
|
-
max_loops =
|
119
|
+
max_loops = 0
|
120
|
+
@defdep_fragment_definitions.each_value do |v|
|
121
|
+
max_loops += v.size
|
122
|
+
end
|
123
|
+
|
120
124
|
loops = 0
|
121
125
|
|
122
126
|
# Instead of tracking independent fragments _as you visit_,
|
123
127
|
# determine them at the end. This way, we can treat fragments with the
|
124
128
|
# same name as if they were the same name. If _any_ of the fragments
|
125
129
|
# with that name has a dependency, we record it.
|
126
|
-
independent_fragment_nodes = @defdep_fragment_definitions.values - @defdep_immediate_dependencies.keys
|
130
|
+
independent_fragment_nodes = @defdep_fragment_definitions.values.flatten - @defdep_immediate_dependencies.keys
|
127
131
|
|
128
132
|
while fragment_node = independent_fragment_nodes.pop
|
129
133
|
loops += 1
|
130
134
|
if loops > max_loops
|
131
|
-
raise("Resolution loops exceeded the number of definitions; infinite loop detected.")
|
135
|
+
raise("Resolution loops exceeded the number of definitions; infinite loop detected. (Max: #{max_loops}, Current: #{loops})")
|
132
136
|
end
|
133
137
|
# Since it's independent, let's remove it from here.
|
134
138
|
# That way, we can use the remainder to identify cycles
|
135
139
|
@defdep_immediate_dependencies.delete(fragment_node)
|
136
|
-
fragment_usages = @defdep_dependent_definitions[fragment_node]
|
140
|
+
fragment_usages = @defdep_dependent_definitions[fragment_node.name]
|
137
141
|
if fragment_usages.empty?
|
138
142
|
# If we didn't record any usages during the visit,
|
139
143
|
# then this fragment is unused.
|
@@ -151,10 +155,15 @@ module GraphQL
|
|
151
155
|
if block_given?
|
152
156
|
yield(definition_node, removed, fragment_node)
|
153
157
|
end
|
154
|
-
if remaining.empty? &&
|
158
|
+
if remaining.empty? &&
|
159
|
+
definition_node.is_a?(GraphQL::Language::Nodes::FragmentDefinition) &&
|
160
|
+
definition_node.name != fragment_node.name
|
155
161
|
# If all of this definition's dependencies have
|
156
162
|
# been resolved, we can now resolve its
|
157
163
|
# own dependents.
|
164
|
+
#
|
165
|
+
# But, it's possible to have a duplicate-named fragment here.
|
166
|
+
# Skip it in that case
|
158
167
|
independent_fragment_nodes << definition_node
|
159
168
|
end
|
160
169
|
end
|
@@ -166,7 +175,7 @@ module GraphQL
|
|
166
175
|
# then they're still in there
|
167
176
|
@defdep_immediate_dependencies.each do |defn_node, deps|
|
168
177
|
deps.each do |spread|
|
169
|
-
if
|
178
|
+
if !@defdep_fragment_definitions.key?(spread.name)
|
170
179
|
dependency_map.unmet_dependencies[@defdep_node_paths[defn_node]] << @defdep_node_paths[spread]
|
171
180
|
deps.delete(spread)
|
172
181
|
end
|
@@ -124,7 +124,7 @@ module GraphQL
|
|
124
124
|
# @yieldparam subscription_id [String]
|
125
125
|
# @return [void]
|
126
126
|
def each_subscription_id(event)
|
127
|
-
raise
|
127
|
+
raise GraphQL::RequiredImplementationMissingError
|
128
128
|
end
|
129
129
|
|
130
130
|
# The system wants to send an update to this subscription.
|
@@ -132,7 +132,7 @@ module GraphQL
|
|
132
132
|
# @param subscription_id [String]
|
133
133
|
# @return [Hash] Containing required keys
|
134
134
|
def read_subscription(subscription_id)
|
135
|
-
raise
|
135
|
+
raise GraphQL::RequiredImplementationMissingError
|
136
136
|
end
|
137
137
|
|
138
138
|
# A subscription query was re-evaluated, returning `result`.
|
@@ -141,7 +141,7 @@ module GraphQL
|
|
141
141
|
# @param result [Hash]
|
142
142
|
# @return [void]
|
143
143
|
def deliver(subscription_id, result)
|
144
|
-
raise
|
144
|
+
raise GraphQL::RequiredImplementationMissingError
|
145
145
|
end
|
146
146
|
|
147
147
|
# `query` was executed and found subscriptions to `events`.
|
@@ -150,7 +150,7 @@ module GraphQL
|
|
150
150
|
# @param events [Array<GraphQL::Subscriptions::Event>]
|
151
151
|
# @return [void]
|
152
152
|
def write_subscription(query, events)
|
153
|
-
raise
|
153
|
+
raise GraphQL::RequiredImplementationMissingError
|
154
154
|
end
|
155
155
|
|
156
156
|
# A subscription was terminated server-side.
|
@@ -158,7 +158,7 @@ module GraphQL
|
|
158
158
|
# @param subscription_id [String]
|
159
159
|
# @return void.
|
160
160
|
def delete_subscription(subscription_id)
|
161
|
-
raise
|
161
|
+
raise GraphQL::RequiredImplementationMissingError
|
162
162
|
end
|
163
163
|
|
164
164
|
# @return [String] A new unique identifier for a subscription
|
@@ -13,7 +13,7 @@ module GraphQL
|
|
13
13
|
# @param input_text [String] Untransformed GraphQL-Ruby code
|
14
14
|
# @return [String] The input text, with a transformation applied if necessary
|
15
15
|
def apply(input_text)
|
16
|
-
raise
|
16
|
+
raise GraphQL::RequiredImplementationMissingError, "Return transformed text here"
|
17
17
|
end
|
18
18
|
|
19
19
|
# Recursively transform a `.define`-DSL-based type expression into a class-ready expression, for example:
|
data/lib/graphql/version.rb
CHANGED
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.9.
|
4
|
+
version: 1.9.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-10-
|
11
|
+
date: 2019-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|