graphql 1.2.6 → 1.3.0

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.
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