graphql 1.13.23 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
  3. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  4. data/lib/graphql/analysis/ast/visitor.rb +1 -1
  5. data/lib/graphql/analysis/ast.rb +0 -10
  6. data/lib/graphql/analysis.rb +0 -7
  7. data/lib/graphql/backtrace/table.rb +0 -18
  8. data/lib/graphql/backtrace/tracer.rb +1 -2
  9. data/lib/graphql/backtrace.rb +2 -8
  10. data/lib/graphql/dig.rb +1 -1
  11. data/lib/graphql/execution/errors.rb +1 -9
  12. data/lib/graphql/execution/interpreter/runtime.rb +6 -13
  13. data/lib/graphql/execution/interpreter.rb +0 -22
  14. data/lib/graphql/execution/lazy.rb +1 -1
  15. data/lib/graphql/execution/lookahead.rb +6 -13
  16. data/lib/graphql/execution/multiplex.rb +50 -107
  17. data/lib/graphql/execution.rb +11 -3
  18. data/lib/graphql/introspection/directive_type.rb +2 -2
  19. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  20. data/lib/graphql/introspection/entry_points.rb +2 -15
  21. data/lib/graphql/introspection/field_type.rb +1 -1
  22. data/lib/graphql/introspection/schema_type.rb +2 -2
  23. data/lib/graphql/introspection/type_type.rb +5 -5
  24. data/lib/graphql/language/document_from_schema_definition.rb +0 -17
  25. data/lib/graphql/pagination/connections.rb +2 -28
  26. data/lib/graphql/query/context.rb +1 -185
  27. data/lib/graphql/query/input_validation_result.rb +0 -9
  28. data/lib/graphql/query/literal_input.rb +8 -13
  29. data/lib/graphql/query/validation_pipeline.rb +6 -34
  30. data/lib/graphql/query/variable_validation_error.rb +2 -2
  31. data/lib/graphql/query/variables.rb +8 -31
  32. data/lib/graphql/query.rb +5 -34
  33. data/lib/graphql/railtie.rb +0 -104
  34. data/lib/graphql/relay/range_add.rb +0 -4
  35. data/lib/graphql/relay.rb +0 -15
  36. data/lib/graphql/schema/addition.rb +1 -8
  37. data/lib/graphql/schema/argument.rb +1 -25
  38. data/lib/graphql/schema/build_from_definition.rb +0 -1
  39. data/lib/graphql/schema/directive.rb +1 -22
  40. data/lib/graphql/schema/enum.rb +3 -19
  41. data/lib/graphql/schema/enum_value.rb +0 -22
  42. data/lib/graphql/schema/field.rb +22 -220
  43. data/lib/graphql/schema/input_object.rb +11 -57
  44. data/lib/graphql/schema/interface.rb +1 -30
  45. data/lib/graphql/schema/introspection_system.rb +3 -8
  46. data/lib/graphql/schema/late_bound_type.rb +2 -2
  47. data/lib/graphql/schema/list.rb +3 -24
  48. data/lib/graphql/schema/loader.rb +0 -1
  49. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -6
  50. data/lib/graphql/schema/member/build_type.rb +4 -6
  51. data/lib/graphql/schema/member/has_arguments.rb +16 -20
  52. data/lib/graphql/schema/member/has_fields.rb +3 -3
  53. data/lib/graphql/schema/member/has_interfaces.rb +1 -13
  54. data/lib/graphql/schema/member/validates_input.rb +2 -2
  55. data/lib/graphql/schema/member.rb +0 -6
  56. data/lib/graphql/schema/mutation.rb +0 -9
  57. data/lib/graphql/schema/non_null.rb +3 -9
  58. data/lib/graphql/schema/object.rb +0 -40
  59. data/lib/graphql/schema/relay_classic_mutation.rb +17 -28
  60. data/lib/graphql/schema/scalar.rb +1 -16
  61. data/lib/graphql/schema/union.rb +0 -16
  62. data/lib/graphql/schema/warden.rb +3 -12
  63. data/lib/graphql/schema/wrapper.rb +0 -5
  64. data/lib/graphql/schema.rb +106 -945
  65. data/lib/graphql/static_validation/base_visitor.rb +4 -21
  66. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +12 -12
  67. data/lib/graphql/static_validation/validator.rb +2 -24
  68. data/lib/graphql/static_validation.rb +0 -2
  69. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
  70. data/lib/graphql/subscriptions/event.rb +1 -1
  71. data/lib/graphql/subscriptions/instrumentation.rb +0 -51
  72. data/lib/graphql/subscriptions.rb +4 -13
  73. data/lib/graphql/tracing/data_dog_tracing.rb +16 -20
  74. data/lib/graphql/tracing/platform_tracing.rb +4 -32
  75. data/lib/graphql/tracing.rb +0 -1
  76. data/lib/graphql/types/relay/connection_behaviors.rb +2 -6
  77. data/lib/graphql/types/relay/default_relay.rb +0 -10
  78. data/lib/graphql/types/relay/node_behaviors.rb +5 -1
  79. data/lib/graphql/types/relay.rb +0 -2
  80. data/lib/graphql/types/string.rb +1 -1
  81. data/lib/graphql/version.rb +1 -1
  82. data/lib/graphql.rb +1 -66
  83. metadata +28 -167
  84. data/lib/graphql/analysis/analyze_query.rb +0 -98
  85. data/lib/graphql/analysis/field_usage.rb +0 -45
  86. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  87. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  88. data/lib/graphql/analysis/query_complexity.rb +0 -88
  89. data/lib/graphql/analysis/query_depth.rb +0 -43
  90. data/lib/graphql/analysis/reducer_state.rb +0 -48
  91. data/lib/graphql/argument.rb +0 -131
  92. data/lib/graphql/authorization.rb +0 -82
  93. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  94. data/lib/graphql/backwards_compatibility.rb +0 -61
  95. data/lib/graphql/base_type.rb +0 -232
  96. data/lib/graphql/boolean_type.rb +0 -2
  97. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  98. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  99. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  100. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  101. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  102. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  103. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  104. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  105. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  106. data/lib/graphql/compatibility.rb +0 -5
  107. data/lib/graphql/define/assign_argument.rb +0 -12
  108. data/lib/graphql/define/assign_connection.rb +0 -13
  109. data/lib/graphql/define/assign_enum_value.rb +0 -18
  110. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  111. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  112. data/lib/graphql/define/assign_object_field.rb +0 -42
  113. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  114. data/lib/graphql/define/instance_definable.rb +0 -255
  115. data/lib/graphql/define/no_definition_error.rb +0 -7
  116. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  117. data/lib/graphql/define/type_definer.rb +0 -31
  118. data/lib/graphql/define.rb +0 -31
  119. data/lib/graphql/deprecated_dsl.rb +0 -55
  120. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  121. data/lib/graphql/directive/include_directive.rb +0 -2
  122. data/lib/graphql/directive/skip_directive.rb +0 -2
  123. data/lib/graphql/directive.rb +0 -107
  124. data/lib/graphql/enum_type.rb +0 -133
  125. data/lib/graphql/execution/execute.rb +0 -333
  126. data/lib/graphql/execution/flatten.rb +0 -40
  127. data/lib/graphql/execution/typecast.rb +0 -50
  128. data/lib/graphql/field/resolve.rb +0 -59
  129. data/lib/graphql/field.rb +0 -226
  130. data/lib/graphql/float_type.rb +0 -2
  131. data/lib/graphql/function.rb +0 -128
  132. data/lib/graphql/id_type.rb +0 -2
  133. data/lib/graphql/input_object_type.rb +0 -138
  134. data/lib/graphql/int_type.rb +0 -2
  135. data/lib/graphql/interface_type.rb +0 -72
  136. data/lib/graphql/internal_representation/document.rb +0 -27
  137. data/lib/graphql/internal_representation/node.rb +0 -206
  138. data/lib/graphql/internal_representation/print.rb +0 -51
  139. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  140. data/lib/graphql/internal_representation/scope.rb +0 -88
  141. data/lib/graphql/internal_representation/visit.rb +0 -36
  142. data/lib/graphql/internal_representation.rb +0 -7
  143. data/lib/graphql/list_type.rb +0 -80
  144. data/lib/graphql/non_null_type.rb +0 -71
  145. data/lib/graphql/object_type.rb +0 -130
  146. data/lib/graphql/query/arguments.rb +0 -189
  147. data/lib/graphql/query/arguments_cache.rb +0 -24
  148. data/lib/graphql/query/executor.rb +0 -52
  149. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  150. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  151. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  152. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  153. data/lib/graphql/query/serial_execution.rb +0 -40
  154. data/lib/graphql/relay/array_connection.rb +0 -83
  155. data/lib/graphql/relay/base_connection.rb +0 -189
  156. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  157. data/lib/graphql/relay/connection_resolve.rb +0 -43
  158. data/lib/graphql/relay/connection_type.rb +0 -54
  159. data/lib/graphql/relay/edge.rb +0 -27
  160. data/lib/graphql/relay/edge_type.rb +0 -19
  161. data/lib/graphql/relay/edges_instrumentation.rb +0 -39
  162. data/lib/graphql/relay/global_id_resolve.rb +0 -17
  163. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  164. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  165. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  166. data/lib/graphql/relay/mutation/result.rb +0 -38
  167. data/lib/graphql/relay/mutation.rb +0 -106
  168. data/lib/graphql/relay/node.rb +0 -39
  169. data/lib/graphql/relay/page_info.rb +0 -7
  170. data/lib/graphql/relay/relation_connection.rb +0 -188
  171. data/lib/graphql/relay/type_extensions.rb +0 -32
  172. data/lib/graphql/scalar_type.rb +0 -91
  173. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  174. data/lib/graphql/schema/default_parse_error.rb +0 -10
  175. data/lib/graphql/schema/default_type_error.rb +0 -17
  176. data/lib/graphql/schema/member/accepts_definition.rb +0 -164
  177. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
  178. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  179. data/lib/graphql/schema/middleware_chain.rb +0 -82
  180. data/lib/graphql/schema/possible_types.rb +0 -44
  181. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  182. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  183. data/lib/graphql/schema/traversal.rb +0 -228
  184. data/lib/graphql/schema/validation.rb +0 -313
  185. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  186. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  187. data/lib/graphql/string_type.rb +0 -2
  188. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  189. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  190. data/lib/graphql/types/relay/node_field.rb +0 -24
  191. data/lib/graphql/types/relay/nodes_field.rb +0 -43
  192. data/lib/graphql/union_type.rb +0 -115
  193. data/lib/graphql/upgrader/member.rb +0 -937
  194. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -1,228 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- class Schema
4
- # Visit the members of this schema and build up artifacts for runtime.
5
- # @api private
6
- class Traversal
7
- # @return [Hash<String => GraphQL::BaseType]
8
- attr_reader :type_map
9
-
10
- # @return [Hash<String => Hash<String => GraphQL::Field>>]
11
- attr_reader :instrumented_field_map
12
-
13
- # @return [Hash<String => Array<GraphQL::Field || GraphQL::Argument || GraphQL::Directive>]
14
- attr_reader :type_reference_map
15
-
16
- # @return [Hash<String => Array<GraphQL::BaseType>]
17
- attr_reader :union_memberships
18
-
19
-
20
- # @param schema [GraphQL::Schema]
21
- def initialize(schema, introspection: true)
22
- @schema = schema
23
- @introspection = introspection
24
- built_in_insts = [
25
- GraphQL::Relay::ConnectionInstrumentation,
26
- GraphQL::Relay::EdgesInstrumentation,
27
- GraphQL::Relay::Mutation::Instrumentation,
28
- ]
29
-
30
- if schema.query_execution_strategy != GraphQL::Execution::Interpreter
31
- built_in_insts << GraphQL::Schema::Member::Instrumentation
32
- end
33
-
34
- @field_instrumenters =
35
- schema.instrumenters[:field] +
36
- built_in_insts +
37
- schema.instrumenters[:field_after_built_ins]
38
-
39
- # These fields have types specified by _name_,
40
- # So we need to inspect the schema and find those types,
41
- # then update their references.
42
- @late_bound_fields = []
43
- @type_map = {}
44
- @instrumented_field_map = Hash.new { |h, k| h[k] = {} }
45
- @type_reference_map = Hash.new { |h, k| h[k] = [] }
46
- @union_memberships = Hash.new { |h, k| h[k] = [] }
47
- visit(schema, schema, nil)
48
- resolve_late_bound_fields
49
- end
50
-
51
- private
52
-
53
- # A brute-force appraoch to late binding.
54
- # Just keep trying the whole list, hoping that they
55
- # eventually all resolve.
56
- # This could be replaced with proper dependency tracking.
57
- def resolve_late_bound_fields
58
- # This is a bit tricky, with the writes going to internal state.
59
- prev_late_bound_fields = @late_bound_fields
60
- # Things might get added here during `visit...`
61
- # or they might be added manually if we can't find them by hand
62
- @late_bound_fields = []
63
- prev_late_bound_fields.each do |(owner_type, field_defn, dynamic_field)|
64
- if @type_map.key?(field_defn.type.unwrap.name)
65
- late_bound_return_type = field_defn.type
66
- resolved_type = @type_map.fetch(late_bound_return_type.unwrap.name)
67
- wrapped_resolved_type = rewrap_resolved_type(late_bound_return_type, resolved_type)
68
- # Update the field definition in place? :thinking_face:
69
- field_defn.type = wrapped_resolved_type
70
- visit_field_on_type(@schema, owner_type, field_defn, dynamic_field: dynamic_field)
71
- else
72
- @late_bound_fields << [owner_type, field_defn, dynamic_field]
73
- end
74
- end
75
-
76
- if @late_bound_fields.any?
77
- # If we visited each field and failed to resolve _any_,
78
- # then we're stuck.
79
- if @late_bound_fields == prev_late_bound_fields
80
- type_names = prev_late_bound_fields.map { |f| f[1] }.map(&:type).map(&:unwrap).map(&:name).uniq
81
- raise <<-ERR
82
- Some late-bound types couldn't be resolved:
83
-
84
- - #{type_names}
85
- - Found __* types: #{@type_map.keys.select { |k| k.start_with?("__") }}
86
- ERR
87
- else
88
- resolve_late_bound_fields
89
- end
90
- end
91
- end
92
-
93
- # The late-bound type may be wrapped with list or non-null types.
94
- # Apply the same wrapping to the resolve type and
95
- # return the maybe-wrapped type
96
- def rewrap_resolved_type(late_bound_type, resolved_inner_type)
97
- case late_bound_type
98
- when GraphQL::NonNullType
99
- rewrap_resolved_type(late_bound_type.of_type, resolved_inner_type).to_non_null_type
100
- when GraphQL::ListType
101
- rewrap_resolved_type(late_bound_type.of_type, resolved_inner_type).to_list_type
102
- when GraphQL::Schema::LateBoundType
103
- resolved_inner_type
104
- else
105
- raise "Unexpected late_bound_type: #{late_bound_type.inspect} (#{late_bound_type.class})"
106
- end
107
- end
108
-
109
- def visit(schema, member, context_description)
110
- case member
111
- when GraphQL::Schema
112
- member.directives.each { |name, directive| visit(schema, directive, "Directive #{name}") }
113
- # Find the starting points, then visit them
114
- visit_roots = [member.query, member.mutation, member.subscription]
115
- if @introspection
116
- introspection_types = schema.introspection_system.types.values
117
- visit_roots.concat(introspection_types)
118
- if member.query
119
- member.introspection_system.entry_points.each do |introspection_field|
120
- # Visit this so that arguments class is preconstructed
121
- # Skip validation since it begins with "__"
122
- visit_field_on_type(schema, member.query, introspection_field, dynamic_field: true)
123
- end
124
- end
125
- end
126
- visit_roots.concat(member.orphan_types)
127
- visit_roots.compact!
128
- visit_roots.each { |t| visit(schema, t, t.name) }
129
- when GraphQL::Directive
130
- member.arguments.each do |name, argument|
131
- @type_reference_map[argument.type.unwrap.to_s] << argument
132
- visit(schema, argument.type, "Directive argument #{member.name}.#{name}")
133
- end
134
- # Construct arguments class here, which is later used to generate GraphQL::Query::Arguments
135
- # to be passed to a resolver proc
136
- GraphQL::Query::Arguments.construct_arguments_class(member)
137
- when GraphQL::BaseType
138
- type_defn = member.unwrap
139
- prev_type = @type_map[type_defn.name]
140
- # Continue to visit this type if it's the first time we've seen it:
141
- if prev_type.nil?
142
- validate_type(type_defn, context_description)
143
- @type_map[type_defn.name] = type_defn
144
- case type_defn
145
- when GraphQL::ObjectType
146
- type_defn.interfaces.each { |i| visit(schema, i, "Interface on #{type_defn.name}") }
147
- visit_fields(schema, type_defn)
148
- when GraphQL::InterfaceType
149
- visit_fields(schema, type_defn)
150
- type_defn.orphan_types.each do |t|
151
- visit(schema, t, "Orphan type for #{type_defn.name}")
152
- end
153
- when GraphQL::UnionType
154
- type_defn.possible_types.each do |t|
155
- @union_memberships[t.name] << type_defn
156
- visit(schema, t, "Possible type for #{type_defn.name}")
157
- end
158
- when GraphQL::InputObjectType
159
- type_defn.arguments.each do |name, arg|
160
- @type_reference_map[arg.type.unwrap.to_s] << arg
161
- visit(schema, arg.type, "Input field #{type_defn.name}.#{name}")
162
- end
163
-
164
- # Construct arguments class here, which is later used to generate GraphQL::Query::Arguments
165
- # to be passed to a resolver proc
166
- if type_defn.arguments_class.nil?
167
- GraphQL::Query::Arguments.construct_arguments_class(type_defn)
168
- end
169
- end
170
- elsif !prev_type.equal?(type_defn)
171
- # If the previous entry in the map isn't the same object we just found, raise.
172
- raise("Duplicate type definition found for name '#{type_defn.name}' at '#{context_description}' (#{prev_type.metadata[:type_class] || prev_type}, #{type_defn.metadata[:type_class] || type_defn})")
173
- end
174
- when Class
175
- if member.respond_to?(:graphql_definition)
176
- graphql_member = member.graphql_definition(silence_deprecation_warning: true)
177
- visit(schema, graphql_member, context_description)
178
- else
179
- raise GraphQL::Schema::InvalidTypeError.new("Unexpected traversal member: #{member} (#{member.class.name})")
180
- end
181
- else
182
- message = "Unexpected schema traversal member: #{member} (#{member.class.name})"
183
- raise GraphQL::Schema::InvalidTypeError.new(message)
184
- end
185
- end
186
-
187
- def visit_fields(schema, type_defn)
188
- type_defn.all_fields.each do |field_defn|
189
- visit_field_on_type(schema, type_defn, field_defn)
190
- end
191
- end
192
-
193
- def visit_field_on_type(schema, type_defn, field_defn, dynamic_field: false)
194
- base_return_type = field_defn.type.unwrap
195
- if base_return_type.is_a?(GraphQL::Schema::LateBoundType)
196
- @late_bound_fields << [type_defn, field_defn, dynamic_field]
197
- return
198
- end
199
- if dynamic_field
200
- # Don't apply instrumentation to dynamic fields since they're shared constants
201
- instrumented_field_defn = field_defn
202
- else
203
- instrumented_field_defn = @field_instrumenters.reduce(field_defn) do |defn, inst|
204
- inst.instrument(type_defn, defn)
205
- end
206
- @instrumented_field_map[type_defn.name][instrumented_field_defn.name] = instrumented_field_defn
207
- end
208
- @type_reference_map[instrumented_field_defn.type.unwrap.name] << instrumented_field_defn
209
- visit(schema, instrumented_field_defn.type, "Field #{type_defn.name}.#{instrumented_field_defn.name}'s return type")
210
- instrumented_field_defn.arguments.each do |name, arg|
211
- @type_reference_map[arg.type.unwrap.to_s] << arg
212
- visit(schema, arg.type, "Argument #{name} on #{type_defn.name}.#{instrumented_field_defn.name}")
213
- end
214
-
215
- # Construct arguments class here, which is later used to generate GraphQL::Query::Arguments
216
- # to be passed to a resolver proc
217
- GraphQL::Query::Arguments.construct_arguments_class(instrumented_field_defn)
218
- end
219
-
220
- def validate_type(member, context_description)
221
- error_message = GraphQL::Schema::Validation.validate(member)
222
- if error_message
223
- raise GraphQL::Schema::InvalidTypeError.new("#{context_description} is invalid: #{error_message}")
224
- end
225
- end
226
- end
227
- end
228
- end
@@ -1,313 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- class Schema
4
- # This module provides a function for validating GraphQL types.
5
- #
6
- # Its {RULES} contain objects that respond to `#call(type)`. Rules are
7
- # looked up for given types (by class ancestry), then applied to
8
- # the object until an error is returned.
9
- #
10
- # Remove this in GraphQL-Ruby 2.0 when schema instances are removed.
11
- class Validation
12
- # Lookup the rules for `object` based on its class,
13
- # Then returns an error message or `nil`
14
- # @param object [Object] something to be validated
15
- # @return [String, Nil] error message, if there was one
16
- def self.validate(object)
17
- RULES.each do |parent_class, validations|
18
- if object.is_a?(parent_class)
19
- validations.each do |rule|
20
- if error = rule.call(object)
21
- return error
22
- end
23
- end
24
- end
25
- end
26
- nil
27
- end
28
-
29
- module Rules
30
- # @param property_name [Symbol] The method to validate
31
- # @param allowed_classes [Class] Classes which the return value may be an instance of
32
- # @return [Proc] A proc which will validate the input by calling `property_name` and asserting it is an instance of one of `allowed_classes`
33
- def self.assert_property(property_name, *allowed_classes)
34
- # Hide LateBoundType from user-facing errors
35
- allowed_classes_message = allowed_classes.map(&:name).reject {|n| n.include?("LateBoundType") }.join(" or ")
36
- ->(obj) {
37
- property_value = obj.public_send(property_name)
38
- is_valid_value = allowed_classes.any? { |allowed_class| property_value.is_a?(allowed_class) }
39
- is_valid_value ? nil : "#{property_name} must return #{allowed_classes_message}, not #{property_value.class.name} (#{property_value.inspect})"
40
- }
41
- end
42
-
43
- # @param property_name [Symbol] The method whose return value will be validated
44
- # @param from_class [Class] The class for keys in the return value
45
- # @param to_class [Class] The class for values in the return value
46
- # @return [Proc] A proc to validate that validates the input by calling `property_name` and asserting that the return value is a Hash of `{from_class => to_class}` pairs
47
- def self.assert_property_mapping(property_name, from_class, to_class)
48
- ->(obj) {
49
- property_value = obj.public_send(property_name)
50
- if !property_value.is_a?(Hash)
51
- "#{property_name} must be a hash of {#{from_class.name} => #{to_class.name}}, not a #{property_value.class.name} (#{property_value.inspect})"
52
- else
53
- invalid_key, invalid_value = property_value.find { |key, value| !key.is_a?(from_class) || !value.is_a?(to_class) }
54
- if invalid_key
55
- "#{property_name} must map #{from_class} => #{to_class}, not #{invalid_key.class.name} => #{invalid_value.class.name} (#{invalid_key.inspect} => #{invalid_value.inspect})"
56
- else
57
- nil # OK
58
- end
59
- end
60
- }
61
- end
62
-
63
- # @param property_name [Symbol] The method whose return value will be validated
64
- # @param list_member_class [Class] The class which each member of the returned array should be an instance of
65
- # @return [Proc] A proc to validate the input by calling `property_name` and asserting that the return is an Array of `list_member_class` instances
66
- def self.assert_property_list_of(property_name, list_member_class)
67
- ->(obj) {
68
- property_value = obj.public_send(property_name)
69
- if !property_value.is_a?(Array)
70
- "#{property_name} must be an Array of #{list_member_class.name}, not a #{property_value.class.name} (#{property_value.inspect})"
71
- else
72
- invalid_member = property_value.find { |value| !value.is_a?(list_member_class) }
73
- if invalid_member
74
- "#{property_name} must contain #{list_member_class.name}, not #{invalid_member.class.name} (#{invalid_member.inspect})"
75
- else
76
- nil # OK
77
- end
78
- end
79
- }
80
- end
81
-
82
- def self.count_at_least(item_name, minimum_count, get_items_proc)
83
- ->(type) {
84
- items = get_items_proc.call(type)
85
-
86
- if items.size < minimum_count
87
- "#{type.name} must define at least #{minimum_count} #{item_name}. #{items.size} defined."
88
- else
89
- nil
90
- end
91
- }
92
- end
93
-
94
- def self.assert_named_items_are_valid(item_name, get_items_proc)
95
- ->(type) {
96
- items = get_items_proc.call(type)
97
- error_message = nil
98
- items.each do |item|
99
- item_message = GraphQL::Schema::Validation.validate(item)
100
- if item_message
101
- error_message = "#{item_name} #{item.name.inspect} #{item_message}"
102
- break
103
- end
104
- end
105
- error_message
106
- }
107
- end
108
-
109
- HAS_AT_LEAST_ONE_FIELD = Rules.count_at_least("field", 1, ->(type) { type.all_fields })
110
- FIELDS_ARE_VALID = Rules.assert_named_items_are_valid("field", ->(type) { type.all_fields })
111
- HAS_AT_LEAST_ONE_ARGUMENT = Rules.count_at_least("argument", 1, ->(type) { type.arguments })
112
-
113
- HAS_ONE_OR_MORE_POSSIBLE_TYPES = ->(type) {
114
- type.possible_types.length >= 1 ? nil : "must have at least one possible type"
115
- }
116
-
117
- NAME_IS_STRING = Rules.assert_property(:name, String)
118
- DESCRIPTION_IS_STRING_OR_NIL = Rules.assert_property(:description, String, NilClass)
119
- ARGUMENTS_ARE_STRING_TO_ARGUMENT = Rules.assert_property_mapping(:arguments, String, GraphQL::Argument)
120
- ARGUMENTS_ARE_VALID = Rules.assert_named_items_are_valid("argument", ->(type) { type.arguments.values })
121
-
122
- DEFAULT_VALUE_IS_VALID_FOR_TYPE = ->(type) {
123
- if !type.default_value.nil?
124
- coerced_value = begin
125
- type.type.coerce_isolated_result(type.default_value)
126
- rescue => ex
127
- ex
128
- end
129
-
130
- if coerced_value.nil? || coerced_value.is_a?(StandardError)
131
- msg = "default value #{type.default_value.inspect} is not valid for type #{type.type}"
132
- msg += " (#{coerced_value})" if coerced_value.is_a?(StandardError)
133
- msg
134
- end
135
- end
136
- }
137
-
138
- DEPRECATED_ARGUMENTS_ARE_OPTIONAL = ->(argument) {
139
- if argument.deprecation_reason && argument.type.non_null?
140
- "must be optional because it's deprecated"
141
- end
142
- }
143
-
144
- TYPE_IS_VALID_INPUT_TYPE = ->(type) {
145
- outer_type = type.type
146
- inner_type = outer_type.respond_to?(:unwrap) ? outer_type.unwrap : nil
147
-
148
- case inner_type
149
- when GraphQL::ScalarType, GraphQL::InputObjectType, GraphQL::EnumType
150
- # OK
151
- else
152
- "type must be a valid input type (Scalar or InputObject), not #{outer_type.class} (#{outer_type})"
153
- end
154
- }
155
-
156
- SCHEMA_CAN_RESOLVE_TYPES = ->(schema) {
157
- if schema.types.values.any? { |type| type.kind.abstract? } && schema.resolve_type_proc.nil?
158
- "schema contains Interfaces or Unions, so you must define a `resolve_type -> (obj, ctx) { ... }` function"
159
- else
160
- # :+1:
161
- end
162
- }
163
-
164
- SCHEMA_CAN_FETCH_IDS = ->(schema) {
165
- has_node_field = schema.query && schema.query.fields.each_value.any?(&:relay_node_field)
166
- if has_node_field && schema.object_from_id_proc.nil?
167
- "schema contains `node(id:...)` field, so you must define a `object_from_id -> (id, ctx) { ... }` function"
168
- else
169
- # :rocket:
170
- end
171
- }
172
-
173
- SCHEMA_CAN_GENERATE_IDS = ->(schema) {
174
- has_id_field = schema.types.values.any? { |t| t.kind.fields? && t.all_fields.any? { |f| f.resolve_proc.is_a?(GraphQL::Relay::GlobalIdResolve) } }
175
- if has_id_field && schema.id_from_object_proc.nil?
176
- "schema contains `global_id_field`, so you must define a `id_from_object -> (obj, type, ctx) { ... }` function"
177
- else
178
- # :ok_hand:
179
- end
180
- }
181
-
182
- SCHEMA_INSTRUMENTERS_ARE_VALID = ->(schema) {
183
- errs = []
184
- schema.instrumenters[:query].each do |inst|
185
- if !inst.respond_to?(:before_query) || !inst.respond_to?(:after_query)
186
- errs << "`instrument(:query, #{inst})` is invalid: must respond to `before_query(query)` and `after_query(query)` "
187
- end
188
- end
189
-
190
- schema.instrumenters[:field].each do |inst|
191
- if !inst.respond_to?(:instrument)
192
- errs << "`instrument(:field, #{inst})` is invalid: must respond to `instrument(type, field)`"
193
- end
194
- end
195
-
196
- if errs.any?
197
- errs.join("Invalid instrumenters:\n" + errs.join("\n"))
198
- else
199
- nil
200
- end
201
- }
202
-
203
- RESERVED_TYPE_NAME = ->(type) {
204
- if type.name.start_with?('__') && !type.introspection?
205
- # TODO: make this a hard failure in a later version
206
- GraphQL::Deprecation.warn("Name #{type.name.inspect} must not begin with \"__\", which is reserved by GraphQL introspection.")
207
- nil
208
- else
209
- # ok name
210
- end
211
- }
212
-
213
- RESERVED_NAME = ->(named_thing) {
214
- if named_thing.name.start_with?('__')
215
- # TODO: make this a hard failure in a later version
216
- GraphQL::Deprecation.warn("Name #{named_thing.name.inspect} must not begin with \"__\", which is reserved by GraphQL introspection.")
217
- nil
218
- else
219
- # no worries
220
- end
221
- }
222
-
223
- INTERFACES_ARE_IMPLEMENTED = ->(obj_type) {
224
- field_errors = []
225
- obj_type.interfaces.each do |interface_type|
226
- interface_type.fields.each do |field_name, field_defn|
227
- object_field = obj_type.get_field(field_name)
228
- if object_field.nil?
229
- field_errors << %|"#{field_name}" is required by #{interface_type.name} but not implemented by #{obj_type.name}|
230
- elsif !GraphQL::Execution::Typecast.subtype?(field_defn.type, object_field.type)
231
- field_errors << %|"#{field_name}" is required by #{interface_type.name} to return #{field_defn.type} but #{obj_type.name}.#{field_name} returns #{object_field.type}|
232
- else
233
- field_defn.arguments.each do |arg_name, arg_defn|
234
- object_field_arg = object_field.arguments[arg_name]
235
- if object_field_arg.nil?
236
- field_errors << %|"#{arg_name}" argument is required by #{interface_type.name}.#{field_name} but not accepted by #{obj_type.name}.#{field_name}|
237
- elsif arg_defn.type != object_field_arg.type
238
- field_errors << %|"#{arg_name}" is required by #{interface_type.name}.#{field_defn.name} to accept #{arg_defn.type} but #{obj_type.name}.#{field_name} accepts #{object_field_arg.type} for "#{arg_name}"|
239
- end
240
- end
241
-
242
- object_field.arguments.each do |arg_name, arg_defn|
243
- if field_defn.arguments[arg_name].nil? && arg_defn.type.is_a?(GraphQL::NonNullType)
244
- field_errors << %|"#{arg_name}" is not accepted by #{interface_type.name}.#{field_name} but required by #{obj_type.name}.#{field_name}|
245
- end
246
- end
247
- end
248
- end
249
- end
250
- if field_errors.any?
251
- "#{obj_type.name} failed to implement some interfaces: #{field_errors.join(", ")}"
252
- else
253
- nil
254
- end
255
- }
256
- end
257
-
258
- # A mapping of `{Class => [Proc, Proc...]}` pairs.
259
- # To validate an instance, find entries where `object.is_a?(key)` is true.
260
- # Then apply each rule from the matching values.
261
- RULES = {
262
- GraphQL::Field => [
263
- Rules::NAME_IS_STRING,
264
- Rules::RESERVED_NAME,
265
- Rules::DESCRIPTION_IS_STRING_OR_NIL,
266
- Rules.assert_property(:deprecation_reason, String, NilClass),
267
- Rules.assert_property(:type, GraphQL::BaseType, GraphQL::Schema::LateBoundType),
268
- Rules.assert_property(:property, Symbol, NilClass),
269
- Rules::ARGUMENTS_ARE_STRING_TO_ARGUMENT,
270
- Rules::ARGUMENTS_ARE_VALID,
271
- ],
272
- GraphQL::Argument => [
273
- Rules::NAME_IS_STRING,
274
- Rules::RESERVED_NAME,
275
- Rules::DESCRIPTION_IS_STRING_OR_NIL,
276
- Rules.assert_property(:deprecation_reason, String, NilClass),
277
- Rules::TYPE_IS_VALID_INPUT_TYPE,
278
- Rules::DEFAULT_VALUE_IS_VALID_FOR_TYPE,
279
- Rules::DEPRECATED_ARGUMENTS_ARE_OPTIONAL,
280
- ],
281
- GraphQL::BaseType => [
282
- Rules::NAME_IS_STRING,
283
- Rules::RESERVED_TYPE_NAME,
284
- Rules::DESCRIPTION_IS_STRING_OR_NIL,
285
- ],
286
- GraphQL::ObjectType => [
287
- Rules::HAS_AT_LEAST_ONE_FIELD,
288
- Rules.assert_property_list_of(:interfaces, GraphQL::InterfaceType),
289
- Rules::FIELDS_ARE_VALID,
290
- Rules::INTERFACES_ARE_IMPLEMENTED,
291
- ],
292
- GraphQL::InputObjectType => [
293
- Rules::HAS_AT_LEAST_ONE_ARGUMENT,
294
- Rules::ARGUMENTS_ARE_STRING_TO_ARGUMENT,
295
- Rules::ARGUMENTS_ARE_VALID,
296
- ],
297
- GraphQL::UnionType => [
298
- Rules.assert_property_list_of(:possible_types, GraphQL::ObjectType),
299
- Rules::HAS_ONE_OR_MORE_POSSIBLE_TYPES,
300
- ],
301
- GraphQL::InterfaceType => [
302
- Rules::FIELDS_ARE_VALID,
303
- ],
304
- GraphQL::Schema => [
305
- Rules::SCHEMA_INSTRUMENTERS_ARE_VALID,
306
- Rules::SCHEMA_CAN_RESOLVE_TYPES,
307
- Rules::SCHEMA_CAN_FETCH_IDS,
308
- Rules::SCHEMA_CAN_GENERATE_IDS,
309
- ],
310
- }
311
- end
312
- end
313
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- module StaticValidation
4
- class DefaultVisitor < BaseVisitor
5
- include(GraphQL::StaticValidation::DefinitionDependencies)
6
-
7
- StaticValidation::ALL_RULES.reverse_each do |r|
8
- include(r)
9
- end
10
-
11
- include(GraphQL::InternalRepresentation::Rewrite)
12
- include(ContextMethods)
13
- end
14
- end
15
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- module StaticValidation
4
- class NoValidateVisitor < StaticValidation::BaseVisitor
5
- include(GraphQL::InternalRepresentation::Rewrite)
6
- include(GraphQL::StaticValidation::DefinitionDependencies)
7
- include(ContextMethods)
8
- end
9
- end
10
- end
@@ -1,2 +0,0 @@
1
- # frozen_string_literal: true
2
- GraphQL::STRING_TYPE = GraphQL::Types::String.graphql_definition(silence_deprecation_warning: true)
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphQL
4
- class Subscriptions
5
- # @api private
6
- # @deprecated This module is no longer needed.
7
- module SubscriptionRoot
8
- def self.extended(child_cls)
9
- GraphQL::Deprecation.warn "`extend GraphQL::Subscriptions::SubscriptionRoot` is no longer required; you can remove it from your Subscription type (#{child_cls})"
10
- child_cls.include(InstanceMethods)
11
- end
12
-
13
- # This is for maintaining backwards compatibility:
14
- # if a subscription field is created without a `subscription:` resolver class,
15
- # then implement the method with the previous default behavior.
16
- module InstanceMethods
17
- def skip_subscription_root(*)
18
- if context.query.subscription_update?
19
- object
20
- else
21
- context.skip
22
- end
23
- end
24
- end
25
-
26
- def field(*args, extensions: [], **rest, &block)
27
- extensions += [Extension]
28
- # Backwards-compat for schemas
29
- if !rest[:subscription]
30
- name = args.first
31
- alias_method(name, :skip_subscription_root)
32
- end
33
- super(*args, extensions: extensions, **rest, &block)
34
- end
35
-
36
- class Extension < GraphQL::Schema::FieldExtension
37
- def after_resolve(value:, context:, object:, arguments:, **rest)
38
- if value.is_a?(GraphQL::ExecutionError)
39
- value
40
- elsif (events = context.namespace(:subscriptions)[:events])
41
- # This is the first execution, so gather an Event
42
- # for the backend to register:
43
- event = Subscriptions::Event.new(
44
- name: field.name,
45
- arguments: arguments_without_field_extras(arguments: arguments),
46
- context: context,
47
- field: field,
48
- )
49
- events << event
50
- value
51
- elsif context.query.subscription_topic == Subscriptions::Event.serialize(
52
- field.name,
53
- arguments_without_field_extras(arguments: arguments),
54
- field,
55
- scope: (field.subscription_scope ? context[field.subscription_scope] : nil),
56
- )
57
- # This is a subscription update. The resolver returned `skip` if it should be skipped,
58
- # or else it returned an object to resolve the update.
59
- value
60
- else
61
- # This is a subscription update, but this event wasn't triggered.
62
- context.skip
63
- end
64
- end
65
-
66
- private
67
-
68
- def arguments_without_field_extras(arguments:)
69
- arguments.dup.tap do |event_args|
70
- field.extras.each { |k| event_args.delete(k) }
71
- end
72
- end
73
- end
74
- end
75
- end
76
- end