graphql 1.9.17 → 1.11.7

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (230) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +18 -2
  3. data/lib/generators/graphql/install_generator.rb +27 -0
  4. data/lib/generators/graphql/object_generator.rb +52 -8
  5. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  6. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  7. data/lib/generators/graphql/templates/base_field.erb +2 -0
  8. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  9. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  10. data/lib/generators/graphql/templates/base_mutation.erb +2 -0
  11. data/lib/generators/graphql/templates/base_object.erb +2 -0
  12. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  13. data/lib/generators/graphql/templates/base_union.erb +2 -0
  14. data/lib/generators/graphql/templates/enum.erb +2 -0
  15. data/lib/generators/graphql/templates/graphql_controller.erb +14 -10
  16. data/lib/generators/graphql/templates/interface.erb +2 -0
  17. data/lib/generators/graphql/templates/loader.erb +2 -0
  18. data/lib/generators/graphql/templates/mutation.erb +2 -0
  19. data/lib/generators/graphql/templates/mutation_type.erb +2 -0
  20. data/lib/generators/graphql/templates/object.erb +2 -0
  21. data/lib/generators/graphql/templates/query_type.erb +2 -0
  22. data/lib/generators/graphql/templates/scalar.erb +2 -0
  23. data/lib/generators/graphql/templates/schema.erb +10 -0
  24. data/lib/generators/graphql/templates/union.erb +3 -1
  25. data/lib/graphql/analysis/ast/field_usage.rb +1 -1
  26. data/lib/graphql/analysis/ast/query_complexity.rb +178 -67
  27. data/lib/graphql/analysis/ast/visitor.rb +3 -3
  28. data/lib/graphql/analysis/ast.rb +12 -11
  29. data/lib/graphql/argument.rb +10 -38
  30. data/lib/graphql/backtrace/table.rb +10 -2
  31. data/lib/graphql/backtrace/tracer.rb +2 -1
  32. data/lib/graphql/base_type.rb +4 -0
  33. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
  34. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
  35. data/lib/graphql/define/assign_enum_value.rb +1 -1
  36. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  37. data/lib/graphql/define/assign_object_field.rb +3 -3
  38. data/lib/graphql/define/defined_object_proxy.rb +3 -0
  39. data/lib/graphql/define/instance_definable.rb +18 -108
  40. data/lib/graphql/directive/deprecated_directive.rb +1 -12
  41. data/lib/graphql/directive.rb +8 -1
  42. data/lib/graphql/enum_type.rb +5 -71
  43. data/lib/graphql/execution/directive_checks.rb +2 -2
  44. data/lib/graphql/execution/errors.rb +2 -3
  45. data/lib/graphql/execution/execute.rb +1 -1
  46. data/lib/graphql/execution/instrumentation.rb +1 -1
  47. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  48. data/lib/graphql/execution/interpreter/arguments.rb +51 -0
  49. data/lib/graphql/execution/interpreter/arguments_cache.rb +79 -0
  50. data/lib/graphql/execution/interpreter/handles_raw_value.rb +25 -0
  51. data/lib/graphql/execution/interpreter/runtime.rb +227 -254
  52. data/lib/graphql/execution/interpreter.rb +34 -11
  53. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  54. data/lib/graphql/execution/lookahead.rb +39 -114
  55. data/lib/graphql/execution/multiplex.rb +14 -5
  56. data/lib/graphql/field.rb +14 -118
  57. data/lib/graphql/filter.rb +1 -1
  58. data/lib/graphql/function.rb +1 -30
  59. data/lib/graphql/input_object_type.rb +6 -24
  60. data/lib/graphql/integer_decoding_error.rb +17 -0
  61. data/lib/graphql/interface_type.rb +7 -23
  62. data/lib/graphql/internal_representation/scope.rb +2 -2
  63. data/lib/graphql/internal_representation/visit.rb +2 -2
  64. data/lib/graphql/introspection/base_object.rb +2 -5
  65. data/lib/graphql/introspection/directive_type.rb +1 -1
  66. data/lib/graphql/introspection/entry_points.rb +7 -7
  67. data/lib/graphql/introspection/field_type.rb +7 -3
  68. data/lib/graphql/introspection/input_value_type.rb +33 -9
  69. data/lib/graphql/introspection/introspection_query.rb +6 -92
  70. data/lib/graphql/introspection/schema_type.rb +4 -9
  71. data/lib/graphql/introspection/type_type.rb +11 -7
  72. data/lib/graphql/introspection.rb +96 -0
  73. data/lib/graphql/invalid_null_error.rb +18 -0
  74. data/lib/graphql/language/block_string.rb +24 -5
  75. data/lib/graphql/language/definition_slice.rb +21 -10
  76. data/lib/graphql/language/document_from_schema_definition.rb +89 -64
  77. data/lib/graphql/language/lexer.rb +7 -3
  78. data/lib/graphql/language/lexer.rl +7 -3
  79. data/lib/graphql/language/nodes.rb +52 -91
  80. data/lib/graphql/language/parser.rb +719 -717
  81. data/lib/graphql/language/parser.y +104 -98
  82. data/lib/graphql/language/printer.rb +1 -1
  83. data/lib/graphql/language/sanitized_printer.rb +222 -0
  84. data/lib/graphql/language/visitor.rb +2 -2
  85. data/lib/graphql/language.rb +2 -1
  86. data/lib/graphql/name_validator.rb +6 -7
  87. data/lib/graphql/non_null_type.rb +0 -10
  88. data/lib/graphql/object_type.rb +45 -56
  89. data/lib/graphql/pagination/active_record_relation_connection.rb +41 -0
  90. data/lib/graphql/pagination/array_connection.rb +77 -0
  91. data/lib/graphql/pagination/connection.rb +208 -0
  92. data/lib/graphql/pagination/connections.rb +145 -0
  93. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  94. data/lib/graphql/pagination/relation_connection.rb +185 -0
  95. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  96. data/lib/graphql/pagination.rb +6 -0
  97. data/lib/graphql/query/arguments.rb +4 -2
  98. data/lib/graphql/query/context.rb +36 -9
  99. data/lib/graphql/query/fingerprint.rb +26 -0
  100. data/lib/graphql/query/input_validation_result.rb +23 -6
  101. data/lib/graphql/query/literal_input.rb +30 -10
  102. data/lib/graphql/query/null_context.rb +5 -1
  103. data/lib/graphql/query/validation_pipeline.rb +4 -1
  104. data/lib/graphql/query/variable_validation_error.rb +1 -1
  105. data/lib/graphql/query/variables.rb +16 -7
  106. data/lib/graphql/query.rb +64 -15
  107. data/lib/graphql/rake_task/validate.rb +3 -0
  108. data/lib/graphql/rake_task.rb +9 -9
  109. data/lib/graphql/relay/array_connection.rb +10 -12
  110. data/lib/graphql/relay/base_connection.rb +23 -13
  111. data/lib/graphql/relay/connection_type.rb +2 -1
  112. data/lib/graphql/relay/edge_type.rb +1 -0
  113. data/lib/graphql/relay/edges_instrumentation.rb +1 -1
  114. data/lib/graphql/relay/mutation.rb +1 -86
  115. data/lib/graphql/relay/node.rb +2 -2
  116. data/lib/graphql/relay/range_add.rb +14 -5
  117. data/lib/graphql/relay/relation_connection.rb +8 -10
  118. data/lib/graphql/scalar_type.rb +15 -59
  119. data/lib/graphql/schema/argument.rb +113 -11
  120. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  121. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
  122. data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
  123. data/lib/graphql/schema/build_from_definition.rb +212 -190
  124. data/lib/graphql/schema/built_in_types.rb +5 -5
  125. data/lib/graphql/schema/default_type_error.rb +2 -0
  126. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  127. data/lib/graphql/schema/directive/include.rb +1 -1
  128. data/lib/graphql/schema/directive/skip.rb +1 -1
  129. data/lib/graphql/schema/directive.rb +34 -3
  130. data/lib/graphql/schema/enum.rb +52 -4
  131. data/lib/graphql/schema/enum_value.rb +6 -1
  132. data/lib/graphql/schema/field/connection_extension.rb +44 -20
  133. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  134. data/lib/graphql/schema/field.rb +200 -129
  135. data/lib/graphql/schema/find_inherited_value.rb +13 -0
  136. data/lib/graphql/schema/finder.rb +13 -11
  137. data/lib/graphql/schema/input_object.rb +131 -22
  138. data/lib/graphql/schema/interface.rb +26 -8
  139. data/lib/graphql/schema/introspection_system.rb +108 -37
  140. data/lib/graphql/schema/late_bound_type.rb +3 -2
  141. data/lib/graphql/schema/list.rb +47 -0
  142. data/lib/graphql/schema/loader.rb +134 -96
  143. data/lib/graphql/schema/member/base_dsl_methods.rb +29 -12
  144. data/lib/graphql/schema/member/build_type.rb +19 -5
  145. data/lib/graphql/schema/member/cached_graphql_definition.rb +5 -0
  146. data/lib/graphql/schema/member/has_arguments.rb +105 -5
  147. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  148. data/lib/graphql/schema/member/has_fields.rb +20 -10
  149. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  150. data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
  151. data/lib/graphql/schema/member/validates_input.rb +33 -0
  152. data/lib/graphql/schema/member.rb +6 -0
  153. data/lib/graphql/schema/mutation.rb +5 -1
  154. data/lib/graphql/schema/non_null.rb +30 -0
  155. data/lib/graphql/schema/object.rb +65 -12
  156. data/lib/graphql/schema/possible_types.rb +9 -4
  157. data/lib/graphql/schema/printer.rb +0 -15
  158. data/lib/graphql/schema/relay_classic_mutation.rb +5 -3
  159. data/lib/graphql/schema/resolver/has_payload_type.rb +5 -2
  160. data/lib/graphql/schema/resolver.rb +26 -18
  161. data/lib/graphql/schema/scalar.rb +27 -3
  162. data/lib/graphql/schema/subscription.rb +8 -18
  163. data/lib/graphql/schema/timeout.rb +29 -15
  164. data/lib/graphql/schema/traversal.rb +1 -1
  165. data/lib/graphql/schema/type_expression.rb +21 -13
  166. data/lib/graphql/schema/type_membership.rb +2 -2
  167. data/lib/graphql/schema/union.rb +37 -3
  168. data/lib/graphql/schema/unique_within_type.rb +1 -2
  169. data/lib/graphql/schema/validation.rb +10 -2
  170. data/lib/graphql/schema/warden.rb +115 -29
  171. data/lib/graphql/schema.rb +903 -195
  172. data/lib/graphql/static_validation/all_rules.rb +1 -0
  173. data/lib/graphql/static_validation/base_visitor.rb +10 -6
  174. data/lib/graphql/static_validation/literal_validator.rb +52 -27
  175. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +43 -83
  176. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +17 -5
  177. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +33 -25
  178. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
  179. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  180. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
  181. data/lib/graphql/static_validation/rules/fields_will_merge.rb +29 -21
  182. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  183. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  184. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  185. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
  186. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -5
  187. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
  188. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -6
  189. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  190. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
  191. data/lib/graphql/static_validation/type_stack.rb +2 -2
  192. data/lib/graphql/static_validation/validation_context.rb +1 -1
  193. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  194. data/lib/graphql/static_validation/validator.rb +30 -8
  195. data/lib/graphql/static_validation.rb +1 -0
  196. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +89 -19
  197. data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
  198. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  199. data/lib/graphql/subscriptions/event.rb +23 -5
  200. data/lib/graphql/subscriptions/instrumentation.rb +10 -5
  201. data/lib/graphql/subscriptions/serialize.rb +22 -4
  202. data/lib/graphql/subscriptions/subscription_root.rb +15 -5
  203. data/lib/graphql/subscriptions.rb +108 -35
  204. data/lib/graphql/tracing/active_support_notifications_tracing.rb +14 -10
  205. data/lib/graphql/tracing/appoptics_tracing.rb +171 -0
  206. data/lib/graphql/tracing/appsignal_tracing.rb +8 -0
  207. data/lib/graphql/tracing/data_dog_tracing.rb +8 -0
  208. data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
  209. data/lib/graphql/tracing/platform_tracing.rb +53 -9
  210. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  211. data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
  212. data/lib/graphql/tracing/scout_tracing.rb +19 -0
  213. data/lib/graphql/tracing/skylight_tracing.rb +8 -0
  214. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  215. data/lib/graphql/tracing.rb +14 -34
  216. data/lib/graphql/types/big_int.rb +1 -1
  217. data/lib/graphql/types/int.rb +9 -2
  218. data/lib/graphql/types/iso_8601_date.rb +3 -3
  219. data/lib/graphql/types/iso_8601_date_time.rb +25 -10
  220. data/lib/graphql/types/relay/base_connection.rb +11 -7
  221. data/lib/graphql/types/relay/base_edge.rb +2 -1
  222. data/lib/graphql/types/string.rb +7 -1
  223. data/lib/graphql/unauthorized_error.rb +1 -1
  224. data/lib/graphql/union_type.rb +13 -28
  225. data/lib/graphql/unresolved_type_error.rb +2 -2
  226. data/lib/graphql/version.rb +1 -1
  227. data/lib/graphql.rb +31 -6
  228. data/readme.md +1 -1
  229. metadata +34 -9
  230. data/lib/graphql/literal_validation_error.rb +0 -6
@@ -4,24 +4,22 @@ require "graphql/schema/build_from_definition/resolve_map"
4
4
  module GraphQL
5
5
  class Schema
6
6
  module BuildFromDefinition
7
+ if !String.method_defined?(:-@)
8
+ using GraphQL::StringDedupBackport
9
+ end
10
+
7
11
  class << self
8
- def from_definition(definition_string, default_resolve:, parser: DefaultParser)
9
- document = parser.parse(definition_string)
10
- Builder.build(document, default_resolve: default_resolve)
12
+ # @see {Schema.from_definition}
13
+ def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
14
+ from_document(parser.parse(definition_string), **kwargs)
11
15
  end
12
- end
13
16
 
14
- # @api private
15
- DefaultParser = GraphQL::Language::Parser
17
+ def from_definition_path(definition_path, parser: GraphQL.default_parser, **kwargs)
18
+ from_document(parser.parse_file(definition_path), **kwargs)
19
+ end
16
20
 
17
- # @api private
18
- module DefaultResolve
19
- def self.call(type, field, obj, args, ctx)
20
- if field.arguments.any?
21
- obj.public_send(field.name, args, ctx)
22
- else
23
- obj.public_send(field.name)
24
- end
21
+ def from_document(document, default_resolve:, using: {}, relay: false, interpreter: true)
22
+ Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using, interpreter: interpreter)
25
23
  end
26
24
  end
27
25
 
@@ -29,28 +27,30 @@ module GraphQL
29
27
  module Builder
30
28
  extend self
31
29
 
32
- def build(document, default_resolve: DefaultResolve)
30
+ def build(document, default_resolve:, using: {}, interpreter: true, relay:)
33
31
  raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
34
32
 
35
33
  if default_resolve.is_a?(Hash)
36
34
  default_resolve = ResolveMap.new(default_resolve)
37
35
  end
38
36
 
39
- schema_definition = nil
37
+ schema_defns = document.definitions.select { |d| d.is_a?(GraphQL::Language::Nodes::SchemaDefinition) }
38
+ if schema_defns.size > 1
39
+ raise InvalidDocumentError.new('Must provide only one schema definition.')
40
+ end
41
+ schema_definition = schema_defns.first
40
42
  types = {}
41
- types.merge!(GraphQL::Schema::BUILT_IN_TYPES)
42
43
  directives = {}
43
- type_resolver = ->(type) { -> { resolve_type(types, type) } }
44
+ type_resolver = ->(type) { resolve_type(types, type) }
44
45
 
45
46
  document.definitions.each do |definition|
46
47
  case definition
47
48
  when GraphQL::Language::Nodes::SchemaDefinition
48
- raise InvalidDocumentError.new('Must provide only one schema definition.') if schema_definition
49
- schema_definition = definition
49
+ nil # already handled
50
50
  when GraphQL::Language::Nodes::EnumTypeDefinition
51
51
  types[definition.name] = build_enum_type(definition, type_resolver)
52
52
  when GraphQL::Language::Nodes::ObjectTypeDefinition
53
- types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve)
53
+ types[definition.name] = build_object_type(definition, type_resolver)
54
54
  when GraphQL::Language::Nodes::InterfaceTypeDefinition
55
55
  types[definition.name] = build_interface_type(definition, type_resolver)
56
56
  when GraphQL::Language::Nodes::UnionTypeDefinition
@@ -64,6 +64,21 @@ module GraphQL
64
64
  end
65
65
  end
66
66
 
67
+ # At this point, if types named by the built in types are _late-bound_ types,
68
+ # that means they were referenced in the schema but not defined in the schema.
69
+ # That's supported for built-in types. (Eg, you can use `String` without defining it.)
70
+ # In that case, insert the concrete type definition now.
71
+ #
72
+ # However, if the type in `types` is a _concrete_ type definition, that means that
73
+ # the document contained an explicit definition of the scalar type.
74
+ # Don't override it in this case.
75
+ GraphQL::Schema::BUILT_IN_TYPES.each do |scalar_name, built_in_scalar|
76
+ existing_type = types[scalar_name]
77
+ if existing_type.is_a?(GraphQL::Schema::LateBoundType)
78
+ types[scalar_name] = built_in_scalar
79
+ end
80
+ end
81
+
67
82
  directives = GraphQL::Schema.default_directives.merge(directives)
68
83
 
69
84
  if schema_definition
@@ -89,54 +104,86 @@ module GraphQL
89
104
 
90
105
  raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
91
106
 
92
- schema = Schema.define do
93
- raise_definition_error true
107
+ Class.new(GraphQL::Schema) do
108
+ begin
109
+ # Add these first so that there's some chance of resolving late-bound types
110
+ orphan_types types.values
111
+ query query_root_type
112
+ mutation mutation_root_type
113
+ subscription subscription_root_type
114
+ rescue Schema::UnresolvedLateBoundTypeError => err
115
+ type_name = err.type.name
116
+ err_backtrace = err.backtrace
117
+ raise InvalidDocumentError, "Type \"#{type_name}\" not found in document.", err_backtrace
118
+ end
94
119
 
95
- query query_root_type
96
- mutation mutation_root_type
97
- subscription subscription_root_type
98
- orphan_types types.values
99
120
  if default_resolve.respond_to?(:resolve_type)
100
- resolve_type(default_resolve.method(:resolve_type))
121
+ def self.resolve_type(*args)
122
+ self.definition_default_resolve.resolve_type(*args)
123
+ end
101
124
  else
102
- resolve_type(NullResolveType)
125
+ def self.resolve_type(*args)
126
+ NullResolveType.call(*args)
127
+ end
103
128
  end
104
129
 
105
130
  directives directives.values
106
- end
107
131
 
108
- schema.ast_node = schema_definition if schema_definition
132
+ if schema_definition
133
+ ast_node(schema_definition)
134
+ end
135
+
136
+ if interpreter
137
+ use GraphQL::Execution::Interpreter
138
+ use GraphQL::Analysis::AST
139
+ end
140
+
141
+ using.each do |plugin, options|
142
+ if options
143
+ use(plugin, **options)
144
+ else
145
+ use(plugin)
146
+ end
147
+ end
148
+
149
+ # Empty `orphan_types` -- this will make unreachable types ... unreachable.
150
+ own_orphan_types.clear
151
+
152
+ class << self
153
+ attr_accessor :definition_default_resolve
154
+ end
109
155
 
110
- schema
156
+ self.definition_default_resolve = default_resolve
157
+
158
+ def definition_default_resolve
159
+ self.class.definition_default_resolve
160
+ end
161
+
162
+ def self.inherited(child_class)
163
+ child_class.definition_default_resolve = self.definition_default_resolve
164
+ end
165
+ end
111
166
  end
112
167
 
113
168
  NullResolveType = ->(type, obj, ctx) {
114
169
  raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
115
170
  }
116
171
 
117
- NullScalarCoerce = ->(val, _ctx) { val }
118
-
119
172
  def build_enum_type(enum_type_definition, type_resolver)
120
- enum = GraphQL::EnumType.define(
121
- name: enum_type_definition.name,
122
- description: enum_type_definition.description,
123
- values: enum_type_definition.values.map do |enum_value_definition|
124
- value = EnumType::EnumValue.define(
125
- name: enum_value_definition.name,
173
+ builder = self
174
+ Class.new(GraphQL::Schema::Enum) do
175
+ graphql_name(enum_type_definition.name)
176
+ description(enum_type_definition.description)
177
+ ast_node(enum_type_definition)
178
+ enum_type_definition.values.each do |enum_value_definition|
179
+ value(enum_value_definition.name,
126
180
  value: enum_value_definition.name,
127
- deprecation_reason: build_deprecation_reason(enum_value_definition.directives),
181
+ deprecation_reason: builder.build_deprecation_reason(enum_value_definition.directives),
128
182
  description: enum_value_definition.description,
183
+ ast_node: enum_value_definition,
129
184
  )
130
-
131
- value.ast_node = enum_value_definition
132
-
133
- value
134
185
  end
135
- )
136
-
137
- enum.ast_node = enum_type_definition
138
-
139
- enum
186
+ end
140
187
  end
141
188
 
142
189
  def build_deprecation_reason(directives)
@@ -144,65 +191,67 @@ module GraphQL
144
191
  return unless deprecated_directive
145
192
 
146
193
  reason = deprecated_directive.arguments.find{ |a| a.name == 'reason' }
147
- return GraphQL::Directive::DEFAULT_DEPRECATION_REASON unless reason
194
+ return GraphQL::Schema::Directive::DEFAULT_DEPRECATION_REASON unless reason
148
195
 
149
196
  reason.value
150
197
  end
151
198
 
152
199
  def build_scalar_type(scalar_type_definition, type_resolver, default_resolve:)
153
- scalar_type = GraphQL::ScalarType.define(
154
- name: scalar_type_definition.name,
155
- description: scalar_type_definition.description,
156
- coerce: NullScalarCoerce,
157
- )
158
-
159
- scalar_type.ast_node = scalar_type_definition
160
-
161
- if default_resolve.respond_to?(:coerce_input)
162
- scalar_type = scalar_type.redefine(
163
- coerce_input: ->(val, ctx) { default_resolve.coerce_input(scalar_type, val, ctx) },
164
- coerce_result: ->(val, ctx) { default_resolve.coerce_result(scalar_type, val, ctx) },
165
- )
200
+ builder = self
201
+ Class.new(GraphQL::Schema::Scalar) do
202
+ graphql_name(scalar_type_definition.name)
203
+ description(scalar_type_definition.description)
204
+ ast_node(scalar_type_definition)
205
+
206
+ if default_resolve.respond_to?(:coerce_input)
207
+ # Put these method definitions in another method to avoid retaining `type_resolve`
208
+ # from this method's bindiing
209
+ builder.build_scalar_type_coerce_method(self, :coerce_input, default_resolve)
210
+ builder.build_scalar_type_coerce_method(self, :coerce_result, default_resolve)
211
+ end
166
212
  end
213
+ end
167
214
 
168
- scalar_type
215
+ def build_scalar_type_coerce_method(scalar_class, method_name, default_definition_resolve)
216
+ scalar_class.define_singleton_method(method_name) do |val, ctx|
217
+ default_definition_resolve.public_send(method_name, self, val, ctx)
218
+ end
169
219
  end
170
220
 
171
221
  def build_union_type(union_type_definition, type_resolver)
172
- union = GraphQL::UnionType.define(
173
- name: union_type_definition.name,
174
- description: union_type_definition.description,
175
- possible_types: union_type_definition.types.map{ |type_name| type_resolver.call(type_name) },
176
- )
222
+ Class.new(GraphQL::Schema::Union) do
223
+ graphql_name(union_type_definition.name)
224
+ description(union_type_definition.description)
225
+ possible_types(*union_type_definition.types.map { |type_name| type_resolver.call(type_name) })
226
+ ast_node(union_type_definition)
227
+ end
228
+ end
177
229
 
178
- union.ast_node = union_type_definition
230
+ def build_object_type(object_type_definition, type_resolver)
231
+ builder = self
179
232
 
180
- union
181
- end
233
+ Class.new(GraphQL::Schema::Object) do
234
+ graphql_name(object_type_definition.name)
235
+ description(object_type_definition.description)
236
+ ast_node(object_type_definition)
237
+
238
+ object_type_definition.interfaces.each do |interface_name|
239
+ interface_defn = type_resolver.call(interface_name)
240
+ implements(interface_defn)
241
+ end
182
242
 
183
- def build_object_type(object_type_definition, type_resolver, default_resolve:)
184
- type_def = nil
185
- typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
186
- type_def = GraphQL::ObjectType.define(
187
- name: object_type_definition.name,
188
- description: object_type_definition.description,
189
- fields: Hash[build_fields(object_type_definition.fields, type_resolver, default_resolve: typed_resolve_fn)],
190
- interfaces: object_type_definition.interfaces.map{ |interface_name| type_resolver.call(interface_name) },
191
- )
192
- type_def.ast_node = object_type_definition
193
- type_def
243
+ builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
244
+ end
194
245
  end
195
246
 
196
247
  def build_input_object_type(input_object_type_definition, type_resolver)
197
- input = GraphQL::InputObjectType.define(
198
- name: input_object_type_definition.name,
199
- description: input_object_type_definition.description,
200
- arguments: Hash[build_input_arguments(input_object_type_definition, type_resolver)],
201
- )
202
-
203
- input.ast_node = input_object_type_definition
204
-
205
- input
248
+ builder = self
249
+ Class.new(GraphQL::Schema::InputObject) do
250
+ graphql_name(input_object_type_definition.name)
251
+ description(input_object_type_definition.description)
252
+ ast_node(input_object_type_definition)
253
+ builder.build_arguments(self, input_object_type_definition.fields, type_resolver)
254
+ end
206
255
  end
207
256
 
208
257
  def build_default_value(default_value)
@@ -220,129 +269,102 @@ module GraphQL
220
269
  end
221
270
  end
222
271
 
223
- def build_input_arguments(input_object_type_definition, type_resolver)
224
- input_object_type_definition.fields.map do |input_argument|
225
- kwargs = {}
272
+ NO_DEFAULT_VALUE = {}.freeze
273
+
274
+ def build_arguments(type_class, arguments, type_resolver)
275
+ builder = self
226
276
 
227
- if !input_argument.default_value.nil?
228
- kwargs[:default_value] = build_default_value(input_argument.default_value)
277
+ arguments.each do |argument_defn|
278
+ default_value_kwargs = if !argument_defn.default_value.nil?
279
+ { default_value: builder.build_default_value(argument_defn.default_value) }
280
+ else
281
+ NO_DEFAULT_VALUE
229
282
  end
230
283
 
231
- argument = GraphQL::Argument.define(
232
- name: input_argument.name,
233
- type: type_resolver.call(input_argument.type),
234
- description: input_argument.description,
284
+ type_class.argument(
285
+ argument_defn.name,
286
+ type: type_resolver.call(argument_defn.type),
287
+ required: false,
288
+ description: argument_defn.description,
289
+ deprecation_reason: builder.build_deprecation_reason(argument_defn.directives),
290
+ ast_node: argument_defn,
291
+ camelize: false,
235
292
  method_access: false,
236
- **kwargs,
293
+ **default_value_kwargs
237
294
  )
238
-
239
- argument.ast_node = input_argument
240
-
241
- [
242
- input_argument.name,
243
- argument
244
- ]
245
295
  end
246
296
  end
247
297
 
248
298
  def build_directive(directive_definition, type_resolver)
249
- directive = GraphQL::Directive.define(
250
- name: directive_definition.name,
251
- description: directive_definition.description,
252
- arguments: Hash[build_directive_arguments(directive_definition, type_resolver)],
253
- locations: directive_definition.locations.map { |location| location.name.to_sym },
254
- )
255
-
256
- directive.ast_node = directive_definition
257
-
258
- directive
259
- end
260
-
261
- def build_directive_arguments(directive_definition, type_resolver)
262
- directive_definition.arguments.map do |directive_argument|
263
- kwargs = {}
264
-
265
- if !directive_argument.default_value.nil?
266
- kwargs[:default_value] = build_default_value(directive_argument.default_value)
267
- end
268
-
269
- argument = GraphQL::Argument.define(
270
- name: directive_argument.name,
271
- type: type_resolver.call(directive_argument.type),
272
- description: directive_argument.description,
273
- method_access: false,
274
- **kwargs,
275
- )
276
-
277
- argument.ast_node = directive_argument
278
-
279
- [
280
- directive_argument.name,
281
- argument
282
- ]
299
+ builder = self
300
+ Class.new(GraphQL::Schema::Directive) do
301
+ graphql_name(directive_definition.name)
302
+ description(directive_definition.description)
303
+ locations(*directive_definition.locations.map { |location| location.name.to_sym })
304
+ ast_node(directive_definition)
305
+ builder.build_arguments(self, directive_definition.arguments, type_resolver)
283
306
  end
284
307
  end
285
308
 
286
309
  def build_interface_type(interface_type_definition, type_resolver)
287
- interface = GraphQL::InterfaceType.define(
288
- name: interface_type_definition.name,
289
- description: interface_type_definition.description,
290
- fields: Hash[build_fields(interface_type_definition.fields, type_resolver, default_resolve: nil)],
291
- )
292
-
293
- interface.ast_node = interface_type_definition
294
-
295
- interface
310
+ builder = self
311
+ Module.new do
312
+ include GraphQL::Schema::Interface
313
+ graphql_name(interface_type_definition.name)
314
+ description(interface_type_definition.description)
315
+ ast_node(interface_type_definition)
316
+
317
+ builder.build_fields(self, interface_type_definition.fields, type_resolver, default_resolve: nil)
318
+ end
296
319
  end
297
320
 
298
- def build_fields(field_definitions, type_resolver, default_resolve:)
299
- field_definitions.map do |field_definition|
300
- field_arguments = Hash[field_definition.arguments.map do |argument|
301
- kwargs = {}
302
-
303
- if !argument.default_value.nil?
304
- kwargs[:default_value] = build_default_value(argument.default_value)
305
- end
306
-
307
- arg = GraphQL::Argument.define(
308
- name: argument.name,
309
- description: argument.description,
310
- type: type_resolver.call(argument.type),
311
- method_access: false,
312
- **kwargs,
313
- )
314
-
315
- arg.ast_node = argument
316
-
317
- [argument.name, arg]
318
- end]
321
+ def build_fields(owner, field_definitions, type_resolver, default_resolve:)
322
+ builder = self
319
323
 
320
- field = GraphQL::Field.define(
321
- name: field_definition.name,
324
+ field_definitions.each do |field_definition|
325
+ type_name = resolve_type_name(field_definition.type)
326
+ resolve_method_name = -"resolve_field_#{field_definition.name}"
327
+ schema_field_defn = owner.field(
328
+ field_definition.name,
322
329
  description: field_definition.description,
323
330
  type: type_resolver.call(field_definition.type),
324
- arguments: field_arguments,
325
- resolve: ->(obj, args, ctx) { default_resolve.call(field, obj, args, ctx) },
331
+ null: true,
332
+ connection: type_name.end_with?("Connection"),
333
+ connection_extension: nil,
326
334
  deprecation_reason: build_deprecation_reason(field_definition.directives),
335
+ ast_node: field_definition,
336
+ method_conflict_warning: false,
337
+ camelize: false,
338
+ resolver_method: resolve_method_name,
327
339
  )
328
340
 
329
- field.ast_node = field_definition
330
-
331
- type_name = resolve_type_name(field_definition.type)
332
- field.connection = type_name.end_with?("Connection")
333
- [field_definition.name, field]
341
+ builder.build_arguments(schema_field_defn, field_definition.arguments, type_resolver)
342
+
343
+ # Don't do this for interfaces
344
+ if default_resolve
345
+ owner.class_eval <<-RUBY, __FILE__, __LINE__
346
+ # frozen_string_literal: true
347
+ def #{resolve_method_name}(**args)
348
+ field_instance = self.class.get_field("#{field_definition.name}")
349
+ context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
350
+ end
351
+ RUBY
352
+ end
334
353
  end
335
354
  end
336
355
 
337
356
  def resolve_type(types, ast_node)
338
- type = GraphQL::Schema::TypeExpression.build_type(types, ast_node)
339
- if type.nil?
340
- while ast_node.respond_to?(:of_type)
341
- ast_node = ast_node.of_type
342
- end
343
- raise InvalidDocumentError.new("Type \"#{ast_node.name}\" not found in document.")
357
+ case ast_node
358
+ when GraphQL::Language::Nodes::TypeName
359
+ type_name = ast_node.name
360
+ types[type_name] ||= GraphQL::Schema::LateBoundType.new(type_name)
361
+ when GraphQL::Language::Nodes::NonNullType
362
+ resolve_type(types, ast_node.of_type).to_non_null_type
363
+ when GraphQL::Language::Nodes::ListType
364
+ resolve_type(types, ast_node.of_type).to_list_type
365
+ else
366
+ raise "Unexpected ast_node: #{ast_node.inspect}"
344
367
  end
345
- type
346
368
  end
347
369
 
348
370
  def resolve_type_name(type)
@@ -2,11 +2,11 @@
2
2
  module GraphQL
3
3
  class Schema
4
4
  BUILT_IN_TYPES = {
5
- "Int" => INT_TYPE,
6
- "String" => STRING_TYPE,
7
- "Float" => FLOAT_TYPE,
8
- "Boolean" => BOOLEAN_TYPE,
9
- "ID" => ID_TYPE,
5
+ "Int" => GraphQL::Types::Int,
6
+ "String" => GraphQL::Types::String,
7
+ "Float" => GraphQL::Types::Float,
8
+ "Boolean" => GraphQL::Types::Boolean,
9
+ "ID" => GraphQL::Types::ID,
10
10
  }
11
11
  end
12
12
  end
@@ -8,6 +8,8 @@ module GraphQL
8
8
  ctx.errors << type_error
9
9
  when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
10
10
  raise type_error
11
+ when GraphQL::IntegerDecodingError
12
+ nil
11
13
  end
12
14
  end
13
15
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Directive < GraphQL::Schema::Member
5
+ class Deprecated < GraphQL::Schema::Directive
6
+ description "Marks an element of a GraphQL schema as no longer supported."
7
+ locations(GraphQL::Schema::Directive::FIELD_DEFINITION, GraphQL::Schema::Directive::ENUM_VALUE, GraphQL::Schema::Directive::ARGUMENT_DEFINITION, GraphQL::Schema::Directive::INPUT_FIELD_DEFINITION)
8
+
9
+ reason_description = "Explains why this element was deprecated, usually also including a "\
10
+ "suggestion for how to access supported similar data. Formatted "\
11
+ "in [Markdown](https://daringfireball.net/projects/markdown/)."
12
+
13
+ argument :reason, String, reason_description, default_value: Directive::DEFAULT_DEPRECATION_REASON, required: false
14
+ default_directive true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -16,7 +16,7 @@ module GraphQL
16
16
 
17
17
  default_directive true
18
18
 
19
- def self.include?(obj, args, ctx)
19
+ def self.static_include?(args, ctx)
20
20
  !!args[:if]
21
21
  end
22
22
  end
@@ -16,7 +16,7 @@ module GraphQL
16
16
 
17
17
  default_directive true
18
18
 
19
- def self.include?(obj, args, ctx)
19
+ def self.static_include?(args, ctx)
20
20
  !args[:if]
21
21
  end
22
22
  end
@@ -9,8 +9,14 @@ module GraphQL
9
9
  class Directive < GraphQL::Schema::Member
10
10
  extend GraphQL::Schema::Member::HasArguments
11
11
  class << self
12
+ # Return a name based on the class name,
13
+ # but downcase the first letter.
12
14
  def default_graphql_name
13
- super.downcase
15
+ @default_graphql_name ||= begin
16
+ camelized_name = super
17
+ camelized_name[0] = camelized_name[0].downcase
18
+ camelized_name
19
+ end
14
20
  end
15
21
 
16
22
  def locations(*new_locations)
@@ -27,26 +33,39 @@ module GraphQL
27
33
  elsif @default_directive.nil?
28
34
  @default_directive = (superclass.respond_to?(:default_directive) ? superclass.default_directive : false)
29
35
  else
30
- @default_directive
36
+ !!@default_directive
31
37
  end
32
38
  end
33
39
 
40
+ def default_directive?
41
+ default_directive
42
+ end
43
+
34
44
  def to_graphql
35
45
  defn = GraphQL::Directive.new
36
46
  defn.name = self.graphql_name
37
47
  defn.description = self.description
38
48
  defn.locations = self.locations
39
49
  defn.default_directive = self.default_directive
50
+ defn.ast_node = ast_node
40
51
  defn.metadata[:type_class] = self
41
52
  arguments.each do |name, arg_defn|
42
53
  arg_graphql = arg_defn.to_graphql
43
54
  defn.arguments[arg_graphql.name] = arg_graphql
44
55
  end
56
+ # Make a reference to a classic-style Arguments class
57
+ defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(defn)
58
+
45
59
  defn
46
60
  end
47
61
 
48
62
  # If false, this part of the query won't be evaluated
49
- def include?(_object, _arguments, _context)
63
+ def include?(_object, arguments, context)
64
+ static_include?(arguments, context)
65
+ end
66
+
67
+ # Determines whether {Execution::Lookahead} considers the field to be selected
68
+ def static_include?(_arguments, _context)
50
69
  true
51
70
  end
52
71
 
@@ -54,6 +73,18 @@ module GraphQL
54
73
  def resolve(object, arguments, context)
55
74
  yield
56
75
  end
76
+
77
+ def on_field?
78
+ locations.include?(FIELD)
79
+ end
80
+
81
+ def on_fragment?
82
+ locations.include?(FRAGMENT_SPREAD) && locations.include?(INLINE_FRAGMENT)
83
+ end
84
+
85
+ def on_operation?
86
+ locations.include?(QUERY) && locations.include?(MUTATION) && locations.include?(SUBSCRIPTION)
87
+ end
57
88
  end
58
89
 
59
90
  LOCATIONS = [