graphql 1.9.17 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/templates/schema.erb +7 -0
  3. data/lib/graphql/analysis/ast/field_usage.rb +1 -1
  4. data/lib/graphql/analysis/ast/visitor.rb +3 -3
  5. data/lib/graphql/analysis/ast.rb +12 -11
  6. data/lib/graphql/argument.rb +7 -35
  7. data/lib/graphql/backtrace/table.rb +10 -2
  8. data/lib/graphql/base_type.rb +4 -0
  9. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
  10. data/lib/graphql/define/assign_enum_value.rb +1 -1
  11. data/lib/graphql/define/assign_object_field.rb +3 -3
  12. data/lib/graphql/define/defined_object_proxy.rb +8 -2
  13. data/lib/graphql/define/instance_definable.rb +10 -106
  14. data/lib/graphql/directive/deprecated_directive.rb +1 -12
  15. data/lib/graphql/directive.rb +4 -1
  16. data/lib/graphql/enum_type.rb +5 -71
  17. data/lib/graphql/execution/directive_checks.rb +2 -2
  18. data/lib/graphql/execution/errors.rb +2 -3
  19. data/lib/graphql/execution/execute.rb +1 -1
  20. data/lib/graphql/execution/interpreter/runtime.rb +106 -55
  21. data/lib/graphql/execution/interpreter.rb +5 -11
  22. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  23. data/lib/graphql/execution/lookahead.rb +5 -5
  24. data/lib/graphql/execution/multiplex.rb +13 -3
  25. data/lib/graphql/field.rb +9 -117
  26. data/lib/graphql/filter.rb +1 -1
  27. data/lib/graphql/function.rb +1 -30
  28. data/lib/graphql/input_object_type.rb +2 -24
  29. data/lib/graphql/interface_type.rb +2 -23
  30. data/lib/graphql/introspection/base_object.rb +2 -5
  31. data/lib/graphql/introspection/directive_type.rb +1 -1
  32. data/lib/graphql/introspection/entry_points.rb +7 -7
  33. data/lib/graphql/introspection/input_value_type.rb +27 -9
  34. data/lib/graphql/introspection/schema_type.rb +1 -6
  35. data/lib/graphql/introspection/type_type.rb +5 -5
  36. data/lib/graphql/language/definition_slice.rb +21 -10
  37. data/lib/graphql/language/document_from_schema_definition.rb +50 -44
  38. data/lib/graphql/language/nodes.rb +3 -3
  39. data/lib/graphql/language/parser.rb +644 -646
  40. data/lib/graphql/language/parser.y +6 -4
  41. data/lib/graphql/language.rb +1 -1
  42. data/lib/graphql/non_null_type.rb +0 -10
  43. data/lib/graphql/object_type.rb +1 -21
  44. data/lib/graphql/pagination/active_record_relation_connection.rb +35 -0
  45. data/lib/graphql/pagination/array_connection.rb +77 -0
  46. data/lib/graphql/pagination/connection.rb +171 -0
  47. data/lib/graphql/pagination/connections.rb +108 -0
  48. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  49. data/lib/graphql/pagination/relation_connection.rb +151 -0
  50. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  51. data/lib/graphql/pagination.rb +6 -0
  52. data/lib/graphql/query/arguments.rb +2 -1
  53. data/lib/graphql/query/context.rb +2 -5
  54. data/lib/graphql/query/literal_input.rb +30 -10
  55. data/lib/graphql/query/variable_validation_error.rb +1 -1
  56. data/lib/graphql/query/variables.rb +7 -3
  57. data/lib/graphql/query.rb +9 -5
  58. data/lib/graphql/relay/base_connection.rb +4 -0
  59. data/lib/graphql/relay/connection_type.rb +2 -1
  60. data/lib/graphql/relay/edge_type.rb +1 -0
  61. data/lib/graphql/relay/edges_instrumentation.rb +1 -1
  62. data/lib/graphql/relay/mutation.rb +1 -86
  63. data/lib/graphql/relay/node.rb +2 -2
  64. data/lib/graphql/scalar_type.rb +1 -58
  65. data/lib/graphql/schema/argument.rb +51 -6
  66. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
  67. data/lib/graphql/schema/build_from_definition/resolve_map.rb +10 -4
  68. data/lib/graphql/schema/build_from_definition.rb +167 -178
  69. data/lib/graphql/schema/built_in_types.rb +5 -5
  70. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  71. data/lib/graphql/schema/directive.rb +28 -2
  72. data/lib/graphql/schema/enum.rb +40 -3
  73. data/lib/graphql/schema/enum_value.rb +5 -1
  74. data/lib/graphql/schema/field/connection_extension.rb +11 -1
  75. data/lib/graphql/schema/field.rb +59 -31
  76. data/lib/graphql/schema/find_inherited_value.rb +13 -0
  77. data/lib/graphql/schema/finder.rb +13 -11
  78. data/lib/graphql/schema/input_object.rb +107 -2
  79. data/lib/graphql/schema/interface.rb +10 -7
  80. data/lib/graphql/schema/introspection_system.rb +108 -37
  81. data/lib/graphql/schema/late_bound_type.rb +1 -0
  82. data/lib/graphql/schema/list.rb +41 -0
  83. data/lib/graphql/schema/loader.rb +16 -4
  84. data/lib/graphql/schema/member/base_dsl_methods.rb +21 -11
  85. data/lib/graphql/schema/member/build_type.rb +5 -1
  86. data/lib/graphql/schema/member/cached_graphql_definition.rb +5 -0
  87. data/lib/graphql/schema/member/has_arguments.rb +2 -2
  88. data/lib/graphql/schema/member/has_ast_node.rb +17 -0
  89. data/lib/graphql/schema/member/has_fields.rb +4 -4
  90. data/lib/graphql/schema/member/validates_input.rb +33 -0
  91. data/lib/graphql/schema/member.rb +5 -0
  92. data/lib/graphql/schema/mutation.rb +1 -1
  93. data/lib/graphql/schema/non_null.rb +25 -0
  94. data/lib/graphql/schema/object.rb +15 -5
  95. data/lib/graphql/schema/printer.rb +1 -2
  96. data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
  97. data/lib/graphql/schema/resolver.rb +3 -15
  98. data/lib/graphql/schema/scalar.rb +19 -3
  99. data/lib/graphql/schema/subscription.rb +5 -5
  100. data/lib/graphql/schema/traversal.rb +1 -1
  101. data/lib/graphql/schema/type_expression.rb +21 -13
  102. data/lib/graphql/schema/type_membership.rb +2 -2
  103. data/lib/graphql/schema/union.rb +2 -3
  104. data/lib/graphql/schema/validation.rb +2 -2
  105. data/lib/graphql/schema/warden.rb +45 -20
  106. data/lib/graphql/schema.rb +764 -151
  107. data/lib/graphql/static_validation/base_visitor.rb +10 -6
  108. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +9 -4
  109. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +10 -7
  110. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
  111. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  112. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
  113. data/lib/graphql/static_validation/rules/fields_will_merge.rb +4 -4
  114. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  115. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
  116. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +3 -3
  117. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -6
  118. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  119. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +1 -1
  120. data/lib/graphql/static_validation/type_stack.rb +2 -2
  121. data/lib/graphql/static_validation/validator.rb +1 -1
  122. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +3 -3
  123. data/lib/graphql/subscriptions/event.rb +7 -4
  124. data/lib/graphql/subscriptions/instrumentation.rb +10 -5
  125. data/lib/graphql/subscriptions/subscription_root.rb +0 -1
  126. data/lib/graphql/subscriptions.rb +34 -9
  127. data/lib/graphql/tracing/active_support_notifications_tracing.rb +14 -10
  128. data/lib/graphql/tracing/appsignal_tracing.rb +8 -0
  129. data/lib/graphql/tracing/data_dog_tracing.rb +8 -0
  130. data/lib/graphql/tracing/new_relic_tracing.rb +8 -0
  131. data/lib/graphql/tracing/platform_tracing.rb +26 -6
  132. data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
  133. data/lib/graphql/tracing/scout_tracing.rb +8 -0
  134. data/lib/graphql/tracing/skylight_tracing.rb +8 -0
  135. data/lib/graphql/tracing.rb +7 -3
  136. data/lib/graphql/types/int.rb +1 -1
  137. data/lib/graphql/types/relay/base_connection.rb +3 -1
  138. data/lib/graphql/union_type.rb +13 -28
  139. data/lib/graphql/unresolved_type_error.rb +2 -2
  140. data/lib/graphql/version.rb +1 -1
  141. data/lib/graphql.rb +2 -1
  142. metadata +15 -4
@@ -71,7 +71,7 @@ module GraphQL
71
71
  module ContextMethods
72
72
  def on_operation_definition(node, parent)
73
73
  object_type = @schema.root_type_for_operation(node.operation_type)
74
- @object_types.push(object_type)
74
+ push_type(object_type)
75
75
  @path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
76
76
  super
77
77
  @object_types.pop
@@ -98,9 +98,9 @@ module GraphQL
98
98
  @field_definitions.push(field_definition)
99
99
  if !field_definition.nil?
100
100
  next_object_type = field_definition.type.unwrap
101
- @object_types.push(next_object_type)
101
+ push_type(next_object_type)
102
102
  else
103
- @object_types.push(nil)
103
+ push_type(nil)
104
104
  end
105
105
  @path.push(node.alias || node.name)
106
106
  super
@@ -120,7 +120,7 @@ module GraphQL
120
120
  argument_defn = if (arg = @argument_definitions.last)
121
121
  arg_type = arg.type.unwrap
122
122
  if arg_type.kind.input_object?
123
- arg_type.input_fields[node.name]
123
+ arg_type.arguments[node.name]
124
124
  else
125
125
  nil
126
126
  end
@@ -187,15 +187,19 @@ module GraphQL
187
187
 
188
188
  def on_fragment_with_type(node)
189
189
  object_type = if node.type
190
- @schema.types.fetch(node.type.name, nil)
190
+ @schema.get_type(node.type.name)
191
191
  else
192
192
  @object_types.last
193
193
  end
194
- @object_types.push(object_type)
194
+ push_type(object_type)
195
195
  yield(node)
196
196
  @object_types.pop
197
197
  @path.pop
198
198
  end
199
+
200
+ def push_type(t)
201
+ @object_types.push(t)
202
+ end
199
203
  end
200
204
 
201
205
  private
@@ -11,7 +11,7 @@ module GraphQL
11
11
  nil
12
12
  else
13
13
  arg_ret_type = arg_defn.type.unwrap
14
- if !arg_ret_type.is_a?(GraphQL::InputObjectType)
14
+ if !arg_ret_type.kind.input_object?
15
15
  nil
16
16
  else
17
17
  arg_ret_type
@@ -54,7 +54,7 @@ module GraphQL
54
54
  node.value.arguments.include?(err.ast_value)
55
55
  else
56
56
  # otherwise we just check equality
57
- node.value == (err.ast_value)
57
+ node.value == err.ast_value
58
58
  end
59
59
  if !matched
60
60
  # This node isn't the node that caused the error,
@@ -67,9 +67,14 @@ module GraphQL
67
67
  error ||= begin
68
68
  kind_of_node = node_type(parent)
69
69
  error_arg_name = parent_name(parent, parent_defn)
70
+ string_value = if node.value == Float::INFINITY
71
+ ""
72
+ else
73
+ " (#{GraphQL::Language::Printer.new.print(node.value)})"
74
+ end
70
75
 
71
76
  GraphQL::StaticValidation::ArgumentLiteralsAreCompatibleError.new(
72
- "Argument '#{node.name}' on #{kind_of_node} '#{error_arg_name}' has an invalid value. Expected type '#{arg_defn.type}'.",
77
+ "Argument '#{node.name}' on #{kind_of_node} '#{error_arg_name}' has an invalid value#{string_value}. Expected type '#{arg_defn.type.to_type_signature}'.",
73
78
  nodes: parent,
74
79
  type: kind_of_node,
75
80
  argument: node.name
@@ -92,7 +97,7 @@ module GraphQL
92
97
  elsif parent.is_a?(GraphQL::Language::Nodes::InputObject)
93
98
  type_defn.name
94
99
  else
95
- parent.name
100
+ parent.graphql_name
96
101
  end
97
102
  end
98
103
 
@@ -10,10 +10,10 @@ module GraphQL
10
10
  nil
11
11
  else
12
12
  arg_ret_type = arg_defn.type.unwrap
13
- if !arg_ret_type.is_a?(GraphQL::InputObjectType)
14
- nil
15
- else
13
+ if arg_ret_type.kind.input_object?
16
14
  arg_ret_type
15
+ else
16
+ nil
17
17
  end
18
18
  end
19
19
  when GraphQL::Language::Nodes::Directive
@@ -45,12 +45,15 @@ module GraphQL
45
45
  private
46
46
 
47
47
  def parent_name(parent, type_defn)
48
- if parent.is_a?(GraphQL::Language::Nodes::Field)
48
+ case parent
49
+ when GraphQL::Language::Nodes::Field
49
50
  parent.alias || parent.name
50
- elsif parent.is_a?(GraphQL::Language::Nodes::InputObject)
51
- type_defn.name
52
- else
51
+ when GraphQL::Language::Nodes::InputObject
52
+ type_defn.graphql_name
53
+ when GraphQL::Language::Nodes::Argument, GraphQL::Language::Nodes::Directive
53
54
  parent.name
55
+ else
56
+ raise "Invariant: Unexpected parent #{parent.inspect} (#{parent.class})"
54
57
  end
55
58
  end
56
59
 
@@ -56,7 +56,7 @@ module GraphQL
56
56
  "'@#{directive_defn.graphql_name}' can't be applied to #{location_name} (allowed: #{allowed_location_names.join(", ")})",
57
57
  nodes: directive_ast,
58
58
  target: location_name,
59
- name: directive_defn.name
59
+ name: directive_defn.graphql_name
60
60
  ))
61
61
  end
62
62
  end
@@ -9,16 +9,16 @@ module GraphQL
9
9
  if field.nil?
10
10
  if parent_type.kind.union?
11
11
  add_error(GraphQL::StaticValidation::FieldsHaveAppropriateSelectionsError.new(
12
- "Selections can't be made directly on unions (see selections on #{parent_type.name})",
12
+ "Selections can't be made directly on unions (see selections on #{parent_type.graphql_name})",
13
13
  nodes: parent,
14
- node_name: parent_type.name
14
+ node_name: parent_type.graphql_name
15
15
  ))
16
16
  else
17
17
  add_error(GraphQL::StaticValidation::FieldsAreDefinedOnTypeError.new(
18
- "Field '#{node.name}' doesn't exist on type '#{parent_type.name}'",
18
+ "Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'",
19
19
  nodes: node,
20
20
  field: node.name,
21
- type: parent_type.name
21
+ type: parent_type.graphql_name
22
22
  ))
23
23
  end
24
24
  else
@@ -27,12 +27,12 @@ module GraphQL
27
27
  nil
28
28
  elsif resolved_type.kind.scalar? && ast_node.selections.any?
29
29
  if ast_node.selections.first.is_a?(GraphQL::Language::Nodes::InlineFragment)
30
- "Selections can't be made on scalars (%{node_name} returns #{resolved_type.name} but has inline fragments [#{ast_node.selections.map(&:type).map(&:name).join(", ")}])"
30
+ "Selections can't be made on scalars (%{node_name} returns #{resolved_type.graphql_name} but has inline fragments [#{ast_node.selections.map(&:type).map(&:name).join(", ")}])"
31
31
  else
32
- "Selections can't be made on scalars (%{node_name} returns #{resolved_type.name} but has selections [#{ast_node.selections.map(&:name).join(", ")}])"
32
+ "Selections can't be made on scalars (%{node_name} returns #{resolved_type.graphql_name} but has selections [#{ast_node.selections.map(&:name).join(", ")}])"
33
33
  end
34
34
  elsif resolved_type.kind.fields? && ast_node.selections.empty?
35
- "Field must have selections (%{node_name} returns #{resolved_type.name} but has no selections. Did you mean '#{ast_node.name} { ... }'?)"
35
+ "Field must have selections (%{node_name} returns #{resolved_type.graphql_name} but has no selections. Did you mean '#{ast_node.name} { ... }'?)"
36
36
  else
37
37
  nil
38
38
  end
@@ -55,13 +55,13 @@ module GraphQL
55
55
  "name": node_name.to_s
56
56
  }
57
57
  unless resolved_type.nil?
58
- extensions["type"] = resolved_type.to_s
58
+ extensions["type"] = resolved_type.to_type_signature
59
59
  end
60
60
  add_error(GraphQL::StaticValidation::FieldsHaveAppropriateSelectionsError.new(
61
61
  msg % { node_name: node_name },
62
62
  nodes: ast_node,
63
63
  node_name: node_name.to_s,
64
- type: resolved_type.nil? ? nil : resolved_type.to_s
64
+ type: resolved_type.nil? ? nil : resolved_type.graphql_name,
65
65
  ))
66
66
  false
67
67
  else
@@ -93,8 +93,8 @@ module GraphQL
93
93
 
94
94
  return if fragment1.nil? || fragment2.nil?
95
95
 
96
- fragment_type1 = context.schema.types[fragment1.type.name]
97
- fragment_type2 = context.schema.types[fragment2.type.name]
96
+ fragment_type1 = context.warden.get_type(fragment1.type.name)
97
+ fragment_type2 = context.warden.get_type(fragment2.type.name)
98
98
 
99
99
  return if fragment_type1.nil? || fragment_type2.nil?
100
100
 
@@ -146,7 +146,7 @@ module GraphQL
146
146
  fragment = context.fragments[fragment_name]
147
147
  return if fragment.nil?
148
148
 
149
- fragment_type = context.schema.types[fragment.type.name]
149
+ fragment_type = context.warden.get_type(fragment.type.name)
150
150
  return if fragment_type.nil?
151
151
 
152
152
  fragment_fields, fragment_spreads = fields_and_fragments_from_selection(fragment, owner_type: fragment_type, parents: [*fragment_spread.parents, fragment_type])
@@ -316,7 +316,7 @@ module GraphQL
316
316
  definition = context.schema.get_field(owner_type, node.name)
317
317
  fields << Field.new(node, definition, owner_type, parents)
318
318
  when GraphQL::Language::Nodes::InlineFragment
319
- fragment_type = node.type ? context.schema.types[node.type.name] : owner_type
319
+ fragment_type = node.type ? context.warden.get_type(node.type.name) : owner_type
320
320
  find_fields_and_fragments(node.selections, parents: [*parents, fragment_type], owner_type: owner_type, fields: fields, fragment_spreads: fragment_spreads) if fragment_type
321
321
  when GraphQL::Language::Nodes::FragmentSpread
322
322
  fragment_spreads << FragmentSpread.new(node.name, parents)
@@ -50,12 +50,12 @@ module GraphQL
50
50
  if child_types.none? { |c| parent_types.include?(c) }
51
51
  name = node.respond_to?(:name) ? " #{node.name}" : ""
52
52
  add_error(GraphQL::StaticValidation::FragmentSpreadsArePossibleError.new(
53
- "Fragment#{name} on #{child_type.name} can't be spread inside #{parent_type.name}",
53
+ "Fragment#{name} on #{child_type.graphql_name} can't be spread inside #{parent_type.graphql_name}",
54
54
  nodes: node,
55
55
  path: path,
56
56
  fragment_name: name.empty? ? "unknown" : name,
57
- type: child_type.name,
58
- parent: parent_type.name
57
+ type: child_type.graphql_name,
58
+ parent: parent_type.graphql_name
59
59
  ))
60
60
  end
61
61
  end
@@ -46,10 +46,10 @@ module GraphQL
46
46
  path = [*context.path, missing_field]
47
47
  missing_field_type = parent_type.arguments[missing_field].type
48
48
  add_error(RequiredInputObjectAttributesArePresentError.new(
49
- "Argument '#{missing_field}' on InputObject '#{parent_type}' is required. Expected type #{missing_field_type}",
49
+ "Argument '#{missing_field}' on InputObject '#{parent_type.to_type_signature}' is required. Expected type #{missing_field_type.to_type_signature}",
50
50
  argument_name: missing_field,
51
- argument_type: missing_field_type.to_s,
52
- input_object_type: parent_type.to_s,
51
+ argument_type: missing_field_type.to_type_signature,
52
+ input_object_type: parent_type.to_type_signature,
53
53
  path: path,
54
54
  nodes: ast_node,
55
55
  ))
@@ -13,7 +13,7 @@ module GraphQL
13
13
  error_type: VariableDefaultValuesAreCorrectlyTypedError::VIOLATIONS[:INVALID_ON_NON_NULL]
14
14
  ))
15
15
  else
16
- type = context.schema.type_from_ast(node.type)
16
+ type = context.schema.type_from_ast(node.type, context: context)
17
17
  if type.nil?
18
18
  # This is handled by another validator
19
19
  else
@@ -26,13 +26,13 @@ module GraphQL
26
26
  end
27
27
 
28
28
  if !valid
29
- error_message ||= "Default value for $#{node.name} doesn't match type #{type}"
29
+ error_message ||= "Default value for $#{node.name} doesn't match type #{type.to_type_signature}"
30
30
  VariableDefaultValuesAreCorrectlyTypedError
31
31
  add_error(GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTypedError.new(
32
32
  error_message,
33
33
  nodes: node,
34
34
  name: node.name,
35
- type: type.to_s,
35
+ type: type.to_type_signature,
36
36
  error_type: VariableDefaultValuesAreCorrectlyTypedError::VIOLATIONS[:INVALID_TYPE]
37
37
  ))
38
38
  end
@@ -52,17 +52,16 @@ module GraphQL
52
52
  private
53
53
 
54
54
  def validate_usage(arguments, arg_node, ast_var)
55
- var_type = context.schema.type_from_ast(ast_var.type)
55
+ var_type = context.schema.type_from_ast(ast_var.type, context: context)
56
56
  if var_type.nil?
57
57
  return
58
58
  end
59
59
  if !ast_var.default_value.nil?
60
- unless var_type.is_a?(GraphQL::NonNullType)
60
+ unless var_type.kind.non_null?
61
61
  # If the value is required, but the argument is not,
62
62
  # and yet there's a non-nil default, then we impliclty
63
63
  # make the argument also a required type.
64
-
65
- var_type = GraphQL::NonNullType.new(of_type: var_type)
64
+ var_type = var_type.to_non_null_type
66
65
  end
67
66
  end
68
67
 
@@ -85,10 +84,10 @@ module GraphQL
85
84
 
86
85
  def create_error(error_message, var_type, ast_var, arg_defn, arg_node)
87
86
  add_error(GraphQL::StaticValidation::VariableUsagesAreAllowedError.new(
88
- "#{error_message} on variable $#{ast_var.name} and argument #{arg_node.name} (#{var_type.to_s} / #{arg_defn.type.to_s})",
87
+ "#{error_message} on variable $#{ast_var.name} and argument #{arg_node.name} (#{var_type.to_type_signature} / #{arg_defn.type.to_type_signature})",
89
88
  nodes: arg_node,
90
89
  name: ast_var.name,
91
- type: var_type.to_s,
90
+ type: var_type.to_type_signature,
92
91
  argument: arg_node.name,
93
92
  error: error_message
94
93
  ))
@@ -15,7 +15,7 @@ module GraphQL
15
15
  ))
16
16
  elsif !type.kind.input?
17
17
  add_error(GraphQL::StaticValidation::VariablesAreInputTypesError.new(
18
- "#{type.name} isn't a valid input type (on $#{node.name})",
18
+ "#{type.graphql_name} isn't a valid input type (on $#{node.name})",
19
19
  nodes: node,
20
20
  name: node.name,
21
21
  type: type_name
@@ -2,7 +2,7 @@
2
2
  module GraphQL
3
3
  module StaticValidation
4
4
  # The problem is
5
- # - Variable usage must be determined at the OperationDefinition level
5
+ # - Variable $usage must be determined at the OperationDefinition level
6
6
  # - You can't tell how fragments use variables until you visit FragmentDefinitions (which may be at the end of the document)
7
7
  #
8
8
  # So, this validator includes some crazy logic to follow fragment spreads recursively, while avoiding infinite loops.
@@ -55,7 +55,7 @@ module GraphQL
55
55
  module FragmentWithTypeStrategy
56
56
  def push(stack, node)
57
57
  object_type = if node.type
58
- stack.schema.types.fetch(node.type.name, nil)
58
+ stack.schema.get_type(node.type.name)
59
59
  else
60
60
  stack.object_types.last
61
61
  end
@@ -148,7 +148,7 @@ module GraphQL
148
148
  if stack.argument_definitions.last
149
149
  arg_type = stack.argument_definitions.last.type.unwrap
150
150
  if arg_type.kind.input_object?
151
- argument_defn = arg_type.input_fields[node.name]
151
+ argument_defn = arg_type.arguments[node.name]
152
152
  else
153
153
  argument_defn = nil
154
154
  end
@@ -23,7 +23,7 @@ module GraphQL
23
23
  # @return [Array<Hash>]
24
24
  def validate(query, validate: true)
25
25
  query.trace("validate", { validate: validate, query: query }) do
26
- can_skip_rewrite = query.context.interpreter? && query.schema.using_ast_analysis?
26
+ can_skip_rewrite = query.context.interpreter? && query.schema.using_ast_analysis? && query.schema.is_a?(Class)
27
27
  errors = if validate == false && can_skip_rewrite
28
28
  []
29
29
  else
@@ -10,7 +10,7 @@ module GraphQL
10
10
  # - Take care to reload context when re-delivering the subscription. (see {Query#subscription_update?})
11
11
  #
12
12
  # @example Adding ActionCableSubscriptions to your schema
13
- # MySchema = GraphQL::Schema.define do
13
+ # class MySchema < GraphQL::Schema
14
14
  # # ...
15
15
  # use GraphQL::Subscriptions::ActionCableSubscriptions
16
16
  # end
@@ -26,7 +26,7 @@ module GraphQL
26
26
  # variables = ensure_hash(data["variables"])
27
27
  # operation_name = data["operationName"]
28
28
  # context = {
29
- # # Re-implement whatever context methods you need
29
+ # # Re-implement whatever context methods you need
30
30
  # # in this channel or ApplicationCable::Channel
31
31
  # # current_user: current_user,
32
32
  # # Make sure the channel is in the context
@@ -41,7 +41,7 @@ module GraphQL
41
41
  # })
42
42
  #
43
43
  # payload = {
44
- # result: result.subscription? ? { data: nil } : result.to_h,
44
+ # result: result.to_h,
45
45
  # more: result.subscription?,
46
46
  # }
47
47
  #
@@ -49,7 +49,7 @@ module GraphQL
49
49
  raise ArgumentError, "Unexpected arguments: #{arguments}, must be Hash or GraphQL::Arguments"
50
50
  end
51
51
 
52
- sorted_h = normalized_args.to_h.sort.to_h
52
+ sorted_h = stringify_args(field, normalized_args.to_h)
53
53
  Serialize.dump_recursive([scope, name, sorted_h])
54
54
  end
55
55
 
@@ -71,18 +71,21 @@ module GraphQL
71
71
  arg_defn = get_arg_definition(arg_owner, normalized_arg_name)
72
72
  end
73
73
 
74
- next_args[normalized_arg_name] = stringify_args(arg_defn[1].type, v)
74
+ next_args[normalized_arg_name] = stringify_args(arg_defn.type, v)
75
75
  end
76
- next_args
76
+ # Make sure they're deeply sorted
77
+ next_args.sort.to_h
77
78
  when Array
78
79
  args.map { |a| stringify_args(arg_owner, a) }
80
+ when GraphQL::Schema::InputObject
81
+ stringify_args(arg_owner, args.to_h)
79
82
  else
80
83
  args
81
84
  end
82
85
  end
83
86
 
84
87
  def get_arg_definition(arg_owner, arg_name)
85
- arg_owner.arguments.find { |k, v| k == arg_name || v.keyword.to_s == arg_name }
88
+ arg_owner.arguments[arg_name] || arg_owner.arguments.each_value.find { |v| v.keyword.to_s == arg_name }
86
89
  end
87
90
  end
88
91
  end
@@ -11,7 +11,7 @@ module GraphQL
11
11
  end
12
12
 
13
13
  def instrument(type, field)
14
- if type == @schema.subscription
14
+ if type == @schema.subscription.graphql_definition
15
15
  # This is a root field of `subscription`
16
16
  subscribing_resolve_proc = SubscriptionRegistrationResolve.new(field.resolve_proc)
17
17
  field.redefine(resolve: subscribing_resolve_proc)
@@ -44,7 +44,10 @@ module GraphQL
44
44
 
45
45
  # Wrap the proc with subscription registration logic
46
46
  def call(obj, args, ctx)
47
- @inner_proc.call(obj, args, ctx) if @inner_proc && !@inner_proc.is_a?(GraphQL::Field::Resolve::BuiltInResolve)
47
+ result = nil
48
+ if @inner_proc && !@inner_proc.is_a?(GraphQL::Field::Resolve::BuiltInResolve)
49
+ result = @inner_proc.call(obj, args, ctx)
50
+ end
48
51
 
49
52
  events = ctx.namespace(:subscriptions)[:events]
50
53
 
@@ -56,10 +59,12 @@ module GraphQL
56
59
  arguments: args,
57
60
  context: ctx,
58
61
  )
59
- ctx.skip
62
+ result
60
63
  elsif ctx.irep_node.subscription_topic == ctx.query.subscription_topic
61
- # The root object is _already_ the subscription update:
62
- if obj.is_a?(GraphQL::Schema::Object)
64
+ if !result.nil?
65
+ result
66
+ elsif obj.is_a?(GraphQL::Schema::Object)
67
+ # The root object is _already_ the subscription update:
63
68
  obj.object
64
69
  else
65
70
  obj
@@ -44,7 +44,6 @@ module GraphQL
44
44
  context: context,
45
45
  field: field,
46
46
  )
47
- # TODO compat with non-class-based subscriptions?
48
47
  value
49
48
  elsif context.query.subscription_topic == Subscriptions::Event.serialize(
50
49
  field.name,
@@ -18,12 +18,17 @@ module GraphQL
18
18
 
19
19
  # @see {Subscriptions#initialize} for options, concrete implementations may add options.
20
20
  def self.use(defn, options = {})
21
- schema = defn.target
22
- options[:schema] = schema
23
- schema.subscriptions = self.new(options)
21
+ schema = defn.is_a?(Class) ? defn : defn.target
22
+
23
+ if schema.subscriptions
24
+ raise ArgumentError, "Can't reinstall subscriptions. #{schema} is using #{schema.subscriptions}, can't also add #{self}"
25
+ end
26
+
24
27
  instrumentation = Subscriptions::Instrumentation.new(schema: schema)
25
- defn.instrument(:field, instrumentation)
26
28
  defn.instrument(:query, instrumentation)
29
+ defn.instrument(:field, instrumentation)
30
+ options[:schema] = schema
31
+ schema.subscriptions = self.new(**options)
27
32
  nil
28
33
  end
29
34
 
@@ -90,7 +95,7 @@ module GraphQL
90
95
  operation_name = query_data.fetch(:operation_name)
91
96
  # Re-evaluate the saved query
92
97
  result = @schema.execute(
93
- {
98
+ **{
94
99
  query: query_string,
95
100
  context: context,
96
101
  subscription_topic: event.topic,
@@ -188,7 +193,11 @@ module GraphQL
188
193
  # @return [Any] normalized arguments value
189
194
  def normalize_arguments(event_name, arg_owner, args)
190
195
  case arg_owner
191
- when GraphQL::Field, GraphQL::InputObjectType
196
+ when GraphQL::Field, GraphQL::InputObjectType, GraphQL::Schema::Field, Class
197
+ if arg_owner.is_a?(Class) && !arg_owner.kind.input_object?
198
+ # it's a type, but not an input object
199
+ return args
200
+ end
192
201
  normalized_args = {}
193
202
  missing_arg_names = []
194
203
  args.each do |k, v|
@@ -202,16 +211,32 @@ module GraphQL
202
211
  end
203
212
 
204
213
  if arg_defn
205
- normalized_args[normalized_arg_name] = normalize_arguments(event_name, arg_defn.type, v)
214
+ if arg_defn.loads
215
+ normalized_arg_name = arg_defn.keyword.to_s
216
+ end
217
+ normalized = normalize_arguments(event_name, arg_defn.type, v)
218
+ normalized_args[normalized_arg_name] = normalized
206
219
  else
207
220
  # Couldn't find a matching argument definition
208
221
  missing_arg_names << arg_name
209
222
  end
210
223
  end
211
224
 
225
+ # Backfill default values so that trigger arguments
226
+ # match query arguments.
227
+ arg_owner.arguments.each do |name, arg_defn|
228
+ if arg_defn.default_value? && !normalized_args.key?(arg_defn.name)
229
+ normalized_args[arg_defn.name] = arg_defn.default_value
230
+ end
231
+ end
232
+
212
233
  if missing_arg_names.any?
213
234
  arg_owner_name = if arg_owner.is_a?(GraphQL::Field)
214
235
  "Subscription.#{arg_owner.name}"
236
+ elsif arg_owner.is_a?(GraphQL::Schema::Field)
237
+ arg_owner.path
238
+ elsif arg_owner.is_a?(Class)
239
+ arg_owner.graphql_name
215
240
  else
216
241
  arg_owner.to_s
217
242
  end
@@ -219,9 +244,9 @@ module GraphQL
219
244
  end
220
245
 
221
246
  normalized_args
222
- when GraphQL::ListType
247
+ when GraphQL::ListType, GraphQL::Schema::List
223
248
  args.map { |a| normalize_arguments(event_name, arg_owner.of_type, a) }
224
- when GraphQL::NonNullType
249
+ when GraphQL::NonNullType, GraphQL::Schema::NonNull
225
250
  normalize_arguments(event_name, arg_owner.of_type, args)
226
251
  else
227
252
  args
@@ -8,19 +8,23 @@ module GraphQL
8
8
  module ActiveSupportNotificationsTracing
9
9
  # A cache of frequently-used keys to avoid needless string allocations
10
10
  KEYS = {
11
- "lex" => "graphql.lex",
12
- "parse" => "graphql.parse",
13
- "validate" => "graphql.validate",
14
- "analyze_multiplex" => "graphql.analyze_multiplex",
15
- "analyze_query" => "graphql.analyze_query",
16
- "execute_query" => "graphql.execute_query",
17
- "execute_query_lazy" => "graphql.execute_query_lazy",
18
- "execute_field" => "graphql.execute_field",
19
- "execute_field_lazy" => "graphql.execute_field_lazy",
11
+ "lex" => "lex.graphql",
12
+ "parse" => "parse.graphql",
13
+ "validate" => "validate.graphql",
14
+ "analyze_multiplex" => "analyze_multiplex.graphql",
15
+ "analyze_query" => "analyze_query.graphql",
16
+ "execute_query" => "execute_query.graphql",
17
+ "execute_query_lazy" => "execute_query_lazy.graphql",
18
+ "execute_field" => "execute_field.graphql",
19
+ "execute_field_lazy" => "execute_field_lazy.graphql",
20
+ "authorized" => "authorized.graphql",
21
+ "authorized_lazy" => "authorized_lazy.graphql",
22
+ "resolve_type" => "resolve_type.graphql",
23
+ "resolve_type_lazy" => "resolve_type.graphql",
20
24
  }
21
25
 
22
26
  def self.trace(key, metadata)
23
- prefixed_key = KEYS[key] || "graphql.#{key}"
27
+ prefixed_key = KEYS[key] || "#{key}.graphql"
24
28
  ActiveSupport::Notifications.instrument(prefixed_key, metadata) do
25
29
  yield
26
30
  end
@@ -23,6 +23,14 @@ module GraphQL
23
23
  def platform_field_key(type, field)
24
24
  "#{type.graphql_name}.#{field.graphql_name}.graphql"
25
25
  end
26
+
27
+ def platform_authorized_key(type)
28
+ "#{type.graphql_name}.authorized.graphql"
29
+ end
30
+
31
+ def platform_resolve_type_key(type)
32
+ "#{type.graphql_name}.resolve_type.graphql"
33
+ end
26
34
  end
27
35
  end
28
36
  end
@@ -63,6 +63,14 @@ module GraphQL
63
63
  def platform_field_key(type, field)
64
64
  "#{type.graphql_name}.#{field.graphql_name}"
65
65
  end
66
+
67
+ def platform_authorized_key(type)
68
+ "#{type.graphql_name}.authorized"
69
+ end
70
+
71
+ def platform_resolve_type_key(type)
72
+ "#{type.graphql_name}.resolve_type"
73
+ end
66
74
  end
67
75
  end
68
76
  end
@@ -49,6 +49,14 @@ module GraphQL
49
49
  def platform_field_key(type, field)
50
50
  "GraphQL/#{type.graphql_name}/#{field.graphql_name}"
51
51
  end
52
+
53
+ def platform_authorized_key(type)
54
+ "GraphQL/Authorize/#{type.graphql_name}"
55
+ end
56
+
57
+ def platform_resolve_type_key(type)
58
+ "GraphQL/ResolveType/#{type.graphql_name}"
59
+ end
52
60
  end
53
61
  end
54
62
  end