graphql 1.7.14 → 1.8.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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'