graphql 1.1.0 → 1.2.0

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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/analyze_query.rb +4 -2
  3. data/lib/graphql/analysis/field_usage.rb +4 -4
  4. data/lib/graphql/analysis/query_complexity.rb +16 -21
  5. data/lib/graphql/argument.rb +13 -6
  6. data/lib/graphql/base_type.rb +2 -1
  7. data/lib/graphql/compatibility/execution_specification.rb +76 -0
  8. data/lib/graphql/compatibility/query_parser_specification.rb +16 -2
  9. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -5
  10. data/lib/graphql/compatibility/schema_parser_specification.rb +6 -0
  11. data/lib/graphql/define/assign_argument.rb +8 -2
  12. data/lib/graphql/define/instance_definable.rb +12 -15
  13. data/lib/graphql/directive.rb +2 -1
  14. data/lib/graphql/enum_type.rb +5 -7
  15. data/lib/graphql/field.rb +6 -11
  16. data/lib/graphql/field/resolve.rb +1 -0
  17. data/lib/graphql/input_object_type.rb +9 -9
  18. data/lib/graphql/interface_type.rb +2 -1
  19. data/lib/graphql/internal_representation.rb +1 -0
  20. data/lib/graphql/internal_representation/node.rb +31 -9
  21. data/lib/graphql/internal_representation/rewrite.rb +26 -26
  22. data/lib/graphql/internal_representation/selections.rb +41 -0
  23. data/lib/graphql/introspection/input_value_type.rb +6 -2
  24. data/lib/graphql/language/generation.rb +2 -0
  25. data/lib/graphql/language/lexer.rl +4 -0
  26. data/lib/graphql/language/nodes.rb +3 -0
  27. data/lib/graphql/language/parser.rb +525 -509
  28. data/lib/graphql/language/parser.y +2 -0
  29. data/lib/graphql/object_type.rb +2 -2
  30. data/lib/graphql/query.rb +21 -0
  31. data/lib/graphql/query/context.rb +52 -4
  32. data/lib/graphql/query/serial_execution.rb +3 -4
  33. data/lib/graphql/query/serial_execution/field_resolution.rb +35 -36
  34. data/lib/graphql/query/serial_execution/operation_resolution.rb +9 -15
  35. data/lib/graphql/query/serial_execution/selection_resolution.rb +14 -11
  36. data/lib/graphql/query/serial_execution/value_resolution.rb +18 -17
  37. data/lib/graphql/query/variables.rb +1 -1
  38. data/lib/graphql/relay/mutation.rb +5 -8
  39. data/lib/graphql/scalar_type.rb +1 -2
  40. data/lib/graphql/schema.rb +2 -13
  41. data/lib/graphql/schema/build_from_definition.rb +28 -13
  42. data/lib/graphql/schema/loader.rb +4 -1
  43. data/lib/graphql/schema/printer.rb +10 -3
  44. data/lib/graphql/schema/timeout_middleware.rb +18 -2
  45. data/lib/graphql/schema/unique_within_type.rb +6 -3
  46. data/lib/graphql/static_validation/literal_validator.rb +3 -1
  47. data/lib/graphql/union_type.rb +1 -2
  48. data/lib/graphql/version.rb +1 -1
  49. data/readme.md +1 -0
  50. data/spec/graphql/analysis/analyze_query_spec.rb +6 -8
  51. data/spec/graphql/argument_spec.rb +18 -0
  52. data/spec/graphql/define/assign_argument_spec.rb +48 -0
  53. data/spec/graphql/define/instance_definable_spec.rb +4 -2
  54. data/spec/graphql/execution_error_spec.rb +66 -0
  55. data/spec/graphql/input_object_type_spec.rb +81 -0
  56. data/spec/graphql/internal_representation/rewrite_spec.rb +104 -21
  57. data/spec/graphql/introspection/input_value_type_spec.rb +43 -6
  58. data/spec/graphql/introspection/schema_type_spec.rb +1 -0
  59. data/spec/graphql/introspection/type_type_spec.rb +2 -0
  60. data/spec/graphql/language/generation_spec.rb +3 -2
  61. data/spec/graphql/query/arguments_spec.rb +17 -4
  62. data/spec/graphql/query/context_spec.rb +23 -0
  63. data/spec/graphql/query/variables_spec.rb +15 -1
  64. data/spec/graphql/relay/mutation_spec.rb +42 -2
  65. data/spec/graphql/schema/build_from_definition_spec.rb +4 -2
  66. data/spec/graphql/schema/loader_spec.rb +59 -1
  67. data/spec/graphql/schema/printer_spec.rb +2 -0
  68. data/spec/graphql/schema/reduce_types_spec.rb +1 -1
  69. data/spec/graphql/schema/timeout_middleware_spec.rb +2 -2
  70. data/spec/graphql/schema/unique_within_type_spec.rb +9 -0
  71. data/spec/graphql/schema/validation_spec.rb +15 -3
  72. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +122 -0
  73. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +78 -0
  74. data/spec/support/dairy_app.rb +9 -0
  75. data/spec/support/minimum_input_object.rb +4 -0
  76. data/spec/support/star_wars_schema.rb +1 -1
  77. metadata +5 -5
  78. data/lib/graphql/query/serial_execution/execution_context.rb +0 -37
  79. data/spec/graphql/query/serial_execution/execution_context_spec.rb +0 -54
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1d1d8b93486b17d67f6714c1ad867c5f5eb403a4
4
- data.tar.gz: 68dc546c4124fd8fb3752c911b63be9f9753ffc2
3
+ metadata.gz: 8e06bd99f6bb6350c2d7111d5014ef9c71154f8a
4
+ data.tar.gz: 1b90cfb31081700c64abab2f8f26a665bd2fe6fa
5
5
  SHA512:
6
- metadata.gz: eb42f273418ba3eda88ca784f3af4a20b0a57223b02adbf64736953446312e87ece3392f2c7b3d696ebbd66cecc8a38809ff6ff79bb623942dd6bced33c4f5bc
7
- data.tar.gz: 54669eb238917fedceba3df22ac927461a0a427b1d259a3277e6be1ffef420ada7ee1fc5abd63f605a4d5397e88a23d1d8ea73f95ebfd9cbaa97554b09b05089
6
+ metadata.gz: d8c0847198e4c6403cffac42b6cf8ab3cf1446d04ebcb91d2cb916244e170f0072d6ef9ee1ac355c4585ab62d0eac73048d34cb89e990b0cf62bde639d8fd166
7
+ data.tar.gz: ce1ea3d57512c38593c50ba2531994b5ce5ed83b0cb91ee13e4e78402d3ed4494c8d8ec88db2c037460e0379820b47821c0fcdb03a18cc804de17157fc252acd
@@ -32,8 +32,10 @@ module GraphQL
32
32
  def reduce_node(irep_node, reducer_states)
33
33
  visit_analyzers(:enter, irep_node, reducer_states)
34
34
 
35
- irep_node.children.each do |name, child_irep_node|
36
- reduce_node(child_irep_node, reducer_states)
35
+ irep_node.typed_children.each do |type_defn, children|
36
+ children.each do |name, child_irep_node|
37
+ reduce_node(child_irep_node, reducer_states)
38
+ end
37
39
  end
38
40
 
39
41
  visit_analyzers(:leave, irep_node, reducer_states)
@@ -26,10 +26,10 @@ module GraphQL
26
26
 
27
27
  def call(memo, visit_type, irep_node)
28
28
  if irep_node.ast_node.is_a?(GraphQL::Language::Nodes::Field) && visit_type == :leave
29
- irep_node.definitions.each do |type_defn, field_defn|
30
- field = "#{type_defn.name}.#{field_defn.name}"
31
- memo[:used_fields] << field
32
- memo[:used_deprecated_fields] << field if field_defn.deprecation_reason
29
+ field = "#{irep_node.owner_type.name}.#{irep_node.definition.name}"
30
+ memo[:used_fields] << field
31
+ if irep_node.definition.deprecation_reason
32
+ memo[:used_deprecated_fields] << field
33
33
  end
34
34
  end
35
35
 
@@ -46,7 +46,7 @@ module GraphQL
46
46
  type_complexities = memo[:complexities_on_type].pop
47
47
  child_complexity = type_complexities.max_possible_complexity
48
48
  own_complexity = get_complexity(irep_node, memo[:query], child_complexity)
49
- memo[:complexities_on_type].last.merge(irep_node.definitions, own_complexity)
49
+ memo[:complexities_on_type].last.merge(irep_node.owner_type, own_complexity)
50
50
  end
51
51
  end
52
52
  end
@@ -65,24 +65,18 @@ module GraphQL
65
65
  # Get a complexity value for a field,
66
66
  # by getting the number or calling its proc
67
67
  def get_complexity(irep_node, query, child_complexity)
68
- max_possible_complexity = 0
69
- irep_node.definitions.each do |type_defn, field_defn|
70
- defined_complexity = field_defn.complexity
71
- type_cpx = case defined_complexity
72
- when Proc
73
- args = query.arguments_for(irep_node, field_defn)
74
- defined_complexity.call(query.context, args, child_complexity)
75
- when Numeric
76
- defined_complexity + (child_complexity || 0)
77
- else
78
- raise("Invalid complexity: #{defined_complexity.inspect} on #{field_defn.name}")
79
- end
80
-
81
- if type_cpx > max_possible_complexity
82
- max_possible_complexity = type_cpx
83
- end
68
+ type_defn = irep_node.owner_type
69
+ field_defn = irep_node.definition
70
+ defined_complexity = field_defn.complexity
71
+ case defined_complexity
72
+ when Proc
73
+ args = query.arguments_for(irep_node, field_defn)
74
+ defined_complexity.call(query.context, args, child_complexity)
75
+ when Numeric
76
+ defined_complexity + (child_complexity || 0)
77
+ else
78
+ raise("Invalid complexity: #{defined_complexity.inspect} on #{field_defn.name}")
84
79
  end
85
- max_possible_complexity
86
80
  end
87
81
 
88
82
  # Selections on an object may apply differently depending on what is _actually_ returned by the resolve function.
@@ -112,9 +106,10 @@ module GraphQL
112
106
  max_complexity
113
107
  end
114
108
 
115
- # Store the complexity score for each of `types`
116
- def merge(definitions, complexity)
117
- definitions.each { |type_defn, field_defn| @types[type_defn] += complexity }
109
+ # Store the complexity for the branch on `type_defn`.
110
+ # Later we will see if this is the max complexity among branches.
111
+ def merge(type_defn, complexity)
112
+ @types[type_defn] += complexity
118
113
  end
119
114
 
120
115
  private
@@ -17,24 +17,31 @@ module GraphQL
17
17
  class Argument
18
18
  include GraphQL::Define::InstanceDefinable
19
19
  accepts_definitions :name, :type, :description, :default_value
20
- lazy_defined_attr_accessor :type, :description, :default_value, :name
20
+ attr_accessor :type, :description, :default_value, :name
21
+
22
+ ensure_defined(:name, :description, :default_value, :type=, :type)
23
+
24
+ def default_value?
25
+ !!@has_default_value
26
+ end
27
+
28
+ def default_value=(new_default_value)
29
+ @has_default_value = true
30
+ @default_value = new_default_value
31
+ end
21
32
 
22
33
  # @!attribute name
23
34
  # @return [String] The name of this argument on its {GraphQL::Field} or {GraphQL::InputObjectType}
24
35
 
25
36
  # @param new_input_type [GraphQL::BaseType, Proc] Assign a new input type for this argument (if it's a proc, it will be called after schema initialization)
26
37
  def type=(new_input_type)
27
- ensure_defined
28
38
  @clean_type = nil
29
39
  @dirty_type = new_input_type
30
40
  end
31
41
 
32
42
  # @return [GraphQL::BaseType] the input type for this argument
33
43
  def type
34
- @clean_type ||= begin
35
- ensure_defined
36
- GraphQL::BaseType.resolve_related_type(@dirty_type)
37
- end
44
+ @clean_type ||= GraphQL::BaseType.resolve_related_type(@dirty_type)
38
45
  end
39
46
  end
40
47
  end
@@ -8,7 +8,8 @@ module GraphQL
8
8
  global_id_field: GraphQL::Define::AssignGlobalIdField,
9
9
  }
10
10
 
11
- lazy_defined_attr_accessor :name, :description
11
+ attr_accessor :name, :description
12
+ ensure_defined(:name, :description)
12
13
 
13
14
  # @!attribute name
14
15
  # @return [String] the name of this type, must be unique within a Schema
@@ -407,6 +407,82 @@ module GraphQL
407
407
  error_messages = res["errors"].map { |e| e["message"] }
408
408
  assert_equal ["Error on Nullable"], error_messages
409
409
  end
410
+
411
+ def test_it_only_resolves_fields_once_on_typed_fragments
412
+ count = 0
413
+ counter_type = nil
414
+
415
+ has_count_interface = GraphQL::InterfaceType.define do
416
+ name "HasCount"
417
+ field :count, types.Int
418
+ field :counter, ->{ counter_type }
419
+ end
420
+
421
+ counter_type = GraphQL::ObjectType.define do
422
+ name "Counter"
423
+ interfaces [has_count_interface]
424
+ field :count, types.Int, resolve: ->(o,a,c) { count += 1 }
425
+ field :counter, has_count_interface, resolve: ->(o,a,c) { :counter }
426
+ end
427
+
428
+ alt_counter_type = GraphQL::ObjectType.define do
429
+ name "AltCounter"
430
+ interfaces [has_count_interface]
431
+ field :count, types.Int, resolve: ->(o,a,c) { count += 1 }
432
+ field :counter, has_count_interface, resolve: ->(o,a,c) { :counter }
433
+ end
434
+
435
+ has_counter_interface = GraphQL::InterfaceType.define do
436
+ name "HasCounter"
437
+ field :counter, counter_type
438
+ end
439
+
440
+ query_type = GraphQL::ObjectType.define do
441
+ name "Query"
442
+ interfaces [has_counter_interface]
443
+ field :counter, has_count_interface, resolve: ->(o,a,c) { :counter }
444
+ end
445
+
446
+ schema = GraphQL::Schema.define(
447
+ query: query_type,
448
+ resolve_type: ->(o, c) { o == :counter ? counter_type : nil },
449
+ orphan_types: [alt_counter_type],
450
+ )
451
+
452
+ res = schema.execute("
453
+ {
454
+ counter { count }
455
+ ... on HasCounter {
456
+ counter { count }
457
+ }
458
+ }
459
+ ")
460
+
461
+ expected_data = {
462
+ "counter" => { "count" => 1 }
463
+ }
464
+ assert_equal expected_data, res["data"]
465
+ assert_equal 1, count
466
+
467
+ # Deep typed children are correctly distinguished:
468
+ res = schema.execute("
469
+ {
470
+ counter {
471
+ ... on Counter {
472
+ counter { count }
473
+ }
474
+ ... on AltCounter {
475
+ counter { count, t: __typename }
476
+ }
477
+ }
478
+ }
479
+ ")
480
+
481
+ expected_data = {
482
+ "counter" => { "counter" => { "count" => 2 } }
483
+ }
484
+ assert_equal expected_data, res["data"]
485
+ end
410
486
  end
411
487
  end
412
488
  end
@@ -57,12 +57,15 @@ module GraphQL
57
57
  int: 3,
58
58
  float: 4.7e-24,
59
59
  bool: false,
60
- string: "☀︎🏆\\n \\" \u00b6 /",
60
+ string: "☀︎🏆 \\b \\f \\n \\r \\t \\" \u00b6 \\u00b6 / \\/",
61
61
  enum: ENUM_NAME,
62
62
  array: [7, 8, 9]
63
63
  object: {a: [1,2,3], b: {c: "4"}}
64
64
  unicode_bom: "\xef\xbb\xbfquery"
65
65
  keywordEnum: on
66
+ nullValue: null
67
+ nullValueInObject: {a: null, b: "b"}
68
+ nullValueInArray: ["a", null, "b"]
66
69
  )
67
70
  }
68
71
  |
@@ -71,7 +74,7 @@ module GraphQL
71
74
  assert_equal 3, inputs[0].value, "Integers"
72
75
  assert_equal 0.47e-23, inputs[1].value, "Floats"
73
76
  assert_equal false, inputs[2].value, "Booleans"
74
- assert_equal %|☀︎🏆\n " ¶ /|, inputs[3].value, "Strings"
77
+ assert_equal %|☀︎🏆 \b \f \n \r \t " ¶ ¶ / /|, inputs[3].value, "Strings"
75
78
  assert_instance_of GraphQL::Language::Nodes::Enum, inputs[4].value
76
79
  assert_equal "ENUM_NAME", inputs[4].value.name, "Enums"
77
80
  assert_equal [7,8,9], inputs[5].value, "Lists"
@@ -85,6 +88,17 @@ module GraphQL
85
88
 
86
89
  assert_equal %|\xef\xbb\xbfquery|, inputs[7].value, "Unicode BOM"
87
90
  assert_equal "on", inputs[8].value.name, "Enum value 'on'"
91
+
92
+ assert_instance_of GraphQL::Language::Nodes::NullValue, inputs[9].value
93
+
94
+ args = inputs[10].value.arguments
95
+ assert_instance_of GraphQL::Language::Nodes::NullValue, args.find{ |arg| arg.name == 'a' }.value
96
+ assert_equal 'b', args.find{ |arg| arg.name == 'b' }.value
97
+
98
+ values = inputs[11].value
99
+ assert_equal 'a', values[0]
100
+ assert_instance_of GraphQL::Language::Nodes::NullValue, values[1]
101
+ assert_equal 'b', values[2]
88
102
  end
89
103
  end
90
104
  end
@@ -70,11 +70,6 @@ module GraphQL
70
70
  assert_raises_parse_error("{ ...on }")
71
71
  assert_raises_parse_error("fragment on on Type { field }")
72
72
  end
73
-
74
- def test_it_rejects_null
75
- err = assert_raises_parse_error("{ field(input: null) }")
76
- assert_includes(err.message, "null")
77
- end
78
73
  end
79
74
  end
80
75
  end
@@ -184,6 +184,11 @@ module GraphQL
184
184
  assert_equal GraphQL::Language::Nodes::InterfaceTypeDefinition, interface_type_definition.class
185
185
  assert_equal 'Comment for interface definitions', interface_type_definition.description
186
186
  assert_equal 'Amount of wheels', interface_type_definition.fields[0].description
187
+
188
+ brand_field = interface_type_definition.fields[1]
189
+ assert_equal 1, brand_field.arguments.length
190
+ assert_equal 'argument', brand_field.arguments[0].name
191
+ assert_instance_of GraphQL::Language::Nodes::NullValue, brand_field.arguments[0].default_value
187
192
  end
188
193
  end
189
194
  end
@@ -230,6 +235,7 @@ module GraphQL
230
235
  interface Vehicle {
231
236
  # Amount of wheels
232
237
  wheels: Int!
238
+ brand(argument: String = null): String!
233
239
  }
234
240
 
235
241
  # Comment at the end of schema
@@ -2,16 +2,22 @@ module GraphQL
2
2
  module Define
3
3
  # Turn argument configs into a {GraphQL::Argument}.
4
4
  module AssignArgument
5
- def self.call(target, name, type = nil, description = nil, default_value: nil, &block)
5
+ def self.call(target, name, type = nil, description = nil, **rest, &block)
6
6
  argument = if block_given?
7
7
  GraphQL::Argument.define(&block)
8
8
  else
9
9
  GraphQL::Argument.new
10
10
  end
11
+
12
+ unsupported_keys = rest.keys - [:default_value]
13
+ if unsupported_keys.any?
14
+ raise ArgumentError.new("unknown keyword#{unsupported_keys.length > 1 ? 's' : ''}: #{unsupported_keys.join(', ')}")
15
+ end
16
+
11
17
  argument.name = name.to_s
12
18
  type && argument.type = type
13
19
  description && argument.description = description
14
- !default_value.nil? && argument.default_value = default_value
20
+ rest.key?(:default_value) && argument.default_value = rest[:default_value]
15
21
 
16
22
  target.arguments[name.to_s] = argument
17
23
  end
@@ -71,13 +71,13 @@ module GraphQL
71
71
  module InstanceDefinable
72
72
  def self.included(base)
73
73
  base.extend(ClassMethods)
74
+ base.ensure_defined(:metadata)
74
75
  end
75
76
 
76
77
  # `metadata` can store arbitrary key-values with an object.
77
78
  #
78
79
  # @return [Hash<Object, Object>] Hash for user-defined storage
79
80
  def metadata
80
- ensure_defined
81
81
  @metadata ||= {}
82
82
  end
83
83
 
@@ -174,21 +174,18 @@ module GraphQL
174
174
  @own_dictionary = own_dictionary.merge(new_assignments)
175
175
  end
176
176
 
177
- # Define a reader and writer for each of `attr_names` which
178
- # ensures that the definition block was called before accessing it.
179
- def lazy_defined_attr_accessor(*attr_names)
180
- attr_names.each do |attr_name|
181
- ivar_name = :"@#{attr_name}"
182
- define_method(attr_name) do
183
- ensure_defined
184
- instance_variable_get(ivar_name)
185
- end
186
-
187
- define_method("#{attr_name}=") do |new_value|
188
- ensure_defined
189
- instance_variable_set(ivar_name, new_value)
177
+ def ensure_defined(*method_names)
178
+ ensure_defined_module = Module.new
179
+ ensure_defined_module.module_eval {
180
+ method_names.each do |method_name|
181
+ define_method(method_name) { |*args, &block|
182
+ ensure_defined
183
+ super(*args, &block)
184
+ }
190
185
  end
191
- end
186
+ }
187
+ self.prepend(ensure_defined_module)
188
+ nil
192
189
  end
193
190
 
194
191
  # @return [Hash] combined definitions for self and ancestors
@@ -9,7 +9,8 @@ module GraphQL
9
9
  include GraphQL::Define::InstanceDefinable
10
10
  accepts_definitions :locations, :name, :description, :arguments, argument: GraphQL::Define::AssignArgument
11
11
 
12
- lazy_defined_attr_accessor :locations, :arguments, :name, :description
12
+ attr_accessor :locations, :arguments, :name, :description
13
+ ensure_defined(:locations, :arguments, :name, :description)
13
14
 
14
15
  LOCATIONS = [
15
16
  QUERY = :QUERY,
@@ -72,6 +72,7 @@ module GraphQL
72
72
 
73
73
  class EnumType < GraphQL::BaseType
74
74
  accepts_definitions :values, value: GraphQL::Define::AssignEnumValue
75
+ ensure_defined(:values, :validate_non_null_input, :coerce_non_null_input, :coerce_result)
75
76
 
76
77
  def initialize
77
78
  @values_by_name = {}
@@ -90,7 +91,6 @@ module GraphQL
90
91
 
91
92
  # @return [Hash<String => EnumValue>] `{name => value}` pairs contained in this type
92
93
  def values
93
- ensure_defined
94
94
  @values_by_name
95
95
  end
96
96
 
@@ -99,7 +99,6 @@ module GraphQL
99
99
  end
100
100
 
101
101
  def validate_non_null_input(value_name, warden)
102
- ensure_defined
103
102
  result = GraphQL::Query::InputValidationResult.new
104
103
  allowed_values = warden.enum_values(self)
105
104
  matching_value = allowed_values.find { |v| v.name == value_name }
@@ -120,7 +119,6 @@ module GraphQL
120
119
  # @param value_name [String] the string representation of this enum value
121
120
  # @return [Object] the underlying value for this enum value
122
121
  def coerce_non_null_input(value_name)
123
- ensure_defined
124
122
  if @values_by_name.key?(value_name)
125
123
  @values_by_name.fetch(value_name).value
126
124
  else
@@ -129,7 +127,6 @@ module GraphQL
129
127
  end
130
128
 
131
129
  def coerce_result(value, warden = nil)
132
- ensure_defined
133
130
  all_values = warden ? warden.enum_values(self) : @values_by_name.each_value
134
131
  enum_value = all_values.find { |val| val.value == value }
135
132
  if enum_value
@@ -148,9 +145,10 @@ module GraphQL
148
145
  # Created with the `value` helper
149
146
  class EnumValue
150
147
  include GraphQL::Define::InstanceDefinable
151
- accepts_definitions :name, :description, :deprecation_reason, :value
152
-
153
- lazy_defined_attr_accessor :name, :description, :deprecation_reason, :value
148
+ ATTRIBUTES = [:name, :description, :deprecation_reason, :value]
149
+ accepts_definitions(*ATTRIBUTES)
150
+ attr_accessor(*ATTRIBUTES)
151
+ ensure_defined(*ATTRIBUTES)
154
152
  end
155
153
 
156
154
  class UnresolvedValueError < GraphQL::Error
@@ -126,7 +126,11 @@ module GraphQL
126
126
  argument: GraphQL::Define::AssignArgument
127
127
 
128
128
 
129
- lazy_defined_attr_accessor :name, :deprecation_reason, :description, :property, :hash_key, :mutation, :arguments, :complexity
129
+ attr_accessor :name, :deprecation_reason, :description, :property, :hash_key, :mutation, :arguments, :complexity
130
+ ensure_defined(
131
+ :name, :deprecation_reason, :description, :property, :hash_key, :mutation, :arguments, :complexity,
132
+ :resolve, :resolve=, :type, :type=, :name=, :property=, :hash_key=
133
+ )
130
134
 
131
135
  # @!attribute [r] resolve_proc
132
136
  # @return [<#call(obj, args,ctx)>] A proc-like object which can be called to return the field's value
@@ -158,7 +162,6 @@ module GraphQL
158
162
  # @param arguments [Hash] Arguments declared in the query
159
163
  # @param context [GraphQL::Query::Context]
160
164
  def resolve(object, arguments, context)
161
- ensure_defined
162
165
  resolve_proc.call(object, arguments, context)
163
166
  end
164
167
 
@@ -166,22 +169,17 @@ module GraphQL
166
169
  # a new resolve proc will be build based on its {#name}, {#property} or {#hash_key}.
167
170
  # @param new_resolve_proc [<#call(obj, args, ctx)>, nil]
168
171
  def resolve=(new_resolve_proc)
169
- ensure_defined
170
172
  @resolve_proc = new_resolve_proc || build_default_resolver
171
173
  end
172
174
 
173
175
  def type=(new_return_type)
174
- ensure_defined
175
176
  @clean_type = nil
176
177
  @dirty_type = new_return_type
177
178
  end
178
179
 
179
180
  # Get the return type for this field.
180
181
  def type
181
- @clean_type ||= begin
182
- ensure_defined
183
- GraphQL::BaseType.resolve_related_type(@dirty_type)
184
- end
182
+ @clean_type ||= GraphQL::BaseType.resolve_related_type(@dirty_type)
185
183
  end
186
184
 
187
185
  # You can only set a field's name _once_ -- this to prevent
@@ -189,7 +187,6 @@ module GraphQL
189
187
  #
190
188
  # This is important because {#name} may be used by {#resolve}.
191
189
  def name=(new_name)
192
- ensure_defined
193
190
  if @name.nil?
194
191
  @name = new_name
195
192
  elsif @name != new_name
@@ -199,14 +196,12 @@ module GraphQL
199
196
 
200
197
  # @param new_property [Symbol] A method to call to resolve this field. Overrides the existing resolve proc.
201
198
  def property=(new_property)
202
- ensure_defined
203
199
  @property = new_property
204
200
  self.resolve = nil # reset resolve proc
205
201
  end
206
202
 
207
203
  # @param new_hash_key [Symbol] A key to access with `#[key]` to resolve this field. Overrides the existing resolve proc.
208
204
  def hash_key=(new_hash_key)
209
- ensure_defined
210
205
  @hash_key = new_hash_key
211
206
  self.resolve = nil # reset resolve proc
212
207
  end