graphql 2.0.13 → 2.3.10
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.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +3 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/generators/graphql/relay.rb +18 -1
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +6 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +8 -0
- data/lib/graphql/analysis/analyzer.rb +89 -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 +183 -0
- data/lib/graphql/analysis/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +283 -0
- data/lib/graphql/analysis.rb +92 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/backtrace/table.rb +2 -2
- data/lib/graphql/backtrace/trace.rb +93 -0
- data/lib/graphql/backtrace/tracer.rb +1 -1
- data/lib/graphql/backtrace.rb +2 -1
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +88 -0
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +89 -45
- data/lib/graphql/dataloader.rb +115 -142
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
- data/lib/graphql/execution/interpreter/resolve.rb +19 -0
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
- data/lib/graphql/execution/interpreter/runtime.rb +331 -455
- data/lib/graphql/execution/interpreter.rb +125 -61
- data/lib/graphql/execution/lazy.rb +6 -12
- data/lib/graphql/execution/lookahead.rb +124 -46
- data/lib/graphql/execution/multiplex.rb +3 -117
- data/lib/graphql/execution.rb +0 -1
- data/lib/graphql/introspection/directive_type.rb +3 -3
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +11 -5
- data/lib/graphql/introspection/field_type.rb +2 -2
- data/lib/graphql/introspection/schema_type.rb +10 -13
- data/lib/graphql/introspection/type_type.rb +17 -10
- data/lib/graphql/introspection.rb +3 -2
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +75 -59
- data/lib/graphql/language/lexer.rb +358 -1506
- data/lib/graphql/language/nodes.rb +166 -93
- data/lib/graphql/language/parser.rb +795 -1953
- data/lib/graphql/language/printer.rb +340 -160
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +188 -141
- data/lib/graphql/language.rb +61 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +33 -6
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +117 -112
- data/lib/graphql/query/null_context.rb +12 -25
- data/lib/graphql/query/validation_pipeline.rb +6 -5
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +86 -30
- data/lib/graphql/railtie.rb +9 -6
- data/lib/graphql/rake_task.rb +29 -11
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/schema/addition.rb +59 -23
- data/lib/graphql/schema/always_visible.rb +11 -0
- data/lib/graphql/schema/argument.rb +55 -26
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +56 -32
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +15 -3
- data/lib/graphql/schema/enum.rb +35 -24
- data/lib/graphql/schema/enum_value.rb +2 -3
- data/lib/graphql/schema/field/connection_extension.rb +2 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +147 -107
- data/lib/graphql/schema/field_extension.rb +1 -4
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/has_single_input_argument.rb +158 -0
- data/lib/graphql/schema/input_object.rb +47 -11
- data/lib/graphql/schema/interface.rb +15 -21
- data/lib/graphql/schema/introspection_system.rb +7 -17
- data/lib/graphql/schema/late_bound_type.rb +10 -0
- data/lib/graphql/schema/list.rb +2 -2
- data/lib/graphql/schema/loader.rb +2 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -14
- data/lib/graphql/schema/member/build_type.rb +11 -3
- data/lib/graphql/schema/member/has_arguments.rb +170 -130
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +100 -38
- data/lib/graphql/schema/member/has_interfaces.rb +65 -10
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +16 -5
- data/lib/graphql/schema/printer.rb +11 -8
- data/lib/graphql/schema/relay_classic_mutation.rb +7 -129
- data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
- data/lib/graphql/schema/resolver.rb +47 -32
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/subset.rb +397 -0
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +11 -2
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +60 -0
- data/lib/graphql/schema/validator.rb +4 -2
- data/lib/graphql/schema/warden.rb +238 -93
- data/lib/graphql/schema.rb +498 -103
- data/lib/graphql/static_validation/all_rules.rb +2 -1
- data/lib/graphql/static_validation/base_visitor.rb +7 -6
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/literal_validator.rb +24 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +10 -10
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- 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/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -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 +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +5 -5
- data/lib/graphql/static_validation/validator.rb +4 -1
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +11 -4
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/event.rb +11 -10
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +20 -13
- data/lib/graphql/testing/helpers.rb +151 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +251 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/data_dog_trace.rb +183 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +9 -21
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
- data/lib/graphql/tracing/legacy_trace.rb +69 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +45 -0
- data/lib/graphql/tracing/platform_trace.rb +118 -0
- data/lib/graphql/tracing/platform_tracing.rb +17 -3
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/trace.rb +76 -0
- data/lib/graphql/tracing.rb +20 -40
- data/lib/graphql/type_kinds.rb +7 -4
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +1 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +68 -6
- data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
- data/lib/graphql/types/relay/node_behaviors.rb +8 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
- data/lib/graphql/types/relay.rb +0 -1
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +27 -20
- data/readme.md +13 -3
- metadata +96 -47
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- 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 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -269
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/language/lexer.rl +0 -280
- data/lib/graphql/language/parser.y +0 -554
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
- data/lib/graphql/types/relay/default_relay.rb +0 -21
data/lib/graphql/language.rb
CHANGED
@@ -8,9 +8,10 @@ require "graphql/language/lexer"
|
|
8
8
|
require "graphql/language/nodes"
|
9
9
|
require "graphql/language/cache"
|
10
10
|
require "graphql/language/parser"
|
11
|
-
require "graphql/language/
|
11
|
+
require "graphql/language/static_visitor"
|
12
12
|
require "graphql/language/visitor"
|
13
13
|
require "graphql/language/definition_slice"
|
14
|
+
require "strscan"
|
14
15
|
|
15
16
|
module GraphQL
|
16
17
|
module Language
|
@@ -31,6 +32,65 @@ module GraphQL
|
|
31
32
|
else
|
32
33
|
JSON.generate(value, quirks_mode: true)
|
33
34
|
end
|
35
|
+
rescue JSON::GeneratorError
|
36
|
+
if Float::INFINITY == value
|
37
|
+
"Infinity"
|
38
|
+
else
|
39
|
+
raise
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns a new string if any single-quoted newlines were escaped.
|
44
|
+
# Otherwise, returns `query_str` unchanged.
|
45
|
+
# @return [String]
|
46
|
+
def self.escape_single_quoted_newlines(query_str)
|
47
|
+
scanner = StringScanner.new(query_str)
|
48
|
+
inside_single_quoted_string = false
|
49
|
+
new_query_str = nil
|
50
|
+
while !scanner.eos?
|
51
|
+
if (match = scanner.scan(/(?:\\"|[^"\n\r]|""")+/m)) && new_query_str
|
52
|
+
new_query_str << match
|
53
|
+
elsif scanner.scan('"')
|
54
|
+
new_query_str && (new_query_str << '"')
|
55
|
+
inside_single_quoted_string = !inside_single_quoted_string
|
56
|
+
elsif scanner.scan("\n")
|
57
|
+
if inside_single_quoted_string
|
58
|
+
new_query_str ||= query_str[0, scanner.pos - 1]
|
59
|
+
new_query_str << '\\n'
|
60
|
+
else
|
61
|
+
new_query_str && (new_query_str << "\n")
|
62
|
+
end
|
63
|
+
elsif scanner.scan("\r")
|
64
|
+
if inside_single_quoted_string
|
65
|
+
new_query_str ||= query_str[0, scanner.pos - 1]
|
66
|
+
new_query_str << '\\r'
|
67
|
+
else
|
68
|
+
new_query_str && (new_query_str << "\r")
|
69
|
+
end
|
70
|
+
elsif scanner.eos?
|
71
|
+
break
|
72
|
+
else
|
73
|
+
raise ArgumentError, "Unmatchable string scanner segment: #{scanner.rest.inspect}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
new_query_str || query_str
|
77
|
+
end
|
78
|
+
|
79
|
+
INVALID_NUMBER_FOLLOWED_BY_NAME_REGEXP = %r{
|
80
|
+
(
|
81
|
+
((?<num>#{Lexer::INT_REGEXP}(#{Lexer::FLOAT_EXP_REGEXP})?)(?<name>#{Lexer::IDENTIFIER_REGEXP})#{Lexer::IGNORE_REGEXP}:)
|
82
|
+
|
|
83
|
+
((?<num>#{Lexer::INT_REGEXP}#{Lexer::FLOAT_DECIMAL_REGEXP}#{Lexer::FLOAT_EXP_REGEXP})(?<name>#{Lexer::IDENTIFIER_REGEXP})#{Lexer::IGNORE_REGEXP}:)
|
84
|
+
|
|
85
|
+
((?<num>#{Lexer::INT_REGEXP}#{Lexer::FLOAT_DECIMAL_REGEXP})(?<name>#{Lexer::IDENTIFIER_REGEXP})#{Lexer::IGNORE_REGEXP}:)
|
86
|
+
)}x
|
87
|
+
|
88
|
+
def self.add_space_between_numbers_and_names(query_str)
|
89
|
+
if query_str.match?(INVALID_NUMBER_FOLLOWED_BY_NAME_REGEXP)
|
90
|
+
query_str.gsub(INVALID_NUMBER_FOLLOWED_BY_NAME_REGEXP, "\\k<num> \\k<name>:")
|
91
|
+
else
|
92
|
+
query_str
|
93
|
+
end
|
34
94
|
end
|
35
95
|
end
|
36
96
|
end
|
@@ -12,10 +12,14 @@ module GraphQL
|
|
12
12
|
attr_reader :id
|
13
13
|
# @return [Object] The value found with this ID
|
14
14
|
attr_reader :object
|
15
|
-
|
15
|
+
# @return [GraphQL::Query::Context]
|
16
|
+
attr_reader :context
|
17
|
+
|
18
|
+
def initialize(argument:, id:, object:, context:)
|
16
19
|
@id = id
|
17
20
|
@argument = argument
|
18
21
|
@object = object
|
22
|
+
@context = context
|
19
23
|
super("No object found for `#{argument.graphql_name}: #{id.inspect}`")
|
20
24
|
end
|
21
25
|
end
|
@@ -7,14 +7,6 @@ module GraphQL
|
|
7
7
|
class ActiveRecordRelationConnection < Pagination::RelationConnection
|
8
8
|
private
|
9
9
|
|
10
|
-
def relation_larger_than(relation, initial_offset, size)
|
11
|
-
if already_loaded?(relation)
|
12
|
-
(relation.size + initial_offset) > size
|
13
|
-
else
|
14
|
-
set_offset(sliced_nodes, initial_offset + size).exists?
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
10
|
def relation_count(relation)
|
19
11
|
int_or_hash = if already_loaded?(relation)
|
20
12
|
relation.size
|
@@ -35,10 +35,10 @@ module GraphQL
|
|
35
35
|
def load_nodes
|
36
36
|
@nodes ||= begin
|
37
37
|
sliced_nodes = if before && after
|
38
|
-
end_idx = index_from_cursor(before)-
|
38
|
+
end_idx = index_from_cursor(before) - 2
|
39
39
|
end_idx < 0 ? [] : items[index_from_cursor(after)..end_idx] || []
|
40
40
|
elsif before
|
41
|
-
end_idx = index_from_cursor(before)-2
|
41
|
+
end_idx = index_from_cursor(before) - 2
|
42
42
|
end_idx < 0 ? [] : items[0..end_idx] || []
|
43
43
|
elsif after
|
44
44
|
items[index_from_cursor(after)..-1] || []
|
@@ -56,12 +56,12 @@ module GraphQL
|
|
56
56
|
false
|
57
57
|
end
|
58
58
|
|
59
|
-
@has_next_page = if
|
60
|
-
# There are more items after these items
|
61
|
-
sliced_nodes.count > first
|
62
|
-
elsif before
|
59
|
+
@has_next_page = if before
|
63
60
|
# The original array is longer than the `before` index
|
64
61
|
index_from_cursor(before) < items.length + 1
|
62
|
+
elsif first
|
63
|
+
# There are more items after these items
|
64
|
+
sliced_nodes.count > first
|
65
65
|
else
|
66
66
|
false
|
67
67
|
end
|
@@ -19,7 +19,15 @@ module GraphQL
|
|
19
19
|
attr_reader :items
|
20
20
|
|
21
21
|
# @return [GraphQL::Query::Context]
|
22
|
-
|
22
|
+
attr_reader :context
|
23
|
+
|
24
|
+
def context=(new_ctx)
|
25
|
+
@context = new_ctx
|
26
|
+
if @was_authorized_by_scope_items.nil?
|
27
|
+
@was_authorized_by_scope_items = detect_was_authorized_by_scope_items
|
28
|
+
end
|
29
|
+
@context
|
30
|
+
end
|
23
31
|
|
24
32
|
# @return [Object] the object this collection belongs to
|
25
33
|
attr_accessor :parent
|
@@ -58,7 +66,7 @@ module GraphQL
|
|
58
66
|
# @param arguments [Hash] The arguments to the field that returned the collection wrapped by this connection
|
59
67
|
# @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given and no `default_page_size` is set.
|
60
68
|
# @param default_page_size [Integer, nil] A configured value to determine the result size when neither first or last are given.
|
61
|
-
def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size:
|
69
|
+
def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, last: nil, before: nil, edge_class: nil, arguments: nil)
|
62
70
|
@items = items
|
63
71
|
@parent = parent
|
64
72
|
@context = context
|
@@ -71,18 +79,23 @@ module GraphQL
|
|
71
79
|
@edge_class = edge_class || self.class::Edge
|
72
80
|
# This is only true if the object was _initialized_ with an override
|
73
81
|
# or if one is assigned later.
|
74
|
-
@has_max_page_size_override = max_page_size !=
|
75
|
-
@max_page_size = if max_page_size ==
|
82
|
+
@has_max_page_size_override = max_page_size != NOT_CONFIGURED
|
83
|
+
@max_page_size = if max_page_size == NOT_CONFIGURED
|
76
84
|
nil
|
77
85
|
else
|
78
86
|
max_page_size
|
79
87
|
end
|
80
|
-
@has_default_page_size_override = default_page_size !=
|
81
|
-
@default_page_size = if default_page_size ==
|
88
|
+
@has_default_page_size_override = default_page_size != NOT_CONFIGURED
|
89
|
+
@default_page_size = if default_page_size == NOT_CONFIGURED
|
82
90
|
nil
|
83
91
|
else
|
84
92
|
default_page_size
|
85
93
|
end
|
94
|
+
@was_authorized_by_scope_items = detect_was_authorized_by_scope_items
|
95
|
+
end
|
96
|
+
|
97
|
+
def was_authorized_by_scope_items?
|
98
|
+
@was_authorized_by_scope_items
|
86
99
|
end
|
87
100
|
|
88
101
|
def max_page_size=(new_value)
|
@@ -208,6 +221,16 @@ module GraphQL
|
|
208
221
|
|
209
222
|
private
|
210
223
|
|
224
|
+
def detect_was_authorized_by_scope_items
|
225
|
+
if @context &&
|
226
|
+
(current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
227
|
+
(query_runtime_state = current_runtime_state[@context.query])
|
228
|
+
query_runtime_state.was_authorized_by_scope_items
|
229
|
+
else
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
211
234
|
# @param argument [nil, Integer] `first` or `last`, as provided by the client
|
212
235
|
# @param max_page_size [nil, Integer]
|
213
236
|
# @return [nil, Integer] `nil` if the input was `nil`, otherwise a value between `0` and `max_page_size`
|
@@ -247,6 +270,10 @@ module GraphQL
|
|
247
270
|
def cursor
|
248
271
|
@cursor ||= @connection.cursor_for(@node)
|
249
272
|
end
|
273
|
+
|
274
|
+
def was_authorized_by_scope_items?
|
275
|
+
@connection.was_authorized_by_scope_items?
|
276
|
+
end
|
250
277
|
end
|
251
278
|
end
|
252
279
|
end
|
@@ -13,8 +13,7 @@ module GraphQL
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def relation_count(relation)
|
16
|
-
|
17
|
-
relation.to_a.count
|
16
|
+
relation.all.count(relation.options.slice(:limit, :skip))
|
18
17
|
end
|
19
18
|
|
20
19
|
def null_relation(relation)
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Query
|
4
|
+
class Context
|
5
|
+
class ScopedContext
|
6
|
+
def initialize(query_context)
|
7
|
+
@query_context = query_context
|
8
|
+
@scoped_contexts = nil
|
9
|
+
@all_keys = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def merged_context
|
13
|
+
if @scoped_contexts.nil?
|
14
|
+
GraphQL::EmptyObjects::EMPTY_HASH
|
15
|
+
else
|
16
|
+
merged_ctx = {}
|
17
|
+
each_present_path_ctx do |path_ctx|
|
18
|
+
merged_ctx = path_ctx.merge(merged_ctx)
|
19
|
+
end
|
20
|
+
merged_ctx
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def merge!(hash, at: current_path)
|
25
|
+
@all_keys ||= Set.new
|
26
|
+
@all_keys.merge(hash.keys)
|
27
|
+
ctx = @scoped_contexts ||= {}
|
28
|
+
at.each do |path_part|
|
29
|
+
ctx = ctx[path_part] ||= { parent: ctx }
|
30
|
+
end
|
31
|
+
this_scoped_ctx = ctx[:scoped_context] ||= {}
|
32
|
+
this_scoped_ctx.merge!(hash)
|
33
|
+
end
|
34
|
+
|
35
|
+
def key?(key)
|
36
|
+
if @all_keys && @all_keys.include?(key)
|
37
|
+
each_present_path_ctx do |path_ctx|
|
38
|
+
if path_ctx.key?(key)
|
39
|
+
return true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def [](key)
|
47
|
+
each_present_path_ctx do |path_ctx|
|
48
|
+
if path_ctx.key?(key)
|
49
|
+
return path_ctx[key]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def current_path
|
56
|
+
@query_context.current_path || GraphQL::EmptyObjects::EMPTY_ARRAY
|
57
|
+
end
|
58
|
+
|
59
|
+
def dig(key, *other_keys)
|
60
|
+
each_present_path_ctx do |path_ctx|
|
61
|
+
if path_ctx.key?(key)
|
62
|
+
found_value = path_ctx[key]
|
63
|
+
if other_keys.any?
|
64
|
+
return found_value.dig(*other_keys)
|
65
|
+
else
|
66
|
+
return found_value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# Start at the current location,
|
76
|
+
# but look up the tree for previously-assigned scoped values
|
77
|
+
def each_present_path_ctx
|
78
|
+
ctx = @scoped_contexts
|
79
|
+
if ctx.nil?
|
80
|
+
# no-op
|
81
|
+
else
|
82
|
+
current_path.each do |path_part|
|
83
|
+
if ctx.key?(path_part)
|
84
|
+
ctx = ctx[path_part]
|
85
|
+
else
|
86
|
+
break
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
while ctx
|
91
|
+
if (scoped_ctx = ctx[:scoped_context])
|
92
|
+
yield(scoped_ctx)
|
93
|
+
end
|
94
|
+
ctx = ctx[:parent]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -1,39 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "graphql/query/context/scoped_context"
|
3
|
+
|
2
4
|
module GraphQL
|
3
5
|
class Query
|
4
6
|
# Expose some query-specific info to field resolve functions.
|
5
7
|
# It delegates `[]` to the hash that's passed to `GraphQL::Query#initialize`.
|
6
8
|
class Context
|
7
|
-
module SharedMethods
|
8
|
-
# Return this value to tell the runtime
|
9
|
-
# to exclude this field from the response altogether
|
10
|
-
def skip
|
11
|
-
GraphQL::Execution::SKIP
|
12
|
-
end
|
13
|
-
|
14
|
-
# Add error at query-level.
|
15
|
-
# @param error [GraphQL::ExecutionError] an execution error
|
16
|
-
# @return [void]
|
17
|
-
def add_error(error)
|
18
|
-
if !error.is_a?(ExecutionError)
|
19
|
-
raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
|
20
|
-
end
|
21
|
-
errors << error
|
22
|
-
nil
|
23
|
-
end
|
24
|
-
|
25
|
-
# @example Print the GraphQL backtrace during field resolution
|
26
|
-
# puts ctx.backtrace
|
27
|
-
#
|
28
|
-
# @return [GraphQL::Backtrace] The backtrace for this point in query execution
|
29
|
-
def backtrace
|
30
|
-
GraphQL::Backtrace.new(self)
|
31
|
-
end
|
32
|
-
|
33
|
-
def execution_errors
|
34
|
-
@execution_errors ||= ExecutionErrors.new(self)
|
35
|
-
end
|
36
|
-
end
|
37
9
|
|
38
10
|
class ExecutionErrors
|
39
11
|
def initialize(ctx)
|
@@ -57,7 +29,6 @@ module GraphQL
|
|
57
29
|
alias :push :add
|
58
30
|
end
|
59
31
|
|
60
|
-
include SharedMethods
|
61
32
|
extend Forwardable
|
62
33
|
|
63
34
|
# @return [Array<GraphQL::ExecutionError>] errors returned during execution
|
@@ -75,11 +46,10 @@ module GraphQL
|
|
75
46
|
# Make a new context which delegates key lookup to `values`
|
76
47
|
# @param query [GraphQL::Query] the query who owns this context
|
77
48
|
# @param values [Hash] A hash of arbitrary values which will be accessible at query-time
|
78
|
-
def initialize(query:, schema: query.schema, values
|
49
|
+
def initialize(query:, schema: query.schema, values:)
|
79
50
|
@query = query
|
80
51
|
@schema = schema
|
81
52
|
@provided_values = values || {}
|
82
|
-
@object = object
|
83
53
|
# Namespaced storage, where user-provided values are in `nil` namespace:
|
84
54
|
@storage = Hash.new { |h, k| h[k] = {} }
|
85
55
|
@storage[nil] = @provided_values
|
@@ -90,81 +60,6 @@ module GraphQL
|
|
90
60
|
@scoped_context = ScopedContext.new(self)
|
91
61
|
end
|
92
62
|
|
93
|
-
class ScopedContext
|
94
|
-
def initialize(query_context)
|
95
|
-
@query_context = query_context
|
96
|
-
@path_contexts = {}
|
97
|
-
@no_path = [].freeze
|
98
|
-
end
|
99
|
-
|
100
|
-
def merged_context
|
101
|
-
merged_ctx = {}
|
102
|
-
each_present_path_ctx do |path_ctx|
|
103
|
-
merged_ctx = path_ctx.merge(merged_ctx)
|
104
|
-
end
|
105
|
-
merged_ctx
|
106
|
-
end
|
107
|
-
|
108
|
-
def merge!(hash)
|
109
|
-
current_ctx = @path_contexts[current_path] ||= {}
|
110
|
-
current_ctx.merge!(hash)
|
111
|
-
end
|
112
|
-
|
113
|
-
def current_path
|
114
|
-
@query_context.namespace(:interpreter)[:current_path] || @no_path
|
115
|
-
end
|
116
|
-
|
117
|
-
def key?(key)
|
118
|
-
each_present_path_ctx do |path_ctx|
|
119
|
-
if path_ctx.key?(key)
|
120
|
-
return true
|
121
|
-
end
|
122
|
-
end
|
123
|
-
false
|
124
|
-
end
|
125
|
-
|
126
|
-
def [](key)
|
127
|
-
each_present_path_ctx do |path_ctx|
|
128
|
-
if path_ctx.key?(key)
|
129
|
-
return path_ctx[key]
|
130
|
-
end
|
131
|
-
end
|
132
|
-
nil
|
133
|
-
end
|
134
|
-
|
135
|
-
def dig(key, *other_keys)
|
136
|
-
each_present_path_ctx do |path_ctx|
|
137
|
-
if path_ctx.key?(key)
|
138
|
-
found_value = path_ctx[key]
|
139
|
-
if other_keys.any?
|
140
|
-
return found_value.dig(*other_keys)
|
141
|
-
else
|
142
|
-
return found_value
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
nil
|
147
|
-
end
|
148
|
-
|
149
|
-
private
|
150
|
-
|
151
|
-
# Start at the current location,
|
152
|
-
# but look up the tree for previously-assigned scoped values
|
153
|
-
def each_present_path_ctx
|
154
|
-
search_path = current_path.dup
|
155
|
-
if (current_path_ctx = @path_contexts[search_path])
|
156
|
-
yield(current_path_ctx)
|
157
|
-
end
|
158
|
-
|
159
|
-
while search_path.size > 0
|
160
|
-
search_path.pop # look one level higher
|
161
|
-
if (search_path_ctx = @path_contexts[search_path])
|
162
|
-
yield(search_path_ctx)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
63
|
# @return [Hash] A hash that will be added verbatim to the result hash, as `"extensions" => { ... }`
|
169
64
|
def response_extensions
|
170
65
|
namespace(:__query_result_extensions__)
|
@@ -189,6 +84,11 @@ module GraphQL
|
|
189
84
|
|
190
85
|
def_delegators :@query, :trace, :interpreter?
|
191
86
|
|
87
|
+
def types
|
88
|
+
@query.types
|
89
|
+
end
|
90
|
+
|
91
|
+
RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path])
|
192
92
|
# @!method []=(key, value)
|
193
93
|
# Reassign `key` to the hash passed to {Schema#execute} as `context:`
|
194
94
|
|
@@ -196,11 +96,65 @@ module GraphQL
|
|
196
96
|
def [](key)
|
197
97
|
if @scoped_context.key?(key)
|
198
98
|
@scoped_context[key]
|
199
|
-
|
99
|
+
elsif @provided_values.key?(key)
|
200
100
|
@provided_values[key]
|
101
|
+
elsif RUNTIME_METADATA_KEYS.include?(key)
|
102
|
+
if key == :current_path
|
103
|
+
current_path
|
104
|
+
else
|
105
|
+
(current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
106
|
+
(query_runtime_state = current_runtime_state[@query]) &&
|
107
|
+
(query_runtime_state.public_send(key))
|
108
|
+
end
|
109
|
+
else
|
110
|
+
# not found
|
111
|
+
nil
|
201
112
|
end
|
202
113
|
end
|
203
114
|
|
115
|
+
# Return this value to tell the runtime
|
116
|
+
# to exclude this field from the response altogether
|
117
|
+
def skip
|
118
|
+
GraphQL::Execution::SKIP
|
119
|
+
end
|
120
|
+
|
121
|
+
# Add error at query-level.
|
122
|
+
# @param error [GraphQL::ExecutionError] an execution error
|
123
|
+
# @return [void]
|
124
|
+
def add_error(error)
|
125
|
+
if !error.is_a?(ExecutionError)
|
126
|
+
raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
|
127
|
+
end
|
128
|
+
errors << error
|
129
|
+
nil
|
130
|
+
end
|
131
|
+
|
132
|
+
# @example Print the GraphQL backtrace during field resolution
|
133
|
+
# puts ctx.backtrace
|
134
|
+
#
|
135
|
+
# @return [GraphQL::Backtrace] The backtrace for this point in query execution
|
136
|
+
def backtrace
|
137
|
+
GraphQL::Backtrace.new(self)
|
138
|
+
end
|
139
|
+
|
140
|
+
def execution_errors
|
141
|
+
@execution_errors ||= ExecutionErrors.new(self)
|
142
|
+
end
|
143
|
+
|
144
|
+
def current_path
|
145
|
+
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
146
|
+
query_runtime_state = current_runtime_state && current_runtime_state[@query]
|
147
|
+
|
148
|
+
path = query_runtime_state &&
|
149
|
+
(result = query_runtime_state.current_result) &&
|
150
|
+
(result.path)
|
151
|
+
if path && (rn = query_runtime_state.current_result_name)
|
152
|
+
path = path.dup
|
153
|
+
path.push(rn)
|
154
|
+
end
|
155
|
+
path
|
156
|
+
end
|
157
|
+
|
204
158
|
def delete(key)
|
205
159
|
if @scoped_context.key?(key)
|
206
160
|
@scoped_context.delete(key)
|
@@ -212,7 +166,11 @@ module GraphQL
|
|
212
166
|
UNSPECIFIED_FETCH_DEFAULT = Object.new
|
213
167
|
|
214
168
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
215
|
-
if
|
169
|
+
if RUNTIME_METADATA_KEYS.include?(key)
|
170
|
+
(runtime = Thread.current[:__graphql_runtime_info]) &&
|
171
|
+
(query_runtime_state = runtime[@query]) &&
|
172
|
+
(query_runtime_state.public_send(key))
|
173
|
+
elsif @scoped_context.key?(key)
|
216
174
|
scoped_context[key]
|
217
175
|
elsif @provided_values.key?(key)
|
218
176
|
@provided_values[key]
|
@@ -226,7 +184,16 @@ module GraphQL
|
|
226
184
|
end
|
227
185
|
|
228
186
|
def dig(key, *other_keys)
|
229
|
-
if
|
187
|
+
if RUNTIME_METADATA_KEYS.include?(key)
|
188
|
+
(current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
189
|
+
(query_runtime_state = current_runtime_state[@query]) &&
|
190
|
+
(obj = query_runtime_state.public_send(key)) &&
|
191
|
+
if other_keys.empty?
|
192
|
+
obj
|
193
|
+
else
|
194
|
+
obj.dig(*other_keys)
|
195
|
+
end
|
196
|
+
elsif @scoped_context.key?(key)
|
230
197
|
@scoped_context.dig(key, *other_keys)
|
231
198
|
else
|
232
199
|
@provided_values.dig(key, *other_keys)
|
@@ -259,7 +226,11 @@ module GraphQL
|
|
259
226
|
# @param ns [Object] a usage-specific namespace identifier
|
260
227
|
# @return [Hash] namespaced storage
|
261
228
|
def namespace(ns)
|
262
|
-
|
229
|
+
if ns == :interpreter
|
230
|
+
self
|
231
|
+
else
|
232
|
+
@storage[ns]
|
233
|
+
end
|
263
234
|
end
|
264
235
|
|
265
236
|
# @return [Boolean] true if this namespace was accessed before
|
@@ -267,6 +238,10 @@ module GraphQL
|
|
267
238
|
@storage.key?(ns)
|
268
239
|
end
|
269
240
|
|
241
|
+
def logger
|
242
|
+
@query && @query.logger
|
243
|
+
end
|
244
|
+
|
270
245
|
def inspect
|
271
246
|
"#<Query::Context ...>"
|
272
247
|
end
|
@@ -279,6 +254,36 @@ module GraphQL
|
|
279
254
|
scoped_merge!(key => value)
|
280
255
|
nil
|
281
256
|
end
|
257
|
+
|
258
|
+
# Use this when you need to do a scoped set _inside_ a lazy-loaded (or batch-loaded)
|
259
|
+
# block of code.
|
260
|
+
#
|
261
|
+
# @example using scoped context inside a promise
|
262
|
+
# scoped_ctx = context.scoped
|
263
|
+
# SomeBatchLoader.load(...).then do |thing|
|
264
|
+
# # use a scoped_ctx which was created _before_ dataloading:
|
265
|
+
# scoped_ctx.set!(:thing, thing)
|
266
|
+
# end
|
267
|
+
# @return [Context::Scoped]
|
268
|
+
def scoped
|
269
|
+
Scoped.new(@scoped_context, current_path)
|
270
|
+
end
|
271
|
+
|
272
|
+
class Scoped
|
273
|
+
def initialize(scoped_context, path)
|
274
|
+
@path = path
|
275
|
+
@scoped_context = scoped_context
|
276
|
+
end
|
277
|
+
|
278
|
+
def merge!(hash)
|
279
|
+
@scoped_context.merge!(hash, at: @path)
|
280
|
+
end
|
281
|
+
|
282
|
+
def set!(key, value)
|
283
|
+
@scoped_context.merge!({ key => value }, at: @path)
|
284
|
+
nil
|
285
|
+
end
|
286
|
+
end
|
282
287
|
end
|
283
288
|
end
|
284
289
|
end
|