graphql 1.9.0.pre1 → 1.9.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql.rb +5 -1
- data/lib/graphql/analysis/ast/analyzer.rb +1 -1
- data/lib/graphql/analysis/ast/visitor.rb +6 -1
- data/lib/graphql/backwards_compatibility.rb +1 -1
- data/lib/graphql/dig.rb +19 -0
- data/lib/graphql/directive.rb +13 -1
- data/lib/graphql/directive/include_directive.rb +1 -7
- data/lib/graphql/directive/skip_directive.rb +1 -8
- data/lib/graphql/execution/interpreter.rb +23 -13
- data/lib/graphql/execution/interpreter/resolve.rb +56 -0
- data/lib/graphql/execution/interpreter/runtime.rb +174 -74
- data/lib/graphql/execution/lazy.rb +7 -1
- data/lib/graphql/execution/lookahead.rb +71 -6
- data/lib/graphql/execution_error.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +5 -1
- data/lib/graphql/introspection/type_type.rb +4 -4
- data/lib/graphql/language.rb +0 -1
- data/lib/graphql/language/block_string.rb +37 -0
- data/lib/graphql/language/document_from_schema_definition.rb +1 -1
- data/lib/graphql/language/lexer.rb +55 -36
- data/lib/graphql/language/lexer.rl +8 -3
- data/lib/graphql/language/nodes.rb +27 -4
- data/lib/graphql/language/parser.rb +55 -55
- data/lib/graphql/language/parser.y +11 -11
- data/lib/graphql/language/printer.rb +1 -1
- data/lib/graphql/language/visitor.rb +22 -13
- data/lib/graphql/literal_validation_error.rb +6 -0
- data/lib/graphql/query.rb +13 -0
- data/lib/graphql/query/arguments.rb +2 -1
- data/lib/graphql/query/context.rb +3 -10
- data/lib/graphql/query/executor.rb +1 -1
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/relay/connection_resolve.rb +1 -1
- data/lib/graphql/relay/relation_connection.rb +1 -1
- data/lib/graphql/schema.rb +81 -11
- data/lib/graphql/schema/argument.rb +1 -1
- data/lib/graphql/schema/build_from_definition.rb +2 -4
- data/lib/graphql/schema/directive.rb +103 -0
- data/lib/graphql/schema/directive/feature.rb +66 -0
- data/lib/graphql/schema/directive/include.rb +25 -0
- data/lib/graphql/schema/directive/skip.rb +25 -0
- data/lib/graphql/schema/directive/transform.rb +48 -0
- data/lib/graphql/schema/enum_value.rb +2 -2
- data/lib/graphql/schema/field.rb +63 -17
- data/lib/graphql/schema/input_object.rb +1 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +4 -2
- data/lib/graphql/schema/member/build_type.rb +33 -1
- data/lib/graphql/schema/member/has_fields.rb +8 -73
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -1
- data/lib/graphql/schema/resolver.rb +1 -1
- data/lib/graphql/static_validation.rb +2 -1
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +25 -10
- data/lib/graphql/static_validation/definition_dependencies.rb +3 -3
- data/lib/graphql/static_validation/{message.rb → error.rb} +11 -11
- data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
- data/lib/graphql/static_validation/literal_validator.rb +54 -11
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +34 -5
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +31 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +2 -2
- data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +7 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +35 -0
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +5 -1
- data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +11 -2
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +11 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +14 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +24 -6
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +5 -1
- data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -1
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +5 -1
- data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -1
- data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_named.rb +4 -1
- data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +5 -1
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +13 -3
- data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +4 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +2 -2
- data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +9 -2
- data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +7 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +47 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +4 -1
- data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +4 -3
- data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +20 -6
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +5 -1
- data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +8 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +12 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +18 -2
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
- data/lib/graphql/static_validation/validator.rb +24 -14
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -2
- data/lib/graphql/tracing/skylight_tracing.rb +2 -2
- data/lib/graphql/unauthorized_field_error.rb +23 -0
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/analysis/ast_spec.rb +40 -0
- data/spec/graphql/authorization_spec.rb +93 -20
- data/spec/graphql/base_type_spec.rb +3 -1
- data/spec/graphql/execution/interpreter_spec.rb +127 -4
- data/spec/graphql/execution/lazy_spec.rb +49 -0
- data/spec/graphql/execution/lookahead_spec.rb +113 -21
- data/spec/graphql/execution/multiplex_spec.rb +2 -1
- data/spec/graphql/introspection/type_type_spec.rb +1 -1
- data/spec/graphql/language/lexer_spec.rb +72 -3
- data/spec/graphql/language/printer_spec.rb +18 -6
- data/spec/graphql/query/arguments_spec.rb +21 -0
- data/spec/graphql/query/context_spec.rb +10 -0
- data/spec/graphql/schema/build_from_definition_spec.rb +144 -29
- data/spec/graphql/schema/directive/feature_spec.rb +81 -0
- data/spec/graphql/schema/directive/transform_spec.rb +39 -0
- data/spec/graphql/schema/enum_spec.rb +5 -3
- data/spec/graphql/schema/field_extension_spec.rb +3 -3
- data/spec/graphql/schema/field_spec.rb +19 -0
- data/spec/graphql/schema/input_object_spec.rb +81 -0
- data/spec/graphql/schema/member/build_type_spec.rb +46 -0
- data/spec/graphql/schema/member/scoped_spec.rb +3 -3
- data/spec/graphql/schema/printer_spec.rb +244 -96
- data/spec/graphql/schema/relay_classic_mutation_spec.rb +26 -0
- data/spec/graphql/schema/resolver_spec.rb +1 -1
- data/spec/graphql/schema/warden_spec.rb +35 -11
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +212 -72
- data/spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +72 -29
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +10 -5
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -5
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +22 -2
- data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/operation_names_are_valid_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +13 -4
- data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb +58 -0
- data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +14 -7
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +14 -7
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +8 -4
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +6 -3
- data/spec/graphql/static_validation/validator_spec.rb +6 -4
- data/spec/graphql/tracing/new_relic_tracing_spec.rb +10 -0
- data/spec/graphql/tracing/skylight_tracing_spec.rb +10 -0
- data/spec/graphql/types/iso_8601_date_time_spec.rb +1 -2
- data/spec/integration/mongoid/star_trek/schema.rb +5 -5
- data/spec/integration/rails/graphql/relay/relation_connection_spec.rb +37 -8
- data/spec/integration/rails/graphql/schema_spec.rb +2 -2
- data/spec/integration/rails/spec_helper.rb +10 -0
- data/spec/integration/tmp/app/graphql/types/bird_type.rb +7 -0
- data/spec/integration/tmp/dummy/Gemfile +45 -0
- data/spec/integration/tmp/dummy/README.rdoc +28 -0
- data/spec/integration/tmp/dummy/Rakefile +6 -0
- data/spec/integration/tmp/dummy/app/assets/javascripts/application.js +16 -0
- data/spec/integration/tmp/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/integration/tmp/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/integration/tmp/dummy/app/controllers/graphql_controller.rb +43 -0
- data/spec/integration/tmp/dummy/app/graphql/dummy_schema.rb +34 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_enum.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_input_object.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_interface.rb +5 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_object.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_scalar.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_union.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/mutation_type.rb +10 -0
- data/spec/integration/tmp/dummy/app/graphql/types/query_type.rb +15 -0
- data/spec/integration/tmp/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/integration/tmp/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/integration/tmp/dummy/bin/bundle +3 -0
- data/spec/integration/tmp/dummy/bin/rails +4 -0
- data/spec/integration/tmp/dummy/bin/rake +4 -0
- data/spec/integration/tmp/dummy/bin/setup +29 -0
- data/spec/integration/tmp/dummy/config.ru +4 -0
- data/spec/integration/tmp/dummy/config/application.rb +32 -0
- data/spec/integration/tmp/dummy/config/boot.rb +3 -0
- data/spec/integration/tmp/dummy/config/environment.rb +5 -0
- data/spec/integration/tmp/dummy/config/environments/development.rb +38 -0
- data/spec/integration/tmp/dummy/config/environments/production.rb +76 -0
- data/spec/integration/tmp/dummy/config/environments/test.rb +42 -0
- data/spec/integration/tmp/dummy/config/initializers/assets.rb +11 -0
- data/spec/integration/tmp/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/integration/tmp/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/integration/tmp/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/integration/tmp/dummy/config/initializers/inflections.rb +16 -0
- data/spec/integration/tmp/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/integration/tmp/dummy/config/initializers/session_store.rb +3 -0
- data/spec/integration/tmp/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
- data/spec/integration/tmp/dummy/config/initializers/wrap_parameters.rb +9 -0
- data/spec/integration/tmp/dummy/config/locales/en.yml +23 -0
- data/spec/integration/tmp/dummy/config/routes.rb +61 -0
- data/spec/integration/tmp/dummy/config/secrets.yml +22 -0
- data/spec/integration/tmp/dummy/db/seeds.rb +7 -0
- data/spec/integration/tmp/dummy/public/404.html +67 -0
- data/spec/integration/tmp/dummy/public/422.html +67 -0
- data/spec/integration/tmp/dummy/public/500.html +66 -0
- data/spec/integration/tmp/dummy/public/favicon.ico +0 -0
- data/spec/integration/tmp/dummy/public/robots.txt +5 -0
- data/spec/support/dummy/schema.rb +2 -2
- data/spec/support/error_bubbling_helpers.rb +23 -0
- data/spec/support/jazz.rb +53 -6
- data/spec/support/lazy_helpers.rb +26 -8
- data/spec/support/new_relic.rb +3 -0
- data/spec/support/skylight.rb +3 -0
- data/spec/support/star_wars/schema.rb +13 -9
- data/spec/support/static_validation_helpers.rb +3 -1
- metadata +145 -22
- data/lib/graphql/language/comments.rb +0 -45
- data/spec/graphql/schema/member/has_fields_spec.rb +0 -132
- data/spec/integration/tmp/app/graphql/types/family_type.rb +0 -9
@@ -254,7 +254,7 @@ module GraphQL
|
|
254
254
|
return ''.dup unless node.description
|
255
255
|
|
256
256
|
description = indent != '' && !first_in_block ? "\n".dup : "".dup
|
257
|
-
description << GraphQL::Language::
|
257
|
+
description << GraphQL::Language::BlockString.print(node.description, indent: indent)
|
258
258
|
end
|
259
259
|
|
260
260
|
def print_field_definitions(fields)
|
@@ -85,18 +85,21 @@ module GraphQL
|
|
85
85
|
if node == DELETE_NODE
|
86
86
|
# This might be passed to `super(DELETE_NODE, ...)`
|
87
87
|
# by a user hook, don't want to keep visiting in that case.
|
88
|
-
|
88
|
+
[node, parent]
|
89
89
|
else
|
90
90
|
# Run hooks if there are any
|
91
91
|
begin_hooks_ok = @visitors.none? || begin_visit(node, parent)
|
92
92
|
if begin_hooks_ok
|
93
93
|
node.children.each do |child_node|
|
94
|
+
new_child_and_node = on_node_with_modifications(child_node, node)
|
94
95
|
# Reassign `node` in case the child hook makes a modification
|
95
|
-
|
96
|
+
if new_child_and_node.is_a?(Array)
|
97
|
+
node = new_child_and_node[1]
|
98
|
+
end
|
96
99
|
end
|
97
100
|
end
|
98
101
|
@visitors.any? && end_visit(node, parent)
|
99
|
-
|
102
|
+
[node, parent]
|
100
103
|
end
|
101
104
|
end
|
102
105
|
|
@@ -155,20 +158,26 @@ module GraphQL
|
|
155
158
|
# copy `parent` so that it contains the copy of that node as a child,
|
156
159
|
# then return the copies
|
157
160
|
def on_node_with_modifications(node, parent)
|
158
|
-
|
159
|
-
if
|
160
|
-
|
161
|
-
new_parent =
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
161
|
+
new_node_and_new_parent = visit_node(node, parent)
|
162
|
+
if new_node_and_new_parent.is_a?(Array)
|
163
|
+
new_node = new_node_and_new_parent[0]
|
164
|
+
new_parent = new_node_and_new_parent[1]
|
165
|
+
if new_node.is_a?(Nodes::AbstractNode) && !node.equal?(new_node)
|
166
|
+
# The user-provided hook returned a new node.
|
167
|
+
new_parent = new_parent && new_parent.replace_child(node, new_node)
|
168
|
+
return new_node, new_parent
|
169
|
+
elsif new_node == DELETE_NODE
|
170
|
+
# The user-provided hook requested to remove this node
|
171
|
+
new_parent = new_parent && new_parent.delete_child(node)
|
172
|
+
return nil, new_parent
|
173
|
+
else
|
174
|
+
new_node_and_new_parent
|
175
|
+
end
|
167
176
|
else
|
168
177
|
# The user-provided hook didn't make any modifications.
|
169
178
|
# In fact, the hook might have returned who-knows-what, so
|
170
179
|
# ignore the return value and use the original values.
|
171
|
-
|
180
|
+
[node, parent]
|
172
181
|
end
|
173
182
|
end
|
174
183
|
|
data/lib/graphql/query.rb
CHANGED
@@ -135,10 +135,23 @@ module GraphQL
|
|
135
135
|
end
|
136
136
|
end
|
137
137
|
|
138
|
+
def_delegators :@schema, :interpreter?
|
139
|
+
|
138
140
|
def subscription_update?
|
139
141
|
@subscription_topic && subscription?
|
140
142
|
end
|
141
143
|
|
144
|
+
# A lookahead for the root selections of this query
|
145
|
+
# @return [GraphQL::Execution::Lookahead]
|
146
|
+
def lookahead
|
147
|
+
@lookahead ||= begin
|
148
|
+
ast_node = selected_operation
|
149
|
+
root_type = warden.root_type_for_operation(ast_node.operation_type || "query")
|
150
|
+
root_type = root_type.metadata[:type_class] || raise("Invariant: `lookahead` only works with class-based types")
|
151
|
+
GraphQL::Execution::Lookahead.new(query: self, root_type: root_type, ast_nodes: [ast_node])
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
142
155
|
# @api private
|
143
156
|
def result_values=(result_hash)
|
144
157
|
if @executed
|
@@ -6,6 +6,7 @@ module GraphQL
|
|
6
6
|
# {Arguments} recursively wraps the input in {Arguments} instances.
|
7
7
|
class Arguments
|
8
8
|
extend Forwardable
|
9
|
+
include GraphQL::Dig
|
9
10
|
|
10
11
|
def self.construct_arguments_class(argument_owner)
|
11
12
|
argument_definitions = argument_owner.arguments
|
@@ -40,7 +41,7 @@ module GraphQL
|
|
40
41
|
def initialize(values, context:, defaults_used:)
|
41
42
|
@argument_values = values.inject({}) do |memo, (inner_key, inner_value)|
|
42
43
|
arg_name = inner_key.to_s
|
43
|
-
arg_defn = self.class.argument_definitions[arg_name]
|
44
|
+
arg_defn = self.class.argument_definitions[arg_name] || raise("Not found #{arg_name} among #{self.class.argument_definitions.keys}")
|
44
45
|
arg_default_used = defaults_used.include?(arg_name)
|
45
46
|
arg_value = wrap_value(inner_value, arg_defn.type, context)
|
46
47
|
string_key = arg_defn.expose_as
|
@@ -7,7 +7,7 @@ module GraphQL
|
|
7
7
|
# It delegates `[]` to the hash that's passed to `GraphQL::Query#initialize`.
|
8
8
|
class Context
|
9
9
|
module SharedMethods
|
10
|
-
# @return [Object] The target for field
|
10
|
+
# @return [Object] The target for field resolution
|
11
11
|
attr_accessor :object
|
12
12
|
|
13
13
|
# @return [Hash, Array, String, Integer, Float, Boolean, nil] The resolved value for this field
|
@@ -155,13 +155,6 @@ module GraphQL
|
|
155
155
|
@path = []
|
156
156
|
@value = nil
|
157
157
|
@context = self # for SharedMethods
|
158
|
-
# The interpreter will set this
|
159
|
-
@interpreter = nil
|
160
|
-
end
|
161
|
-
|
162
|
-
# @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
|
163
|
-
def interpreter?
|
164
|
-
@interpreter
|
165
158
|
end
|
166
159
|
|
167
160
|
# @api private
|
@@ -170,8 +163,8 @@ module GraphQL
|
|
170
163
|
# @api private
|
171
164
|
attr_writer :value
|
172
165
|
|
173
|
-
def_delegators :@provided_values, :[], :[]=, :to_h, :key?, :fetch, :dig
|
174
|
-
def_delegators :@query, :trace
|
166
|
+
def_delegators :@provided_values, :[], :[]=, :to_h, :to_hash, :key?, :fetch, :dig
|
167
|
+
def_delegators :@query, :trace, :interpreter?
|
175
168
|
|
176
169
|
# @!method [](key)
|
177
170
|
# Lookup `key` from the hash passed to {Schema#execute} as `context:`
|
@@ -12,7 +12,7 @@ module GraphQL
|
|
12
12
|
@query = query
|
13
13
|
end
|
14
14
|
|
15
|
-
#
|
15
|
+
# Evaluate {operation_name} on {query}.
|
16
16
|
# Handle {GraphQL::ExecutionError}s by putting them in the "errors" key.
|
17
17
|
# @return [Hash] A GraphQL response, with either a "data" key or an "errors" key
|
18
18
|
def result
|
@@ -36,7 +36,7 @@ module GraphQL
|
|
36
36
|
@valid
|
37
37
|
end
|
38
38
|
|
39
|
-
# @return [Array<GraphQL::StaticValidation::
|
39
|
+
# @return [Array<GraphQL::StaticValidation::Error >] Static validation errors for the query string
|
40
40
|
def validation_errors
|
41
41
|
ensure_has_validated
|
42
42
|
@validation_errors
|
@@ -124,7 +124,7 @@ module GraphQL
|
|
124
124
|
# If a relation contains a `.group` clause, a `.count` will return a Hash.
|
125
125
|
def relation_count(relation)
|
126
126
|
count_or_hash = if(defined?(ActiveRecord::Relation) && relation.is_a?(ActiveRecord::Relation))
|
127
|
-
relation.count(:all)
|
127
|
+
relation.respond_to?(:unscope)? relation.unscope(:order).count(:all) : relation.count(:all)
|
128
128
|
else # eg, Sequel::Dataset, don't mess up others
|
129
129
|
relation.count
|
130
130
|
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -33,6 +33,11 @@ require "graphql/schema/interface"
|
|
33
33
|
require "graphql/schema/scalar"
|
34
34
|
require "graphql/schema/object"
|
35
35
|
require "graphql/schema/union"
|
36
|
+
require "graphql/schema/directive"
|
37
|
+
require "graphql/schema/directive/include"
|
38
|
+
require "graphql/schema/directive/skip"
|
39
|
+
require "graphql/schema/directive/feature"
|
40
|
+
require "graphql/schema/directive/transform"
|
36
41
|
|
37
42
|
require "graphql/schema/resolver"
|
38
43
|
require "graphql/schema/mutation"
|
@@ -79,11 +84,13 @@ module GraphQL
|
|
79
84
|
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
80
85
|
:max_depth, :max_complexity, :default_max_page_size,
|
81
86
|
:orphan_types, :resolve_type, :type_error, :parse_error,
|
87
|
+
:error_bubbling,
|
82
88
|
:raise_definition_error,
|
83
89
|
:object_from_id, :id_from_object,
|
84
90
|
:default_mask,
|
85
91
|
:cursor_encoder,
|
86
92
|
directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.name] = d; m } },
|
93
|
+
directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
|
87
94
|
instrument: ->(schema, type, instrumenter, after_built_ins: false) {
|
88
95
|
if type == :field && after_built_ins
|
89
96
|
type = :field_after_built_ins
|
@@ -114,6 +121,9 @@ module GraphQL
|
|
114
121
|
:introspection_namespace,
|
115
122
|
:analysis_engine
|
116
123
|
|
124
|
+
# [Boolean] True if this object bubbles validation errors up from a field into its parent InputObject, if there is one.
|
125
|
+
attr_accessor :error_bubbling
|
126
|
+
|
117
127
|
# Single, long-lived instance of the provided subscriptions class, if there is one.
|
118
128
|
# @return [GraphQL::Subscriptions]
|
119
129
|
attr_accessor :subscriptions
|
@@ -141,7 +151,6 @@ module GraphQL
|
|
141
151
|
# @see {Query#tracers} for query-specific tracers
|
142
152
|
attr_reader :tracers
|
143
153
|
|
144
|
-
DIRECTIVES = [GraphQL::Directive::IncludeDirective, GraphQL::Directive::SkipDirective, GraphQL::Directive::DeprecatedDirective]
|
145
154
|
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"]
|
146
155
|
|
147
156
|
attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
|
@@ -150,7 +159,7 @@ module GraphQL
|
|
150
159
|
@tracers = []
|
151
160
|
@definition_error = nil
|
152
161
|
@orphan_types = []
|
153
|
-
@directives =
|
162
|
+
@directives = self.class.default_directives
|
154
163
|
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
155
164
|
@middleware = MiddlewareChain.new(final_step: GraphQL::Execution::Execute::FieldResolveStep)
|
156
165
|
@query_analyzers = []
|
@@ -174,8 +183,18 @@ module GraphQL
|
|
174
183
|
@context_class = GraphQL::Query::Context
|
175
184
|
@introspection_namespace = nil
|
176
185
|
@introspection_system = nil
|
186
|
+
@interpeter = false
|
187
|
+
@error_bubbling = true
|
188
|
+
end
|
189
|
+
|
190
|
+
# @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
|
191
|
+
def interpreter?
|
192
|
+
@interpreter
|
177
193
|
end
|
178
194
|
|
195
|
+
# @api private
|
196
|
+
attr_writer :interpreter
|
197
|
+
|
179
198
|
def inspect
|
180
199
|
"#<#{self.class.name} ...>"
|
181
200
|
end
|
@@ -225,7 +244,7 @@ module GraphQL
|
|
225
244
|
|
226
245
|
# Validate a query string according to this schema.
|
227
246
|
# @param string_or_document [String, GraphQL::Language::Nodes::Document]
|
228
|
-
# @return [Array<GraphQL::StaticValidation::
|
247
|
+
# @return [Array<GraphQL::StaticValidation::Error >]
|
229
248
|
def validate(string_or_document, rules: nil)
|
230
249
|
doc = if string_or_document.is_a?(String)
|
231
250
|
GraphQL.parse(string_or_document)
|
@@ -556,7 +575,8 @@ module GraphQL
|
|
556
575
|
|
557
576
|
# Can't delegate to `class`
|
558
577
|
alias :_schema_class :class
|
559
|
-
def_delegators :_schema_class, :visible?, :accessible?, :authorized?, :unauthorized_object, :inaccessible_fields
|
578
|
+
def_delegators :_schema_class, :visible?, :accessible?, :authorized?, :unauthorized_object, :unauthorized_field, :inaccessible_fields
|
579
|
+
def_delegators :_schema_class, :directive
|
560
580
|
|
561
581
|
# A function to call when {#execute} receives an invalid query string
|
562
582
|
#
|
@@ -673,8 +693,9 @@ module GraphQL
|
|
673
693
|
:execution_strategy_for_operation,
|
674
694
|
:validate, :multiplex_analyzers, :lazy?, :lazy_method_name, :after_lazy, :sync_lazy,
|
675
695
|
# Configuration
|
676
|
-
:analysis_engine, :analysis_engine=, :using_ast_analysis?,
|
696
|
+
:analysis_engine, :analysis_engine=, :using_ast_analysis?, :interpreter?,
|
677
697
|
:max_complexity=, :max_depth=,
|
698
|
+
:error_bubbling=,
|
678
699
|
:metadata,
|
679
700
|
:default_mask,
|
680
701
|
:default_filter, :redefine,
|
@@ -708,10 +729,14 @@ module GraphQL
|
|
708
729
|
schema_defn.mutation = mutation
|
709
730
|
schema_defn.subscription = subscription
|
710
731
|
schema_defn.max_complexity = max_complexity
|
732
|
+
schema_defn.error_bubbling = error_bubbling
|
711
733
|
schema_defn.max_depth = max_depth
|
712
734
|
schema_defn.default_max_page_size = default_max_page_size
|
713
735
|
schema_defn.orphan_types = orphan_types
|
714
|
-
|
736
|
+
|
737
|
+
prepped_dirs = {}
|
738
|
+
directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
|
739
|
+
schema_defn.directives = prepped_dirs
|
715
740
|
schema_defn.introspection_namespace = introspection
|
716
741
|
schema_defn.resolve_type = method(:resolve_type)
|
717
742
|
schema_defn.object_from_id = method(:object_from_id)
|
@@ -842,6 +867,14 @@ module GraphQL
|
|
842
867
|
end
|
843
868
|
end
|
844
869
|
|
870
|
+
def error_bubbling(new_error_bubbling = nil)
|
871
|
+
if !new_error_bubbling.nil?
|
872
|
+
@error_bubbling = new_error_bubbling
|
873
|
+
else
|
874
|
+
@error_bubbling
|
875
|
+
end
|
876
|
+
end
|
877
|
+
|
845
878
|
def max_depth(new_max_depth = nil)
|
846
879
|
if new_max_depth
|
847
880
|
@max_depth = new_max_depth
|
@@ -874,9 +907,11 @@ module GraphQL
|
|
874
907
|
end
|
875
908
|
end
|
876
909
|
|
877
|
-
def rescue_from(
|
910
|
+
def rescue_from(*err_classes, &handler_block)
|
878
911
|
@rescues ||= {}
|
879
|
-
|
912
|
+
err_classes.each do |err_class|
|
913
|
+
@rescues[err_class] = handler_block
|
914
|
+
end
|
880
915
|
end
|
881
916
|
|
882
917
|
def resolve_type(type, obj, ctx)
|
@@ -918,7 +953,7 @@ module GraphQL
|
|
918
953
|
# By default, this hook just replaces the unauthorized object with `nil`.
|
919
954
|
#
|
920
955
|
# Whatever value is returned from this method will be used instead of the
|
921
|
-
# unauthorized object (accessible
|
956
|
+
# unauthorized object (accessible as `unauthorized_error.object`). If an
|
922
957
|
# error is raised, then `nil` will be used.
|
923
958
|
#
|
924
959
|
# If you want to add an error to the `"errors"` key, raise a {GraphQL::ExecutionError}
|
@@ -930,6 +965,22 @@ module GraphQL
|
|
930
965
|
nil
|
931
966
|
end
|
932
967
|
|
968
|
+
# This hook is called when a field fails an `authorized?` check.
|
969
|
+
#
|
970
|
+
# By default, this hook implements the same behavior as unauthorized_object.
|
971
|
+
#
|
972
|
+
# Whatever value is returned from this method will be used instead of the
|
973
|
+
# unauthorized field . If an error is raised, then `nil` will be used.
|
974
|
+
#
|
975
|
+
# If you want to add an error to the `"errors"` key, raise a {GraphQL::ExecutionError}
|
976
|
+
# in this hook.
|
977
|
+
#
|
978
|
+
# @param unauthorized_error [GraphQL::UnauthorizedFieldError]
|
979
|
+
# @return [Field] The returned field will be put in the GraphQL response
|
980
|
+
def unauthorized_field(unauthorized_error)
|
981
|
+
unauthorized_object(unauthorized_error)
|
982
|
+
end
|
983
|
+
|
933
984
|
def type_error(type_err, ctx)
|
934
985
|
DefaultTypeError.call(type_err, ctx)
|
935
986
|
end
|
@@ -952,7 +1003,19 @@ module GraphQL
|
|
952
1003
|
@directives = new_directives.reduce({}) { |m, d| m[d.name] = d; m }
|
953
1004
|
end
|
954
1005
|
|
955
|
-
@directives ||=
|
1006
|
+
@directives ||= default_directives
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
def directive(new_directive)
|
1010
|
+
directives[new_directive.graphql_name] = new_directive
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
def default_directives
|
1014
|
+
{
|
1015
|
+
"include" => GraphQL::Directive::IncludeDirective,
|
1016
|
+
"skip" => GraphQL::Directive::SkipDirective,
|
1017
|
+
"deprecated" => GraphQL::Directive::DeprecatedDirective,
|
1018
|
+
}
|
956
1019
|
end
|
957
1020
|
|
958
1021
|
def tracer(new_tracer)
|
@@ -1067,7 +1130,14 @@ module GraphQL
|
|
1067
1130
|
# @param ctx [GraphQL::Query::Context] the context for this query
|
1068
1131
|
# @return [Object] A GraphQL-ready (non-lazy) object
|
1069
1132
|
def self.sync_lazy(value)
|
1070
|
-
|
1133
|
+
if block_given?
|
1134
|
+
# This was already hit by the instance, just give it back
|
1135
|
+
yield(value)
|
1136
|
+
else
|
1137
|
+
# This was called directly on the class, hit the instance
|
1138
|
+
# which has the lazy method map
|
1139
|
+
self.graphql_definition.sync_lazy(value)
|
1140
|
+
end
|
1071
1141
|
end
|
1072
1142
|
|
1073
1143
|
# @see Schema.sync_lazy for a hook to override
|
@@ -28,7 +28,7 @@ module GraphQL
|
|
28
28
|
# @param description [String]
|
29
29
|
# @param default_value [Object]
|
30
30
|
# @param as [Symbol] Override the keyword name when passed to a method
|
31
|
-
# @param prepare [Symbol] A method to call to
|
31
|
+
# @param prepare [Symbol] A method to call to transform this argument's valuebefore sending it to field resolution
|
32
32
|
# @param camelize [Boolean] if true, the name will be camelized when building the schema
|
33
33
|
def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, description: nil, default_value: NO_DEFAULT, as: nil, camelize: true, prepare: nil, owner:, &definition_block)
|
34
34
|
arg_name ||= name
|
@@ -64,9 +64,7 @@ module GraphQL
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
GraphQL::Schema
|
68
|
-
directives[built_in_directive.name] = built_in_directive unless directives[built_in_directive.name]
|
69
|
-
end
|
67
|
+
directives = GraphQL::Schema.default_directives.merge(directives)
|
70
68
|
|
71
69
|
if schema_definition
|
72
70
|
if schema_definition.query
|
@@ -113,7 +111,7 @@ module GraphQL
|
|
113
111
|
end
|
114
112
|
|
115
113
|
NullResolveType = ->(type, obj, ctx) {
|
116
|
-
raise(NotImplementedError, "Generated Schema cannot use Interface or Union types for execution.")
|
114
|
+
raise(NotImplementedError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
|
117
115
|
}
|
118
116
|
|
119
117
|
NullScalarCoerce = ->(val, _ctx) { val }
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Schema
|
5
|
+
# Subclasses of this can influence how {GraphQL::Execution::Interpreter} runs queries.
|
6
|
+
#
|
7
|
+
# - {.include?}: if it returns `false`, the field or fragment will be skipped altogether, as if it were absent
|
8
|
+
# - {.resolve}: Wraps field resolution (so it should call `yield` to continue)
|
9
|
+
class Directive < GraphQL::Schema::Member
|
10
|
+
extend GraphQL::Schema::Member::HasArguments
|
11
|
+
class << self
|
12
|
+
def default_graphql_name
|
13
|
+
super.downcase
|
14
|
+
end
|
15
|
+
|
16
|
+
def locations(*new_locations)
|
17
|
+
if new_locations.any?
|
18
|
+
@locations = new_locations
|
19
|
+
else
|
20
|
+
@locations ||= (superclass.respond_to?(:locations) ? superclass.locations : [])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_directive(new_default_directive = nil)
|
25
|
+
if new_default_directive != nil
|
26
|
+
@default_directive = new_default_directive
|
27
|
+
elsif @default_directive.nil?
|
28
|
+
@default_directive = (superclass.respond_to?(:default_directive) ? superclass.default_directive : false)
|
29
|
+
else
|
30
|
+
@default_directive
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_graphql
|
35
|
+
defn = GraphQL::Directive.new
|
36
|
+
defn.name = self.graphql_name
|
37
|
+
defn.description = self.description
|
38
|
+
defn.locations = self.locations
|
39
|
+
defn.default_directive = self.default_directive
|
40
|
+
defn.metadata[:type_class] = self
|
41
|
+
arguments.each do |name, arg_defn|
|
42
|
+
arg_graphql = arg_defn.to_graphql
|
43
|
+
defn.arguments[arg_graphql.name] = arg_graphql
|
44
|
+
end
|
45
|
+
defn
|
46
|
+
end
|
47
|
+
|
48
|
+
# If false, this part of the query won't be evaluated
|
49
|
+
def include?(_object, _arguments, _context)
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
# Continuing is passed as a block; `yield` to continue
|
54
|
+
def resolve(object, arguments, context)
|
55
|
+
yield
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
LOCATIONS = [
|
60
|
+
QUERY = :QUERY,
|
61
|
+
MUTATION = :MUTATION,
|
62
|
+
SUBSCRIPTION = :SUBSCRIPTION,
|
63
|
+
FIELD = :FIELD,
|
64
|
+
FRAGMENT_DEFINITION = :FRAGMENT_DEFINITION,
|
65
|
+
FRAGMENT_SPREAD = :FRAGMENT_SPREAD,
|
66
|
+
INLINE_FRAGMENT = :INLINE_FRAGMENT,
|
67
|
+
SCHEMA = :SCHEMA,
|
68
|
+
SCALAR = :SCALAR,
|
69
|
+
OBJECT = :OBJECT,
|
70
|
+
FIELD_DEFINITION = :FIELD_DEFINITION,
|
71
|
+
ARGUMENT_DEFINITION = :ARGUMENT_DEFINITION,
|
72
|
+
INTERFACE = :INTERFACE,
|
73
|
+
UNION = :UNION,
|
74
|
+
ENUM = :ENUM,
|
75
|
+
ENUM_VALUE = :ENUM_VALUE,
|
76
|
+
INPUT_OBJECT = :INPUT_OBJECT,
|
77
|
+
INPUT_FIELD_DEFINITION = :INPUT_FIELD_DEFINITION,
|
78
|
+
]
|
79
|
+
|
80
|
+
DEFAULT_DEPRECATION_REASON = 'No longer supported'
|
81
|
+
LOCATION_DESCRIPTIONS = {
|
82
|
+
QUERY: 'Location adjacent to a query operation.',
|
83
|
+
MUTATION: 'Location adjacent to a mutation operation.',
|
84
|
+
SUBSCRIPTION: 'Location adjacent to a subscription operation.',
|
85
|
+
FIELD: 'Location adjacent to a field.',
|
86
|
+
FRAGMENT_DEFINITION: 'Location adjacent to a fragment definition.',
|
87
|
+
FRAGMENT_SPREAD: 'Location adjacent to a fragment spread.',
|
88
|
+
INLINE_FRAGMENT: 'Location adjacent to an inline fragment.',
|
89
|
+
SCHEMA: 'Location adjacent to a schema definition.',
|
90
|
+
SCALAR: 'Location adjacent to a scalar definition.',
|
91
|
+
OBJECT: 'Location adjacent to an object type definition.',
|
92
|
+
FIELD_DEFINITION: 'Location adjacent to a field definition.',
|
93
|
+
ARGUMENT_DEFINITION: 'Location adjacent to an argument definition.',
|
94
|
+
INTERFACE: 'Location adjacent to an interface definition.',
|
95
|
+
UNION: 'Location adjacent to a union definition.',
|
96
|
+
ENUM: 'Location adjacent to an enum definition.',
|
97
|
+
ENUM_VALUE: 'Location adjacent to an enum value definition.',
|
98
|
+
INPUT_OBJECT: 'Location adjacent to an input object type definition.',
|
99
|
+
INPUT_FIELD_DEFINITION: 'Location adjacent to an input object field definition.',
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|