graphql 1.7.14 → 1.8.0.pre1

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 (149) hide show
  1. checksums.yaml +5 -5
  2. data/lib/generators/graphql/function_generator.rb +1 -1
  3. data/lib/generators/graphql/loader_generator.rb +1 -1
  4. data/lib/generators/graphql/mutation_generator.rb +1 -6
  5. data/lib/generators/graphql/templates/function.erb +2 -2
  6. data/lib/generators/graphql/templates/loader.erb +2 -2
  7. data/lib/graphql.rb +2 -0
  8. data/lib/graphql/argument.rb +0 -1
  9. data/lib/graphql/backwards_compatibility.rb +2 -3
  10. data/lib/graphql/base_type.rb +18 -16
  11. data/lib/graphql/compatibility/query_parser_specification.rb +0 -117
  12. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -14
  13. data/lib/graphql/define/assign_object_field.rb +5 -12
  14. data/lib/graphql/deprecated_dsl.rb +28 -0
  15. data/lib/graphql/directive.rb +0 -1
  16. data/lib/graphql/enum_type.rb +1 -3
  17. data/lib/graphql/execution.rb +0 -1
  18. data/lib/graphql/execution/multiplex.rb +29 -12
  19. data/lib/graphql/field.rb +5 -20
  20. data/lib/graphql/function.rb +12 -0
  21. data/lib/graphql/input_object_type.rb +1 -3
  22. data/lib/graphql/internal_representation/node.rb +14 -26
  23. data/lib/graphql/internal_representation/visit.rb +6 -3
  24. data/lib/graphql/introspection/arguments_field.rb +0 -1
  25. data/lib/graphql/introspection/enum_values_field.rb +0 -1
  26. data/lib/graphql/introspection/fields_field.rb +0 -1
  27. data/lib/graphql/introspection/input_fields_field.rb +0 -1
  28. data/lib/graphql/introspection/interfaces_field.rb +0 -1
  29. data/lib/graphql/introspection/of_type_field.rb +0 -1
  30. data/lib/graphql/introspection/possible_types_field.rb +0 -1
  31. data/lib/graphql/introspection/schema_field.rb +0 -1
  32. data/lib/graphql/introspection/type_by_name_field.rb +0 -1
  33. data/lib/graphql/introspection/typename_field.rb +0 -1
  34. data/lib/graphql/language.rb +0 -3
  35. data/lib/graphql/language/generation.rb +182 -3
  36. data/lib/graphql/language/lexer.rb +69 -144
  37. data/lib/graphql/language/lexer.rl +4 -15
  38. data/lib/graphql/language/nodes.rb +76 -136
  39. data/lib/graphql/language/parser.rb +621 -668
  40. data/lib/graphql/language/parser.y +11 -17
  41. data/lib/graphql/language/token.rb +3 -10
  42. data/lib/graphql/object_type.rb +6 -1
  43. data/lib/graphql/query.rb +13 -8
  44. data/lib/graphql/query/arguments.rb +33 -48
  45. data/lib/graphql/query/context.rb +1 -0
  46. data/lib/graphql/query/literal_input.rb +1 -4
  47. data/lib/graphql/relay/connection_resolve.rb +3 -0
  48. data/lib/graphql/relay/global_id_resolve.rb +5 -1
  49. data/lib/graphql/relay/relation_connection.rb +19 -14
  50. data/lib/graphql/schema.rb +219 -12
  51. data/lib/graphql/schema/argument.rb +33 -0
  52. data/lib/graphql/schema/build_from_definition.rb +18 -64
  53. data/lib/graphql/schema/enum.rb +76 -0
  54. data/lib/graphql/schema/field.rb +127 -0
  55. data/lib/graphql/schema/field/dynamic_resolve.rb +63 -0
  56. data/lib/graphql/schema/field/unwrapped_resolve.rb +20 -0
  57. data/lib/graphql/schema/input_object.rb +61 -0
  58. data/lib/graphql/schema/interface.rb +32 -0
  59. data/lib/graphql/schema/loader.rb +2 -2
  60. data/lib/graphql/schema/member.rb +97 -0
  61. data/lib/graphql/schema/member/build_type.rb +106 -0
  62. data/lib/graphql/schema/member/has_fields.rb +56 -0
  63. data/lib/graphql/schema/member/instrumentation.rb +113 -0
  64. data/lib/graphql/schema/member/list_type_proxy.rb +21 -0
  65. data/lib/graphql/schema/member/non_null_type_proxy.rb +21 -0
  66. data/lib/graphql/schema/object.rb +65 -0
  67. data/lib/graphql/schema/printer.rb +266 -33
  68. data/lib/graphql/schema/scalar.rb +25 -0
  69. data/lib/graphql/schema/traversal.rb +26 -17
  70. data/lib/graphql/schema/union.rb +48 -0
  71. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -5
  72. data/lib/graphql/static_validation/rules/fields_will_merge.rb +8 -15
  73. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +1 -11
  74. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -7
  75. data/lib/graphql/tracing.rb +0 -1
  76. data/lib/graphql/tracing/platform_tracing.rb +7 -20
  77. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  78. data/lib/graphql/unresolved_type_error.rb +2 -3
  79. data/lib/graphql/version.rb +1 -1
  80. data/readme.md +1 -1
  81. data/spec/dummy/app/channels/graphql_channel.rb +1 -22
  82. data/spec/dummy/log/development.log +0 -239
  83. data/spec/dummy/log/test.log +0 -204
  84. data/spec/dummy/test/system/action_cable_subscription_test.rb +0 -4
  85. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  86. data/spec/generators/graphql/function_generator_spec.rb +0 -26
  87. data/spec/generators/graphql/loader_generator_spec.rb +0 -24
  88. data/spec/graphql/analysis/max_query_complexity_spec.rb +3 -3
  89. data/spec/graphql/analysis/max_query_depth_spec.rb +3 -3
  90. data/spec/graphql/backtrace_spec.rb +0 -10
  91. data/spec/graphql/base_type_spec.rb +5 -19
  92. data/spec/graphql/boolean_type_spec.rb +3 -3
  93. data/spec/graphql/directive_spec.rb +1 -3
  94. data/spec/graphql/enum_type_spec.rb +5 -18
  95. data/spec/graphql/execution/execute_spec.rb +1 -1
  96. data/spec/graphql/execution/multiplex_spec.rb +2 -2
  97. data/spec/graphql/float_type_spec.rb +2 -2
  98. data/spec/graphql/id_type_spec.rb +1 -1
  99. data/spec/graphql/input_object_type_spec.rb +2 -15
  100. data/spec/graphql/int_type_spec.rb +2 -2
  101. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -2
  102. data/spec/graphql/introspection/schema_type_spec.rb +0 -1
  103. data/spec/graphql/language/generation_spec.rb +186 -21
  104. data/spec/graphql/language/lexer_spec.rb +1 -21
  105. data/spec/graphql/language/nodes_spec.rb +12 -21
  106. data/spec/graphql/language/parser_spec.rb +1 -1
  107. data/spec/graphql/query/arguments_spec.rb +15 -37
  108. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -2
  109. data/spec/graphql/query/variables_spec.rb +1 -1
  110. data/spec/graphql/query_spec.rb +5 -31
  111. data/spec/graphql/rake_task_spec.rb +1 -3
  112. data/spec/graphql/relay/base_connection_spec.rb +1 -1
  113. data/spec/graphql/relay/connection_instrumentation_spec.rb +2 -2
  114. data/spec/graphql/relay/connection_resolve_spec.rb +1 -1
  115. data/spec/graphql/relay/connection_type_spec.rb +1 -1
  116. data/spec/graphql/relay/mutation_spec.rb +3 -3
  117. data/spec/graphql/relay/relation_connection_spec.rb +1 -65
  118. data/spec/graphql/schema/build_from_definition_spec.rb +4 -86
  119. data/spec/graphql/schema/enum_spec.rb +60 -0
  120. data/spec/graphql/schema/field_spec.rb +14 -0
  121. data/spec/graphql/schema/input_object_spec.rb +43 -0
  122. data/spec/graphql/schema/interface_spec.rb +98 -0
  123. data/spec/graphql/schema/object_spec.rb +119 -0
  124. data/spec/graphql/schema/printer_spec.rb +15 -92
  125. data/spec/graphql/schema/scalar_spec.rb +40 -0
  126. data/spec/graphql/schema/union_spec.rb +35 -0
  127. data/spec/graphql/schema/validation_spec.rb +1 -1
  128. data/spec/graphql/schema/warden_spec.rb +11 -11
  129. data/spec/graphql/schema_spec.rb +25 -23
  130. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +2 -10
  131. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
  132. data/spec/graphql/string_type_spec.rb +3 -3
  133. data/spec/graphql/subscriptions_spec.rb +1 -1
  134. data/spec/graphql/tracing/platform_tracing_spec.rb +1 -60
  135. data/spec/support/dummy/schema.rb +25 -39
  136. data/spec/support/jazz.rb +334 -0
  137. data/spec/support/lazy_helpers.rb +21 -23
  138. data/spec/support/star_wars/data.rb +7 -6
  139. data/spec/support/star_wars/schema.rb +109 -142
  140. metadata +39 -33
  141. data/lib/graphql/execution/instrumentation.rb +0 -82
  142. data/lib/graphql/language/block_string.rb +0 -47
  143. data/lib/graphql/language/document_from_schema_definition.rb +0 -277
  144. data/lib/graphql/language/printer.rb +0 -351
  145. data/lib/graphql/tracing/data_dog_tracing.rb +0 -49
  146. data/spec/graphql/execution/instrumentation_spec.rb +0 -165
  147. data/spec/graphql/language/block_string_spec.rb +0 -70
  148. data/spec/graphql/language/document_from_schema_definition_spec.rb +0 -770
  149. data/spec/graphql/language/printer_spec.rb +0 -203
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ # Extend this class to define GraphQL enums in your schema.
5
+ #
6
+ # By default, GraphQL enum values are translated into Ruby strings.
7
+ # You can provide a custom value with the `value:` keyword.
8
+ #
9
+ # @example
10
+ # # equivalent to
11
+ # # enum PizzaTopping {
12
+ # # MUSHROOMS
13
+ # # ONIONS
14
+ # # PEPPERS
15
+ # # }
16
+ # class PizzaTopping < GraphQL::Enum
17
+ # value :MUSHROOMS
18
+ # value :ONIONS
19
+ # value :PEPPERS
20
+ # end
21
+ class Schema
22
+ class Enum < GraphQL::Schema::Member
23
+ # @api private
24
+ Value = Struct.new(:name, :description, :value, :deprecation_reason)
25
+
26
+ class << self
27
+ # Define a value for this enum
28
+ # @param graphql_name [String, Symbol] the GraphQL value for this, usually `SCREAMING_CASE`
29
+ # @param description [String], the GraphQL description for this value, present in documentation
30
+ # @param value [Object], the translated Ruby value for this object (defaults to `graphql_name`)
31
+ # @param deprecation_reason [String] if this object is deprecated, include a message here
32
+ # @return [void]
33
+ def value(graphql_name, description = nil, value: nil, deprecation_reason: nil)
34
+ graphql_name = graphql_name.to_s
35
+ value ||= graphql_name
36
+ own_values << Value.new(graphql_name, description, value, deprecation_reason)
37
+ nil
38
+ end
39
+
40
+ # @return [Array<GraphQL::Schema::Enum::Value>]
41
+ def values
42
+ all_values = own_values
43
+ inherited_values = superclass <= GraphQL::Schema::Enum ? superclass.values : []
44
+ inherited_values.each do |inherited_v|
45
+ if all_values.none? { |v| v.name == inherited_v.name }
46
+ all_values << inherited_v
47
+ end
48
+ end
49
+ all_values
50
+ end
51
+
52
+ # @return [GraphQL::EnumType]
53
+ def to_graphql
54
+ enum_type = GraphQL::EnumType.new
55
+ enum_type.name = graphql_name
56
+ enum_type.description = description
57
+ values.each do |val|
58
+ enum_value = GraphQL::EnumType::EnumValue.new
59
+ enum_value.name = val.name
60
+ enum_value.description = val.description
61
+ enum_value.value = val.value
62
+ enum_value.deprecation_reason = val.deprecation_reason
63
+ enum_type.add_value(enum_value)
64
+ end
65
+ enum_type
66
+ end
67
+
68
+ private
69
+
70
+ def own_values
71
+ @own_values ||= []
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+ # test_via: ../object.rb
3
+ require "graphql/schema/field/dynamic_resolve"
4
+ require "graphql/schema/field/unwrapped_resolve"
5
+ module GraphQL
6
+ class Schema
7
+ class Field
8
+ include GraphQL::Schema::Member::CachedGraphQLDefinition
9
+
10
+ # @return [String]
11
+ attr_reader :name
12
+
13
+ # @return [String]
14
+ attr_reader :description
15
+
16
+ def initialize(name, return_type_expr = nil, desc = nil, null: nil, field: nil, function: nil, deprecation_reason: nil, method: nil, connection: nil, max_page_size: nil, resolve: nil, &args_block)
17
+ if !(field || function)
18
+ if return_type_expr.nil?
19
+ raise ArgumentError "missing possitional argument `type`"
20
+ end
21
+ if null.nil?
22
+ raise ArgumentError, "missing keyword argument null:"
23
+ end
24
+ end
25
+ @name = name.to_s
26
+ @description = desc
27
+ @field = field
28
+ @function = function
29
+ @resolve = resolve
30
+ @deprecation_reason = deprecation_reason
31
+ @method = method
32
+ @return_type_expr = return_type_expr
33
+ @return_type_null = null
34
+ @args_block = args_block
35
+ @connection = connection
36
+ @max_page_size = max_page_size
37
+ end
38
+
39
+ # @return [GraphQL::Field]
40
+ def to_graphql
41
+ method_name = @method || Member::BuildType.underscore(@name)
42
+
43
+ field_defn = if @field
44
+ @field.dup
45
+ elsif @function
46
+ GraphQL::Function.build_field(@function)
47
+ else
48
+ GraphQL::Field.new
49
+ end
50
+ field_defn.name = @name
51
+
52
+ if @return_type_expr
53
+ return_type_name = Member::BuildType.to_type_name(@return_type_expr)
54
+ connection = @connection.nil? ? return_type_name.end_with?("Connection") : @connection
55
+ field_defn.type = -> {
56
+ Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
57
+ }
58
+ elsif @connection.nil? && (@field || @function)
59
+ return_type_name = Member::BuildType.to_type_name(field_defn.type)
60
+ connection = return_type_name.end_with?("Connection")
61
+ else
62
+ connection = @connection
63
+ end
64
+
65
+ if @description
66
+ field_defn.description = @description
67
+ end
68
+
69
+ if @deprecation_reason
70
+ field_defn.deprecation_reason = @deprecation_reason
71
+ end
72
+
73
+ field_defn.resolve = if @resolve || @function || @field
74
+ prev_resolve = @resolve || field_defn.resolve_proc
75
+ UnwrappedResolve.new(inner_resolve: prev_resolve)
76
+ else
77
+ DynamicResolve.new(method_name: method_name, connection: connection)
78
+ end
79
+
80
+ field_defn.connection = connection
81
+ field_defn.connection_max_page_size = @max_page_size
82
+
83
+ field_proxy = FieldProxy.new(field_defn, argument_class: self.class.argument_class)
84
+ # apply this first, so it can be overriden below
85
+ if connection
86
+ field_proxy.argument :after, "String", "Returns the elements in the list that come after the specified global ID.", required: false
87
+ field_proxy.argument :before, "String", "Returns the elements in the list that come before the specified global ID.", required: false
88
+ field_proxy.argument :first, "Int", "Returns the first _n_ elements from the list.", required: false
89
+ field_proxy.argument :last, "Int", "Returns the last _n_ elements from the list.", required: false
90
+ end
91
+
92
+ if @args_block
93
+ field_proxy.instance_eval(&@args_block)
94
+ end
95
+
96
+ field_defn
97
+ end
98
+
99
+ class << self
100
+ def argument_class(new_arg_class = nil)
101
+ if new_arg_class
102
+ @argument_class = new_arg_class
103
+ else
104
+ @argument_class || GraphQL::Schema::Argument
105
+ end
106
+ end
107
+ end
108
+
109
+
110
+ # This object exists only to be `instance_eval`'d
111
+ # when the `field(...)` method is called with a block.
112
+ # This object receives that block.
113
+ class FieldProxy
114
+ def initialize(field, argument_class:)
115
+ @field = field
116
+ @argument_class = argument_class
117
+ end
118
+
119
+ # This is the `argument(...)` DSL for class-based field definitons
120
+ def argument(*args)
121
+ arg = @argument_class.new(*args)
122
+ @field.arguments[arg.name] = arg.graphql_definition
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Field
6
+ class DynamicResolve
7
+ def initialize(method_name:, connection:)
8
+ @method_name = method_name
9
+ @connection = connection
10
+ end
11
+
12
+ def call(obj, args, ctx)
13
+ if obj.respond_to?(@method_name)
14
+ public_send_field(obj, @method_name, args)
15
+ elsif obj.object.respond_to?(@method_name)
16
+ public_send_field(obj.object, @method_name, args)
17
+ elsif obj.is_a?(Hash)
18
+ obj[@method_name]
19
+ else
20
+ raise <<-ERR
21
+ Failed to implement #{ctx.irep_node.owner_type.name}.#{ctx.field.name}, tried:
22
+
23
+ - `#{obj.class}##{@method_name}`, which did not exist
24
+ - `#{obj.object.class}##{@method_name}`, which did not exist
25
+ - Looking up hash key `#{@method_name.inspect}` on `#{obj}`, but it wasn't a Hash
26
+
27
+ To implement this field, define one of the methods above (and check for typos)
28
+ ERR
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def public_send_field(obj, method_name, graphql_args)
35
+ if graphql_args.any?
36
+ # Splat the GraphQL::Arguments to Ruby keyword arguments
37
+ ruby_kwargs = {}
38
+
39
+ graphql_args.keys.each do |key|
40
+ ruby_kwargs[Schema::Member::BuildType.underscore(key).to_sym] = graphql_args[key]
41
+ end
42
+
43
+ if @connection
44
+ # Remove pagination args before passing it to a user method
45
+ ruby_kwargs.delete(:first)
46
+ ruby_kwargs.delete(:last)
47
+ ruby_kwargs.delete(:before)
48
+ ruby_kwargs.delete(:after)
49
+ end
50
+
51
+ if ruby_kwargs.any?
52
+ obj.public_send(method_name, ruby_kwargs)
53
+ else
54
+ obj.public_send(method_name)
55
+ end
56
+ else
57
+ obj.public_send(method_name)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Field
5
+ # This object is backed by an `Object`, but the resolve isn't expecting
6
+ # that wrapper, so unwrap it before calling the inner resolver
7
+ class UnwrappedResolve
8
+ def initialize(inner_resolve:)
9
+ @inner_resolve = inner_resolve
10
+ end
11
+
12
+ def call(obj, args, ctx)
13
+ # Might be nil, still want to call the func in that case
14
+ inner_obj = obj && obj.object
15
+ @inner_resolve.call(inner_obj, args, ctx)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class InputObject < GraphQL::Schema::Member
5
+ extend GraphQL::Delegate
6
+
7
+ def initialize(values, context:)
8
+ @arguments = self.class.arguments_class.new(values, context: context)
9
+ @context = context
10
+ end
11
+
12
+ # A lot of methods work just like GraphQL::Arguments
13
+ def_delegators :@arguments, :[], :key?, :to_h
14
+ def_delegators :to_h, :keys, :values, :each, :any?
15
+
16
+ class << self
17
+ # @return [Class<GraphQL::Arguments>]
18
+ attr_accessor :arguments_class
19
+
20
+ def argument(*args)
21
+ argument = GraphQL::Schema::Argument.new(*args)
22
+ own_arguments << argument
23
+ arg_name = argument.name
24
+ # Add a method access
25
+ define_method(Member::BuildType.underscore(arg_name)) do
26
+ @arguments.public_send(arg_name)
27
+ end
28
+ end
29
+
30
+ def arguments
31
+ all_arguments = own_arguments
32
+ inherited_arguments = (superclass <= GraphQL::Schema::InputObject ? superclass.arguments : [])
33
+ inherited_arguments.each do |inherited_a|
34
+ if all_arguments.none? { |a| a.name == inherited_a.name }
35
+ all_arguments << inherited_a
36
+ end
37
+ end
38
+ all_arguments
39
+ end
40
+
41
+ def own_arguments
42
+ @own_arguments ||= []
43
+ end
44
+
45
+ def to_graphql
46
+ type_defn = GraphQL::InputObjectType.new
47
+ type_defn.name = graphql_name
48
+ type_defn.description = description
49
+ arguments.each do |arg|
50
+ type_defn.arguments[arg.name] = arg.graphql_definition
51
+ end
52
+ # Make a reference to a classic-style Arguments class
53
+ self.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(type_defn)
54
+ # But use this InputObject class at runtime
55
+ type_defn.arguments_class = self
56
+ type_defn
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Interface < GraphQL::Schema::Member
5
+ extend GraphQL::Schema::Member::HasFields
6
+ field_class GraphQL::Schema::Field
7
+
8
+ class << self
9
+
10
+ # When this interface is added to a `GraphQL::Schema::Object`,
11
+ # it calls this method. We add methods to the object by convention,
12
+ # a nested module named `Implementation`
13
+ def apply_implemented(object_class)
14
+ if defined?(self::Implementation)
15
+ object_class.include(self::Implementation)
16
+ end
17
+ end
18
+
19
+ def to_graphql
20
+ type_defn = GraphQL::InterfaceType.new
21
+ type_defn.name = graphql_name
22
+ type_defn.description = description
23
+ fields.each do |field_inst|
24
+ field_defn = field_inst.graphql_definition
25
+ type_defn.fields[field_defn.name] = field_defn
26
+ end
27
+ type_defn
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -97,7 +97,7 @@ module GraphQL
97
97
  }]
98
98
  )
99
99
  when "FIELD"
100
- Field.define(
100
+ GraphQL::Field.define(
101
101
  name: type["name"],
102
102
  type: type_resolver.call(type["type"]),
103
103
  description: type["description"],
@@ -138,7 +138,7 @@ module GraphQL
138
138
  end
139
139
  end
140
140
 
141
- Argument.define(
141
+ GraphQL::Argument.define(
142
142
  name: type["name"],
143
143
  type: type_resolver.call(type["type"]),
144
144
  description: type["description"],
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ # The base class for things that make up the schema,
4
+ # eg objects, enums, scalars.
5
+ #
6
+ # @api private
7
+ class Schema
8
+ class Member
9
+ # Adds a layer of caching over user-supplied `.to_graphql` methods.
10
+ # Users override `.to_graphql`, but all runtime code should use `.graphql_definition`.
11
+ module CachedGraphQLDefinition
12
+ # A cached result of {.to_graphql}.
13
+ # It's cached here so that user-overridden {.to_graphql} implementations
14
+ # are also cached
15
+ def graphql_definition
16
+ @graphql_definition ||= to_graphql
17
+ end
18
+ end
19
+
20
+ # These constants are interpreted as GraphQL types
21
+ #
22
+ # @example
23
+ # field :isDraft, Boolean, null: false
24
+ # field :id, ID, null: false
25
+ module GraphQLTypeNames
26
+ Boolean = "Boolean"
27
+ ID = "ID"
28
+ end
29
+
30
+ include GraphQLTypeNames
31
+ class << self
32
+ include CachedGraphQLDefinition
33
+
34
+ # Delegate to the derived type definition if possible.
35
+ # This is tricky because missing methods cause the definition to be built & cached.
36
+ def method_missing(method_name, *args, &block)
37
+ if graphql_definition.respond_to?(method_name)
38
+ graphql_definition.public_send(method_name, *args, &block)
39
+ else
40
+ super
41
+ end
42
+ end
43
+
44
+ # Check if the derived type definition responds to the method
45
+ # @return [Boolean]
46
+ def respond_to_missing?(method_name, incl_private = false)
47
+ graphql_definition.respond_to?(method_name, incl_private) || super
48
+ end
49
+
50
+ # Call this with a new name to override the default name for this schema member; OR
51
+ # call it without an argument to get the name of this schema member
52
+ #
53
+ # The default name is the Ruby constant name,
54
+ # without any namespaces and with any `-Type` suffix removed
55
+ # @param new_name [String]
56
+ # @return [String]
57
+ def graphql_name(new_name = nil)
58
+ if new_name
59
+ @graphql_name = new_name
60
+ else
61
+ @graphql_name || self.name.split("::").last.sub(/Type\Z/, "")
62
+ end
63
+ end
64
+
65
+ # Call this method to provide a new description; OR
66
+ # call it without an argument to get the description
67
+ # @param new_description [String]
68
+ # @return [String]
69
+ def description(new_description = nil)
70
+ if new_description
71
+ @description = new_description
72
+ else
73
+ @description || (superclass <= GraphQL::Schema::Member ? superclass.description : nil)
74
+ end
75
+ end
76
+
77
+ def to_graphql
78
+ raise NotImplementedError
79
+ end
80
+
81
+ def to_list_type
82
+ ListTypeProxy.new(self)
83
+ end
84
+
85
+ def to_non_null_type
86
+ NonNullTypeProxy.new(self)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ require 'graphql/schema/member/list_type_proxy'
94
+ require 'graphql/schema/member/non_null_type_proxy'
95
+ require 'graphql/schema/member/has_fields'
96
+ require 'graphql/schema/member/instrumentation'
97
+ require 'graphql/schema/member/build_type'