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
@@ -5,37 +5,49 @@ module GraphQL
5
5
  # to make a schema. This schema is missing some important details like
6
6
  # `resolve` functions, but it does include the full type system,
7
7
  # so you can use it to validate queries.
8
+ #
9
+ # @see GraphQL::Schema.from_introspection for a public API
8
10
  module Loader
9
11
  extend self
10
12
 
11
13
  # Create schema with the result of an introspection query.
12
14
  # @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
13
- # @return [GraphQL::Schema] the schema described by `input`
14
- # @deprecated Use {GraphQL::Schema.from_introspection} instead
15
+ # @return [Class] the schema described by `input`
15
16
  def load(introspection_result)
16
17
  schema = introspection_result.fetch("data").fetch("__schema")
17
18
 
18
19
  types = {}
19
- type_resolver = ->(type) { -> { resolve_type(types, type) } }
20
+ type_resolver = ->(type) { resolve_type(types, type) }
20
21
 
21
22
  schema.fetch("types").each do |type|
22
23
  next if type.fetch("name").start_with?("__")
23
24
  type_object = define_type(type, type_resolver)
24
- types[type_object.name] = type_object
25
+ types[type["name"]] = type_object
25
26
  end
26
27
 
27
- kargs = { orphan_types: types.values, resolve_type: NullResolveType }
28
- [:query, :mutation, :subscription].each do |root|
29
- type = schema["#{root}Type"]
30
- kargs[root] = types.fetch(type.fetch("name")) if type
28
+ directives = []
29
+ schema.fetch("directives", []).each do |directive|
30
+ next if GraphQL::Schema.default_directives.include?(directive.fetch("name"))
31
+ directives << define_directive(directive, type_resolver)
31
32
  end
32
33
 
33
- Schema.define(**kargs, raise_definition_error: true)
34
- end
34
+ Class.new(GraphQL::Schema) do
35
+ orphan_types(types.values)
36
+ directives(directives)
37
+
38
+ def self.resolve_type(*)
39
+ raise(GraphQL::RequiredImplementationMissingError, "This schema was loaded from string, so it can't resolve types for objects")
40
+ end
35
41
 
36
- NullResolveType = ->(type, obj, ctx) {
37
- raise(GraphQL::RequiredImplementationMissingError, "This schema was loaded from string, so it can't resolve types for objects")
38
- }
42
+ [:query, :mutation, :subscription].each do |root|
43
+ type = schema["#{root}Type"]
44
+ if type
45
+ type_defn = types.fetch(type.fetch("name"))
46
+ self.public_send(root, type_defn)
47
+ end
48
+ end
49
+ end
50
+ end
39
51
 
40
52
  NullScalarCoerce = ->(val, _ctx) { val }
41
53
 
@@ -45,11 +57,17 @@ module GraphQL
45
57
  def resolve_type(types, type)
46
58
  case kind = type.fetch("kind")
47
59
  when "ENUM", "INTERFACE", "INPUT_OBJECT", "OBJECT", "SCALAR", "UNION"
48
- types.fetch(type.fetch("name"))
60
+ type_name = type.fetch("name")
61
+ type = types[type_name] || Schema::BUILT_IN_TYPES[type_name]
62
+ if type.nil?
63
+ GraphQL::Schema::LateBoundType.new(type_name)
64
+ else
65
+ type
66
+ end
49
67
  when "LIST"
50
- ListType.new(of_type: resolve_type(types, type.fetch("ofType")))
68
+ Schema::List.new(resolve_type(types, type.fetch("ofType")))
51
69
  when "NON_NULL"
52
- NonNullType.new(of_type: resolve_type(types, type.fetch("ofType")))
70
+ Schema::NonNull.new(resolve_type(types, type.fetch("ofType")))
53
71
  else
54
72
  fail GraphQL::RequiredImplementationMissingError, "#{kind} not implemented"
55
73
  end
@@ -77,103 +95,123 @@ module GraphQL
77
95
  end
78
96
 
79
97
  def define_type(type, type_resolver)
98
+ loader = self
80
99
  case type.fetch("kind")
81
100
  when "ENUM"
82
- EnumType.define(
83
- name: type["name"],
84
- description: type["description"],
85
- values: type["enumValues"].map { |enum|
86
- EnumType::EnumValue.define(
87
- name: enum["name"],
88
- description: enum["description"],
89
- deprecation_reason: enum["deprecationReason"],
90
- value: enum["name"]
101
+ Class.new(GraphQL::Schema::Enum) do
102
+ graphql_name(type["name"])
103
+ description(type["description"])
104
+ type["enumValues"].each do |enum_value|
105
+ value(
106
+ enum_value["name"],
107
+ description: enum_value["description"],
108
+ deprecation_reason: enum_value["deprecationReason"],
91
109
  )
92
- })
110
+ end
111
+ end
93
112
  when "INTERFACE"
94
- InterfaceType.define(
95
- name: type["name"],
96
- description: type["description"],
97
- fields: Hash[(type["fields"] || []).map { |field|
98
- [field["name"], define_type(field.merge("kind" => "FIELD"), type_resolver)]
99
- }]
100
- )
113
+ Module.new do
114
+ include GraphQL::Schema::Interface
115
+ graphql_name(type["name"])
116
+ description(type["description"])
117
+ loader.build_fields(self, type["fields"] || [], type_resolver)
118
+ end
101
119
  when "INPUT_OBJECT"
102
- InputObjectType.define(
103
- name: type["name"],
104
- description: type["description"],
105
- arguments: Hash[type["inputFields"].map { |arg|
106
- [arg["name"], define_type(arg.merge("kind" => "ARGUMENT"), type_resolver)]
107
- }]
108
- )
120
+ Class.new(GraphQL::Schema::InputObject) do
121
+ graphql_name(type["name"])
122
+ description(type["description"])
123
+ loader.build_arguments(self, type["inputFields"], type_resolver)
124
+ end
109
125
  when "OBJECT"
110
- ObjectType.define(
111
- name: type["name"],
112
- description: type["description"],
113
- interfaces: (type["interfaces"] || []).map { |interface|
114
- type_resolver.call(interface)
115
- },
116
- fields: Hash[type["fields"].map { |field|
117
- [field["name"], define_type(field.merge("kind" => "FIELD"), type_resolver)]
118
- }]
119
- )
120
- when "FIELD"
121
- GraphQL::Field.define(
122
- name: type["name"],
123
- type: type_resolver.call(type["type"]),
124
- description: type["description"],
125
- arguments: Hash[type["args"].map { |arg|
126
- [arg["name"], define_type(arg.merge("kind" => "ARGUMENT"), type_resolver)]
127
- }]
128
- )
129
- when "ARGUMENT"
130
- kwargs = {}
131
- if type["defaultValue"]
132
- kwargs[:default_value] = begin
133
- default_value_str = type["defaultValue"]
134
-
135
- dummy_query_str = "query getStuff($var: InputObj = #{default_value_str}) { __typename }"
136
-
137
- # Returns a `GraphQL::Language::Nodes::Document`:
138
- dummy_query_ast = GraphQL.parse(dummy_query_str)
139
-
140
- # Reach into the AST for the default value:
141
- input_value_ast = dummy_query_ast.definitions.first.variables.first.default_value
142
-
143
- extract_default_value(default_value_str, input_value_ast)
126
+ Class.new(GraphQL::Schema::Object) do
127
+ graphql_name(type["name"])
128
+ description(type["description"])
129
+ if type["interfaces"]
130
+ type["interfaces"].each do |interface_type|
131
+ implements(type_resolver.call(interface_type))
132
+ end
144
133
  end
134
+ loader.build_fields(self, type["fields"], type_resolver)
145
135
  end
146
-
147
- GraphQL::Argument.define(
148
- name: type["name"],
149
- type: type_resolver.call(type["type"]),
150
- description: type["description"],
151
- method_access: false,
152
- **kwargs
153
- )
154
136
  when "SCALAR"
155
137
  type_name = type.fetch("name")
156
- if GraphQL::Schema::BUILT_IN_TYPES[type_name]
157
- GraphQL::Schema::BUILT_IN_TYPES[type_name]
138
+ if (builtin = GraphQL::Schema::BUILT_IN_TYPES[type_name])
139
+ builtin
158
140
  else
159
- ScalarType.define(
160
- name: type["name"],
161
- description: type["description"],
162
- coerce: NullScalarCoerce,
163
- )
141
+ Class.new(GraphQL::Schema::Scalar) do
142
+ graphql_name(type["name"])
143
+ description(type["description"])
144
+ end
164
145
  end
165
146
  when "UNION"
166
- UnionType.define(
167
- name: type["name"],
168
- description: type["description"],
169
- possible_types: type["possibleTypes"].map { |possible_type|
170
- type_resolver.call(possible_type)
171
- }
172
- )
147
+ Class.new(GraphQL::Schema::Union) do
148
+ graphql_name(type["name"])
149
+ description(type["description"])
150
+ possible_types(*(type["possibleTypes"].map { |pt| type_resolver.call(pt) }))
151
+ end
173
152
  else
174
153
  fail GraphQL::RequiredImplementationMissingError, "#{type["kind"]} not implemented"
175
154
  end
176
155
  end
156
+
157
+ def define_directive(directive, type_resolver)
158
+ loader = self
159
+ Class.new(GraphQL::Schema::Directive) do
160
+ graphql_name(directive["name"])
161
+ description(directive["description"])
162
+ locations(*directive["locations"].map(&:to_sym))
163
+ loader.build_arguments(self, directive["args"], type_resolver)
164
+ end
165
+ end
166
+
167
+ public
168
+
169
+ def build_fields(type_defn, fields, type_resolver)
170
+ loader = self
171
+ fields.each do |field_hash|
172
+ type_defn.field(
173
+ field_hash["name"],
174
+ type: type_resolver.call(field_hash["type"]),
175
+ description: field_hash["description"],
176
+ deprecation_reason: field_hash["deprecationReason"],
177
+ null: true,
178
+ camelize: false,
179
+ ) do
180
+ if field_hash["args"].any?
181
+ loader.build_arguments(self, field_hash["args"], type_resolver)
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ def build_arguments(arg_owner, args, type_resolver)
188
+ args.each do |arg|
189
+ kwargs = {
190
+ type: type_resolver.call(arg["type"]),
191
+ description: arg["description"],
192
+ deprecation_reason: arg["deprecationReason"],
193
+ required: false,
194
+ method_access: false,
195
+ camelize: false,
196
+ }
197
+
198
+ if arg["defaultValue"]
199
+ default_value_str = arg["defaultValue"]
200
+
201
+ dummy_query_str = "query getStuff($var: InputObj = #{default_value_str}) { __typename }"
202
+
203
+ # Returns a `GraphQL::Language::Nodes::Document`:
204
+ dummy_query_ast = GraphQL.parse(dummy_query_str)
205
+
206
+ # Reach into the AST for the default value:
207
+ input_value_ast = dummy_query_ast.definitions.first.variables.first.default_value
208
+
209
+ kwargs[:default_value] = extract_default_value(default_value_str, input_value_ast)
210
+ end
211
+
212
+ arg_owner.argument(arg["name"], **kwargs)
213
+ end
214
+ end
177
215
  end
178
216
  end
179
217
  end
@@ -18,16 +18,17 @@ module GraphQL
18
18
  # @param new_name [String]
19
19
  # @return [String]
20
20
  def graphql_name(new_name = nil)
21
- case
22
- when new_name
21
+ if new_name
23
22
  @graphql_name = new_name
24
- when overridden = overridden_graphql_name
25
- overridden
26
23
  else
27
- default_graphql_name
24
+ overridden_graphql_name || default_graphql_name
28
25
  end
29
26
  end
30
27
 
28
+ def overridden_graphql_name
29
+ defined?(@graphql_name) ? @graphql_name : nil
30
+ end
31
+
31
32
  # Just a convenience method to point out that people should use graphql_name instead
32
33
  def name(new_name = nil)
33
34
  return super() if new_name.nil?
@@ -45,8 +46,23 @@ module GraphQL
45
46
  def description(new_description = nil)
46
47
  if new_description
47
48
  @description = new_description
49
+ elsif defined?(@description)
50
+ @description
48
51
  else
49
- @description || find_inherited_value(:description)
52
+ nil
53
+ end
54
+ end
55
+
56
+ # This pushes some configurations _down_ the inheritance tree,
57
+ # in order to prevent repetitive lookups at runtime.
58
+ module ConfigurationExtension
59
+ def inherited(child_class)
60
+ child_class.introspection(introspection)
61
+ child_class.description(description)
62
+ if overridden_graphql_name
63
+ child_class.graphql_name(overridden_graphql_name)
64
+ end
65
+ super
50
66
  end
51
67
  end
52
68
 
@@ -54,8 +70,10 @@ module GraphQL
54
70
  def introspection(new_introspection = nil)
55
71
  if !new_introspection.nil?
56
72
  @introspection = new_introspection
73
+ elsif defined?(@introspection)
74
+ @introspection
57
75
  else
58
- @introspection || find_inherited_value(:introspection, false)
76
+ false
59
77
  end
60
78
  end
61
79
 
@@ -68,8 +86,11 @@ module GraphQL
68
86
  def mutation(mutation_class = nil)
69
87
  if mutation_class
70
88
  @mutation = mutation_class
89
+ elsif defined?(@mutation)
90
+ @mutation
91
+ else
92
+ nil
71
93
  end
72
- @mutation
73
94
  end
74
95
 
75
96
  # @return [GraphQL::BaseType] Convert this type to a legacy-style object.
@@ -79,10 +100,6 @@ module GraphQL
79
100
 
80
101
  alias :unwrap :itself
81
102
 
82
- def overridden_graphql_name
83
- @graphql_name || find_inherited_value(:overridden_graphql_name)
84
- end
85
-
86
103
  # Creates the default name for a schema member.
87
104
  # The default name is the Ruby constant name,
88
105
  # without any namespaces and with any `-Type` suffix removed
@@ -4,6 +4,10 @@ module GraphQL
4
4
  class Member
5
5
  # @api private
6
6
  module BuildType
7
+ if !String.method_defined?(:match?)
8
+ using GraphQL::StringMatchBackport
9
+ end
10
+
7
11
  LIST_TYPE_ERROR = "Use an array of [T] or [T, null: true] for list types; other arrays are not supported"
8
12
 
9
13
  module_function
@@ -64,6 +68,8 @@ module GraphQL
64
68
  else
65
69
  raise ArgumentError, LIST_TYPE_ERROR
66
70
  end
71
+ when GraphQL::Schema::NonNull, GraphQL::Schema::List
72
+ type_expr
67
73
  when Module
68
74
  # This is a way to check that it's the right kind of module:
69
75
  if type_expr.respond_to?(:graphql_definition)
@@ -72,12 +78,14 @@ module GraphQL
72
78
  # Eg `String` => GraphQL::STRING_TYPE
73
79
  parse_type(type_expr.name, null: true)
74
80
  end
81
+ when Proc
82
+ parse_type(type_expr.call, null: true)
75
83
  when false
76
84
  raise ArgumentError, "Received `false` instead of a type, maybe a `!` should be replaced with `null: true` (for fields) or `required: true` (for arguments)"
77
85
  end
78
86
 
79
87
  if return_type.nil?
80
- raise "Unexpected type input: #{type_expr} (#{type_expr.class})"
88
+ raise "Unexpected type input: #{type_expr.inspect} (#{type_expr.class})"
81
89
  end
82
90
 
83
91
  # Apply list_type first, that way the
@@ -158,10 +166,16 @@ module GraphQL
158
166
  end
159
167
 
160
168
  def underscore(string)
161
- string
162
- .gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2') # URLDecoder -> URL_Decoder
163
- .gsub(/([a-z\d])([A-Z])/,'\1_\2') # someThing -> some_Thing
164
- .downcase
169
+ if string.match?(/\A[a-z_]+\Z/)
170
+ return string
171
+ end
172
+ string2 = string.dup
173
+
174
+ string2.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') # URLDecoder -> URL_Decoder
175
+ string2.gsub!(/([a-z\d])([A-Z])/,'\1_\2') # someThing -> some_Thing
176
+ string2.downcase!
177
+
178
+ string2
165
179
  end
166
180
  end
167
181
  end
@@ -15,6 +15,11 @@ module GraphQL
15
15
  @graphql_definition ||= to_graphql
16
16
  end
17
17
 
18
+ # This is for a common interface with .define-based types
19
+ def type_class
20
+ self
21
+ end
22
+
18
23
  # Wipe out the cached graphql_definition so that `.to_graphql` will be called again.
19
24
  def initialize_copy(original)
20
25
  super
@@ -43,6 +43,7 @@ module GraphQL
43
43
  # @param arg_defn [GraphQL::Schema::Argument]
44
44
  # @return [GraphQL::Schema::Argument]
45
45
  def add_argument(arg_defn)
46
+ @own_arguments ||= {}
46
47
  own_arguments[arg_defn.name] = arg_defn
47
48
  arg_defn
48
49
  end
@@ -58,17 +59,112 @@ module GraphQL
58
59
  end
59
60
  end
60
61
 
62
+ # @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
63
+ def get_argument(argument_name)
64
+ a = own_arguments[argument_name]
65
+
66
+ if a || !self.is_a?(Class)
67
+ a
68
+ else
69
+ for ancestor in ancestors
70
+ if ancestor.respond_to?(:own_arguments) && a = ancestor.own_arguments[argument_name]
71
+ return a
72
+ end
73
+ end
74
+ nil
75
+ end
76
+ end
77
+
61
78
  # @param new_arg_class [Class] A class to use for building argument definitions
62
79
  def argument_class(new_arg_class = nil)
63
80
  self.class.argument_class(new_arg_class)
64
81
  end
65
82
 
83
+ # @api private
84
+ # @param values [Hash<String, Object>]
85
+ # @param context [GraphQL::Query::Context]
86
+ # @return [Hash<Symbol, Object>, Execution::Lazy<Hash>]
87
+ def coerce_arguments(parent_object, values, context)
88
+ # Cache this hash to avoid re-merging it
89
+ arg_defns = self.arguments
90
+
91
+ if arg_defns.empty?
92
+ GraphQL::Execution::Interpreter::Arguments.new(argument_values: nil)
93
+ else
94
+ argument_values = {}
95
+ arg_lazies = arg_defns.map do |arg_name, arg_defn|
96
+ arg_key = arg_defn.keyword
97
+ has_value = false
98
+ default_used = false
99
+ if values.key?(arg_name)
100
+ has_value = true
101
+ value = values[arg_name]
102
+ elsif values.key?(arg_key)
103
+ has_value = true
104
+ value = values[arg_key]
105
+ elsif arg_defn.default_value?
106
+ has_value = true
107
+ value = arg_defn.default_value
108
+ default_used = true
109
+ end
110
+
111
+ if has_value
112
+ loads = arg_defn.loads
113
+ loaded_value = nil
114
+ if loads && !arg_defn.from_resolver?
115
+ loaded_value = if arg_defn.type.list?
116
+ loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, context) }
117
+ context.schema.after_any_lazies(loaded_values) { |result| result }
118
+ else
119
+ load_application_object(arg_defn, loads, value, context)
120
+ end
121
+ end
122
+
123
+ coerced_value = if loaded_value
124
+ loaded_value
125
+ else
126
+ context.schema.error_handler.with_error_handling(context) do
127
+ arg_defn.type.coerce_input(value, context)
128
+ end
129
+ end
130
+
131
+ context.schema.after_lazy(coerced_value) do |coerced_value|
132
+ prepared_value = context.schema.error_handler.with_error_handling(context) do
133
+ arg_defn.prepare_value(parent_object, coerced_value, context: context)
134
+ end
135
+
136
+ # TODO code smell to access such a deeply-nested constant in a distant module
137
+ argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
138
+ value: prepared_value,
139
+ definition: arg_defn,
140
+ default_used: default_used,
141
+ )
142
+ end
143
+ end
144
+ end
145
+
146
+ context.schema.after_any_lazies(arg_lazies) do
147
+ GraphQL::Execution::Interpreter::Arguments.new(
148
+ argument_values: argument_values,
149
+ )
150
+ end
151
+ end
152
+ end
153
+
154
+ def arguments_statically_coercible?
155
+ return @arguments_statically_coercible if defined?(@arguments_statically_coercible)
156
+
157
+ @arguments_statically_coercible = arguments.each_value.all?(&:statically_coercible?)
158
+ end
159
+
66
160
  module ArgumentClassAccessor
67
161
  def argument_class(new_arg_class = nil)
68
162
  if new_arg_class
69
163
  @argument_class = new_arg_class
164
+ elsif defined?(@argument_class) && @argument_class
165
+ @argument_class
70
166
  else
71
- @argument_class || (superclass.respond_to?(:argument_class) ? superclass.argument_class : GraphQL::Schema::Argument)
167
+ superclass.respond_to?(:argument_class) ? superclass.argument_class : GraphQL::Schema::Argument
72
168
  end
73
169
  end
74
170
  end
@@ -85,8 +181,11 @@ module GraphQL
85
181
  context.schema.object_from_id(id, context)
86
182
  end
87
183
 
88
- def load_application_object(argument, lookup_as_type, id)
184
+ def load_application_object(argument, lookup_as_type, id, context)
89
185
  # See if any object can be found for this ID
186
+ if id.nil?
187
+ return nil
188
+ end
90
189
  loaded_application_object = object_from_id(lookup_as_type, id, context)
91
190
  context.schema.after_lazy(loaded_application_object) do |application_object|
92
191
  if application_object.nil?
@@ -97,7 +196,7 @@ module GraphQL
97
196
  # (Don't want to allow arbitrary access to objects this way)
98
197
  resolved_application_object_type = context.schema.resolve_type(lookup_as_type, application_object, context)
99
198
  context.schema.after_lazy(resolved_application_object_type) do |application_object_type|
100
- possible_object_types = context.schema.possible_types(lookup_as_type)
199
+ possible_object_types = context.warden.possible_types(lookup_as_type)
101
200
  if !possible_object_types.include?(application_object_type)
102
201
  err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
103
202
  load_application_object_failed(err)
@@ -105,7 +204,7 @@ module GraphQL
105
204
  # This object was loaded successfully
106
205
  # and resolved to the right type,
107
206
  # now apply the `.authorized?` class method if there is one
108
- if (class_based_type = application_object_type.metadata[:type_class])
207
+ if (class_based_type = application_object_type.type_class)
109
208
  context.schema.after_lazy(class_based_type.authorized?(application_object, context)) do |authed|
110
209
  if authed
111
210
  application_object
@@ -130,8 +229,9 @@ module GraphQL
130
229
  end
131
230
  end
132
231
 
232
+ NO_ARGUMENTS = {}.freeze
133
233
  def own_arguments
134
- @own_arguments ||= {}
234
+ @own_arguments || NO_ARGUMENTS
135
235
  end
136
236
  end
137
237
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Member
5
+ module HasAstNode
6
+ # If this schema was parsed from a `.graphql` file (or other SDL),
7
+ # this is the AST node that defined this part of the schema.
8
+ def ast_node(new_ast_node = nil)
9
+ if new_ast_node
10
+ @ast_node = new_ast_node
11
+ elsif defined?(@ast_node)
12
+ @ast_node
13
+ else
14
+ nil
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end