graphql 1.9.17 → 1.11.7

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