graphql 1.9.14 → 1.9.15
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/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
|