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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7576d86b005acda0b6db32b531eb5ee5994b46d5
|
4
|
+
data.tar.gz: 5d27e5a79e0b2ab1d8c64edd8aa4ed5bc66b72e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 001ec87271eaefae504d24deac1c3b6d241f1b944b2297050e3d35a8a72c6a016ec9dd6a48f3c1bdef1ab5f9eb6aac2f5f31ca745bfdf9edb077abbc6f8158d7
|
7
|
+
data.tar.gz: fafac00586652e70e096f68a92dd20bcf712e09343d721638987f3ba8d69e77250fd25de5743ca521687c1a22a8df5355b4f7b84f500ff898446c29fe08e4bed
|
data/lib/graphql.rb
CHANGED
@@ -60,13 +60,15 @@ require "graphql/type_kinds"
|
|
60
60
|
require "graphql/backwards_compatibility"
|
61
61
|
require "graphql/scalar_type"
|
62
62
|
|
63
|
-
require "graphql/directive"
|
64
63
|
require "graphql/name_validator"
|
65
64
|
|
66
65
|
require "graphql/language"
|
67
66
|
require "graphql/analysis"
|
68
67
|
require "graphql/tracing"
|
68
|
+
require "graphql/execution"
|
69
|
+
require "graphql/dig"
|
69
70
|
require "graphql/schema"
|
71
|
+
require "graphql/directive"
|
70
72
|
require "graphql/execution"
|
71
73
|
require "graphql/types"
|
72
74
|
require "graphql/relay"
|
@@ -82,6 +84,7 @@ require "graphql/introspection"
|
|
82
84
|
|
83
85
|
require "graphql/analysis_error"
|
84
86
|
require "graphql/coercion_error"
|
87
|
+
require "graphql/literal_validation_error"
|
85
88
|
require "graphql/runtime_type_error"
|
86
89
|
require "graphql/invalid_null_error"
|
87
90
|
require "graphql/invalid_name_error"
|
@@ -101,3 +104,4 @@ require "graphql/backtrace"
|
|
101
104
|
require "graphql/deprecated_dsl"
|
102
105
|
require "graphql/authorization"
|
103
106
|
require "graphql/unauthorized_error"
|
107
|
+
require "graphql/unauthorized_field_error"
|
@@ -25,7 +25,7 @@ module GraphQL
|
|
25
25
|
raise NotImplementedError
|
26
26
|
end
|
27
27
|
|
28
|
-
# Don't use make_visit_method
|
28
|
+
# Don't use make_visit_method because it breaks `super`
|
29
29
|
def self.build_visitor_hooks(member_name)
|
30
30
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
31
31
|
def on_enter_#{member_name}(node, parent, visitor)
|
@@ -81,7 +81,7 @@ module GraphQL
|
|
81
81
|
|
82
82
|
def on_inline_fragment(node, parent)
|
83
83
|
on_fragment_with_type(node) do
|
84
|
-
@path.push("...#{node.type ? " on #{node.type.
|
84
|
+
@path.push("...#{node.type ? " on #{node.type.name}" : ""}")
|
85
85
|
call_analyzers(:on_enter_inline_fragment, node, parent)
|
86
86
|
super
|
87
87
|
call_analyzers(:on_leave_inline_fragment, node, parent)
|
@@ -203,6 +203,11 @@ module GraphQL
|
|
203
203
|
@field_definitions.last
|
204
204
|
end
|
205
205
|
|
206
|
+
# @return [GraphQL::Field, nil] The GraphQL field which returned the object that the current field belongs to
|
207
|
+
def previous_field_definition
|
208
|
+
@field_definitions[-2]
|
209
|
+
end
|
210
|
+
|
206
211
|
# @return [GraphQL::Directive, nil] The most-recently-entered GraphQL::Directive, if currently inside one
|
207
212
|
def directive_definition
|
208
213
|
@directive_definitions.last
|
data/lib/graphql/dig.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module Dig
|
4
|
+
# implemented using the old activesupport #dig instead of the ruby built-in
|
5
|
+
# so we can use some of the magic in Schema::InputObject and Query::Arguments
|
6
|
+
# to handle stringified/symbolized keys.
|
7
|
+
#
|
8
|
+
# @param args [Array<[String, Symbol>] Retrieves the value object corresponding to the each key objects repeatedly
|
9
|
+
# @return [Object]
|
10
|
+
def dig(own_key, *rest_keys)
|
11
|
+
val = self[own_key]
|
12
|
+
if val.nil? || rest_keys.empty?
|
13
|
+
val
|
14
|
+
else
|
15
|
+
val.dig(*rest_keys)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/graphql/directive.rb
CHANGED
@@ -14,7 +14,15 @@ module GraphQL
|
|
14
14
|
attr_accessor :ast_node
|
15
15
|
# @api private
|
16
16
|
attr_writer :default_directive
|
17
|
-
ensure_defined(:locations, :arguments, :name, :description, :default_directive?)
|
17
|
+
ensure_defined(:locations, :arguments, :graphql_name, :name, :description, :default_directive?)
|
18
|
+
|
19
|
+
# Future-compatible alias
|
20
|
+
# @see {GraphQL::SchemaMember}
|
21
|
+
alias :graphql_name :name
|
22
|
+
|
23
|
+
# Future-compatible alias
|
24
|
+
# @see {GraphQL::SchemaMember}
|
25
|
+
alias :graphql_definition :itself
|
18
26
|
|
19
27
|
LOCATIONS = [
|
20
28
|
QUERY = :QUERY,
|
@@ -84,6 +92,10 @@ module GraphQL
|
|
84
92
|
def default_directive?
|
85
93
|
@default_directive
|
86
94
|
end
|
95
|
+
|
96
|
+
def inspect
|
97
|
+
"#<GraphQL::Directive #{name}>"
|
98
|
+
end
|
87
99
|
end
|
88
100
|
end
|
89
101
|
|
@@ -1,8 +1,2 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
GraphQL::Directive::IncludeDirective = GraphQL::Directive.
|
3
|
-
name "include"
|
4
|
-
description "Directs the executor to include this field or fragment only when the `if` argument is true."
|
5
|
-
locations([GraphQL::Directive::FIELD, GraphQL::Directive::FRAGMENT_SPREAD, GraphQL::Directive::INLINE_FRAGMENT])
|
6
|
-
argument :if, !GraphQL::BOOLEAN_TYPE, 'Included when true.'
|
7
|
-
default_directive true
|
8
|
-
end
|
2
|
+
GraphQL::Directive::IncludeDirective = GraphQL::Schema::Directive::Include.graphql_definition
|
@@ -1,9 +1,2 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
GraphQL::Directive::SkipDirective = GraphQL::Directive.
|
3
|
-
name "skip"
|
4
|
-
description "Directs the executor to skip this field or fragment when the `if` argument is true."
|
5
|
-
locations([GraphQL::Directive::FIELD, GraphQL::Directive::FRAGMENT_SPREAD, GraphQL::Directive::INLINE_FRAGMENT])
|
6
|
-
|
7
|
-
argument :if, !GraphQL::BOOLEAN_TYPE, 'Skipped when true.'
|
8
|
-
default_directive true
|
9
|
-
end
|
2
|
+
GraphQL::Directive::SkipDirective = GraphQL::Schema::Directive::Skip.graphql_definition
|
@@ -2,13 +2,12 @@
|
|
2
2
|
require "graphql/execution/interpreter/execution_errors"
|
3
3
|
require "graphql/execution/interpreter/hash_response"
|
4
4
|
require "graphql/execution/interpreter/runtime"
|
5
|
+
require "graphql/execution/interpreter/resolve"
|
5
6
|
|
6
7
|
module GraphQL
|
7
8
|
module Execution
|
8
9
|
class Interpreter
|
9
10
|
def initialize
|
10
|
-
# A buffer shared by all queries running in this interpreter
|
11
|
-
@lazies = []
|
12
11
|
end
|
13
12
|
|
14
13
|
# Support `Executor` :S
|
@@ -19,9 +18,16 @@ module GraphQL
|
|
19
18
|
end
|
20
19
|
|
21
20
|
def self.use(schema_defn)
|
22
|
-
schema_defn.
|
23
|
-
|
24
|
-
schema_defn.
|
21
|
+
schema_defn.target.interpreter = true
|
22
|
+
# Reach through the legacy objects for the actual class defn
|
23
|
+
schema_class = schema_defn.target.class
|
24
|
+
# This is not good, since both of these are holding state now,
|
25
|
+
# we have to update both :(
|
26
|
+
[schema_class, schema_defn].each do |schema_config|
|
27
|
+
schema_config.query_execution_strategy(GraphQL::Execution::Interpreter)
|
28
|
+
schema_config.mutation_execution_strategy(GraphQL::Execution::Interpreter)
|
29
|
+
schema_config.subscription_execution_strategy(GraphQL::Execution::Interpreter)
|
30
|
+
end
|
25
31
|
end
|
26
32
|
|
27
33
|
def self.begin_multiplex(multiplex)
|
@@ -51,14 +57,14 @@ module GraphQL
|
|
51
57
|
}
|
52
58
|
end
|
53
59
|
|
60
|
+
# Run the eager part of `query`
|
61
|
+
# @return {Interpreter::Runtime}
|
54
62
|
def evaluate(query)
|
55
|
-
query.context.interpreter = true
|
56
63
|
# Although queries in a multiplex _share_ an Interpreter instance,
|
57
64
|
# they also have another item of state, which is private to that query
|
58
65
|
# in particular, assign it here:
|
59
66
|
runtime = Runtime.new(
|
60
67
|
query: query,
|
61
|
-
lazies: @lazies,
|
62
68
|
response: HashResponse.new,
|
63
69
|
)
|
64
70
|
query.context.namespace(:interpreter)[:runtime] = runtime
|
@@ -70,18 +76,22 @@ module GraphQL
|
|
70
76
|
runtime
|
71
77
|
end
|
72
78
|
|
79
|
+
# Run the lazy part of `query` or `multiplex`.
|
80
|
+
# @return [void]
|
73
81
|
def sync_lazies(query: nil, multiplex: nil)
|
74
82
|
tracer = query || multiplex
|
75
83
|
if query.nil? && multiplex.queries.length == 1
|
76
84
|
query = multiplex.queries[0]
|
77
85
|
end
|
86
|
+
queries = multiplex ? multiplex.queries : [query]
|
87
|
+
final_values = queries.map do |query|
|
88
|
+
runtime = query.context.namespace(:interpreter)[:runtime]
|
89
|
+
# it might not be present if the query has an error
|
90
|
+
runtime ? runtime.final_value : nil
|
91
|
+
end
|
92
|
+
final_values.compact!
|
78
93
|
tracer.trace("execute_query_lazy", {multiplex: multiplex, query: query}) do
|
79
|
-
|
80
|
-
next_wave = @lazies.dup
|
81
|
-
@lazies.clear
|
82
|
-
# This will cause a side-effect with `.write(...)`
|
83
|
-
next_wave.each(&:value)
|
84
|
-
end
|
94
|
+
Interpreter::Resolve.resolve_all(final_values)
|
85
95
|
end
|
86
96
|
end
|
87
97
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Execution
|
5
|
+
class Interpreter
|
6
|
+
module Resolve
|
7
|
+
def self.resolve_all(results)
|
8
|
+
while results.any?
|
9
|
+
results = resolve(results)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# After getting `results` back from an interpreter evaluation,
|
14
|
+
# continue it until you get a response-ready Ruby value.
|
15
|
+
#
|
16
|
+
# `results` is one level of _depth_ of a query or multiplex.
|
17
|
+
#
|
18
|
+
# Resolve all lazy values in that depth before moving on
|
19
|
+
# to the next level.
|
20
|
+
#
|
21
|
+
# It's assumed that the lazies will
|
22
|
+
# return {Lazy} instances if there's more work to be done,
|
23
|
+
# or return {Hash}/{Array} if the query should be continued.
|
24
|
+
#
|
25
|
+
# @param results [Array]
|
26
|
+
# @return [Array] Same size, filled with finished values
|
27
|
+
def self.resolve(results)
|
28
|
+
next_results = []
|
29
|
+
|
30
|
+
# Work through the queue until it's empty
|
31
|
+
while results.size > 0
|
32
|
+
result_value = results.shift
|
33
|
+
|
34
|
+
if result_value.is_a?(Lazy)
|
35
|
+
result_value = result_value.value
|
36
|
+
end
|
37
|
+
|
38
|
+
if result_value.is_a?(Lazy)
|
39
|
+
# Since this field returned another lazy,
|
40
|
+
# add it to the same queue
|
41
|
+
results << result_value
|
42
|
+
elsif result_value.is_a?(Hash)
|
43
|
+
# This is part of the next level, add it
|
44
|
+
next_results.concat(result_value.values)
|
45
|
+
elsif result_value.is_a?(Array)
|
46
|
+
# This is part of the next level, add it
|
47
|
+
next_results.concat(result_value)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
next_results
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -5,6 +5,8 @@ module GraphQL
|
|
5
5
|
class Interpreter
|
6
6
|
# I think it would be even better if we could somehow make
|
7
7
|
# `continue_field` not recursive. "Trampolining" it somehow.
|
8
|
+
#
|
9
|
+
# @api private
|
8
10
|
class Runtime
|
9
11
|
# @return [GraphQL::Query]
|
10
12
|
attr_reader :query
|
@@ -15,14 +17,18 @@ module GraphQL
|
|
15
17
|
# @return [GraphQL::Query::Context]
|
16
18
|
attr_reader :context
|
17
19
|
|
18
|
-
def initialize(query:,
|
20
|
+
def initialize(query:, response:)
|
19
21
|
@query = query
|
20
22
|
@schema = query.schema
|
21
23
|
@context = query.context
|
22
|
-
@
|
24
|
+
@interpreter_context = @context.namespace(:interpreter)
|
23
25
|
@response = response
|
24
26
|
@dead_paths = {}
|
25
27
|
@types_at_paths = {}
|
28
|
+
# A cache of { Class => { String => Schema::Field } }
|
29
|
+
# Which assumes that MyObject.get_field("myField") will return the same field
|
30
|
+
# during the lifetime of a query
|
31
|
+
@fields_cache = Hash.new { |h, k| h[k] = {} }
|
26
32
|
end
|
27
33
|
|
28
34
|
def final_value
|
@@ -34,7 +40,7 @@ module GraphQL
|
|
34
40
|
end
|
35
41
|
|
36
42
|
# This _begins_ the execution. Some deferred work
|
37
|
-
# might be stored up in
|
43
|
+
# might be stored up in lazies.
|
38
44
|
# @return [void]
|
39
45
|
def run_eager
|
40
46
|
root_operation = query.selected_operation
|
@@ -42,44 +48,59 @@ module GraphQL
|
|
42
48
|
legacy_root_type = schema.root_type_for_operation(root_op_type)
|
43
49
|
root_type = legacy_root_type.metadata[:type_class] || raise("Invariant: type must be class-based: #{legacy_root_type}")
|
44
50
|
object_proxy = root_type.authorized_new(query.root_value, context)
|
45
|
-
|
51
|
+
object_proxy = schema.sync_lazy(object_proxy)
|
46
52
|
path = []
|
47
53
|
evaluate_selections(path, object_proxy, root_type, root_operation.selections, root_operation_type: root_op_type)
|
54
|
+
nil
|
48
55
|
end
|
49
56
|
|
50
|
-
|
51
|
-
|
52
|
-
def gather_selections(owner_type, selections, selections_by_name)
|
57
|
+
def gather_selections(owner_object, owner_type, selections, selections_by_name)
|
53
58
|
selections.each do |node|
|
59
|
+
# Skip gathering this if the directive says so
|
60
|
+
if !directives_include?(node, owner_object, owner_type)
|
61
|
+
next
|
62
|
+
end
|
63
|
+
|
54
64
|
case node
|
55
65
|
when GraphQL::Language::Nodes::Field
|
56
|
-
|
57
|
-
|
58
|
-
|
66
|
+
response_key = node.alias || node.name
|
67
|
+
selections = selections_by_name[response_key]
|
68
|
+
# if there was already a selection of this field,
|
69
|
+
# use an array to hold all selections,
|
70
|
+
# otherise, use the single node to represent the selection
|
71
|
+
if selections
|
72
|
+
# This field was already selected at least once,
|
73
|
+
# add this node to the list of selections
|
74
|
+
s = Array(selections)
|
59
75
|
s << node
|
76
|
+
selections_by_name[response_key] = s
|
77
|
+
else
|
78
|
+
# No selection was found for this field yet
|
79
|
+
selections_by_name[response_key] = node
|
60
80
|
end
|
61
81
|
when GraphQL::Language::Nodes::InlineFragment
|
62
|
-
if
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
if include_fragmment
|
72
|
-
gather_selections(owner_type, node.selections, selections_by_name)
|
82
|
+
if node.type
|
83
|
+
type_defn = schema.types[node.type.name]
|
84
|
+
type_defn = type_defn.metadata[:type_class]
|
85
|
+
# Faster than .map{}.include?()
|
86
|
+
query.warden.possible_types(type_defn).each do |t|
|
87
|
+
if t.metadata[:type_class] == owner_type
|
88
|
+
gather_selections(owner_object, owner_type, node.selections, selections_by_name)
|
89
|
+
break
|
90
|
+
end
|
73
91
|
end
|
92
|
+
else
|
93
|
+
# it's an untyped fragment, definitely continue
|
94
|
+
gather_selections(owner_object, owner_type, node.selections, selections_by_name)
|
74
95
|
end
|
75
96
|
when GraphQL::Language::Nodes::FragmentSpread
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
97
|
+
fragment_def = query.fragments[node.name]
|
98
|
+
type_defn = schema.types[fragment_def.type.name]
|
99
|
+
type_defn = type_defn.metadata[:type_class]
|
100
|
+
schema.possible_types(type_defn).each do |t|
|
101
|
+
if t.metadata[:type_class] == owner_type
|
102
|
+
gather_selections(owner_object, owner_type, fragment_def.selections, selections_by_name)
|
103
|
+
break
|
83
104
|
end
|
84
105
|
end
|
85
106
|
else
|
@@ -90,11 +111,20 @@ module GraphQL
|
|
90
111
|
|
91
112
|
def evaluate_selections(path, owner_object, owner_type, selections, root_operation_type: nil)
|
92
113
|
selections_by_name = {}
|
93
|
-
gather_selections(owner_type, selections, selections_by_name)
|
94
|
-
selections_by_name.each do |result_name,
|
95
|
-
|
114
|
+
gather_selections(owner_object, owner_type, selections, selections_by_name)
|
115
|
+
selections_by_name.each do |result_name, field_ast_nodes_or_ast_node|
|
116
|
+
# As a performance optimization, the hash key will be a `Node` if
|
117
|
+
# there's only one selection of the field. But if there are multiple
|
118
|
+
# selections of the field, it will be an Array of nodes
|
119
|
+
if field_ast_nodes_or_ast_node.is_a?(Array)
|
120
|
+
field_ast_nodes = field_ast_nodes_or_ast_node
|
121
|
+
ast_node = field_ast_nodes.first
|
122
|
+
else
|
123
|
+
field_ast_nodes = nil
|
124
|
+
ast_node = field_ast_nodes_or_ast_node
|
125
|
+
end
|
96
126
|
field_name = ast_node.name
|
97
|
-
field_defn = owner_type.get_field(field_name)
|
127
|
+
field_defn = @fields_cache[owner_type][field_name] ||= owner_type.get_field(field_name)
|
98
128
|
is_introspection = false
|
99
129
|
if field_defn.nil?
|
100
130
|
field_defn = if owner_type == schema.query.metadata[:type_class] && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
|
@@ -118,6 +148,9 @@ module GraphQL
|
|
118
148
|
# the field's return type at this path in order
|
119
149
|
# to propagate `null`
|
120
150
|
set_type_at_path(next_path, return_type)
|
151
|
+
# Set this before calling `run_with_directives`, so that the directive can have the latest path
|
152
|
+
@interpreter_context[:current_path] = next_path
|
153
|
+
@interpreter_context[:current_field] = field_defn
|
121
154
|
|
122
155
|
object = owner_object
|
123
156
|
|
@@ -125,6 +158,7 @@ module GraphQL
|
|
125
158
|
object = field_defn.owner.authorized_new(object, context)
|
126
159
|
end
|
127
160
|
|
161
|
+
|
128
162
|
kwarg_arguments = arguments(object, field_defn, ast_node)
|
129
163
|
# It might turn out that making arguments for every field is slow.
|
130
164
|
# If we have to cache them, we'll need a more subtle approach here.
|
@@ -136,30 +170,47 @@ module GraphQL
|
|
136
170
|
kwarg_arguments[:execution_errors] = ExecutionErrors.new(context, ast_node, next_path)
|
137
171
|
when :path
|
138
172
|
kwarg_arguments[:path] = next_path
|
173
|
+
when :lookahead
|
174
|
+
if !field_ast_nodes
|
175
|
+
field_ast_nodes = [ast_node]
|
176
|
+
end
|
177
|
+
kwarg_arguments[:lookahead] = Execution::Lookahead.new(
|
178
|
+
query: query,
|
179
|
+
ast_nodes: field_ast_nodes,
|
180
|
+
field: field_defn,
|
181
|
+
)
|
139
182
|
else
|
140
183
|
kwarg_arguments[extra] = field_defn.fetch_extra(extra, context)
|
141
184
|
end
|
142
185
|
end
|
143
186
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
187
|
+
# Optimize for the case that field is selected only once
|
188
|
+
if field_ast_nodes.nil? || field_ast_nodes.size == 1
|
189
|
+
next_selections = ast_node.selections
|
190
|
+
else
|
191
|
+
next_selections = []
|
192
|
+
field_ast_nodes.each { |f| next_selections.concat(f.selections) }
|
148
193
|
end
|
149
194
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
195
|
+
resolve_with_directives(object, ast_node) do
|
196
|
+
# Actually call the field resolver and capture the result
|
197
|
+
app_result = query.trace("execute_field", {field: field_defn, path: next_path}) do
|
198
|
+
field_defn.resolve(object, kwarg_arguments, context)
|
199
|
+
end
|
200
|
+
after_lazy(app_result, field: field_defn, path: next_path, eager: root_operation_type == "mutation") do |inner_result|
|
201
|
+
continue_value = continue_value(next_path, inner_result, field_defn, return_type.non_null?, ast_node)
|
202
|
+
if HALT != continue_value
|
203
|
+
continue_field(next_path, continue_value, field_defn, return_type, ast_node, next_selections, false)
|
204
|
+
end
|
154
205
|
end
|
155
206
|
end
|
156
207
|
end
|
157
208
|
end
|
158
209
|
|
159
210
|
HALT = Object.new
|
160
|
-
def continue_value(path, value, field,
|
211
|
+
def continue_value(path, value, field, is_non_null, ast_node)
|
161
212
|
if value.nil?
|
162
|
-
if
|
213
|
+
if is_non_null
|
163
214
|
err = GraphQL::InvalidNullError.new(field.owner, field, value)
|
164
215
|
write_invalid_null_in_response(path, err)
|
165
216
|
else
|
@@ -187,7 +238,7 @@ module GraphQL
|
|
187
238
|
err
|
188
239
|
end
|
189
240
|
|
190
|
-
continue_value(path, next_value, field,
|
241
|
+
continue_value(path, next_value, field, is_non_null, ast_node)
|
191
242
|
elsif GraphQL::Execution::Execute::SKIP == value
|
192
243
|
HALT
|
193
244
|
else
|
@@ -195,11 +246,20 @@ module GraphQL
|
|
195
246
|
end
|
196
247
|
end
|
197
248
|
|
198
|
-
|
249
|
+
# The resolver for `field` returned `value`. Continue to execute the query,
|
250
|
+
# treating `value` as `type` (probably the return type of the field).
|
251
|
+
#
|
252
|
+
# Use `next_selections` to resolve object fields, if there are any.
|
253
|
+
#
|
254
|
+
# Location information from `path` and `ast_node`.
|
255
|
+
#
|
256
|
+
# @return [Lazy, Array, Hash, Object] Lazy, Array, and Hash are all traversed to resolve lazy values later
|
257
|
+
def continue_field(path, value, field, type, ast_node, next_selections, is_non_null)
|
199
258
|
case type.kind.name
|
200
259
|
when "SCALAR", "ENUM"
|
201
260
|
r = type.coerce_result(value, context)
|
202
261
|
write_in_response(path, r)
|
262
|
+
r
|
203
263
|
when "UNION", "INTERFACE"
|
204
264
|
resolved_type = query.resolve_type(type, value)
|
205
265
|
possible_types = query.possible_types(type)
|
@@ -209,9 +269,10 @@ module GraphQL
|
|
209
269
|
type_error = GraphQL::UnresolvedTypeError.new(value, field, parent_type, resolved_type, possible_types)
|
210
270
|
schema.type_error(type_error, context)
|
211
271
|
write_in_response(path, nil)
|
272
|
+
nil
|
212
273
|
else
|
213
274
|
resolved_type = resolved_type.metadata[:type_class]
|
214
|
-
continue_field(path, value, field, resolved_type, ast_node, next_selections)
|
275
|
+
continue_field(path, value, field, resolved_type, ast_node, next_selections, is_non_null)
|
215
276
|
end
|
216
277
|
when "OBJECT"
|
217
278
|
object_proxy = begin
|
@@ -220,49 +281,73 @@ module GraphQL
|
|
220
281
|
err
|
221
282
|
end
|
222
283
|
after_lazy(object_proxy, path: path, field: field) do |inner_object|
|
223
|
-
continue_value = continue_value(path, inner_object, field,
|
284
|
+
continue_value = continue_value(path, inner_object, field, is_non_null, ast_node)
|
224
285
|
if HALT != continue_value
|
225
|
-
|
286
|
+
response_hash = {}
|
287
|
+
write_in_response(path, response_hash)
|
226
288
|
evaluate_selections(path, continue_value, type, next_selections)
|
289
|
+
response_hash
|
227
290
|
end
|
228
291
|
end
|
229
292
|
when "LIST"
|
230
|
-
|
293
|
+
response_list = []
|
294
|
+
write_in_response(path, response_list)
|
231
295
|
inner_type = type.of_type
|
232
296
|
idx = 0
|
233
297
|
value.each do |inner_value|
|
234
298
|
next_path = path.dup
|
235
299
|
next_path << idx
|
236
300
|
next_path.freeze
|
301
|
+
idx += 1
|
237
302
|
set_type_at_path(next_path, inner_type)
|
303
|
+
# This will update `response_list` with the lazy
|
238
304
|
after_lazy(inner_value, path: next_path, field: field) do |inner_inner_value|
|
239
|
-
|
305
|
+
# reset `is_non_null` here and below, because the inner type will have its own nullability constraint
|
306
|
+
continue_value = continue_value(next_path, inner_inner_value, field, false, ast_node)
|
240
307
|
if HALT != continue_value
|
241
|
-
continue_field(next_path, continue_value, field, inner_type, ast_node, next_selections)
|
308
|
+
continue_field(next_path, continue_value, field, inner_type, ast_node, next_selections, false)
|
242
309
|
end
|
243
310
|
end
|
244
|
-
idx += 1
|
245
311
|
end
|
312
|
+
response_list
|
246
313
|
when "NON_NULL"
|
247
314
|
inner_type = type.of_type
|
248
315
|
# For fields like `__schema: __Schema!`
|
249
316
|
inner_type = resolve_if_late_bound_type(inner_type)
|
250
317
|
# Don't `set_type_at_path` because we want the static type,
|
251
318
|
# we're going to use that to determine whether a `nil` should be propagated or not.
|
252
|
-
continue_field(path, value, field, inner_type, ast_node, next_selections)
|
319
|
+
continue_field(path, value, field, inner_type, ast_node, next_selections, true)
|
253
320
|
else
|
254
321
|
raise "Invariant: Unhandled type kind #{type.kind} (#{type})"
|
255
322
|
end
|
256
323
|
end
|
257
324
|
|
258
|
-
def
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
325
|
+
def resolve_with_directives(object, ast_node)
|
326
|
+
run_directive(object, ast_node, 0) { yield }
|
327
|
+
end
|
328
|
+
|
329
|
+
def run_directive(object, ast_node, idx)
|
330
|
+
dir_node = ast_node.directives[idx]
|
331
|
+
if !dir_node
|
332
|
+
yield
|
333
|
+
else
|
334
|
+
dir_defn = schema.directives.fetch(dir_node.name)
|
335
|
+
if !dir_defn.is_a?(Class)
|
336
|
+
dir_defn = dir_defn.metadata[:type_class] || raise("Only class-based directives are supported (not `@#{dir_node.name}`)")
|
337
|
+
end
|
338
|
+
dir_args = arguments(nil, dir_defn, dir_node)
|
339
|
+
dir_defn.resolve(object, dir_args, context) do
|
340
|
+
run_directive(object, ast_node, idx + 1) { yield }
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
# Check {Schema::Directive.include?} for each directive that's present
|
346
|
+
def directives_include?(node, graphql_object, parent_type)
|
347
|
+
node.directives.each do |dir_node|
|
348
|
+
dir_defn = schema.directives.fetch(dir_node.name).metadata[:type_class] || raise("Only class-based directives are supported (not #{dir_node.name.inspect})")
|
349
|
+
args = arguments(graphql_object, dir_defn, dir_node)
|
350
|
+
if !dir_defn.include?(graphql_object, args, context)
|
266
351
|
return false
|
267
352
|
end
|
268
353
|
end
|
@@ -283,8 +368,12 @@ module GraphQL
|
|
283
368
|
# @param eager [Boolean] Set to `true` for mutation root fields only
|
284
369
|
# @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
|
285
370
|
def after_lazy(obj, field:, path:, eager: false)
|
371
|
+
@interpreter_context[:current_path] = path
|
372
|
+
@interpreter_context[:current_field] = field
|
286
373
|
if schema.lazy?(obj)
|
287
|
-
lazy = GraphQL::Execution::Lazy.new do
|
374
|
+
lazy = GraphQL::Execution::Lazy.new(path: path, field: field) do
|
375
|
+
@interpreter_context[:current_path] = path
|
376
|
+
@interpreter_context[:current_field] = field
|
288
377
|
# Wrap the execution of _this_ method with tracing,
|
289
378
|
# but don't wrap the continuation below
|
290
379
|
inner_obj = query.trace("execute_field_lazy", {field: field, path: path}) do
|
@@ -302,21 +391,38 @@ module GraphQL
|
|
302
391
|
if eager
|
303
392
|
lazy.value
|
304
393
|
else
|
305
|
-
|
394
|
+
write_in_response(path, lazy)
|
395
|
+
lazy
|
306
396
|
end
|
307
397
|
else
|
308
398
|
yield(obj)
|
309
399
|
end
|
310
400
|
end
|
311
401
|
|
312
|
-
def
|
402
|
+
def each_argument_pair(ast_args_or_hash)
|
403
|
+
case ast_args_or_hash
|
404
|
+
when GraphQL::Language::Nodes::Field, GraphQL::Language::Nodes::InputObject, GraphQL::Language::Nodes::Directive
|
405
|
+
ast_args_or_hash.arguments.each do |arg|
|
406
|
+
yield(arg.name, arg.value)
|
407
|
+
end
|
408
|
+
when Hash
|
409
|
+
ast_args_or_hash.each do |key, value|
|
410
|
+
normalized_name = GraphQL::Schema::Member::BuildType.camelize(key.to_s)
|
411
|
+
yield(normalized_name, value)
|
412
|
+
end
|
413
|
+
else
|
414
|
+
raise "Invariant, unexpected #{ast_args_or_hash.inspect}"
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
def arguments(graphql_object, arg_owner, ast_node_or_hash)
|
313
419
|
kwarg_arguments = {}
|
314
420
|
arg_defns = arg_owner.arguments
|
315
|
-
|
316
|
-
arg_defn = arg_defns[
|
421
|
+
each_argument_pair(ast_node_or_hash) do |arg_name, arg_value|
|
422
|
+
arg_defn = arg_defns[arg_name]
|
317
423
|
# Need to distinguish between client-provided `nil`
|
318
424
|
# and nothing-at-all
|
319
|
-
is_present, value = arg_to_value(graphql_object, arg_defn.type,
|
425
|
+
is_present, value = arg_to_value(graphql_object, arg_defn.type, arg_value)
|
320
426
|
if is_present
|
321
427
|
# This doesn't apply to directives, which are legacy
|
322
428
|
# Can remove this when Skip and Include use classes or something.
|
@@ -328,7 +434,8 @@ module GraphQL
|
|
328
434
|
end
|
329
435
|
arg_defns.each do |name, arg_defn|
|
330
436
|
if arg_defn.default_value? && !kwarg_arguments.key?(arg_defn.keyword)
|
331
|
-
|
437
|
+
_is_present, value = arg_to_value(graphql_object, arg_defn.type, arg_defn.default_value)
|
438
|
+
kwarg_arguments[arg_defn.keyword] = value
|
332
439
|
end
|
333
440
|
end
|
334
441
|
kwarg_arguments
|
@@ -432,9 +539,6 @@ module GraphQL
|
|
432
539
|
def type_at(path)
|
433
540
|
t = @types_at_paths
|
434
541
|
path.each do |part|
|
435
|
-
if part.is_a?(Integer)
|
436
|
-
part = 0
|
437
|
-
end
|
438
542
|
t = t[part] || (raise("Invariant: #{part.inspect} not found in #{t}"))
|
439
543
|
end
|
440
544
|
t = t[:__type]
|
@@ -444,10 +548,6 @@ module GraphQL
|
|
444
548
|
def set_type_at_path(path, type)
|
445
549
|
types = @types_at_paths
|
446
550
|
path.each do |part|
|
447
|
-
if part.is_a?(Integer)
|
448
|
-
part = 0
|
449
|
-
end
|
450
|
-
|
451
551
|
types = types[part] ||= {}
|
452
552
|
end
|
453
553
|
# Use this magic key so that the hash contains:
|