graphql 0.12.1 → 0.13.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +31 -41
  3. data/lib/graphql/argument.rb +23 -21
  4. data/lib/graphql/base_type.rb +5 -8
  5. data/lib/graphql/define/assign_argument.rb +5 -2
  6. data/lib/graphql/define/type_definer.rb +2 -1
  7. data/lib/graphql/directive.rb +34 -36
  8. data/lib/graphql/directive/include_directive.rb +3 -7
  9. data/lib/graphql/directive/skip_directive.rb +3 -7
  10. data/lib/graphql/enum_type.rb +78 -76
  11. data/lib/graphql/execution_error.rb +1 -3
  12. data/lib/graphql/field.rb +99 -95
  13. data/lib/graphql/input_object_type.rb +49 -47
  14. data/lib/graphql/interface_type.rb +31 -34
  15. data/lib/graphql/introspection.rb +19 -18
  16. data/lib/graphql/introspection/directive_location_enum.rb +8 -0
  17. data/lib/graphql/introspection/directive_type.rb +1 -3
  18. data/lib/graphql/introspection/field_type.rb +1 -1
  19. data/lib/graphql/introspection/fields_field.rb +1 -1
  20. data/lib/graphql/introspection/introspection_query.rb +1 -3
  21. data/lib/graphql/introspection/possible_types_field.rb +7 -1
  22. data/lib/graphql/introspection/schema_field.rb +13 -9
  23. data/lib/graphql/introspection/type_by_name_field.rb +13 -17
  24. data/lib/graphql/introspection/typename_field.rb +12 -8
  25. data/lib/graphql/language.rb +5 -9
  26. data/lib/graphql/language/lexer.rb +668 -0
  27. data/lib/graphql/language/lexer.rl +149 -0
  28. data/lib/graphql/language/parser.rb +842 -116
  29. data/lib/graphql/language/parser.y +264 -0
  30. data/lib/graphql/language/token.rb +21 -0
  31. data/lib/graphql/list_type.rb +33 -31
  32. data/lib/graphql/non_null_type.rb +33 -31
  33. data/lib/graphql/object_type.rb +52 -55
  34. data/lib/graphql/query.rb +83 -80
  35. data/lib/graphql/query/context.rb +5 -1
  36. data/lib/graphql/query/directive_resolution.rb +16 -0
  37. data/lib/graphql/query/executor.rb +3 -3
  38. data/lib/graphql/query/input_validation_result.rb +17 -15
  39. data/lib/graphql/query/serial_execution.rb +5 -5
  40. data/lib/graphql/query/serial_execution/execution_context.rb +4 -3
  41. data/lib/graphql/query/serial_execution/selection_resolution.rb +19 -21
  42. data/lib/graphql/query/serial_execution/value_resolution.rb +1 -1
  43. data/lib/graphql/query/type_resolver.rb +22 -18
  44. data/lib/graphql/query/variable_validation_error.rb +14 -12
  45. data/lib/graphql/schema.rb +87 -77
  46. data/lib/graphql/schema/each_item_validator.rb +16 -12
  47. data/lib/graphql/schema/field_validator.rb +14 -10
  48. data/lib/graphql/schema/implementation_validator.rb +26 -22
  49. data/lib/graphql/schema/middleware_chain.rb +2 -1
  50. data/lib/graphql/schema/possible_types.rb +34 -0
  51. data/lib/graphql/schema/printer.rb +122 -120
  52. data/lib/graphql/schema/type_expression.rb +1 -0
  53. data/lib/graphql/schema/type_map.rb +3 -10
  54. data/lib/graphql/schema/type_reducer.rb +65 -81
  55. data/lib/graphql/schema/type_validator.rb +45 -41
  56. data/lib/graphql/static_validation.rb +7 -9
  57. data/lib/graphql/static_validation/all_rules.rb +29 -24
  58. data/lib/graphql/static_validation/arguments_validator.rb +39 -35
  59. data/lib/graphql/static_validation/literal_validator.rb +44 -40
  60. data/lib/graphql/static_validation/message.rb +30 -26
  61. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +15 -11
  62. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +14 -10
  63. data/lib/graphql/static_validation/rules/directives_are_defined.rb +16 -12
  64. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +59 -0
  65. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +25 -21
  66. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +28 -24
  67. data/lib/graphql/static_validation/rules/fields_will_merge.rb +84 -80
  68. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +49 -43
  69. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +22 -17
  70. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +19 -15
  71. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +25 -20
  72. data/lib/graphql/static_validation/rules/fragments_are_used.rb +36 -23
  73. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +29 -25
  74. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +21 -17
  75. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +79 -70
  76. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +24 -20
  77. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +122 -119
  78. data/lib/graphql/static_validation/type_stack.rb +138 -129
  79. data/lib/graphql/static_validation/validator.rb +29 -25
  80. data/lib/graphql/type_kinds.rb +42 -40
  81. data/lib/graphql/union_type.rb +22 -16
  82. data/lib/graphql/version.rb +1 -1
  83. data/readme.md +12 -27
  84. data/spec/graphql/base_type_spec.rb +3 -3
  85. data/spec/graphql/directive_spec.rb +10 -18
  86. data/spec/graphql/enum_type_spec.rb +7 -7
  87. data/spec/graphql/execution_error_spec.rb +1 -1
  88. data/spec/graphql/field_spec.rb +14 -13
  89. data/spec/graphql/id_type_spec.rb +6 -6
  90. data/spec/graphql/input_object_type_spec.rb +39 -39
  91. data/spec/graphql/interface_type_spec.rb +16 -32
  92. data/spec/graphql/introspection/directive_type_spec.rb +5 -9
  93. data/spec/graphql/introspection/input_value_type_spec.rb +10 -4
  94. data/spec/graphql/introspection/introspection_query_spec.rb +2 -2
  95. data/spec/graphql/introspection/schema_type_spec.rb +2 -2
  96. data/spec/graphql/introspection/type_type_spec.rb +34 -6
  97. data/spec/graphql/language/parser_spec.rb +299 -105
  98. data/spec/graphql/language/visitor_spec.rb +4 -4
  99. data/spec/graphql/list_type_spec.rb +11 -11
  100. data/spec/graphql/object_type_spec.rb +10 -10
  101. data/spec/graphql/query/arguments_spec.rb +7 -7
  102. data/spec/graphql/query/context_spec.rb +11 -3
  103. data/spec/graphql/query/executor_spec.rb +26 -19
  104. data/spec/graphql/query/serial_execution/execution_context_spec.rb +6 -6
  105. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -2
  106. data/spec/graphql/query/type_resolver_spec.rb +3 -3
  107. data/spec/graphql/query_spec.rb +6 -38
  108. data/spec/graphql/scalar_type_spec.rb +28 -19
  109. data/spec/graphql/schema/field_validator_spec.rb +1 -1
  110. data/spec/graphql/schema/middleware_chain_spec.rb +12 -1
  111. data/spec/graphql/schema/printer_spec.rb +12 -4
  112. data/spec/graphql/schema/rescue_middleware_spec.rb +1 -1
  113. data/spec/graphql/schema/type_expression_spec.rb +2 -2
  114. data/spec/graphql/schema/type_reducer_spec.rb +21 -36
  115. data/spec/graphql/schema/type_validator_spec.rb +9 -9
  116. data/spec/graphql/schema_spec.rb +1 -1
  117. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +4 -4
  118. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +4 -4
  119. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +5 -5
  120. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +39 -0
  121. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +5 -5
  122. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +4 -4
  123. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
  124. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +1 -1
  125. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +2 -2
  126. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +2 -2
  127. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +2 -2
  128. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +3 -3
  129. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +3 -3
  130. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +5 -5
  131. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +3 -1
  132. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +4 -4
  133. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +3 -3
  134. data/spec/graphql/static_validation/type_stack_spec.rb +3 -2
  135. data/spec/graphql/static_validation/validator_spec.rb +26 -6
  136. data/spec/graphql/union_type_spec.rb +5 -4
  137. data/spec/spec_helper.rb +2 -5
  138. data/spec/support/dairy_app.rb +30 -9
  139. data/spec/support/dairy_data.rb +1 -1
  140. data/spec/support/star_wars_data.rb +26 -26
  141. data/spec/support/star_wars_schema.rb +1 -1
  142. metadata +40 -21
  143. data/lib/graphql/language/transform.rb +0 -113
  144. data/lib/graphql/query/directive_chain.rb +0 -44
  145. data/lib/graphql/repl.rb +0 -27
  146. data/spec/graphql/language/transform_spec.rb +0 -156
@@ -1,50 +1,56 @@
1
- class GraphQL::StaticValidation::FragmentSpreadsArePossible
2
- include GraphQL::StaticValidation::Message::MessageHelper
3
-
4
- def validate(context)
5
-
6
- context.visitor[GraphQL::Language::Nodes::InlineFragment] << -> (node, parent) {
7
- fragment_parent = context.object_types[-2]
8
- fragment_child = context.object_types.last
9
- validate_fragment_in_scope(fragment_parent, fragment_child, node, context)
10
- }
11
-
12
- spreads_to_validate = []
13
-
14
- context.visitor[GraphQL::Language::Nodes::FragmentSpread] << -> (node, parent) {
15
- fragment_parent = context.object_types.last
16
- spreads_to_validate << [node, fragment_parent]
17
- }
18
-
19
- context.visitor[GraphQL::Language::Nodes::Document].leave << -> (node, parent) {
20
- spreads_to_validate.each do |spread_values|
21
- node, fragment_parent = spread_values
22
- fragment_child_name = context.fragments[node.name].type
23
- fragment_child = context.schema.types[fragment_child_name]
24
- validate_fragment_in_scope(fragment_parent, fragment_child, node, context)
1
+ module GraphQL
2
+ module StaticValidation
3
+ class FragmentSpreadsArePossible
4
+ include GraphQL::StaticValidation::Message::MessageHelper
5
+
6
+ def validate(context)
7
+
8
+ context.visitor[GraphQL::Language::Nodes::InlineFragment] << -> (node, parent) {
9
+ fragment_parent = context.object_types[-2]
10
+ fragment_child = context.object_types.last
11
+ if fragment_child
12
+ validate_fragment_in_scope(fragment_parent, fragment_child, node, context)
13
+ end
14
+ }
15
+
16
+ spreads_to_validate = []
17
+
18
+ context.visitor[GraphQL::Language::Nodes::FragmentSpread] << -> (node, parent) {
19
+ fragment_parent = context.object_types.last
20
+ spreads_to_validate << [node, fragment_parent]
21
+ }
22
+
23
+ context.visitor[GraphQL::Language::Nodes::Document].leave << -> (node, parent) {
24
+ spreads_to_validate.each do |spread_values|
25
+ node, fragment_parent = spread_values
26
+ fragment_child_name = context.fragments[node.name].type
27
+ fragment_child = context.schema.types[fragment_child_name]
28
+ validate_fragment_in_scope(fragment_parent, fragment_child, node, context)
29
+ end
30
+ }
25
31
  end
26
- }
27
- end
28
32
 
29
- private
33
+ private
30
34
 
31
- def validate_fragment_in_scope(parent_type, child_type, node, context)
32
- intersecting_types = get_possible_types(parent_type) & get_possible_types(child_type)
33
- if intersecting_types.none?
34
- name = node.respond_to?(:name) ? " #{node.name}" : ""
35
- context.errors << message("Fragment#{name} on #{child_type.name} can't be spread inside #{parent_type.name}", node)
36
- end
37
- end
35
+ def validate_fragment_in_scope(parent_type, child_type, node, context)
36
+ intersecting_types = get_possible_types(parent_type, context.schema) & get_possible_types(child_type, context.schema)
37
+ if intersecting_types.none?
38
+ name = node.respond_to?(:name) ? " #{node.name}" : ""
39
+ context.errors << message("Fragment#{name} on #{child_type.name} can't be spread inside #{parent_type.name}", node)
40
+ end
41
+ end
38
42
 
39
- def get_possible_types(type)
40
- if type.kind.wraps?
41
- get_possible_types(type.of_type)
42
- elsif type.kind.object?
43
- [type]
44
- elsif type.kind.resolves?
45
- type.possible_types
46
- else
47
- []
43
+ def get_possible_types(type, schema)
44
+ if type.kind.wraps?
45
+ get_possible_types(type.of_type, schema)
46
+ elsif type.kind.object?
47
+ [type]
48
+ elsif type.kind.resolves?
49
+ schema.possible_types(type)
50
+ else
51
+ []
52
+ end
53
+ end
48
54
  end
49
55
  end
50
56
  end
@@ -1,24 +1,29 @@
1
- class GraphQL::StaticValidation::FragmentTypesExist
2
- include GraphQL::StaticValidation::Message::MessageHelper
1
+ module GraphQL
2
+ module StaticValidation
3
+ class FragmentTypesExist
4
+ include GraphQL::StaticValidation::Message::MessageHelper
3
5
 
4
- FRAGMENTS_ON_TYPES = [
5
- GraphQL::Language::Nodes::FragmentDefinition,
6
- GraphQL::Language::Nodes::InlineFragment,
7
- ]
6
+ FRAGMENTS_ON_TYPES = [
7
+ GraphQL::Language::Nodes::FragmentDefinition,
8
+ GraphQL::Language::Nodes::InlineFragment,
9
+ ]
8
10
 
9
- def validate(context)
10
- FRAGMENTS_ON_TYPES.each do |node_class|
11
- context.visitor[node_class] << -> (node, parent) { validate_type_exists(node, context) }
12
- end
13
- end
11
+ def validate(context)
12
+ FRAGMENTS_ON_TYPES.each do |node_class|
13
+ context.visitor[node_class] << -> (node, parent) { validate_type_exists(node, context) }
14
+ end
15
+ end
14
16
 
15
- private
17
+ private
16
18
 
17
- def validate_type_exists(node, context)
18
- type = context.schema.types.fetch(node.type, nil)
19
- if type.nil?
20
- context.errors << message("No such type #{node.type}, so it can't be a fragment condition", node)
21
- GraphQL::Language::Visitor::SKIP
19
+ def validate_type_exists(node, context)
20
+ return unless node.type
21
+ type = context.schema.types.fetch(node.type, nil)
22
+ if type.nil?
23
+ context.errors << message("No such type #{node.type}, so it can't be a fragment condition", node)
24
+ GraphQL::Language::Visitor::SKIP
25
+ end
26
+ end
22
27
  end
23
28
  end
24
29
  end
@@ -1,23 +1,27 @@
1
- class GraphQL::StaticValidation::FragmentsAreFinite
2
- include GraphQL::StaticValidation::Message::MessageHelper
1
+ module GraphQL
2
+ module StaticValidation
3
+ class FragmentsAreFinite
4
+ include GraphQL::StaticValidation::Message::MessageHelper
3
5
 
4
- def validate(context)
5
- context.visitor[GraphQL::Language::Nodes::FragmentDefinition] << -> (node, parent) {
6
- if has_nested_spread(node, [], context)
7
- context.errors << message("Fragment #{node.name} contains an infinite loop", node)
6
+ def validate(context)
7
+ context.visitor[GraphQL::Language::Nodes::FragmentDefinition] << -> (node, parent) {
8
+ if has_nested_spread(node, [], context)
9
+ context.errors << message("Fragment #{node.name} contains an infinite loop", node)
10
+ end
11
+ }
8
12
  end
9
- }
10
- end
11
13
 
12
- private
14
+ private
13
15
 
14
- def has_nested_spread(fragment_def, parent_fragment_names, context)
15
- nested_spreads = fragment_def.selections
16
- .select {|f| f.is_a?(GraphQL::Language::Nodes::FragmentSpread)}
16
+ def has_nested_spread(fragment_def, parent_fragment_names, context)
17
+ nested_spreads = fragment_def.selections
18
+ .select {|f| f.is_a?(GraphQL::Language::Nodes::FragmentSpread)}
17
19
 
18
- nested_spreads.any? do |spread|
19
- nested_def = context.fragments[spread.name]
20
- parent_fragment_names.include?(spread.name) || has_nested_spread(nested_def, parent_fragment_names + [fragment_def.name], context)
20
+ nested_spreads.any? do |spread|
21
+ nested_def = context.fragments[spread.name]
22
+ parent_fragment_names.include?(spread.name) || has_nested_spread(nested_def, parent_fragment_names + [fragment_def.name], context)
23
+ end
24
+ end
21
25
  end
22
26
  end
23
27
  end
@@ -1,27 +1,32 @@
1
- class GraphQL::StaticValidation::FragmentsAreOnCompositeTypes
2
- include GraphQL::StaticValidation::Message::MessageHelper
1
+ module GraphQL
2
+ module StaticValidation
3
+ class FragmentsAreOnCompositeTypes
4
+ include GraphQL::StaticValidation::Message::MessageHelper
3
5
 
4
- HAS_TYPE_CONDITION = [
5
- GraphQL::Language::Nodes::FragmentDefinition,
6
- GraphQL::Language::Nodes::InlineFragment,
7
- ]
6
+ HAS_TYPE_CONDITION = [
7
+ GraphQL::Language::Nodes::FragmentDefinition,
8
+ GraphQL::Language::Nodes::InlineFragment,
9
+ ]
8
10
 
9
- def validate(context)
10
- HAS_TYPE_CONDITION.each do |node_class|
11
- context.visitor[node_class] << -> (node, parent) {
12
- validate_type_is_composite(node, context)
13
- }
14
- end
15
- end
11
+ def validate(context)
12
+ HAS_TYPE_CONDITION.each do |node_class|
13
+ context.visitor[node_class] << -> (node, parent) {
14
+ validate_type_is_composite(node, context)
15
+ }
16
+ end
17
+ end
16
18
 
17
- private
19
+ private
18
20
 
19
- def validate_type_is_composite(node, context)
20
- type_name = node.type
21
- type_def = context.schema.types[type_name]
22
- if type_def.nil? || !type_def.kind.composite?
23
- context.errors << message("Invalid fragment on type #{type_name} (must be Union, Interface or Object)", node)
24
- GraphQL::Language::Visitor::SKIP
21
+ def validate_type_is_composite(node, context)
22
+ type_name = node.type
23
+ return unless type_name
24
+ type_def = context.schema.types[type_name]
25
+ if type_def.nil? || !type_def.kind.composite?
26
+ context.errors << message("Invalid fragment on type #{type_name} (must be Union, Interface or Object)", node)
27
+ GraphQL::Language::Visitor::SKIP
28
+ end
29
+ end
25
30
  end
26
31
  end
27
32
  end
@@ -1,30 +1,43 @@
1
- class GraphQL::StaticValidation::FragmentsAreUsed
2
- include GraphQL::StaticValidation::Message::MessageHelper
1
+ module GraphQL
2
+ module StaticValidation
3
+ class FragmentsAreUsed
4
+ include GraphQL::StaticValidation::Message::MessageHelper
3
5
 
4
- def validate(context)
5
- v = context.visitor
6
- used_fragments = []
7
- defined_fragments = []
8
- v[GraphQL::Language::Nodes::FragmentSpread] << -> (node, parent) { used_fragments << node }
9
- v[GraphQL::Language::Nodes::FragmentDefinition] << -> (node, parent) { defined_fragments << node}
10
- v[GraphQL::Language::Nodes::Document].leave << -> (node, parent) { add_errors(context.errors, used_fragments, defined_fragments) }
11
- end
6
+ def validate(context)
7
+ v = context.visitor
8
+ used_fragments = []
9
+ defined_fragments = []
12
10
 
13
- private
11
+ v[GraphQL::Language::Nodes::Document] << -> (node, parent) {
12
+ defined_fragments = node.definitions.select { |defn| defn.is_a?(GraphQL::Language::Nodes::FragmentDefinition) }
13
+ }
14
14
 
15
- def add_errors(errors, used_fragments, defined_fragments)
16
- undefined_fragments = find_difference(used_fragments, defined_fragments.map(&:name))
17
- undefined_fragments.each do |fragment|
18
- errors << message("Fragment #{fragment.name} was used, but not defined", fragment)
19
- end
15
+ v[GraphQL::Language::Nodes::FragmentSpread] << -> (node, parent) {
16
+ used_fragments << node
17
+ if defined_fragments.none? { |defn| defn.name == node.name }
18
+ GraphQL::Language::Visitor::SKIP
19
+ end
20
+ }
21
+ v[GraphQL::Language::Nodes::Document].leave << -> (node, parent) { add_errors(context.errors, used_fragments, defined_fragments) }
22
+ end
20
23
 
21
- unused_fragments = find_difference(defined_fragments, used_fragments.map(&:name))
22
- unused_fragments.each do |fragment|
23
- errors << message("Fragment #{fragment.name} was defined, but not used", fragment)
24
- end
25
- end
24
+ private
26
25
 
27
- def find_difference(fragments, allowed_fragment_names)
28
- fragments.select {|f| !allowed_fragment_names.include?(f.name) }
26
+ def add_errors(errors, used_fragments, defined_fragments)
27
+ undefined_fragments = find_difference(used_fragments, defined_fragments.map(&:name))
28
+ undefined_fragments.each do |fragment|
29
+ errors << message("Fragment #{fragment.name} was used, but not defined", fragment)
30
+ end
31
+
32
+ unused_fragments = find_difference(defined_fragments, used_fragments.map(&:name))
33
+ unused_fragments.each do |fragment|
34
+ errors << message("Fragment #{fragment.name} was defined, but not used", fragment)
35
+ end
36
+ end
37
+
38
+ def find_difference(fragments, allowed_fragment_names)
39
+ fragments.select {|f| !allowed_fragment_names.include?(f.name) }
40
+ end
41
+ end
29
42
  end
30
43
  end
@@ -1,34 +1,38 @@
1
- class GraphQL::StaticValidation::RequiredArgumentsArePresent
2
- include GraphQL::StaticValidation::Message::MessageHelper
1
+ module GraphQL
2
+ module StaticValidation
3
+ class RequiredArgumentsArePresent
4
+ include GraphQL::StaticValidation::Message::MessageHelper
3
5
 
4
- def validate(context)
5
- v = context.visitor
6
- v[GraphQL::Language::Nodes::Field] << -> (node, parent) { validate_field(node, context) }
7
- v[GraphQL::Language::Nodes::Directive] << -> (node, parent) { validate_directive(node, context) }
8
- end
6
+ def validate(context)
7
+ v = context.visitor
8
+ v[GraphQL::Language::Nodes::Field] << -> (node, parent) { validate_field(node, context) }
9
+ v[GraphQL::Language::Nodes::Directive] << -> (node, parent) { validate_directive(node, context) }
10
+ end
9
11
 
10
- private
12
+ private
11
13
 
12
- def validate_directive(ast_directive, context)
13
- directive_defn = context.schema.directives[ast_directive.name]
14
- assert_required_args(ast_directive, directive_defn, context)
15
- end
14
+ def validate_directive(ast_directive, context)
15
+ directive_defn = context.schema.directives[ast_directive.name]
16
+ assert_required_args(ast_directive, directive_defn, context)
17
+ end
16
18
 
17
- def validate_field(ast_field, context)
18
- return if context.skip_field?(ast_field.name)
19
- defn = context.field_definition
20
- assert_required_args(ast_field, defn, context)
21
- end
19
+ def validate_field(ast_field, context)
20
+ return if context.skip_field?(ast_field.name)
21
+ defn = context.field_definition
22
+ assert_required_args(ast_field, defn, context)
23
+ end
22
24
 
23
- def assert_required_args(ast_node, defn, context)
24
- present_argument_names = ast_node.arguments.map(&:name)
25
- required_argument_names = defn.arguments.values
26
- .select { |a| a.type.kind.non_null? }
27
- .map(&:name)
25
+ def assert_required_args(ast_node, defn, context)
26
+ present_argument_names = ast_node.arguments.map(&:name)
27
+ required_argument_names = defn.arguments.values
28
+ .select { |a| a.type.kind.non_null? }
29
+ .map(&:name)
28
30
 
29
- missing_names = required_argument_names - present_argument_names
30
- if missing_names.any?
31
- context.errors << message("#{ast_node.class.name.split("::").last} '#{ast_node.name}' is missing required arguments: #{missing_names.join(", ")}", ast_node)
31
+ missing_names = required_argument_names - present_argument_names
32
+ if missing_names.any?
33
+ context.errors << message("#{ast_node.class.name.split("::").last} '#{ast_node.name}' is missing required arguments: #{missing_names.join(", ")}", ast_node)
34
+ end
35
+ end
32
36
  end
33
37
  end
34
38
  end
@@ -1,23 +1,27 @@
1
- class GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTyped
2
- include GraphQL::StaticValidation::Message::MessageHelper
1
+ module GraphQL
2
+ module StaticValidation
3
+ class VariableDefaultValuesAreCorrectlyTyped
4
+ include GraphQL::StaticValidation::Message::MessageHelper
3
5
 
4
- def validate(context)
5
- literal_validator = GraphQL::StaticValidation::LiteralValidator.new
6
- context.visitor[GraphQL::Language::Nodes::VariableDefinition] << -> (node, parent) {
7
- if !node.default_value.nil?
8
- validate_default_value(node, literal_validator, context)
6
+ def validate(context)
7
+ literal_validator = GraphQL::StaticValidation::LiteralValidator.new
8
+ context.visitor[GraphQL::Language::Nodes::VariableDefinition] << -> (node, parent) {
9
+ if !node.default_value.nil?
10
+ validate_default_value(node, literal_validator, context)
11
+ end
12
+ }
9
13
  end
10
- }
11
- end
12
14
 
13
- def validate_default_value(node, literal_validator, context)
14
- value = node.default_value
15
- if node.type.is_a?(GraphQL::Language::Nodes::NonNullType)
16
- context.errors << message("Non-null variable $#{node.name} can't have a default value", node)
17
- else
18
- type = context.schema.type_from_ast(node.type)
19
- if !literal_validator.validate(value, type)
20
- context.errors << message("Default value for $#{node.name} doesn't match type #{type}", node)
15
+ def validate_default_value(node, literal_validator, context)
16
+ value = node.default_value
17
+ if node.type.is_a?(GraphQL::Language::Nodes::NonNullType)
18
+ context.errors << message("Non-null variable $#{node.name} can't have a default value", node)
19
+ else
20
+ type = context.schema.type_from_ast(node.type)
21
+ if !literal_validator.validate(value, type)
22
+ context.errors << message("Default value for $#{node.name} doesn't match type #{type}", node)
23
+ end
24
+ end
21
25
  end
22
26
  end
23
27
  end
@@ -1,86 +1,95 @@
1
- class GraphQL::StaticValidation::VariableUsagesAreAllowed
2
- include GraphQL::StaticValidation::Message::MessageHelper
1
+ module GraphQL
2
+ module StaticValidation
3
+ class VariableUsagesAreAllowed
4
+ include GraphQL::StaticValidation::Message::MessageHelper
3
5
 
4
- def validate(context)
5
- # holds { name => ast_node } pairs
6
- declared_variables = {}
6
+ def validate(context)
7
+ # holds { name => ast_node } pairs
8
+ declared_variables = {}
7
9
 
8
- context.visitor[GraphQL::Language::Nodes::OperationDefinition] << -> (node, parent) {
9
- declared_variables = node.variables.each_with_object({}) { |var, memo| memo[var.name] = var }
10
- }
10
+ context.visitor[GraphQL::Language::Nodes::OperationDefinition] << -> (node, parent) {
11
+ declared_variables = node.variables.each_with_object({}) { |var, memo| memo[var.name] = var }
12
+ }
11
13
 
12
- context.visitor[GraphQL::Language::Nodes::Argument] << -> (node, parent) {
13
- return if !node.value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
14
- if parent.is_a?(GraphQL::Language::Nodes::Field)
15
- arguments = context.field_definition.arguments
16
- elsif parent.is_a?(GraphQL::Language::Nodes::Directive)
17
- arguments = context.directive_definition.arguments
18
- elsif parent.is_a?(GraphQL::Language::Nodes::InputObject)
19
- arguments = context.argument_definition.type.unwrap.input_fields
20
- else
21
- raise("Unexpected argument parent: #{parent}")
14
+ context.visitor[GraphQL::Language::Nodes::Argument] << -> (node, parent) {
15
+ return if !node.value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
16
+ if parent.is_a?(GraphQL::Language::Nodes::Field)
17
+ arguments = context.field_definition.arguments
18
+ elsif parent.is_a?(GraphQL::Language::Nodes::Directive)
19
+ arguments = context.directive_definition.arguments
20
+ elsif parent.is_a?(GraphQL::Language::Nodes::InputObject)
21
+ arguments = context.argument_definition.type.unwrap.input_fields
22
+ else
23
+ raise("Unexpected argument parent: #{parent}")
24
+ end
25
+ var_defn_ast = declared_variables[node.value.name]
26
+ # Might be undefined :(
27
+ # VariablesAreUsedAndDefined can't finalize its search until the end of the document.
28
+ var_defn_ast && validate_usage(arguments, node, var_defn_ast, context)
29
+ }
22
30
  end
23
- var_defn_ast = declared_variables[node.value.name]
24
- # Might be undefined :(
25
- # VariablesAreUsedAndDefined can't finalize its search until the end of the document.
26
- var_defn_ast && validate_usage(arguments, node, var_defn_ast, context)
27
- }
28
- end
29
31
 
30
- private
32
+ private
31
33
 
32
- def validate_usage(arguments, arg_node, ast_var, context)
33
- var_type = to_query_type(ast_var.type, context.schema.types)
34
- if !ast_var.default_value.nil?
35
- var_type = GraphQL::NonNullType.new(of_type: var_type)
36
- end
34
+ def validate_usage(arguments, arg_node, ast_var, context)
35
+ var_type = to_query_type(ast_var.type, context.schema.types)
36
+ if !ast_var.default_value.nil?
37
+ var_type = GraphQL::NonNullType.new(of_type: var_type)
38
+ end
37
39
 
38
- arg_defn = arguments[arg_node.name]
39
- arg_defn_type = arg_defn.type
40
+ arg_defn = arguments[arg_node.name]
41
+ arg_defn_type = arg_defn.type
40
42
 
41
- var_inner_type = var_type.unwrap
42
- arg_inner_type = arg_defn_type.unwrap
43
+ var_inner_type = var_type.unwrap
44
+ arg_inner_type = arg_defn_type.unwrap
43
45
 
44
- if var_inner_type != arg_inner_type
45
- context.errors << create_error("Type mismatch", var_type, ast_var, arg_defn, arg_node)
46
- elsif list_dimension(var_type) != list_dimension(arg_defn_type)
47
- context.errors << create_error("List dimension mismatch", var_type, ast_var, arg_defn, arg_node)
48
- elsif !non_null_levels_match(arg_defn_type, var_type)
49
- context.errors << create_error("Nullability mismatch", var_type, ast_var, arg_defn, arg_node)
50
- end
51
- end
46
+ if var_inner_type != arg_inner_type
47
+ context.errors << create_error("Type mismatch", var_type, ast_var, arg_defn, arg_node)
48
+ elsif list_dimension(var_type) != list_dimension(arg_defn_type)
49
+ context.errors << create_error("List dimension mismatch", var_type, ast_var, arg_defn, arg_node)
50
+ elsif !non_null_levels_match(arg_defn_type, var_type)
51
+ context.errors << create_error("Nullability mismatch", var_type, ast_var, arg_defn, arg_node)
52
+ end
53
+ end
52
54
 
53
- def to_query_type(ast_type, types)
54
- if ast_type.is_a?(GraphQL::Language::Nodes::NonNullType)
55
- GraphQL::NonNullType.new(of_type: to_query_type(ast_type.of_type, types))
56
- elsif ast_type.is_a?(GraphQL::Language::Nodes::ListType)
57
- GraphQL::ListType.new(of_type: to_query_type(ast_type.of_type, types))
58
- else
59
- types[ast_type.name]
60
- end
61
- end
55
+ def to_query_type(ast_type, types)
56
+ if ast_type.is_a?(GraphQL::Language::Nodes::NonNullType)
57
+ GraphQL::NonNullType.new(of_type: to_query_type(ast_type.of_type, types))
58
+ elsif ast_type.is_a?(GraphQL::Language::Nodes::ListType)
59
+ GraphQL::ListType.new(of_type: to_query_type(ast_type.of_type, types))
60
+ else
61
+ types[ast_type.name]
62
+ end
63
+ end
62
64
 
63
- def create_error(error_message, var_type, ast_var, arg_defn, arg_node)
64
- message("#{error_message} on variable $#{ast_var.name} and argument #{arg_node.name} (#{var_type.to_s} / #{arg_defn.type.to_s})", arg_node)
65
- end
65
+ def create_error(error_message, var_type, ast_var, arg_defn, arg_node)
66
+ message("#{error_message} on variable $#{ast_var.name} and argument #{arg_node.name} (#{var_type.to_s} / #{arg_defn.type.to_s})", arg_node)
67
+ end
66
68
 
67
- def list_dimension(type)
68
- if type.kind.list?
69
- 1 + list_dimension(type.of_type)
70
- elsif type.kind.non_null?
71
- list_dimension(type.of_type)
72
- else
73
- 0
74
- end
75
- end
69
+ def list_dimension(type)
70
+ if type.kind.list?
71
+ 1 + list_dimension(type.of_type)
72
+ elsif type.kind.non_null?
73
+ list_dimension(type.of_type)
74
+ else
75
+ 0
76
+ end
77
+ end
76
78
 
77
- def non_null_levels_match(arg_type, var_type)
78
- if arg_type.kind.non_null? && !var_type.kind.non_null?
79
- false
80
- elsif arg_type.kind.wraps? && var_type.kind.wraps?
81
- non_null_levels_match(arg_type.of_type, var_type.of_type)
82
- else
83
- true
79
+ def non_null_levels_match(arg_type, var_type)
80
+ if arg_type.kind.non_null? && !var_type.kind.non_null?
81
+ false
82
+ elsif arg_type.kind.wraps? && var_type.kind.wraps?
83
+ # If var_type is a non-null wrapper for a type, and arg_type is nullable, peel off the wrapper
84
+ # That way, a var_type of `[DairyAnimal]!` works with an arg_type of `[DairyAnimal]`
85
+ if var_type.kind.non_null? && !arg_type.kind.non_null?
86
+ var_type = var_type.of_type
87
+ end
88
+ non_null_levels_match(arg_type.of_type, var_type.of_type)
89
+ else
90
+ true
91
+ end
92
+ end
84
93
  end
85
94
  end
86
95
  end