graphql 1.2.6 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (278) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +3 -1
  3. data/lib/graphql/analysis.rb +1 -0
  4. data/lib/graphql/analysis/analyze_query.rb +1 -0
  5. data/lib/graphql/analysis/field_usage.rb +1 -0
  6. data/lib/graphql/analysis/max_query_complexity.rb +1 -0
  7. data/lib/graphql/analysis/max_query_depth.rb +1 -0
  8. data/lib/graphql/analysis/query_complexity.rb +1 -0
  9. data/lib/graphql/analysis/query_depth.rb +1 -0
  10. data/lib/graphql/analysis/reducer_state.rb +1 -0
  11. data/lib/graphql/analysis_error.rb +1 -0
  12. data/lib/graphql/argument.rb +1 -0
  13. data/lib/graphql/base_type.rb +16 -7
  14. data/lib/graphql/boolean_type.rb +1 -0
  15. data/lib/graphql/compatibility.rb +2 -0
  16. data/lib/graphql/compatibility/execution_specification.rb +113 -192
  17. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +53 -0
  18. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +195 -0
  19. data/lib/graphql/compatibility/lazy_execution_specification.rb +186 -0
  20. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +97 -0
  21. data/lib/graphql/compatibility/query_parser_specification.rb +1 -0
  22. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +1 -0
  23. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +1 -0
  24. data/lib/graphql/compatibility/schema_parser_specification.rb +1 -0
  25. data/lib/graphql/define.rb +1 -0
  26. data/lib/graphql/define/assign_argument.rb +1 -0
  27. data/lib/graphql/define/assign_connection.rb +1 -0
  28. data/lib/graphql/define/assign_enum_value.rb +1 -0
  29. data/lib/graphql/define/assign_global_id_field.rb +1 -0
  30. data/lib/graphql/define/assign_object_field.rb +1 -0
  31. data/lib/graphql/define/defined_object_proxy.rb +1 -0
  32. data/lib/graphql/define/instance_definable.rb +11 -12
  33. data/lib/graphql/define/non_null_with_bang.rb +1 -0
  34. data/lib/graphql/define/type_definer.rb +1 -0
  35. data/lib/graphql/directive.rb +1 -0
  36. data/lib/graphql/directive/deprecated_directive.rb +1 -0
  37. data/lib/graphql/directive/include_directive.rb +1 -0
  38. data/lib/graphql/directive/skip_directive.rb +1 -0
  39. data/lib/graphql/enum_type.rb +8 -1
  40. data/lib/graphql/execution.rb +5 -0
  41. data/lib/graphql/execution/directive_checks.rb +1 -0
  42. data/lib/graphql/execution/execute.rb +222 -0
  43. data/lib/graphql/execution/field_result.rb +52 -0
  44. data/lib/graphql/execution/lazy.rb +59 -0
  45. data/lib/graphql/execution/lazy/lazy_method_map.rb +38 -0
  46. data/lib/graphql/execution/lazy/resolve.rb +68 -0
  47. data/lib/graphql/execution/selection_result.rb +84 -0
  48. data/lib/graphql/execution/typecast.rb +4 -4
  49. data/lib/graphql/execution_error.rb +1 -0
  50. data/lib/graphql/field.rb +68 -18
  51. data/lib/graphql/field/resolve.rb +1 -0
  52. data/lib/graphql/float_type.rb +1 -0
  53. data/lib/graphql/id_type.rb +1 -0
  54. data/lib/graphql/input_object_type.rb +6 -0
  55. data/lib/graphql/int_type.rb +1 -0
  56. data/lib/graphql/interface_type.rb +6 -0
  57. data/lib/graphql/internal_representation.rb +2 -1
  58. data/lib/graphql/internal_representation/node.rb +2 -1
  59. data/lib/graphql/internal_representation/rewrite.rb +1 -0
  60. data/lib/graphql/internal_representation/selection.rb +85 -0
  61. data/lib/graphql/introspection.rb +1 -0
  62. data/lib/graphql/introspection/arguments_field.rb +1 -0
  63. data/lib/graphql/introspection/directive_location_enum.rb +1 -0
  64. data/lib/graphql/introspection/directive_type.rb +1 -0
  65. data/lib/graphql/introspection/enum_value_type.rb +1 -0
  66. data/lib/graphql/introspection/enum_values_field.rb +1 -0
  67. data/lib/graphql/introspection/field_type.rb +1 -0
  68. data/lib/graphql/introspection/fields_field.rb +1 -0
  69. data/lib/graphql/introspection/input_fields_field.rb +1 -0
  70. data/lib/graphql/introspection/input_value_type.rb +2 -1
  71. data/lib/graphql/introspection/interfaces_field.rb +1 -0
  72. data/lib/graphql/introspection/introspection_query.rb +1 -0
  73. data/lib/graphql/introspection/of_type_field.rb +1 -0
  74. data/lib/graphql/introspection/possible_types_field.rb +1 -0
  75. data/lib/graphql/introspection/schema_field.rb +1 -0
  76. data/lib/graphql/introspection/schema_type.rb +1 -0
  77. data/lib/graphql/introspection/type_by_name_field.rb +1 -0
  78. data/lib/graphql/introspection/type_kind_enum.rb +1 -0
  79. data/lib/graphql/introspection/type_type.rb +1 -0
  80. data/lib/graphql/introspection/typename_field.rb +1 -0
  81. data/lib/graphql/invalid_null_error.rb +17 -7
  82. data/lib/graphql/language.rb +10 -0
  83. data/lib/graphql/language/comments.rb +2 -1
  84. data/lib/graphql/language/definition_slice.rb +1 -0
  85. data/lib/graphql/language/generation.rb +25 -24
  86. data/lib/graphql/language/nodes.rb +1 -0
  87. data/lib/graphql/language/token.rb +1 -0
  88. data/lib/graphql/language/visitor.rb +1 -0
  89. data/lib/graphql/list_type.rb +1 -0
  90. data/lib/graphql/non_null_type.rb +2 -1
  91. data/lib/graphql/object_type.rb +12 -0
  92. data/lib/graphql/query.rb +40 -43
  93. data/lib/graphql/query/arguments.rb +1 -0
  94. data/lib/graphql/query/context.rb +31 -7
  95. data/lib/graphql/query/executor.rb +8 -1
  96. data/lib/graphql/query/input_validation_result.rb +1 -0
  97. data/lib/graphql/query/literal_input.rb +1 -0
  98. data/lib/graphql/query/serial_execution.rb +3 -4
  99. data/lib/graphql/query/serial_execution/field_resolution.rb +15 -10
  100. data/lib/graphql/query/serial_execution/operation_resolution.rb +3 -5
  101. data/lib/graphql/query/serial_execution/selection_resolution.rb +4 -5
  102. data/lib/graphql/query/serial_execution/value_resolution.rb +26 -11
  103. data/lib/graphql/query/variable_validation_error.rb +1 -0
  104. data/lib/graphql/query/variables.rb +1 -0
  105. data/lib/graphql/relay.rb +1 -0
  106. data/lib/graphql/relay/array_connection.rb +3 -2
  107. data/lib/graphql/relay/base_connection.rb +20 -8
  108. data/lib/graphql/relay/connection_field.rb +1 -0
  109. data/lib/graphql/relay/connection_resolve.rb +14 -1
  110. data/lib/graphql/relay/connection_type.rb +1 -0
  111. data/lib/graphql/relay/edge.rb +1 -0
  112. data/lib/graphql/relay/edge_type.rb +1 -0
  113. data/lib/graphql/relay/global_id_resolve.rb +1 -0
  114. data/lib/graphql/relay/mutation.rb +13 -0
  115. data/lib/graphql/relay/node.rb +1 -0
  116. data/lib/graphql/relay/page_info.rb +1 -0
  117. data/lib/graphql/relay/relation_connection.rb +3 -2
  118. data/lib/graphql/runtime_type_error.rb +4 -0
  119. data/lib/graphql/scalar_type.rb +2 -1
  120. data/lib/graphql/schema.rb +116 -26
  121. data/lib/graphql/schema/base_64_encoder.rb +14 -0
  122. data/lib/graphql/schema/build_from_definition.rb +4 -0
  123. data/lib/graphql/schema/catchall_middleware.rb +1 -0
  124. data/lib/graphql/schema/default_type_error.rb +15 -0
  125. data/lib/graphql/schema/instrumented_field_map.rb +1 -0
  126. data/lib/graphql/schema/invalid_type_error.rb +1 -0
  127. data/lib/graphql/schema/loader.rb +5 -1
  128. data/lib/graphql/schema/middleware_chain.rb +1 -0
  129. data/lib/graphql/schema/possible_types.rb +1 -0
  130. data/lib/graphql/schema/printer.rb +3 -2
  131. data/lib/graphql/schema/reduce_types.rb +1 -0
  132. data/lib/graphql/schema/rescue_middleware.rb +3 -2
  133. data/lib/graphql/schema/timeout_middleware.rb +1 -0
  134. data/lib/graphql/schema/type_expression.rb +1 -0
  135. data/lib/graphql/schema/type_map.rb +1 -0
  136. data/lib/graphql/schema/unique_within_type.rb +1 -0
  137. data/lib/graphql/schema/validation.rb +57 -1
  138. data/lib/graphql/schema/warden.rb +1 -0
  139. data/lib/graphql/static_validation.rb +1 -0
  140. data/lib/graphql/static_validation/all_rules.rb +1 -0
  141. data/lib/graphql/static_validation/arguments_validator.rb +1 -0
  142. data/lib/graphql/static_validation/literal_validator.rb +1 -0
  143. data/lib/graphql/static_validation/message.rb +1 -0
  144. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -0
  145. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -0
  146. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -0
  147. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -0
  148. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -0
  149. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -0
  150. data/lib/graphql/static_validation/rules/fields_will_merge.rb +6 -3
  151. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +1 -0
  152. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -0
  153. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +1 -0
  154. data/lib/graphql/static_validation/rules/fragments_are_named.rb +1 -0
  155. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -0
  156. data/lib/graphql/static_validation/rules/fragments_are_used.rb +1 -0
  157. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -0
  158. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -0
  159. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -0
  160. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -0
  161. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -0
  162. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -0
  163. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -0
  164. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +1 -0
  165. data/lib/graphql/static_validation/type_stack.rb +1 -0
  166. data/lib/graphql/static_validation/validation_context.rb +2 -1
  167. data/lib/graphql/static_validation/validator.rb +2 -1
  168. data/lib/graphql/string_type.rb +1 -0
  169. data/lib/graphql/type_kinds.rb +1 -0
  170. data/lib/graphql/union_type.rb +13 -0
  171. data/lib/graphql/unresolved_type_error.rb +26 -5
  172. data/lib/graphql/version.rb +2 -1
  173. data/readme.md +1 -5
  174. data/spec/graphql/analysis/analyze_query_spec.rb +1 -0
  175. data/spec/graphql/analysis/field_usage_spec.rb +1 -0
  176. data/spec/graphql/analysis/max_query_complexity_spec.rb +1 -0
  177. data/spec/graphql/analysis/max_query_depth_spec.rb +1 -0
  178. data/spec/graphql/analysis/query_complexity_spec.rb +1 -0
  179. data/spec/graphql/analysis/query_depth_spec.rb +1 -0
  180. data/spec/graphql/argument_spec.rb +1 -0
  181. data/spec/graphql/base_type_spec.rb +13 -0
  182. data/spec/graphql/boolean_type_spec.rb +1 -0
  183. data/spec/graphql/compatibility/execution_specification_spec.rb +1 -0
  184. data/spec/graphql/compatibility/lazy_execution_specification_spec.rb +4 -0
  185. data/spec/graphql/compatibility/query_parser_specification_spec.rb +1 -0
  186. data/spec/graphql/compatibility/schema_parser_specification_spec.rb +1 -0
  187. data/spec/graphql/define/assign_argument_spec.rb +1 -0
  188. data/spec/graphql/define/instance_definable_spec.rb +1 -0
  189. data/spec/graphql/directive_spec.rb +1 -0
  190. data/spec/graphql/enum_type_spec.rb +10 -0
  191. data/spec/graphql/execution/execute_spec.rb +5 -0
  192. data/spec/graphql/execution/lazy_spec.rb +252 -0
  193. data/spec/graphql/execution/typecast_spec.rb +1 -0
  194. data/spec/graphql/execution_error_spec.rb +1 -0
  195. data/spec/graphql/field_spec.rb +17 -0
  196. data/spec/graphql/float_type_spec.rb +1 -0
  197. data/spec/graphql/id_type_spec.rb +1 -0
  198. data/spec/graphql/input_object_type_spec.rb +10 -0
  199. data/spec/graphql/int_type_spec.rb +1 -0
  200. data/spec/graphql/interface_type_spec.rb +10 -0
  201. data/spec/graphql/internal_representation/rewrite_spec.rb +1 -0
  202. data/spec/graphql/introspection/directive_type_spec.rb +1 -0
  203. data/spec/graphql/introspection/input_value_type_spec.rb +1 -0
  204. data/spec/graphql/introspection/introspection_query_spec.rb +1 -0
  205. data/spec/graphql/introspection/schema_type_spec.rb +1 -0
  206. data/spec/graphql/introspection/type_type_spec.rb +1 -0
  207. data/spec/graphql/language/definition_slice_spec.rb +1 -0
  208. data/spec/graphql/language/equality_spec.rb +1 -0
  209. data/spec/graphql/language/generation_spec.rb +1 -0
  210. data/spec/graphql/language/lexer_spec.rb +1 -0
  211. data/spec/graphql/language/nodes_spec.rb +1 -0
  212. data/spec/graphql/language/parser_spec.rb +1 -0
  213. data/spec/graphql/language/visitor_spec.rb +1 -0
  214. data/spec/graphql/list_type_spec.rb +1 -0
  215. data/spec/graphql/non_null_type_spec.rb +17 -0
  216. data/spec/graphql/object_type_spec.rb +19 -0
  217. data/spec/graphql/query/arguments_spec.rb +1 -0
  218. data/spec/graphql/query/context_spec.rb +1 -0
  219. data/spec/graphql/query/executor_spec.rb +1 -0
  220. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +1 -0
  221. data/spec/graphql/query/variables_spec.rb +1 -0
  222. data/spec/graphql/query_spec.rb +25 -0
  223. data/spec/graphql/relay/array_connection_spec.rb +1 -0
  224. data/spec/graphql/relay/base_connection_spec.rb +33 -4
  225. data/spec/graphql/relay/connection_field_spec.rb +1 -0
  226. data/spec/graphql/relay/connection_type_spec.rb +1 -0
  227. data/spec/graphql/relay/mutation_spec.rb +6 -0
  228. data/spec/graphql/relay/node_spec.rb +1 -0
  229. data/spec/graphql/relay/page_info_spec.rb +1 -0
  230. data/spec/graphql/relay/relation_connection_spec.rb +1 -0
  231. data/spec/graphql/scalar_type_spec.rb +1 -0
  232. data/spec/graphql/schema/build_from_definition_spec.rb +9 -1
  233. data/spec/graphql/schema/catchall_middleware_spec.rb +1 -0
  234. data/spec/graphql/schema/loader_spec.rb +7 -0
  235. data/spec/graphql/schema/middleware_chain_spec.rb +1 -0
  236. data/spec/graphql/schema/printer_spec.rb +1 -0
  237. data/spec/graphql/schema/reduce_types_spec.rb +1 -0
  238. data/spec/graphql/schema/rescue_middleware_spec.rb +1 -0
  239. data/spec/graphql/schema/timeout_middleware_spec.rb +1 -0
  240. data/spec/graphql/schema/type_expression_spec.rb +1 -0
  241. data/spec/graphql/schema/unique_within_type_spec.rb +1 -0
  242. data/spec/graphql/schema/validation_spec.rb +55 -0
  243. data/spec/graphql/schema/warden_spec.rb +1 -0
  244. data/spec/graphql/schema_spec.rb +39 -0
  245. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +1 -0
  246. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +1 -0
  247. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +1 -0
  248. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +1 -0
  249. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +1 -0
  250. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +1 -0
  251. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +515 -31
  252. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +1 -0
  253. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +1 -0
  254. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +1 -0
  255. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +1 -0
  256. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +1 -0
  257. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -0
  258. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +1 -0
  259. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +1 -0
  260. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +1 -0
  261. data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +1 -0
  262. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +1 -0
  263. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +1 -0
  264. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +1 -0
  265. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +1 -0
  266. data/spec/graphql/static_validation/type_stack_spec.rb +1 -0
  267. data/spec/graphql/static_validation/validator_spec.rb +1 -0
  268. data/spec/graphql/string_type_spec.rb +1 -0
  269. data/spec/graphql/union_type_spec.rb +11 -0
  270. data/spec/spec_helper.rb +1 -0
  271. data/spec/support/dairy_app.rb +1 -0
  272. data/spec/support/dairy_data.rb +1 -0
  273. data/spec/support/minimum_input_object.rb +1 -0
  274. data/spec/support/star_wars_data.rb +1 -0
  275. data/spec/support/star_wars_schema.rb +30 -7
  276. data/spec/support/static_validation_helpers.rb +1 -0
  277. metadata +24 -5
  278. data/lib/graphql/internal_representation/selections.rb +0 -41
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::Schema::CatchallMiddleware do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::Schema::Loader do
@@ -197,6 +198,12 @@ describe GraphQL::Schema::Loader do
197
198
  assert loaded_schema.execute(GraphQL::Introspection::INTROSPECTION_QUERY)
198
199
  end
199
200
 
201
+ it "has no-op coerce functions" do
202
+ custom_scalar = loaded_schema.types["BigInt"]
203
+ assert_equal true, custom_scalar.valid_input?("anything", PermissiveWarden)
204
+ assert_equal true, custom_scalar.valid_input?(12345, PermissiveWarden)
205
+ end
206
+
200
207
  it "sets correct default values on custom scalar arguments" do
201
208
  type = loaded_schema.types["Comment"]
202
209
  field = type.fields['fieldWithArg']
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::Schema::MiddlewareChain do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::Schema::Printer do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::Schema::ReduceTypes do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  class SpecExampleError < StandardError; end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::Schema::TimeoutMiddleware do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::Schema::TypeExpression do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::Schema::UniqueWithinType do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::Schema::Validation do
@@ -6,6 +7,10 @@ describe GraphQL::Schema::Validation do
6
7
  assert_includes validation_error, error_substring
7
8
  end
8
9
 
10
+ def assert_validation_warns(object, warning)
11
+ assert_output("", warning + "\n") { GraphQL::Schema::Validation.validate(object) }
12
+ end
13
+
9
14
  describe "validating Fields" do
10
15
  let(:unnamed_field) {
11
16
  GraphQL::Field.define do
@@ -13,6 +18,13 @@ describe GraphQL::Schema::Validation do
13
18
  end
14
19
  }
15
20
 
21
+ let(:invalid_name_field) {
22
+ GraphQL::Field.define do
23
+ name "__Something"
24
+ type GraphQL::STRING_TYPE
25
+ end
26
+ }
27
+
16
28
  let(:untyped_field) {
17
29
  GraphQL::Field.define do
18
30
  name "Untyped"
@@ -44,6 +56,10 @@ describe GraphQL::Schema::Validation do
44
56
  assert_error_includes unnamed_field, "must return String, not NilClass"
45
57
  end
46
58
 
59
+ it "cannot use reserved name" do
60
+ assert_validation_warns invalid_name_field, 'Name "__Something" must not begin with "__", which is reserved by GraphQL introspection.'
61
+ end
62
+
47
63
  it "requires a BaseType for type" do
48
64
  assert_error_includes untyped_field, "must return GraphQL::BaseType, not Symbol"
49
65
  end
@@ -64,16 +80,27 @@ describe GraphQL::Schema::Validation do
64
80
  end
65
81
  }
66
82
 
83
+ let(:invalid_name_type) {
84
+ GraphQL::BaseType.define do
85
+ name '__Something'
86
+ end
87
+ }
88
+
67
89
  let(:wrongly_described_type) {
68
90
  GraphQL::BaseType.define do
69
91
  name "WronglyDescribed"
70
92
  description 12345
71
93
  end
72
94
  }
95
+
73
96
  it "requires a String name" do
74
97
  assert_error_includes unnamed_type, "must return String, not Symbol"
75
98
  end
76
99
 
100
+ it "cannot use reserved name" do
101
+ assert_validation_warns invalid_name_type, 'Name "__Something" must not begin with "__", which is reserved by GraphQL introspection.'
102
+ end
103
+
77
104
  it "requires String-or-nil description" do
78
105
  assert_error_includes wrongly_described_type, "must return String or NilClass, not Fixnum"
79
106
  end
@@ -86,6 +113,7 @@ describe GraphQL::Schema::Validation do
86
113
  interfaces(55)
87
114
  end
88
115
  }
116
+
89
117
  let(:invalid_interface_member_object) {
90
118
  GraphQL::ObjectType.define do
91
119
  name "InvalidInterfaceMember"
@@ -208,6 +236,13 @@ describe GraphQL::Schema::Validation do
208
236
  end
209
237
  }
210
238
 
239
+ let(:invalid_name_argument) {
240
+ GraphQL::Argument.define do
241
+ name "__Something"
242
+ type GraphQL::INT_TYPE
243
+ end
244
+ }
245
+
211
246
  let(:null_default_value) {
212
247
  GraphQL::Argument.define do
213
248
  name "NullDefault"
@@ -224,8 +259,28 @@ describe GraphQL::Schema::Validation do
224
259
  assert_error_includes invalid_default_argument_for_non_null_argument, 'Variable InvalidDefault of type "Int!" is required and will not use the default value. Perhaps you meant to use type "Int".'
225
260
  end
226
261
 
262
+ it "cannot use reserved name" do
263
+ assert_validation_warns invalid_name_argument, 'Name "__Something" must not begin with "__", which is reserved by GraphQL introspection.'
264
+ end
265
+
227
266
  it "allows null default value for nullable argument" do
228
267
  assert_equal nil, GraphQL::Schema::Validation.validate(null_default_value)
229
268
  end
230
269
  end
270
+
271
+ describe "validating instrumentation" do
272
+ let(:schema) {
273
+ query_type = GraphQL::ObjectType.define(name: "Query")
274
+ GraphQL::Schema.define do
275
+ query(query_type)
276
+ instrument(:field, 1)
277
+ instrument(:query, :oops)
278
+ end
279
+ }
280
+ it "finds instrumenters missing methods" do
281
+ err = assert_raises(NotImplementedError) { schema }
282
+ assert_includes err.message, "before_query(query)"
283
+ assert_includes err.message, "instrument(type, field)"
284
+ end
285
+ end
231
286
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  module MaskHelpers
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::Schema do
@@ -271,4 +272,42 @@ type Query {
271
272
  assert_equal 24, res["data"]["int"]
272
273
  end
273
274
  end
275
+
276
+ describe "#lazy? / #lazy_method_name" do
277
+ class LazyObj; end
278
+ class LazyObjChild < LazyObj; end
279
+
280
+ let(:schema) {
281
+ query_type = GraphQL::ObjectType.define(name: "Query")
282
+ GraphQL::Schema.define do
283
+ query(query_type)
284
+ lazy_resolve(Integer, :itself)
285
+ lazy_resolve(LazyObj, :dup)
286
+ end
287
+ }
288
+
289
+ it "returns registered lazy method names by class/superclass, or returns nil" do
290
+ assert_equal :itself, schema.lazy_method_name(68)
291
+ assert_equal true, schema.lazy?(77)
292
+ assert_equal :dup, schema.lazy_method_name(LazyObj.new)
293
+ assert_equal true, schema.lazy?(LazyObj.new)
294
+ assert_equal :dup, schema.lazy_method_name(LazyObjChild.new)
295
+ assert_equal true, schema.lazy?(LazyObjChild.new)
296
+ assert_equal nil, schema.lazy_method_name({})
297
+ assert_equal false, schema.lazy?({})
298
+ end
299
+ end
300
+
301
+ describe "#dup" do
302
+ it "copies internal state" do
303
+ schema_2 = schema.dup
304
+ refute schema_2.types.equal?(schema.types)
305
+
306
+ refute schema_2.instrumenters.equal?(schema.instrumenters)
307
+ assert_equal schema_2.instrumenters, schema.instrumenters
308
+
309
+ refute schema_2.middleware.equal?(schema.middleware)
310
+ assert_equal schema_2.middleware, schema.middleware
311
+ end
312
+ end
274
313
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::StaticValidation::ArgumentsAreDefined do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::StaticValidation::DirectivesAreDefined do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::StaticValidation::DirectivesAreInValidLocations do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::StaticValidation::FieldsAreDefinedOnType do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::StaticValidation::FieldsHaveAppropriateSelections do
@@ -1,43 +1,527 @@
1
+ # frozen_string_literal: true
1
2
  require "spec_helper"
2
3
 
3
4
  describe GraphQL::StaticValidation::FieldsWillMerge do
4
5
  include StaticValidationHelpers
5
6
 
6
- let(:query_string) {"
7
- query getCheese($sourceVar: [DairyAnimal!] = [YAK]) {
8
- cheese(id: 1) {
9
- id,
10
- nickname: flavor,
11
- nickname: fatContent,
12
- fatContent
13
- differentLevel: fatContent
14
- similarCheese(source: $sourceVar) { __typename }
7
+ let(:schema) {
8
+ GraphQL::Schema.from_definition(%|
9
+ type Query {
10
+ dog: Dog
11
+ cat: Cat
12
+ pet: Pet
13
+ toy: Toy
14
+ }
15
+
16
+ enum PetCommand {
17
+ SIT
18
+ HEEL
19
+ JUMP
20
+ DOWN
21
+ }
22
+
23
+ enum ToySize {
24
+ SMALL
25
+ LARGE
26
+ }
15
27
 
16
- similarCow: similarCheese(source: COW) {
17
- similarCowSource: source,
18
- differentLevel: fatContent
28
+ interface Pet {
29
+ name(surname: Boolean = false): String!
30
+ nickname: String
31
+ toys: [Toy!]!
32
+ }
33
+
34
+ type Dog implements Pet {
35
+ name(surname: Boolean = false): String!
36
+ nickname: String
37
+ doesKnowCommand(dogCommand: PetCommand): Boolean!
38
+ barkVolume: Int!
39
+ toys: [Toy!]!
40
+ }
41
+
42
+ type Cat implements Pet {
43
+ name(surname: Boolean = false): String!
44
+ nickname: String
45
+ doesKnowCommand(catCommand: PetCommand): Boolean!
46
+ meowVolume: Int!
47
+ toys: [Toy!]!
48
+ }
49
+
50
+ type Toy {
51
+ name: String!
52
+ size: ToySize!
53
+ image(maxWidth: Int!): String!
54
+ }
55
+ |)
56
+ }
57
+
58
+ describe "unique fields" do
59
+ let(:query_string) {%|
60
+ {
61
+ dog {
62
+ name
63
+ nickname
19
64
  }
20
- ...cheeseFields
21
- ... on Cheese {
22
- fatContent: flavor
23
- similarCheese(source: SHEEP) { __typename }
65
+ }
66
+ |}
67
+
68
+ it "passes rule" do
69
+ assert_equal [], errors
70
+ end
71
+ end
72
+
73
+ describe "identical fields" do
74
+ let(:query_string) {%|
75
+ {
76
+ dog {
77
+ name
78
+ name
24
79
  }
25
80
  }
81
+ |}
82
+
83
+ it "passes rule" do
84
+ assert_equal [], errors
85
+ end
86
+ end
87
+
88
+ describe "identical fields with identical args" do
89
+ let(:query_string) {%|
90
+ {
91
+ dog {
92
+ doesKnowCommand(dogCommand: SIT)
93
+ doesKnowCommand(dogCommand: SIT)
94
+ }
95
+ }
96
+ |}
97
+
98
+ it "passes rule" do
99
+ assert_equal [], errors
100
+ end
101
+ end
102
+
103
+ describe "identical fields with identical values" do
104
+ let(:query_string) {%|
105
+ query($dogCommand: PetCommand) {
106
+ dog {
107
+ doesKnowCommand(dogCommand: $dogCommand)
108
+ doesKnowCommand(dogCommand: $dogCommand)
109
+ }
110
+ }
111
+ |}
112
+
113
+ it "passes rule" do
114
+ assert_equal [], errors
115
+ end
116
+ end
117
+
118
+ describe "identical aliases and fields" do
119
+ let(:query_string) {%|
120
+ {
121
+ dog {
122
+ otherName: name
123
+ otherName: name
124
+ }
125
+ }
126
+ |}
127
+
128
+ it "passes rule" do
129
+ assert_equal [], errors
130
+ end
131
+ end
132
+
133
+ describe "different args with different aliases" do
134
+ let(:query_string) {%|
135
+ {
136
+ dog {
137
+ knowsSit: doesKnowCommand(dogCommand: SIT)
138
+ knowsDown: doesKnowCommand(dogCommand: DOWN)
139
+ }
140
+ }
141
+ |}
142
+
143
+ it "passes rule" do
144
+ assert_equal [], errors
145
+ end
146
+ end
147
+
148
+ describe "conflicting args value and var" do
149
+ let(:query_string) {%|
150
+ query ($dogCommand: PetCommand) {
151
+ dog {
152
+ doesKnowCommand(dogCommand: SIT)
153
+ doesKnowCommand(dogCommand: $dogCommand)
154
+ }
155
+ }
156
+ |}
157
+
158
+ it "fails rule" do
159
+ assert_equal [%q(Field 'doesKnowCommand' has an argument conflict: {"dogCommand":"SIT"} or {"dogCommand":"$dogCommand"}?)], error_messages
160
+ end
161
+ end
162
+
163
+ describe "conflicting args value and var" do
164
+ let(:query_string) {%|
165
+ query ($varOne: PetCommand, $varTwo: PetCommand) {
166
+ dog {
167
+ doesKnowCommand(dogCommand: $varOne)
168
+ doesKnowCommand(dogCommand: $varTwo)
169
+ }
170
+ }
171
+ |}
172
+
173
+ it "fails rule" do
174
+ assert_equal [%q(Field 'doesKnowCommand' has an argument conflict: {"dogCommand":"$varOne"} or {"dogCommand":"$varTwo"}?)], error_messages
175
+ end
176
+ end
177
+
178
+ describe "different directives with different aliases" do
179
+ let(:query_string) {%|
180
+ {
181
+ dog {
182
+ nameIfTrue: name @include(if: true)
183
+ nameIfFalse: name @include(if: false)
184
+ }
185
+ }
186
+ |}
187
+
188
+ it "passes rule" do
189
+ assert_equal [], errors
190
+ end
191
+ end
192
+
193
+ describe "different skip/include directives accepted" do
194
+ let(:query_string) {%|
195
+ {
196
+ dog {
197
+ name @include(if: true)
198
+ name @include(if: false)
199
+ }
200
+ }
201
+ |}
202
+
203
+ it "passes rule" do
204
+ assert_equal [], errors
205
+ end
206
+ end
207
+
208
+ describe "same aliases with different field targets" do
209
+ let(:query_string) {%|
210
+ {
211
+ dog {
212
+ fido: name
213
+ fido: nickname
214
+ }
215
+ }
216
+ |}
217
+
218
+ it "fails rule" do
219
+ assert_equal ["Field 'fido' has a field conflict: name or nickname?"], error_messages
220
+ end
221
+ end
222
+
223
+ describe "alias masking direct field access" do
224
+ let(:query_string) {%|
225
+ {
226
+ dog {
227
+ name: nickname
228
+ name
229
+ }
230
+ }
231
+ |}
232
+
233
+ it "fails rule" do
234
+ assert_equal ["Field 'name' has a field conflict: nickname or name?"], error_messages
235
+ end
236
+ end
237
+
238
+ describe "different args, second adds an argument" do
239
+ let(:query_string) {%|
240
+ {
241
+ dog {
242
+ doesKnowCommand
243
+ doesKnowCommand(dogCommand: HEEL)
244
+ }
245
+ }
246
+ |}
247
+
248
+ it "fails rule" do
249
+ assert_equal [%q(Field 'doesKnowCommand' has an argument conflict: {} or {"dogCommand":"HEEL"}?)], error_messages
250
+ end
251
+ end
252
+
253
+ describe "different args, second missing an argument" do
254
+ let(:query_string) {%|
255
+ {
256
+ dog {
257
+ doesKnowCommand(dogCommand: SIT)
258
+ doesKnowCommand
259
+ }
260
+ }
261
+ |}
262
+
263
+ it "fails rule" do
264
+ assert_equal [%q(Field 'doesKnowCommand' has an argument conflict: {"dogCommand":"SIT"} or {}?)], error_messages
265
+ end
266
+ end
267
+
268
+ describe "conflicting args" do
269
+ let(:query_string) {%|
270
+ {
271
+ dog {
272
+ doesKnowCommand(dogCommand: SIT)
273
+ doesKnowCommand(dogCommand: HEEL)
274
+ }
275
+ }
276
+ |}
277
+
278
+ it "fails rule" do
279
+ assert_equal [%q(Field 'doesKnowCommand' has an argument conflict: {"dogCommand":"SIT"} or {"dogCommand":"HEEL"}?)], error_messages
280
+ end
281
+ end
282
+
283
+ describe "conflicting arg values" do
284
+ let(:query_string) {%|
285
+ {
286
+ toy {
287
+ image(maxWidth: 10)
288
+ image(maxWidth: 20)
289
+ }
290
+ }
291
+ |}
292
+
293
+ it "fails rule" do
294
+ assert_equal [%q(Field 'image' has an argument conflict: {"maxWidth":"10"} or {"maxWidth":"20"}?)], error_messages
295
+ end
296
+ end
297
+
298
+ describe "encounters conflict in fragments" do
299
+ let(:query_string) {%|
300
+ {
301
+ pet {
302
+ ...A
303
+ ...B
304
+ name
305
+ }
306
+ }
307
+
308
+ fragment A on Dog {
309
+ x: name
310
+ }
311
+
312
+ fragment B on Dog {
313
+ x: nickname
314
+ name: nickname
315
+ }
316
+ |}
317
+
318
+ it "fails rule" do
319
+ assert_equal [
320
+ "Field 'x' has a field conflict: name or nickname?",
321
+ "Field 'name' has a field conflict: nickname or name?",
322
+ ], error_messages
323
+ end
324
+ end
325
+
326
+ describe "deep conflict" do
327
+ let(:query_string) {%|
328
+ {
329
+ dog {
330
+ x: name
331
+ }
332
+
333
+ dog {
334
+ x: nickname
335
+ }
336
+ }
337
+ |}
338
+
339
+ it "fails rule" do
340
+ assert_equal ["Field 'x' has a field conflict: name or nickname?"], error_messages
341
+ end
342
+ end
343
+
344
+ describe "deep conflict with multiple issues" do
345
+ let(:query_string) {%|
346
+ {
347
+ dog {
348
+ x: name
349
+ y: barkVolume
350
+ }
351
+
352
+ dog {
353
+ x: nickname
354
+ y: doesKnowCommand
355
+ }
356
+ }
357
+ |}
358
+
359
+ it "fails rule" do
360
+ assert_equal [
361
+ "Field 'x' has a field conflict: name or nickname?",
362
+ "Field 'y' has a field conflict: barkVolume or doesKnowCommand?",
363
+ ], error_messages
364
+ end
365
+ end
366
+
367
+ describe "very deep conflict" do
368
+ let(:query_string) {%|
369
+ {
370
+ dog {
371
+ toys {
372
+ x: name
373
+ }
374
+ }
375
+
376
+ dog {
377
+ toys {
378
+ x: size
379
+ }
380
+ }
381
+ }
382
+ |}
383
+
384
+ it "fails rule" do
385
+ assert_equal [
386
+ "Field 'x' has a field conflict: name or size?",
387
+ ], error_messages
388
+ end
389
+ end
390
+
391
+ describe "return types must be unambiguous" do
392
+ let(:schema) {
393
+ GraphQL::Schema.from_definition(%|
394
+ type Query {
395
+ someBox: SomeBox
396
+ connection: Connection
397
+ }
398
+
399
+ type Edge {
400
+ id: ID
401
+ name: String
402
+ }
403
+
404
+ interface SomeBox {
405
+ deepBox: SomeBox
406
+ unrelatedField: String
407
+ }
408
+
409
+ type StringBox implements SomeBox {
410
+ scalar: String
411
+ deepBox: StringBox
412
+ unrelatedField: String
413
+ listStringBox: [StringBox]
414
+ stringBox: StringBox
415
+ intBox: IntBox
416
+ }
417
+
418
+ type IntBox implements SomeBox {
419
+ scalar: Int
420
+ deepBox: IntBox
421
+ unrelatedField: String
422
+ listStringBox: [StringBox]
423
+ stringBox: StringBox
424
+ intBox: IntBox
425
+ }
426
+
427
+ interface NonNullStringBox1 {
428
+ scalar: String!
429
+ }
430
+
431
+ type NonNullStringBox1Impl implements SomeBox, NonNullStringBox1 {
432
+ scalar: String!
433
+ unrelatedField: String
434
+ deepBox: SomeBox
435
+ }
436
+
437
+ interface NonNullStringBox2 {
438
+ scalar: String!
439
+ }
440
+
441
+ type NonNullStringBox2Impl implements SomeBox, NonNullStringBox2 {
442
+ scalar: String!
443
+ unrelatedField: String
444
+ deepBox: SomeBox
445
+ }
446
+
447
+ type Connection {
448
+ edges: [Edge]
449
+ }
450
+ |)
26
451
  }
27
- fragment cheeseFields on Cheese {
28
- fatContent,
29
- similarCow: similarCheese(source: COW) { similarCowSource: id, id }
30
- id @skip(if: true)
31
- }
32
- "}
33
-
34
- it "finds field naming conflicts" do
35
- expected_errors = [
36
- "Field 'nickname' has a field conflict: flavor or fatContent?", # alias conflict in query
37
- "Field 'fatContent' has a field conflict: fatContent or flavor?", # alias/name conflict in query and fragment
38
- "Field 'similarCheese' has an argument conflict: {\"source\":\"sourceVar\"} or {\"source\":\"SHEEP\"}?", # different arguments
39
- "Field 'similarCowSource' has a field conflict: source or id?", # nested conflict
40
- ]
41
- assert_equal(expected_errors, error_messages)
452
+
453
+ describe "compatible return shapes on different return types" do
454
+ let(:query_string) {%|
455
+ {
456
+ someBox {
457
+ ... on SomeBox {
458
+ deepBox {
459
+ unrelatedField
460
+ }
461
+ }
462
+ ... on StringBox {
463
+ deepBox {
464
+ unrelatedField
465
+ }
466
+ }
467
+ }
468
+ }
469
+ |}
470
+
471
+ it "passes rule" do
472
+ assert_equal [], errors
473
+ end
474
+ end
475
+
476
+ describe "reports correctly when a non-exclusive follows an exclusive" do
477
+ let(:query_string) {%|
478
+ {
479
+ someBox {
480
+ ... on IntBox {
481
+ deepBox {
482
+ ...X
483
+ }
484
+ }
485
+ }
486
+ someBox {
487
+ ... on StringBox {
488
+ deepBox {
489
+ ...Y
490
+ }
491
+ }
492
+ }
493
+ memoed: someBox {
494
+ ... on IntBox {
495
+ deepBox {
496
+ ...X
497
+ }
498
+ }
499
+ }
500
+ memoed: someBox {
501
+ ... on StringBox {
502
+ deepBox {
503
+ ...Y
504
+ }
505
+ }
506
+ }
507
+ other: someBox {
508
+ ...X
509
+ }
510
+ other: someBox {
511
+ ...Y
512
+ }
513
+ }
514
+ fragment X on SomeBox {
515
+ scalar
516
+ }
517
+ fragment Y on SomeBox {
518
+ scalar: unrelatedField
519
+ }
520
+ |}
521
+
522
+ it "fails rule" do
523
+ assert_includes error_messages, "Field 'scalar' has a field conflict: scalar or unrelatedField?"
524
+ end
525
+ end
42
526
  end
43
527
  end