graphql 2.2.17 → 2.5.16
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/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install_generator.rb +46 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_resolver.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +3 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyzer.rb +90 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +263 -0
- data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +95 -1
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +57 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/subscriptions.rb +96 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +158 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +46 -19
- data/lib/graphql/dataloader/null_dataloader.rb +51 -10
- data/lib/graphql/dataloader/source.rb +20 -9
- data/lib/graphql/dataloader.rb +153 -45
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +23 -25
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +63 -5
- data/lib/graphql/execution/interpreter/runtime.rb +321 -222
- data/lib/graphql/execution/interpreter.rb +23 -30
- data/lib/graphql/execution/lookahead.rb +18 -11
- data/lib/graphql/execution/multiplex.rb +6 -5
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +6 -11
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +20 -17
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/document_from_schema_definition.rb +64 -35
- data/lib/graphql/language/lexer.rb +72 -42
- data/lib/graphql/language/nodes.rb +93 -52
- data/lib/graphql/language/parser.rb +168 -61
- data/lib/graphql/language/printer.rb +31 -15
- data/lib/graphql/language/sanitized_printer.rb +1 -1
- data/lib/graphql/language.rb +61 -1
- data/lib/graphql/pagination/connection.rb +1 -1
- data/lib/graphql/query/context/scoped_context.rb +1 -1
- data/lib/graphql/query/context.rb +46 -47
- data/lib/graphql/query/null_context.rb +3 -5
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query.rb +123 -69
- data/lib/graphql/railtie.rb +7 -0
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +26 -13
- data/lib/graphql/schema/always_visible.rb +7 -2
- data/lib/graphql/schema/argument.rb +57 -8
- data/lib/graphql/schema/build_from_definition.rb +116 -49
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive.rb +54 -2
- data/lib/graphql/schema/enum.rb +107 -24
- data/lib/graphql/schema/enum_value.rb +10 -2
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +134 -45
- data/lib/graphql/schema/field_extension.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +6 -2
- data/lib/graphql/schema/input_object.rb +122 -64
- data/lib/graphql/schema/interface.rb +23 -5
- data/lib/graphql/schema/introspection_system.rb +6 -17
- data/lib/graphql/schema/late_bound_type.rb +4 -0
- data/lib/graphql/schema/list.rb +3 -3
- data/lib/graphql/schema/loader.rb +3 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
- data/lib/graphql/schema/member/has_arguments.rb +44 -58
- data/lib/graphql/schema/member/has_dataloader.rb +62 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +26 -6
- data/lib/graphql/schema/member/has_interfaces.rb +6 -6
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +25 -8
- data/lib/graphql/schema/printer.rb +1 -0
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
- data/lib/graphql/schema/resolver.rb +29 -23
- data/lib/graphql/schema/scalar.rb +1 -6
- data/lib/graphql/schema/subscription.rb +52 -6
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +92 -11
- data/lib/graphql/schema/validator.rb +3 -1
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +445 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +311 -0
- data/lib/graphql/schema/warden.rb +190 -20
- data/lib/graphql/schema.rb +695 -167
- data/lib/graphql/static_validation/all_rules.rb +2 -2
- data/lib/graphql/static_validation/base_visitor.rb +6 -5
- data/lib/graphql/static_validation/literal_validator.rb +4 -4
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +18 -2
- data/lib/graphql/static_validation/validator.rb +6 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -3
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +13 -2
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/subscriptions.rb +7 -5
- data/lib/graphql/testing/helpers.rb +48 -16
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +1 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +5 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
- data/lib/graphql/tracing/appsignal_trace.rb +32 -59
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +46 -162
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +141 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +183 -37
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +818 -0
- data/lib/graphql/tracing/platform_tracing.rb +1 -1
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- data/lib/graphql/tracing/prometheus_trace.rb +73 -73
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -58
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +64 -98
- data/lib/graphql/tracing/statsd_trace.rb +33 -45
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +111 -1
- data/lib/graphql/tracing.rb +31 -30
- data/lib/graphql/type_kinds.rb +2 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +12 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +11 -1
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/types.rb +18 -11
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +64 -54
- metadata +197 -22
- data/lib/graphql/analysis/ast/analyzer.rb +0 -91
- data/lib/graphql/analysis/ast/field_usage.rb +0 -82
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -182
- data/lib/graphql/analysis/ast/visitor.rb +0 -276
- data/lib/graphql/analysis/ast.rb +0 -94
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/trace.rb +0 -93
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
|
@@ -113,7 +113,7 @@ module GraphQL
|
|
|
113
113
|
end
|
|
114
114
|
|
|
115
115
|
def print_field(field, indent: "")
|
|
116
|
-
@current_field = query.
|
|
116
|
+
@current_field = query.types.field(@current_type, field.name)
|
|
117
117
|
old_type = @current_type
|
|
118
118
|
@current_type = @current_field.type.unwrap
|
|
119
119
|
super
|
data/lib/graphql/language.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
require "graphql/language/block_string"
|
|
3
|
+
require "graphql/language/comment"
|
|
3
4
|
require "graphql/language/printer"
|
|
4
5
|
require "graphql/language/sanitized_printer"
|
|
5
6
|
require "graphql/language/document_from_schema_definition"
|
|
@@ -9,9 +10,9 @@ require "graphql/language/nodes"
|
|
|
9
10
|
require "graphql/language/cache"
|
|
10
11
|
require "graphql/language/parser"
|
|
11
12
|
require "graphql/language/static_visitor"
|
|
12
|
-
require "graphql/language/token"
|
|
13
13
|
require "graphql/language/visitor"
|
|
14
14
|
require "graphql/language/definition_slice"
|
|
15
|
+
require "strscan"
|
|
15
16
|
|
|
16
17
|
module GraphQL
|
|
17
18
|
module Language
|
|
@@ -32,6 +33,65 @@ module GraphQL
|
|
|
32
33
|
else
|
|
33
34
|
JSON.generate(value, quirks_mode: true)
|
|
34
35
|
end
|
|
36
|
+
rescue JSON::GeneratorError
|
|
37
|
+
if Float::INFINITY == value
|
|
38
|
+
"Infinity"
|
|
39
|
+
else
|
|
40
|
+
raise
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Returns a new string if any single-quoted newlines were escaped.
|
|
45
|
+
# Otherwise, returns `query_str` unchanged.
|
|
46
|
+
# @return [String]
|
|
47
|
+
def self.escape_single_quoted_newlines(query_str)
|
|
48
|
+
scanner = StringScanner.new(query_str)
|
|
49
|
+
inside_single_quoted_string = false
|
|
50
|
+
new_query_str = nil
|
|
51
|
+
while !scanner.eos?
|
|
52
|
+
if scanner.skip(/(?:\\"|[^"\n\r]|""")+/m)
|
|
53
|
+
new_query_str && (new_query_str << scanner.matched)
|
|
54
|
+
elsif scanner.skip('"')
|
|
55
|
+
new_query_str && (new_query_str << '"')
|
|
56
|
+
inside_single_quoted_string = !inside_single_quoted_string
|
|
57
|
+
elsif scanner.skip("\n")
|
|
58
|
+
if inside_single_quoted_string
|
|
59
|
+
new_query_str ||= query_str[0, scanner.pos - 1]
|
|
60
|
+
new_query_str << '\\n'
|
|
61
|
+
else
|
|
62
|
+
new_query_str && (new_query_str << "\n")
|
|
63
|
+
end
|
|
64
|
+
elsif scanner.skip("\r")
|
|
65
|
+
if inside_single_quoted_string
|
|
66
|
+
new_query_str ||= query_str[0, scanner.pos - 1]
|
|
67
|
+
new_query_str << '\\r'
|
|
68
|
+
else
|
|
69
|
+
new_query_str && (new_query_str << "\r")
|
|
70
|
+
end
|
|
71
|
+
elsif scanner.eos?
|
|
72
|
+
break
|
|
73
|
+
else
|
|
74
|
+
raise ArgumentError, "Unmatchable string scanner segment: #{scanner.rest.inspect}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
new_query_str || query_str
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
INVALID_NUMBER_FOLLOWED_BY_NAME_REGEXP = %r{
|
|
81
|
+
(
|
|
82
|
+
((?<num>#{Lexer::INT_REGEXP}(#{Lexer::FLOAT_EXP_REGEXP})?)(?<name>#{Lexer::IDENTIFIER_REGEXP})#{Lexer::IGNORE_REGEXP}:)
|
|
83
|
+
|
|
|
84
|
+
((?<num>#{Lexer::INT_REGEXP}#{Lexer::FLOAT_DECIMAL_REGEXP}#{Lexer::FLOAT_EXP_REGEXP})(?<name>#{Lexer::IDENTIFIER_REGEXP})#{Lexer::IGNORE_REGEXP}:)
|
|
85
|
+
|
|
|
86
|
+
((?<num>#{Lexer::INT_REGEXP}#{Lexer::FLOAT_DECIMAL_REGEXP})(?<name>#{Lexer::IDENTIFIER_REGEXP})#{Lexer::IGNORE_REGEXP}:)
|
|
87
|
+
)}x
|
|
88
|
+
|
|
89
|
+
def self.add_space_between_numbers_and_names(query_str)
|
|
90
|
+
if query_str.match?(INVALID_NUMBER_FOLLOWED_BY_NAME_REGEXP)
|
|
91
|
+
query_str.gsub(INVALID_NUMBER_FOLLOWED_BY_NAME_REGEXP, "\\k<num> \\k<name>:")
|
|
92
|
+
else
|
|
93
|
+
query_str
|
|
94
|
+
end
|
|
35
95
|
end
|
|
36
96
|
end
|
|
37
97
|
end
|
|
@@ -223,7 +223,7 @@ module GraphQL
|
|
|
223
223
|
|
|
224
224
|
def detect_was_authorized_by_scope_items
|
|
225
225
|
if @context &&
|
|
226
|
-
(current_runtime_state =
|
|
226
|
+
(current_runtime_state = Fiber[:__graphql_runtime_info]) &&
|
|
227
227
|
(query_runtime_state = current_runtime_state[@context.query])
|
|
228
228
|
query_runtime_state.was_authorized_by_scope_items
|
|
229
229
|
else
|
|
@@ -1,41 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require "graphql/query/context/scoped_context"
|
|
3
2
|
|
|
4
3
|
module GraphQL
|
|
5
4
|
class Query
|
|
6
5
|
# Expose some query-specific info to field resolve functions.
|
|
7
6
|
# It delegates `[]` to the hash that's passed to `GraphQL::Query#initialize`.
|
|
8
7
|
class Context
|
|
9
|
-
module SharedMethods
|
|
10
|
-
# Return this value to tell the runtime
|
|
11
|
-
# to exclude this field from the response altogether
|
|
12
|
-
def skip
|
|
13
|
-
GraphQL::Execution::SKIP
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Add error at query-level.
|
|
17
|
-
# @param error [GraphQL::ExecutionError] an execution error
|
|
18
|
-
# @return [void]
|
|
19
|
-
def add_error(error)
|
|
20
|
-
if !error.is_a?(ExecutionError)
|
|
21
|
-
raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
|
|
22
|
-
end
|
|
23
|
-
errors << error
|
|
24
|
-
nil
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# @example Print the GraphQL backtrace during field resolution
|
|
28
|
-
# puts ctx.backtrace
|
|
29
|
-
#
|
|
30
|
-
# @return [GraphQL::Backtrace] The backtrace for this point in query execution
|
|
31
|
-
def backtrace
|
|
32
|
-
GraphQL::Backtrace.new(self)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def execution_errors
|
|
36
|
-
@execution_errors ||= ExecutionErrors.new(self)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
8
|
|
|
40
9
|
class ExecutionErrors
|
|
41
10
|
def initialize(ctx)
|
|
@@ -59,7 +28,6 @@ module GraphQL
|
|
|
59
28
|
alias :push :add
|
|
60
29
|
end
|
|
61
30
|
|
|
62
|
-
include SharedMethods
|
|
63
31
|
extend Forwardable
|
|
64
32
|
|
|
65
33
|
# @return [Array<GraphQL::ExecutionError>] errors returned during execution
|
|
@@ -71,27 +39,21 @@ module GraphQL
|
|
|
71
39
|
# @return [GraphQL::Schema]
|
|
72
40
|
attr_reader :schema
|
|
73
41
|
|
|
74
|
-
# @return [Array<String, Integer>] The current position in the result
|
|
75
|
-
attr_reader :path
|
|
76
|
-
|
|
77
42
|
# Make a new context which delegates key lookup to `values`
|
|
78
43
|
# @param query [GraphQL::Query] the query who owns this context
|
|
79
44
|
# @param values [Hash] A hash of arbitrary values which will be accessible at query-time
|
|
80
|
-
def initialize(query:, schema: query.schema, values
|
|
45
|
+
def initialize(query:, schema: query.schema, values:)
|
|
81
46
|
@query = query
|
|
82
47
|
@schema = schema
|
|
83
48
|
@provided_values = values || {}
|
|
84
|
-
@object = object
|
|
85
49
|
# Namespaced storage, where user-provided values are in `nil` namespace:
|
|
86
50
|
@storage = Hash.new { |h, k| h[k] = {} }
|
|
87
51
|
@storage[nil] = @provided_values
|
|
88
52
|
@errors = []
|
|
89
|
-
@path = []
|
|
90
|
-
@value = nil
|
|
91
|
-
@context = self # for SharedMethods TODO delete sharedmethods
|
|
92
53
|
@scoped_context = ScopedContext.new(self)
|
|
93
54
|
end
|
|
94
55
|
|
|
56
|
+
# Modify this hash to return extensions to client.
|
|
95
57
|
# @return [Hash] A hash that will be added verbatim to the result hash, as `"extensions" => { ... }`
|
|
96
58
|
def response_extensions
|
|
97
59
|
namespace(:__query_result_extensions__)
|
|
@@ -114,9 +76,15 @@ module GraphQL
|
|
|
114
76
|
@provided_values[key] = value
|
|
115
77
|
end
|
|
116
78
|
|
|
117
|
-
def_delegators :@query, :trace
|
|
79
|
+
def_delegators :@query, :trace
|
|
80
|
+
|
|
81
|
+
def types
|
|
82
|
+
@types ||= @query.types
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
attr_writer :types
|
|
118
86
|
|
|
119
|
-
RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path])
|
|
87
|
+
RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path]).freeze
|
|
120
88
|
# @!method []=(key, value)
|
|
121
89
|
# Reassign `key` to the hash passed to {Schema#execute} as `context:`
|
|
122
90
|
|
|
@@ -130,7 +98,7 @@ module GraphQL
|
|
|
130
98
|
if key == :current_path
|
|
131
99
|
current_path
|
|
132
100
|
else
|
|
133
|
-
(current_runtime_state =
|
|
101
|
+
(current_runtime_state = Fiber[:__graphql_runtime_info]) &&
|
|
134
102
|
(query_runtime_state = current_runtime_state[@query]) &&
|
|
135
103
|
(query_runtime_state.public_send(key))
|
|
136
104
|
end
|
|
@@ -140,8 +108,37 @@ module GraphQL
|
|
|
140
108
|
end
|
|
141
109
|
end
|
|
142
110
|
|
|
111
|
+
# Return this value to tell the runtime
|
|
112
|
+
# to exclude this field from the response altogether
|
|
113
|
+
def skip
|
|
114
|
+
GraphQL::Execution::SKIP
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Add error at query-level.
|
|
118
|
+
# @param error [GraphQL::ExecutionError] an execution error
|
|
119
|
+
# @return [void]
|
|
120
|
+
def add_error(error)
|
|
121
|
+
if !error.is_a?(ExecutionError)
|
|
122
|
+
raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
|
|
123
|
+
end
|
|
124
|
+
errors << error
|
|
125
|
+
nil
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @example Print the GraphQL backtrace during field resolution
|
|
129
|
+
# puts ctx.backtrace
|
|
130
|
+
#
|
|
131
|
+
# @return [GraphQL::Backtrace] The backtrace for this point in query execution
|
|
132
|
+
def backtrace
|
|
133
|
+
GraphQL::Backtrace.new(self)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def execution_errors
|
|
137
|
+
@execution_errors ||= ExecutionErrors.new(self)
|
|
138
|
+
end
|
|
139
|
+
|
|
143
140
|
def current_path
|
|
144
|
-
current_runtime_state =
|
|
141
|
+
current_runtime_state = Fiber[:__graphql_runtime_info]
|
|
145
142
|
query_runtime_state = current_runtime_state && current_runtime_state[@query]
|
|
146
143
|
|
|
147
144
|
path = query_runtime_state &&
|
|
@@ -166,7 +163,7 @@ module GraphQL
|
|
|
166
163
|
|
|
167
164
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
|
168
165
|
if RUNTIME_METADATA_KEYS.include?(key)
|
|
169
|
-
(runtime =
|
|
166
|
+
(runtime = Fiber[:__graphql_runtime_info]) &&
|
|
170
167
|
(query_runtime_state = runtime[@query]) &&
|
|
171
168
|
(query_runtime_state.public_send(key))
|
|
172
169
|
elsif @scoped_context.key?(key)
|
|
@@ -184,7 +181,7 @@ module GraphQL
|
|
|
184
181
|
|
|
185
182
|
def dig(key, *other_keys)
|
|
186
183
|
if RUNTIME_METADATA_KEYS.include?(key)
|
|
187
|
-
(current_runtime_state =
|
|
184
|
+
(current_runtime_state = Fiber[:__graphql_runtime_info]) &&
|
|
188
185
|
(query_runtime_state = current_runtime_state[@query]) &&
|
|
189
186
|
(obj = query_runtime_state.public_send(key)) &&
|
|
190
187
|
if other_keys.empty?
|
|
@@ -242,7 +239,7 @@ module GraphQL
|
|
|
242
239
|
end
|
|
243
240
|
|
|
244
241
|
def inspect
|
|
245
|
-
"
|
|
242
|
+
"#<#{self.class} ...>"
|
|
246
243
|
end
|
|
247
244
|
|
|
248
245
|
def scoped_merge!(hash)
|
|
@@ -286,3 +283,5 @@ module GraphQL
|
|
|
286
283
|
end
|
|
287
284
|
end
|
|
288
285
|
end
|
|
286
|
+
|
|
287
|
+
require "graphql/query/context/scoped_context"
|
|
@@ -18,17 +18,15 @@ module GraphQL
|
|
|
18
18
|
extend Forwardable
|
|
19
19
|
|
|
20
20
|
attr_reader :schema, :query, :warden, :dataloader
|
|
21
|
-
def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key
|
|
21
|
+
def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key?, :to_h
|
|
22
22
|
|
|
23
23
|
def initialize
|
|
24
24
|
@query = NullQuery.new
|
|
25
25
|
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
|
26
26
|
@schema = NullSchema
|
|
27
27
|
@warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def interpreter?
|
|
31
|
-
true
|
|
28
|
+
@types = @warden.visibility_profile
|
|
29
|
+
freeze
|
|
32
30
|
end
|
|
33
31
|
end
|
|
34
32
|
end
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
class Query
|
|
4
|
+
# This class is _like_ a {GraphQL::Query}, except it can run on an arbitrary path within a query string.
|
|
5
|
+
#
|
|
6
|
+
# It depends on a "parent" {Query}.
|
|
7
|
+
#
|
|
8
|
+
# During execution, it calls query-related tracing hooks but passes itself as `query:`.
|
|
9
|
+
#
|
|
10
|
+
# The {Partial} will use your {Schema.resolve_type} hook to find the right GraphQL type to use for
|
|
11
|
+
# `object` in some cases.
|
|
12
|
+
#
|
|
13
|
+
# @see Query#run_partials Run via {Query#run_partials}
|
|
14
|
+
class Partial
|
|
15
|
+
include Query::Runnable
|
|
16
|
+
|
|
17
|
+
# @param path [Array<String, Integer>] A path in `query.query_string` to start executing from
|
|
18
|
+
# @param object [Object] A starting object for execution
|
|
19
|
+
# @param query [GraphQL::Query] A full query instance that this partial is based on. Caches are shared.
|
|
20
|
+
# @param context [Hash] Extra context values to merge into `query.context`, if provided
|
|
21
|
+
# @param fragment_node [GraphQL::Language::Nodes::InlineFragment, GraphQL::Language::Nodes::FragmentDefinition]
|
|
22
|
+
def initialize(path: nil, object:, query:, context: nil, fragment_node: nil, type: nil)
|
|
23
|
+
@path = path
|
|
24
|
+
@object = object
|
|
25
|
+
@query = query
|
|
26
|
+
@schema = query.schema
|
|
27
|
+
context_vals = @query.context.to_h
|
|
28
|
+
if context
|
|
29
|
+
context_vals = context_vals.merge(context)
|
|
30
|
+
end
|
|
31
|
+
@context = GraphQL::Query::Context.new(query: self, schema: @query.schema, values: context_vals)
|
|
32
|
+
@multiplex = nil
|
|
33
|
+
@result_values = nil
|
|
34
|
+
@result = nil
|
|
35
|
+
|
|
36
|
+
if fragment_node
|
|
37
|
+
@ast_nodes = [fragment_node]
|
|
38
|
+
@root_type = type || raise(ArgumentError, "Pass `type:` when using `node:`")
|
|
39
|
+
# This is only used when `@leaf`
|
|
40
|
+
@field_definition = nil
|
|
41
|
+
elsif path.nil?
|
|
42
|
+
raise ArgumentError, "`path:` is required if `node:` is not given; add `path:`"
|
|
43
|
+
else
|
|
44
|
+
set_type_info_from_path
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
@leaf = @root_type.unwrap.kind.leaf?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def leaf?
|
|
51
|
+
@leaf
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
attr_reader :context, :query, :ast_nodes, :root_type, :object, :field_definition, :path, :schema
|
|
55
|
+
|
|
56
|
+
attr_accessor :multiplex, :result_values
|
|
57
|
+
|
|
58
|
+
class Result < GraphQL::Query::Result
|
|
59
|
+
def path
|
|
60
|
+
@query.path
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @return [GraphQL::Query::Partial]
|
|
64
|
+
def partial
|
|
65
|
+
@query
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def result
|
|
70
|
+
@result ||= Result.new(query: self, values: result_values)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def current_trace
|
|
74
|
+
@query.current_trace
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def types
|
|
78
|
+
@query.types
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def resolve_type(...)
|
|
82
|
+
@query.resolve_type(...)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def variables
|
|
86
|
+
@query.variables
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def fragments
|
|
90
|
+
@query.fragments
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def valid?
|
|
94
|
+
@query.valid?
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def analyzers
|
|
98
|
+
EmptyObjects::EMPTY_ARRAY
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def analysis_errors=(_ignored)
|
|
102
|
+
# pass
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def subscription?
|
|
106
|
+
@query.subscription?
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def selected_operation
|
|
110
|
+
ast_nodes.first
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def static_errors
|
|
114
|
+
@query.static_errors
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def selected_operation_name
|
|
118
|
+
@query.selected_operation_name
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
def set_type_info_from_path
|
|
124
|
+
selections = [@query.selected_operation]
|
|
125
|
+
type = @query.root_type
|
|
126
|
+
parent_type = nil
|
|
127
|
+
field_defn = nil
|
|
128
|
+
|
|
129
|
+
@path.each do |name_in_doc|
|
|
130
|
+
if name_in_doc.is_a?(Integer)
|
|
131
|
+
if type.list?
|
|
132
|
+
type = type.unwrap
|
|
133
|
+
next
|
|
134
|
+
else
|
|
135
|
+
raise ArgumentError, "Received path with index `#{name_in_doc}`, but type wasn't a list. Type: #{type.to_type_signature}, path: #{@path}"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
next_selections = []
|
|
140
|
+
selections.each do |selection|
|
|
141
|
+
selections_to_check = []
|
|
142
|
+
selections_to_check.concat(selection.selections)
|
|
143
|
+
while (sel = selections_to_check.shift)
|
|
144
|
+
case sel
|
|
145
|
+
when GraphQL::Language::Nodes::InlineFragment
|
|
146
|
+
selections_to_check.concat(sel.selections)
|
|
147
|
+
when GraphQL::Language::Nodes::FragmentSpread
|
|
148
|
+
fragment = @query.fragments[sel.name]
|
|
149
|
+
selections_to_check.concat(fragment.selections)
|
|
150
|
+
when GraphQL::Language::Nodes::Field
|
|
151
|
+
if sel.alias == name_in_doc || sel.name == name_in_doc
|
|
152
|
+
next_selections << sel
|
|
153
|
+
end
|
|
154
|
+
else
|
|
155
|
+
raise "Unexpected selection in partial path: #{sel.class}, #{sel.inspect}"
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
if next_selections.empty?
|
|
161
|
+
raise ArgumentError, "Path `#{@path.inspect}` is not present in this query. `#{name_in_doc.inspect}` was not found. Try a different path or rewrite the query to include it."
|
|
162
|
+
end
|
|
163
|
+
field_name = next_selections.first.name
|
|
164
|
+
field_defn = @schema.get_field(type, field_name, @query.context) || raise("Invariant: no field called #{field_name} on #{type.graphql_name}")
|
|
165
|
+
parent_type = type
|
|
166
|
+
type = field_defn.type
|
|
167
|
+
if type.non_null?
|
|
168
|
+
type = type.of_type
|
|
169
|
+
end
|
|
170
|
+
selections = next_selections
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
@ast_nodes = selections
|
|
174
|
+
@root_type = type
|
|
175
|
+
@field_definition = field_defn
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -100,10 +100,10 @@ module GraphQL
|
|
|
100
100
|
# Depending on the analysis engine, we must use different analyzers
|
|
101
101
|
# remove this once everything has switched over to AST analyzers
|
|
102
102
|
if max_depth
|
|
103
|
-
qa << GraphQL::Analysis::
|
|
103
|
+
qa << GraphQL::Analysis::MaxQueryDepth
|
|
104
104
|
end
|
|
105
105
|
if max_complexity
|
|
106
|
-
qa << GraphQL::Analysis::
|
|
106
|
+
qa << GraphQL::Analysis::MaxQueryComplexity
|
|
107
107
|
end
|
|
108
108
|
qa
|
|
109
109
|
else
|