graphql 1.9.14 → 1.9.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/templates/base_field.erb +0 -4
  3. data/lib/generators/graphql/templates/graphql_controller.erb +1 -1
  4. data/lib/generators/graphql/templates/schema.erb +1 -1
  5. data/lib/graphql.rb +3 -0
  6. data/lib/graphql/analysis/ast/analyzer.rb +1 -1
  7. data/lib/graphql/base_type.rb +1 -1
  8. data/lib/graphql/function.rb +1 -1
  9. data/lib/graphql/input_object_type.rb +2 -1
  10. data/lib/graphql/language/document_from_schema_definition.rb +1 -1
  11. data/lib/graphql/language/lexer.rb +49 -48
  12. data/lib/graphql/language/lexer.rl +49 -48
  13. data/lib/graphql/language/nodes.rb +11 -8
  14. data/lib/graphql/language/parser.rb +4 -1
  15. data/lib/graphql/language/parser.y +4 -1
  16. data/lib/graphql/language/token.rb +1 -1
  17. data/lib/graphql/query/arguments.rb +6 -1
  18. data/lib/graphql/query/literal_input.rb +2 -1
  19. data/lib/graphql/relay/base_connection.rb +3 -3
  20. data/lib/graphql/relay/relation_connection.rb +9 -5
  21. data/lib/graphql/schema.rb +8 -8
  22. data/lib/graphql/schema/argument.rb +1 -11
  23. data/lib/graphql/schema/build_from_definition.rb +1 -1
  24. data/lib/graphql/schema/directive/feature.rb +1 -1
  25. data/lib/graphql/schema/field.rb +19 -2
  26. data/lib/graphql/schema/input_object.rb +4 -0
  27. data/lib/graphql/schema/loader.rb +3 -3
  28. data/lib/graphql/schema/member/base_dsl_methods.rb +2 -2
  29. data/lib/graphql/schema/member/has_fields.rb +15 -6
  30. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  31. data/lib/graphql/schema/resolver.rb +14 -1
  32. data/lib/graphql/schema/wrapper.rb +1 -1
  33. data/lib/graphql/static_validation/definition_dependencies.rb +21 -12
  34. data/lib/graphql/subscriptions.rb +5 -5
  35. data/lib/graphql/upgrader/member.rb +1 -1
  36. data/lib/graphql/version.rb +1 -1
  37. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23da143cfa3964ded042927d8b52fa98598387b3ab471b2ae66a2d25282af9b4
4
- data.tar.gz: e1a2924a847a05c1214b350bb316f093ab36a09b4be20c7e4cb66a2ee429058f
3
+ metadata.gz: 2f0505024fefcdebc975dad9259c3f3470f883b4251380e759de60ba380b3314
4
+ data.tar.gz: d92149e0da6aa4e110525a38badaf2163bf887205e2c6dd75c327302e0cfabb4
5
5
  SHA512:
6
- metadata.gz: c354cc5db0bf2072f25adb3798c90e011b9998cbb287ec825bdcc2f4733070af552810e28e46045b0eace05b9c8db571823a84be5e770c0be76eeb44dcd499fd
7
- data.tar.gz: 8d7d75c3dfa2b001e36d30554eaf313b3f489625519462e53fa7c479a1f0baf4fc7d4c27aec8cc78ceb9ef28dd7182bae61a6c2c768e8a30915657379c2832c7
6
+ metadata.gz: 47b920de6ba95b4c15ebc4aace97d74931cc24efee8c3fb6a6291ea68a13b3ef46b9c613658306e1ff100d0917433431c129baba12553a94dc96a4184cbc5435
7
+ data.tar.gz: 0e9c03e45fd3b3cb40a9b6b948ee1f71952f618511254acb3840195ff9c054036308636c7b2a42858096e70d1764e38458b88b0f2f369f699c7f71cdd0afd415
@@ -1,9 +1,5 @@
1
1
  module Types
2
2
  class BaseField < GraphQL::Schema::Field
3
3
  argument_class Types::BaseArgument
4
-
5
- def resolve_field(obj, args, ctx)
6
- resolve(obj, args, ctx)
7
- end
8
4
  end
9
5
  end
@@ -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(NotImplementedError)
27
+ raise(GraphQL::RequiredImplementationMissingError)
28
28
  end
29
29
  <% end %><% if options[:batch] %>
30
30
  # GraphQL::Batch setup:
@@ -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]
@@ -22,7 +22,7 @@ module GraphQL
22
22
  # in a query error.
23
23
  # @return [Any] The analyzer result
24
24
  def result
25
- raise NotImplementedError
25
+ raise GraphQL::RequiredImplementationMissingError
26
26
  end
27
27
 
28
28
  class << self
@@ -167,7 +167,7 @@ module GraphQL
167
167
  end
168
168
 
169
169
  def coerce_result(value, ctx)
170
- raise NotImplementedError
170
+ raise GraphQL::RequiredImplementationMissingError
171
171
  end
172
172
 
173
173
  # Types with fields may override this
@@ -43,7 +43,7 @@ module GraphQL
43
43
 
44
44
  # @return [Object] This function's resolver
45
45
  def call(obj, args, ctx)
46
- raise NotImplementedError
46
+ raise GraphQL::RequiredImplementationMissingError
47
47
  end
48
48
 
49
49
  # @return [String, nil]
@@ -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 NotImplementedError, "Unexpected default value type #{type.inspect}"
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
- name: :COMMENT,
1375
- value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
1376
- line: meta[:line],
1377
- col: meta[:col],
1378
- prev_token: meta[:previous_token],
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
- name: token_name,
1389
- value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
1390
- line: meta[:line],
1391
- col: meta[:col],
1392
- prev_token: meta[:previous_token],
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
- name: :BAD_UNICODE_ESCAPE,
1432
- value: value,
1433
- line: meta[:line],
1434
- col: meta[:col],
1435
- prev_token: meta[:previous_token],
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
- name: :BAD_UNICODE_ESCAPE,
1443
- value: value,
1444
- line: meta[:line],
1445
- col: meta[:col],
1446
- prev_token: meta[:previous_token],
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
- name: :STRING,
1451
- value: value,
1452
- line: meta[:line],
1453
- col: meta[:col],
1454
- prev_token: meta[:previous_token],
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
- name: :COMMENT,
167
- value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
168
- line: meta[:line],
169
- col: meta[:col],
170
- prev_token: meta[:previous_token],
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
- name: token_name,
181
- value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING),
182
- line: meta[:line],
183
- col: meta[:col],
184
- prev_token: meta[:previous_token],
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
- name: :BAD_UNICODE_ESCAPE,
224
- value: value,
225
- line: meta[:line],
226
- col: meta[:col],
227
- prev_token: meta[:previous_token],
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
- name: :BAD_UNICODE_ESCAPE,
235
- value: value,
236
- line: meta[:line],
237
- col: meta[:col],
238
- prev_token: meta[:previous_token],
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
- name: :STRING,
243
- value: value,
244
- line: meta[:line],
245
- col: meta[:col],
246
- prev_token: meta[:previous_token],
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, @col = position_source.line_and_column
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 NotImplementedError, "#{self.class.name}#visit_method shold return a symbol"
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(name: nil, arguments: [], directives: [], selections: [], **kwargs)
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 = kwargs.fetch(:alias, nil)
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, lexer_token]
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, lexer_token]
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
 
@@ -14,7 +14,7 @@ module GraphQL
14
14
  attr_reader :value
15
15
  attr_reader :prev_token, :line, :col
16
16
 
17
- def initialize(value:, name:, line:, col:, prev_token:)
17
+ def initialize(name, value, line, col, prev_token)
18
18
  @name = name
19
19
  @value = -value
20
20
  @line = line
@@ -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 NotImplementedError, "must return a cursor for this object/connection pair"
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 NotImplementedError, "must return nodes for this connection after paging"
164
+ raise GraphQL::RequiredImplementationMissingError, "must return nodes for this connection after paging"
165
165
  end
166
166
 
167
167
  def sliced_nodes
168
- raise NotImplementedError, "must return all nodes for this connection after chopping off first and last"
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
- paged_nodes.length >= first && sliced_nodes_count > first
29
- elsif GraphQL::Relay::ConnectionType.bidirectional_pagination && last
30
- sliced_nodes_count >= last
31
- else
32
- false
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
@@ -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(NotImplementedError, validation_error)
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(NotImplementedError, "Can't determine GraphQL type for: #{ok_object.inspect}, define `resolve_type (type, obj, ctx) -> { ... }` inside `Schema.define`.")
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(NotImplementedError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
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(NotImplementedError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
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 NotImplementedError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types or Interface types (tried to resolve: #{type.name})"
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 NotImplementedError, "#{self.name}.object_from_id(node_id, ctx) must be implemented to load by ID (tried to load from id `#{node_id}`)"
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 NotImplementedError, "#{self.name}.id_from_object(object, type, ctx) must be implemented to create global ids (tried to create an id for `#{object.inspect}`)"
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
- arg_type = type.unwrap
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(NotImplementedError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
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 NotImplementedError, "Implement `.enabled?(flag_name, object, context)` to return true or false for the feature flag (#{flag_name.inspect})"
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
@@ -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(ConnectionExtension)
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 NotImplementedError, "Unknown field extra for #{self.path}: #{extra_name.inspect}"
602
+ raise GraphQL::RequiredImplementationMissingError, "Unknown field extra for #{self.path}: #{extra_name.inspect}"
586
603
  end
587
604
  end
588
605
 
@@ -57,6 +57,10 @@ module GraphQL
57
57
  to_h
58
58
  end
59
59
 
60
+ def prepare
61
+ self
62
+ end
63
+
60
64
  def unwrap_value(value)
61
65
  case value
62
66
  when Array
@@ -34,7 +34,7 @@ module GraphQL
34
34
  end
35
35
 
36
36
  NullResolveType = ->(type, obj, ctx) {
37
- raise(NotImplementedError, "This schema was loaded from string, so it can't resolve types for objects")
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 NotImplementedError, "#{kind} not implemented"
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 NotImplementedError, "#{type["kind"]} not implemented"
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 NotImplementedError
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 NotImplementedError, 'Anonymous class should declare a `graphql_name`' if name.nil?
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]
@@ -30,7 +30,7 @@ module GraphQL
30
30
 
31
31
  # @return [GraphQL::TypeKinds::TypeKind]
32
32
  def kind
33
- raise NotImplementedError
33
+ raise GraphQL::RequiredImplementationMissingError
34
34
  end
35
35
  end
36
36
  end
@@ -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 NotImplementedError, "#{self.class.name}#resolve should execute the field's logic"
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
@@ -14,7 +14,7 @@ module GraphQL
14
14
  end
15
15
 
16
16
  def to_graphql
17
- raise NotImplementedError
17
+ raise GraphQL::RequiredImplementationMissingError
18
18
  end
19
19
 
20
20
  def unwrap
@@ -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
- # { fragment_definition_node => [dependent_node, dependent_node]}
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] = definition
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[@defdep_fragment_definitions[node.name]] << @defdep_current_parent
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 = @defdep_fragment_definitions.size
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? && definition_node.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
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 @defdep_fragment_definitions[spread.name].nil?
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 NotImplementedError
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 NotImplementedError
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 NotImplementedError
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 NotImplementedError
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 NotImplementedError
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 NotImplementedError, "Return transformed text here"
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:
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.9.14"
3
+ VERSION = "1.9.15"
4
4
  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.9.14
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-14 00:00:00.000000000 Z
11
+ date: 2019-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips