graphql 1.9.0.pre1 → 1.9.0.pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|