graphql 1.4.5 → 1.5.3

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 (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