graphql 1.4.5 → 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/enum_generator.rb +33 -0
  3. data/lib/generators/graphql/function_generator.rb +15 -0
  4. data/lib/generators/graphql/install_generator.rb +118 -0
  5. data/lib/generators/graphql/interface_generator.rb +27 -0
  6. data/lib/generators/graphql/loader_generator.rb +17 -0
  7. data/lib/generators/graphql/mutation_generator.rb +19 -0
  8. data/lib/generators/graphql/object_generator.rb +34 -0
  9. data/lib/generators/graphql/templates/enum.erb +4 -0
  10. data/lib/generators/graphql/templates/function.erb +17 -0
  11. data/lib/generators/graphql/templates/graphql_controller.erb +32 -0
  12. data/lib/generators/graphql/templates/interface.erb +4 -0
  13. data/lib/generators/graphql/templates/loader.erb +15 -0
  14. data/lib/generators/graphql/templates/mutation.erb +12 -0
  15. data/lib/generators/graphql/templates/object.erb +5 -0
  16. data/lib/generators/graphql/templates/query_type.erb +15 -0
  17. data/lib/generators/graphql/templates/schema.erb +34 -0
  18. data/lib/generators/graphql/templates/union.erb +4 -0
  19. data/lib/generators/graphql/type_generator.rb +78 -0
  20. data/lib/generators/graphql/union_generator.rb +33 -0
  21. data/lib/graphql.rb +10 -0
  22. data/lib/graphql/analysis/analyze_query.rb +1 -1
  23. data/lib/graphql/analysis/query_complexity.rb +6 -50
  24. data/lib/graphql/analysis/query_depth.rb +1 -1
  25. data/lib/graphql/argument.rb +21 -0
  26. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +3 -3
  27. data/lib/graphql/define.rb +1 -0
  28. data/lib/graphql/define/assign_argument.rb +3 -19
  29. data/lib/graphql/define/assign_mutation_function.rb +34 -0
  30. data/lib/graphql/define/assign_object_field.rb +26 -14
  31. data/lib/graphql/define/defined_object_proxy.rb +21 -0
  32. data/lib/graphql/define/instance_definable.rb +61 -11
  33. data/lib/graphql/directive.rb +6 -1
  34. data/lib/graphql/execution/directive_checks.rb +1 -0
  35. data/lib/graphql/execution/execute.rb +14 -9
  36. data/lib/graphql/execution/field_result.rb +1 -0
  37. data/lib/graphql/execution/lazy.rb +8 -17
  38. data/lib/graphql/execution/lazy/lazy_method_map.rb +2 -0
  39. data/lib/graphql/execution/lazy/resolve.rb +1 -0
  40. data/lib/graphql/execution/selection_result.rb +1 -0
  41. data/lib/graphql/execution/typecast.rb +39 -26
  42. data/lib/graphql/field.rb +15 -3
  43. data/lib/graphql/field/resolve.rb +3 -3
  44. data/lib/graphql/function.rb +134 -0
  45. data/lib/graphql/id_type.rb +1 -1
  46. data/lib/graphql/input_object_type.rb +1 -1
  47. data/lib/graphql/internal_representation.rb +1 -1
  48. data/lib/graphql/internal_representation/node.rb +35 -107
  49. data/lib/graphql/internal_representation/rewrite.rb +189 -183
  50. data/lib/graphql/internal_representation/visit.rb +38 -0
  51. data/lib/graphql/introspection/input_value_type.rb +10 -1
  52. data/lib/graphql/introspection/schema_type.rb +1 -1
  53. data/lib/graphql/language/lexer.rb +6 -3
  54. data/lib/graphql/language/lexer.rl +6 -3
  55. data/lib/graphql/object_type.rb +53 -13
  56. data/lib/graphql/query.rb +30 -14
  57. data/lib/graphql/query/arguments.rb +2 -0
  58. data/lib/graphql/query/context.rb +2 -2
  59. data/lib/graphql/query/literal_input.rb +9 -0
  60. data/lib/graphql/query/serial_execution/field_resolution.rb +2 -2
  61. data/lib/graphql/query/serial_execution/selection_resolution.rb +1 -1
  62. data/lib/graphql/relay.rb +1 -0
  63. data/lib/graphql/relay/array_connection.rb +1 -1
  64. data/lib/graphql/relay/base_connection.rb +34 -15
  65. data/lib/graphql/relay/connection_resolve.rb +7 -2
  66. data/lib/graphql/relay/mutation.rb +45 -4
  67. data/lib/graphql/relay/node.rb +18 -6
  68. data/lib/graphql/relay/range_add.rb +45 -0
  69. data/lib/graphql/relay/relation_connection.rb +17 -2
  70. data/lib/graphql/runtime_type_error.rb +1 -0
  71. data/lib/graphql/schema.rb +40 -5
  72. data/lib/graphql/schema/base_64_encoder.rb +1 -0
  73. data/lib/graphql/schema/build_from_definition.rb +56 -21
  74. data/lib/graphql/schema/default_parse_error.rb +10 -0
  75. data/lib/graphql/schema/loader.rb +8 -1
  76. data/lib/graphql/schema/null_mask.rb +1 -0
  77. data/lib/graphql/schema/validation.rb +35 -0
  78. data/lib/graphql/static_validation.rb +1 -0
  79. data/lib/graphql/static_validation/all_rules.rb +1 -0
  80. data/lib/graphql/static_validation/arguments_validator.rb +7 -4
  81. data/lib/graphql/static_validation/definition_dependencies.rb +183 -0
  82. data/lib/graphql/static_validation/rules/fields_will_merge.rb +28 -96
  83. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +23 -0
  84. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -5
  85. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -31
  86. data/lib/graphql/static_validation/rules/fragments_are_used.rb +11 -41
  87. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +2 -2
  88. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -7
  89. data/lib/graphql/static_validation/validation_context.rb +22 -1
  90. data/lib/graphql/static_validation/validator.rb +4 -1
  91. data/lib/graphql/string_type.rb +5 -1
  92. data/lib/graphql/version.rb +1 -1
  93. data/readme.md +12 -3
  94. data/spec/generators/graphql/enum_generator_spec.rb +29 -0
  95. data/spec/generators/graphql/function_generator_spec.rb +33 -0
  96. data/spec/generators/graphql/install_generator_spec.rb +185 -0
  97. data/spec/generators/graphql/interface_generator_spec.rb +32 -0
  98. data/spec/generators/graphql/loader_generator_spec.rb +31 -0
  99. data/spec/generators/graphql/mutation_generator_spec.rb +28 -0
  100. data/spec/generators/graphql/object_generator_spec.rb +42 -0
  101. data/spec/generators/graphql/union_generator_spec.rb +50 -0
  102. data/spec/graphql/analysis/query_complexity_spec.rb +2 -1
  103. data/spec/graphql/define/instance_definable_spec.rb +38 -0
  104. data/spec/graphql/directive/skip_directive_spec.rb +1 -0
  105. data/spec/graphql/directive_spec.rb +18 -0
  106. data/spec/graphql/execution/typecast_spec.rb +41 -46
  107. data/spec/graphql/field_spec.rb +1 -1
  108. data/spec/graphql/function_spec.rb +128 -0
  109. data/spec/graphql/internal_representation/rewrite_spec.rb +166 -129
  110. data/spec/graphql/introspection/type_type_spec.rb +1 -1
  111. data/spec/graphql/language/lexer_spec.rb +6 -0
  112. data/spec/graphql/object_type_spec.rb +73 -2
  113. data/spec/graphql/query/arguments_spec.rb +28 -0
  114. data/spec/graphql/query/variables_spec.rb +7 -1
  115. data/spec/graphql/query_spec.rb +30 -0
  116. data/spec/graphql/relay/base_connection_spec.rb +26 -8
  117. data/spec/graphql/relay/connection_resolve_spec.rb +45 -0
  118. data/spec/graphql/relay/connection_type_spec.rb +21 -0
  119. data/spec/graphql/relay/node_spec.rb +30 -2
  120. data/spec/graphql/relay/range_add_spec.rb +113 -0
  121. data/spec/graphql/schema/build_from_definition_spec.rb +114 -0
  122. data/spec/graphql/schema/loader_spec.rb +1 -0
  123. data/spec/graphql/schema/printer_spec.rb +2 -2
  124. data/spec/graphql/schema/validation_spec.rb +80 -11
  125. data/spec/graphql/schema/warden_spec.rb +10 -10
  126. data/spec/graphql/schema_spec.rb +18 -1
  127. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +16 -0
  128. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +50 -3
  129. data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +27 -0
  130. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +57 -0
  131. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -1
  132. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +14 -0
  133. data/spec/graphql/string_type_spec.rb +7 -0
  134. data/spec/spec_helper.rb +3 -3
  135. data/spec/support/base_generator_test.rb +7 -0
  136. data/spec/support/dummy/schema.rb +32 -30
  137. data/spec/support/star_wars/schema.rb +81 -23
  138. metadata +98 -20
  139. data/lib/graphql/internal_representation/selection.rb +0 -85
@@ -13,7 +13,7 @@ module GraphQL
13
13
  attr_accessor :locations, :arguments, :name, :description
14
14
  # @api private
15
15
  attr_writer :default_directive
16
- ensure_defined(:locations, :arguments, :name, :description, :default_directive?)
16
+ ensure_defined(:locations, :arguments, :name, :description, :default_directive?, :default_arguments)
17
17
 
18
18
  LOCATIONS = [
19
19
  QUERY = :QUERY,
@@ -83,6 +83,11 @@ module GraphQL
83
83
  def default_directive?
84
84
  @default_directive
85
85
  end
86
+
87
+ # @return [GraphQL::Query::Arguments] Arguments to use when no args are provided in the query
88
+ def default_arguments
89
+ @default_arguments ||= GraphQL::Query::LiteralInput.defaults_for(self.arguments)
90
+ end
86
91
  end
87
92
  end
88
93
 
@@ -3,6 +3,7 @@ module GraphQL
3
3
  module Execution
4
4
  # Boolean checks for how an AST node's directives should
5
5
  # influence its execution
6
+ # @api private
6
7
  module DirectiveChecks
7
8
  SKIP = "skip"
8
9
  INCLUDE = "include"
@@ -2,6 +2,7 @@
2
2
  module GraphQL
3
3
  module Execution
4
4
  # A valid execution strategy
5
+ # @api private
5
6
  class Execute
6
7
  PROPAGATE_NULL = :__graphql_propagate_null__
7
8
 
@@ -26,13 +27,12 @@ module GraphQL
26
27
 
27
28
  selection_result = SelectionResult.new
28
29
 
29
- selection.each_selection(type: current_type) do |name, subselection|
30
- field = query.get_field(current_type, subselection.definition_name)
30
+ selection.typed_children[current_type].each do |name, subselection|
31
31
  field_result = resolve_field(
32
32
  selection_result,
33
33
  subselection,
34
34
  current_type,
35
- field,
35
+ subselection.definition,
36
36
  object,
37
37
  query_ctx
38
38
  )
@@ -63,7 +63,7 @@ module GraphQL
63
63
  selection: selection,
64
64
  )
65
65
 
66
- arguments = query.arguments_for(selection.irep_node, field)
66
+ arguments = query.arguments_for(selection, field)
67
67
  raw_value = begin
68
68
  query_ctx.schema.middleware.invoke([parent_type, object, field, arguments, field_ctx])
69
69
  rescue GraphQL::ExecutionError => err
@@ -83,11 +83,16 @@ module GraphQL
83
83
  continue_resolve_field(selection, parent_type, field, raw_value, field_ctx)
84
84
  end
85
85
 
86
- FieldResult.new(
87
- owner: owner,
88
- field: field,
89
- value: result,
90
- )
86
+ case result
87
+ when PROPAGATE_NULL, GraphQL::Execution::Lazy, SelectionResult
88
+ FieldResult.new(
89
+ owner: owner,
90
+ field: field,
91
+ value: result,
92
+ )
93
+ else
94
+ result
95
+ end
91
96
  end
92
97
 
93
98
  def continue_resolve_field(selection, parent_type, field, raw_value, field_ctx)
@@ -2,6 +2,7 @@
2
2
  module GraphQL
3
3
  module Execution
4
4
  # This is one key-value pair in a GraphQL response.
5
+ # @api private
5
6
  class FieldResult
6
7
  # @return [Any, Lazy] the GraphQL-ready response value, or a {Lazy} instance
7
8
  attr_reader :value
@@ -10,6 +10,7 @@ module GraphQL
10
10
  # This is an itty-bitty promise-like object, with key differences:
11
11
  # - It has only two states, not-resolved and resolved
12
12
  # - It has no error-catching functionality
13
+ # @api private
13
14
  class Lazy
14
15
  # Traverse `val`, lazily resolving any values along the way
15
16
  # @param val [Object] A data structure containing mixed plain values and `Lazy` instances
@@ -19,16 +20,9 @@ module GraphQL
19
20
  end
20
21
 
21
22
  # Create a {Lazy} which will get its inner value by calling the block
22
- # @param target [Object]
23
- # @param method_name [Symbol]
24
23
  # @param get_value_func [Proc] a block to get the inner value (later)
25
- def initialize(target = nil, method_name = nil, &get_value_func)
26
- if block_given?
27
- @get_value_func = get_value_func
28
- else
29
- @target = target
30
- @method_name = method_name
31
- end
24
+ def initialize(&get_value_func)
25
+ @get_value_func = get_value_func
32
26
  @resolved = false
33
27
  end
34
28
 
@@ -36,22 +30,19 @@ module GraphQL
36
30
  def value
37
31
  if !@resolved
38
32
  @resolved = true
39
- if @get_value_func
40
- @value = @get_value_func.call
41
- else
42
- @value = @target.public_send(@method_name)
33
+ @value = begin
34
+ @get_value_func.call
35
+ rescue GraphQL::ExecutionError => err
36
+ err
43
37
  end
44
38
  end
45
39
  @value
46
- rescue GraphQL::ExecutionError => err
47
- @resolved = true
48
- @value = err
49
40
  end
50
41
 
51
42
  # @return [Lazy] A {Lazy} whose value depends on another {Lazy}, plus any transformations in `block`
52
43
  def then(&block)
53
44
  self.class.new {
54
- next_val = block.call(value)
45
+ block.call(value)
55
46
  }
56
47
  end
57
48
  end
@@ -5,6 +5,8 @@ module GraphQL
5
5
  # {GraphQL::Schema} uses this to match returned values to lazy resolution methods.
6
6
  # Methods may be registered for classes, they apply to its subclasses also.
7
7
  # The result of this lookup is cached for future resolutions.
8
+ # @api private
9
+ # @see {Schema#lazy?} looks up values from this map
8
10
  class LazyMethodMap
9
11
  def initialize
10
12
  @storage = Hash.new do |h, value_class|
@@ -3,6 +3,7 @@ module GraphQL
3
3
  module Execution
4
4
  class Lazy
5
5
  # Helpers for dealing with data structures containing {Lazy} instances
6
+ # @api private
6
7
  module Resolve
7
8
  # Mutate `value`, replacing {Lazy} instances in place with their resolved values
8
9
  # @return [void]
@@ -2,6 +2,7 @@
2
2
  module GraphQL
3
3
  module Execution
4
4
  # A set of key-value pairs suitable for a GraphQL response.
5
+ # @api private
5
6
  class SelectionResult
6
7
  def initialize
7
8
  @storage = {}
@@ -1,35 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  module Execution
4
- # GraphQL object `{value, current_type}` can be cast to `potential_type` when:
5
- # - `current_type == potential_type`
6
- # - `current_type` is a union and it contains `potential_type`
7
- # - `potential_type` is a union and it contains `current_type`
8
- # - `current_type` is an interface and `potential_type` implements it
9
- # - `potential_type` is an interface and `current_type` implements it
4
+ # @api private
10
5
  module Typecast
11
- # While `value` is exposed by GraphQL as an instance of `current_type`,
12
- # should it _also_ be treated as an instance of `potential_type`?
13
- #
14
- # This is used for checking whether fragments apply to an object.
15
- #
16
- # @param current_type [GraphQL::BaseType] the type which GraphQL is using now
17
- # @param potential_type [GraphQL::BaseType] can this type be used from here?
18
- # @param query_ctx [GraphQL::Query::Context] the context for the current query
19
- # @return [Boolean] true if `value` be evaluated as a `potential_type`
20
- def self.compatible?(current_type, potential_type, query_ctx)
21
- if current_type == potential_type
6
+ # @return [Boolean]
7
+ def self.subtype?(parent_type, child_type)
8
+ if parent_type == child_type
9
+ # Equivalent types are subtypes
22
10
  true
23
- elsif current_type.kind.union?
24
- current_type.possible_types.include?(potential_type)
25
- elsif potential_type.kind.union?
26
- potential_type.include?(current_type)
27
- elsif current_type.kind.interface? && potential_type.kind.object?
28
- potential_type.interfaces.include?(current_type)
29
- elsif potential_type.kind.interface? && current_type.kind.object?
30
- current_type.interfaces.include?(potential_type)
11
+ elsif child_type.is_a?(GraphQL::NonNullType)
12
+ # A non-null type is a subtype of a nullable type
13
+ # if its inner type is a subtype of that type
14
+ if parent_type.is_a?(GraphQL::NonNullType)
15
+ subtype?(parent_type.of_type, child_type.of_type)
16
+ else
17
+ subtype?(parent_type, child_type.of_type)
18
+ end
31
19
  else
32
- false
20
+ case parent_type
21
+ when GraphQL::InterfaceType
22
+ # A type is a subtype of an interface
23
+ # if it implements that interface
24
+ case child_type
25
+ when GraphQL::ObjectType
26
+ child_type.interfaces.include?(parent_type)
27
+ else
28
+ false
29
+ end
30
+ when GraphQL::UnionType
31
+ # A type is a subtype of that interface
32
+ # if the union includes that interface
33
+ parent_type.possible_types.include?(child_type)
34
+ when GraphQL::ListType
35
+ # A list type is a subtype of another list type
36
+ # if its inner type is a subtype of the other inner type
37
+ case child_type
38
+ when GraphQL::ListType
39
+ subtype?(parent_type.of_type, child_type.of_type)
40
+ else
41
+ false
42
+ end
43
+ else
44
+ false
45
+ end
33
46
  end
34
47
  end
35
48
  end
@@ -124,16 +124,18 @@ module GraphQL
124
124
  accepts_definitions :name, :description, :deprecation_reason,
125
125
  :resolve, :lazy_resolve,
126
126
  :type, :arguments,
127
- :property, :hash_key, :complexity, :mutation,
127
+ :property, :hash_key, :complexity,
128
+ :mutation, :function,
128
129
  :relay_node_field,
129
130
  :relay_nodes_field,
130
131
  argument: GraphQL::Define::AssignArgument
131
132
 
132
133
  ensure_defined(
133
- :name, :deprecation_reason, :description, :description=, :property, :hash_key, :mutation, :arguments, :complexity,
134
+ :name, :deprecation_reason, :description, :description=, :property, :hash_key,
135
+ :mutation, :arguments, :complexity, :function,
134
136
  :resolve, :resolve=, :lazy_resolve, :lazy_resolve=, :lazy_resolve_proc, :resolve_proc,
135
137
  :type, :type=, :name=, :property=, :hash_key=,
136
- :relay_node_field, :relay_nodes_field,
138
+ :relay_node_field, :relay_nodes_field, :default_arguments
137
139
  )
138
140
 
139
141
  # @return [Boolean] True if this is the Relay find-by-id field
@@ -172,17 +174,22 @@ module GraphQL
172
174
  # @return [Object, nil] The key to access with `obj.[]` to resolve this field (overrides {#name} if present)
173
175
  attr_accessor :hash_key
174
176
 
177
+ # @return [Object, GraphQL::Function] The function used to derive this field
178
+ attr_accessor :function
179
+
175
180
  def initialize
176
181
  @complexity = 1
177
182
  @arguments = {}
178
183
  @resolve_proc = build_default_resolver
179
184
  @lazy_resolve_proc = DefaultLazyResolve
180
185
  @relay_node_field = false
186
+ @default_arguments = nil
181
187
  end
182
188
 
183
189
  def initialize_copy(other)
184
190
  super
185
191
  @arguments = other.arguments.dup
192
+ @default_arguments = nil
186
193
  end
187
194
 
188
195
  # Get a value for this field
@@ -263,6 +270,11 @@ module GraphQL
263
270
  }
264
271
  end
265
272
 
273
+ # @return [GraphQL::Query::Arguments] Arguments to use when no args are provided in the query
274
+ def default_arguments
275
+ @default_arguments ||= GraphQL::Query::LiteralInput.defaults_for(self.arguments)
276
+ end
277
+
266
278
  private
267
279
 
268
280
  def build_default_resolver
@@ -9,7 +9,7 @@ module GraphQL
9
9
  # @return [Proc] A resolver for this field, based on its config
10
10
  def create_proc(field)
11
11
  if field.property
12
- MethodResolve.new(field.property.to_sym)
12
+ MethodResolve.new(field)
13
13
  elsif !field.hash_key.nil?
14
14
  HashKeyResolve.new(field.hash_key)
15
15
  else
@@ -23,8 +23,8 @@ module GraphQL
23
23
 
24
24
  # Resolve the field by `public_send`ing `@method_name`
25
25
  class MethodResolve < BuiltInResolve
26
- def initialize(method_name)
27
- @method_name = method_name
26
+ def initialize(field)
27
+ @method_name = field.property.to_sym
28
28
  end
29
29
 
30
30
  def call(obj, args, ctx)
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ # A reusable container for field logic, including arguments, resolve, return type, and documentation.
4
+ #
5
+ # Class-level values defined with the DSL will be inherited,
6
+ # so {GraphQL::Function}s can extend one another.
7
+ #
8
+ # It's OK to override the instance methods here in order to customize behavior of instances.
9
+ #
10
+ # @example A reusable GraphQL::Function attached as a field
11
+ # class FindRecord < GraphQL::Function
12
+ # attr_reader :type
13
+ #
14
+ # def initialize(model:, type:)
15
+ # @model = model
16
+ # @type = type
17
+ # end
18
+ #
19
+ # argument :id, GraphQL::ID_TYPE
20
+ #
21
+ # def resolve(obj, args, ctx)
22
+ # @model.find(args.id)
23
+ # end
24
+ # end
25
+ #
26
+ # QueryType = GraphQL::ObjectType.define do
27
+ # name "Query"
28
+ # field :post, function: FindRecord.new(model: Post, type: PostType)
29
+ # field :comment, function: FindRecord.new(model: Comment, type: CommentType)
30
+ # end
31
+ class Function
32
+ # @return [Hash<String => GraphQL::Argument>] Arguments, keyed by name
33
+ def arguments
34
+ self.class.arguments
35
+ end
36
+
37
+ # @return [GraphQL::BaseType] Return type
38
+ def type
39
+ self.class.type
40
+ end
41
+
42
+ # @return [Object] This function's resolver
43
+ def call(obj, args, ctx)
44
+ raise NotImplementedError
45
+ end
46
+
47
+ # @return [String, nil]
48
+ def description
49
+ self.class.description
50
+ end
51
+
52
+ # @return [String, nil]
53
+ def deprecation_reason
54
+ self.class.deprecation_reason
55
+ end
56
+
57
+ # @return [Integer, Proc]
58
+ def complexity
59
+ self.class.complexity || 1
60
+ end
61
+
62
+ class << self
63
+ # Define an argument for this function & its subclasses
64
+ # @see {GraphQL::Field} same arguments as the `argument` definition helper
65
+ # @return [void]
66
+ def argument(*args, **kwargs, &block)
67
+ argument = GraphQL::Argument.from_dsl(*args, **kwargs, &block)
68
+ own_arguments[argument.name] = argument
69
+ nil
70
+ end
71
+
72
+ # @return [Hash<String => GraphQL::Argument>] Arguments for this function class, including inherited arguments
73
+ def arguments
74
+ if parent_function?
75
+ own_arguments.merge(superclass.arguments)
76
+ else
77
+ own_arguments.dup
78
+ end
79
+ end
80
+
81
+ # Get or set the return type for this function class & descendants
82
+ # @return [GraphQL::BaseType]
83
+ def type(premade_type = nil, &block)
84
+ if block_given?
85
+ @type = GraphQL::ObjectType.define(&block)
86
+ elsif premade_type
87
+ @type = premade_type
88
+ elsif parent_function?
89
+ @type || superclass.type
90
+ else
91
+ @type
92
+ end
93
+ end
94
+
95
+ # Class-level reader/writer which is inherited
96
+ # @api private
97
+ def self.inherited_value(name)
98
+ self.class_eval <<-RUBY
99
+ def #{name}(new_value = nil)
100
+ if new_value
101
+ @#{name} = new_value
102
+ elsif parent_function?
103
+ @#{name} || superclass.#{name}
104
+ else
105
+ @#{name}
106
+ end
107
+ end
108
+ RUBY
109
+ end
110
+
111
+ # @!method description(new_value = nil)
112
+ # Get or set this class's description
113
+ inherited_value(:description)
114
+ # @!method deprecation_reason(new_value = nil)
115
+ # Get or set this class's deprecation_reason
116
+ inherited_value(:deprecation_reason)
117
+ # @!method complexity(new_value = nil)
118
+ # Get or set this class's complexity
119
+ inherited_value(:complexity)
120
+
121
+ private
122
+
123
+ # Does this function inherit from another function?
124
+ def parent_function?
125
+ superclass <= GraphQL::Function
126
+ end
127
+
128
+ # Arguments defined on this class (not superclasses)
129
+ def own_arguments
130
+ @own_arguments ||= {}
131
+ end
132
+ end
133
+ end
134
+ end