graphql 1.9.17 → 1.11.7
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/core.rb +18 -2
- data/lib/generators/graphql/install_generator.rb +27 -0
- data/lib/generators/graphql/object_generator.rb +52 -8
- data/lib/generators/graphql/templates/base_argument.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_mutation.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -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/enum.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +14 -10
- data/lib/generators/graphql/templates/interface.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/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/object.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +10 -0
- data/lib/generators/graphql/templates/union.erb +3 -1
- data/lib/graphql/analysis/ast/field_usage.rb +1 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +178 -67
- data/lib/graphql/analysis/ast/visitor.rb +3 -3
- data/lib/graphql/analysis/ast.rb +12 -11
- data/lib/graphql/argument.rb +10 -38
- data/lib/graphql/backtrace/table.rb +10 -2
- data/lib/graphql/backtrace/tracer.rb +2 -1
- data/lib/graphql/base_type.rb +4 -0
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
- data/lib/graphql/define/assign_enum_value.rb +1 -1
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/define/assign_object_field.rb +3 -3
- data/lib/graphql/define/defined_object_proxy.rb +3 -0
- data/lib/graphql/define/instance_definable.rb +18 -108
- data/lib/graphql/directive/deprecated_directive.rb +1 -12
- data/lib/graphql/directive.rb +8 -1
- data/lib/graphql/enum_type.rb +5 -71
- data/lib/graphql/execution/directive_checks.rb +2 -2
- data/lib/graphql/execution/errors.rb +2 -3
- data/lib/graphql/execution/execute.rb +1 -1
- data/lib/graphql/execution/instrumentation.rb +1 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +51 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +79 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +25 -0
- data/lib/graphql/execution/interpreter/runtime.rb +227 -254
- data/lib/graphql/execution/interpreter.rb +34 -11
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lookahead.rb +39 -114
- data/lib/graphql/execution/multiplex.rb +14 -5
- data/lib/graphql/field.rb +14 -118
- data/lib/graphql/filter.rb +1 -1
- data/lib/graphql/function.rb +1 -30
- data/lib/graphql/input_object_type.rb +6 -24
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/interface_type.rb +7 -23
- data/lib/graphql/internal_representation/scope.rb +2 -2
- data/lib/graphql/internal_representation/visit.rb +2 -2
- data/lib/graphql/introspection/base_object.rb +2 -5
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +7 -7
- data/lib/graphql/introspection/field_type.rb +7 -3
- data/lib/graphql/introspection/input_value_type.rb +33 -9
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +4 -9
- data/lib/graphql/introspection/type_type.rb +11 -7
- data/lib/graphql/introspection.rb +96 -0
- data/lib/graphql/invalid_null_error.rb +18 -0
- data/lib/graphql/language/block_string.rb +24 -5
- data/lib/graphql/language/definition_slice.rb +21 -10
- data/lib/graphql/language/document_from_schema_definition.rb +89 -64
- data/lib/graphql/language/lexer.rb +7 -3
- data/lib/graphql/language/lexer.rl +7 -3
- data/lib/graphql/language/nodes.rb +52 -91
- data/lib/graphql/language/parser.rb +719 -717
- data/lib/graphql/language/parser.y +104 -98
- data/lib/graphql/language/printer.rb +1 -1
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/visitor.rb +2 -2
- data/lib/graphql/language.rb +2 -1
- data/lib/graphql/name_validator.rb +6 -7
- data/lib/graphql/non_null_type.rb +0 -10
- data/lib/graphql/object_type.rb +45 -56
- data/lib/graphql/pagination/active_record_relation_connection.rb +41 -0
- data/lib/graphql/pagination/array_connection.rb +77 -0
- data/lib/graphql/pagination/connection.rb +208 -0
- data/lib/graphql/pagination/connections.rb +145 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +185 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/query/arguments.rb +4 -2
- data/lib/graphql/query/context.rb +36 -9
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +23 -6
- data/lib/graphql/query/literal_input.rb +30 -10
- data/lib/graphql/query/null_context.rb +5 -1
- data/lib/graphql/query/validation_pipeline.rb +4 -1
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +16 -7
- data/lib/graphql/query.rb +64 -15
- data/lib/graphql/rake_task/validate.rb +3 -0
- data/lib/graphql/rake_task.rb +9 -9
- data/lib/graphql/relay/array_connection.rb +10 -12
- data/lib/graphql/relay/base_connection.rb +23 -13
- data/lib/graphql/relay/connection_type.rb +2 -1
- data/lib/graphql/relay/edge_type.rb +1 -0
- data/lib/graphql/relay/edges_instrumentation.rb +1 -1
- data/lib/graphql/relay/mutation.rb +1 -86
- data/lib/graphql/relay/node.rb +2 -2
- data/lib/graphql/relay/range_add.rb +14 -5
- data/lib/graphql/relay/relation_connection.rb +8 -10
- data/lib/graphql/scalar_type.rb +15 -59
- data/lib/graphql/schema/argument.rb +113 -11
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
- data/lib/graphql/schema/build_from_definition.rb +212 -190
- data/lib/graphql/schema/built_in_types.rb +5 -5
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive.rb +34 -3
- data/lib/graphql/schema/enum.rb +52 -4
- data/lib/graphql/schema/enum_value.rb +6 -1
- data/lib/graphql/schema/field/connection_extension.rb +44 -20
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +200 -129
- data/lib/graphql/schema/find_inherited_value.rb +13 -0
- data/lib/graphql/schema/finder.rb +13 -11
- data/lib/graphql/schema/input_object.rb +131 -22
- data/lib/graphql/schema/interface.rb +26 -8
- data/lib/graphql/schema/introspection_system.rb +108 -37
- data/lib/graphql/schema/late_bound_type.rb +3 -2
- data/lib/graphql/schema/list.rb +47 -0
- data/lib/graphql/schema/loader.rb +134 -96
- data/lib/graphql/schema/member/base_dsl_methods.rb +29 -12
- data/lib/graphql/schema/member/build_type.rb +19 -5
- data/lib/graphql/schema/member/cached_graphql_definition.rb +5 -0
- data/lib/graphql/schema/member/has_arguments.rb +105 -5
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- data/lib/graphql/schema/member/has_fields.rb +20 -10
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/mutation.rb +5 -1
- data/lib/graphql/schema/non_null.rb +30 -0
- data/lib/graphql/schema/object.rb +65 -12
- data/lib/graphql/schema/possible_types.rb +9 -4
- data/lib/graphql/schema/printer.rb +0 -15
- data/lib/graphql/schema/relay_classic_mutation.rb +5 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +5 -2
- data/lib/graphql/schema/resolver.rb +26 -18
- data/lib/graphql/schema/scalar.rb +27 -3
- data/lib/graphql/schema/subscription.rb +8 -18
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/traversal.rb +1 -1
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +2 -2
- data/lib/graphql/schema/union.rb +37 -3
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +10 -2
- data/lib/graphql/schema/warden.rb +115 -29
- data/lib/graphql/schema.rb +903 -195
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +10 -6
- data/lib/graphql/static_validation/literal_validator.rb +52 -27
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +43 -83
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +17 -5
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +33 -25
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +29 -21
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -5
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -6
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +1 -1
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +30 -8
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +89 -19
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
- data/lib/graphql/subscriptions/event.rb +23 -5
- data/lib/graphql/subscriptions/instrumentation.rb +10 -5
- data/lib/graphql/subscriptions/serialize.rb +22 -4
- data/lib/graphql/subscriptions/subscription_root.rb +15 -5
- data/lib/graphql/subscriptions.rb +108 -35
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +14 -10
- data/lib/graphql/tracing/appoptics_tracing.rb +171 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +8 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +8 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
- data/lib/graphql/tracing/platform_tracing.rb +53 -9
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
- data/lib/graphql/tracing/scout_tracing.rb +19 -0
- data/lib/graphql/tracing/skylight_tracing.rb +8 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +14 -34
- data/lib/graphql/types/big_int.rb +1 -1
- data/lib/graphql/types/int.rb +9 -2
- data/lib/graphql/types/iso_8601_date.rb +3 -3
- data/lib/graphql/types/iso_8601_date_time.rb +25 -10
- data/lib/graphql/types/relay/base_connection.rb +11 -7
- data/lib/graphql/types/relay/base_edge.rb +2 -1
- data/lib/graphql/types/string.rb +7 -1
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/union_type.rb +13 -28
- data/lib/graphql/unresolved_type_error.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +31 -6
- data/readme.md +1 -1
- metadata +34 -9
- data/lib/graphql/literal_validation_error.rb +0 -6
@@ -8,7 +8,7 @@ module GraphQL
|
|
8
8
|
# - `complexities_on_type` holds complexity scores for each type in an IRep node
|
9
9
|
def initialize(query)
|
10
10
|
super
|
11
|
-
@
|
11
|
+
@complexities_on_type_by_query = {}
|
12
12
|
end
|
13
13
|
|
14
14
|
# Overide this method to use the complexity result
|
@@ -16,17 +16,72 @@ module GraphQL
|
|
16
16
|
max_possible_complexity
|
17
17
|
end
|
18
18
|
|
19
|
+
class ScopedTypeComplexity
|
20
|
+
# A single proc for {#scoped_children} hashes. Use this to avoid repeated allocations,
|
21
|
+
# since the lexical binding isn't important.
|
22
|
+
HASH_CHILDREN = ->(h, k) { h[k] = {} }
|
23
|
+
|
24
|
+
attr_reader :field_definition, :response_path, :query
|
25
|
+
|
26
|
+
# @param node [Language::Nodes::Field] The AST node; used for providing argument values when necessary
|
27
|
+
# @param field_definition [GraphQL::Field, GraphQL::Schema::Field] Used for getting the `.complexity` configuration
|
28
|
+
# @param query [GraphQL::Query] Used for `query.possible_types`
|
29
|
+
# @param response_path [Array<String>] The path to the response key for the field
|
30
|
+
def initialize(node, field_definition, query, response_path)
|
31
|
+
@node = node
|
32
|
+
@field_definition = field_definition
|
33
|
+
@query = query
|
34
|
+
@response_path = response_path
|
35
|
+
@scoped_children = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns true if this field has no selections, ie, it's a scalar.
|
39
|
+
# We need a quick way to check whether we should continue traversing.
|
40
|
+
def terminal?
|
41
|
+
@scoped_children.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
# This value is only calculated when asked for to avoid needless hash allocations.
|
45
|
+
# Also, if it's never asked for, we determine that this scope complexity
|
46
|
+
# is a scalar field ({#terminal?}).
|
47
|
+
# @return [Hash<Hash<Class => ScopedTypeComplexity>]
|
48
|
+
def scoped_children
|
49
|
+
@scoped_children ||= Hash.new(&HASH_CHILDREN)
|
50
|
+
end
|
51
|
+
|
52
|
+
def own_complexity(child_complexity)
|
53
|
+
defined_complexity = @field_definition.complexity
|
54
|
+
case defined_complexity
|
55
|
+
when Proc
|
56
|
+
arguments = @query.arguments_for(@node, @field_definition)
|
57
|
+
defined_complexity.call(@query.context, arguments.keyword_arguments, child_complexity)
|
58
|
+
when Numeric
|
59
|
+
defined_complexity + child_complexity
|
60
|
+
else
|
61
|
+
raise("Invalid complexity: #{defined_complexity.inspect} on #{@field_definition.name}")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
19
66
|
def on_enter_field(node, parent, visitor)
|
20
67
|
# We don't want to visit fragment definitions,
|
21
68
|
# we'll visit them when we hit the spreads instead
|
22
69
|
return if visitor.visiting_fragment_definition?
|
23
70
|
return if visitor.skipping?
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
71
|
+
parent_type = visitor.parent_type_definition
|
72
|
+
field_key = node.alias || node.name
|
73
|
+
# Find the complexity calculation for this field --
|
74
|
+
# if we're re-entering a selection, we'll already have one.
|
75
|
+
# Otherwise, make a new one and store it.
|
76
|
+
#
|
77
|
+
# `node` and `visitor.field_definition` may appear from a cache,
|
78
|
+
# but I think that's ok. If the arguments _didn't_ match,
|
79
|
+
# then the query would have been rejected as invalid.
|
80
|
+
complexities_on_type = @complexities_on_type_by_query[visitor.query] ||= [ScopedTypeComplexity.new(nil, nil, query, visitor.response_path)]
|
81
|
+
|
82
|
+
complexity = complexities_on_type.last.scoped_children[parent_type][field_key] ||= ScopedTypeComplexity.new(node, visitor.field_definition, visitor.query, visitor.response_path)
|
83
|
+
# Push it on the stack.
|
84
|
+
complexities_on_type.push(complexity)
|
30
85
|
end
|
31
86
|
|
32
87
|
def on_leave_field(node, parent, visitor)
|
@@ -34,88 +89,144 @@ module GraphQL
|
|
34
89
|
# we'll visit them when we hit the spreads instead
|
35
90
|
return if visitor.visiting_fragment_definition?
|
36
91
|
return if visitor.skipping?
|
92
|
+
complexities_on_type = @complexities_on_type_by_query[visitor.query]
|
93
|
+
complexities_on_type.pop
|
94
|
+
end
|
37
95
|
|
38
|
-
|
39
|
-
child_complexity = type_complexities.max_possible_complexity
|
40
|
-
own_complexity = get_complexity(node, visitor.field_definition, child_complexity, visitor)
|
96
|
+
private
|
41
97
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
@complexities_on_type.last.merge(own_complexity)
|
98
|
+
# @return [Integer]
|
99
|
+
def max_possible_complexity
|
100
|
+
@complexities_on_type_by_query.reduce(0) do |total, (query, complexities_on_type)|
|
101
|
+
root_complexity = complexities_on_type.last
|
102
|
+
# Use this entry point to calculate the total complexity
|
103
|
+
total_complexity_for_query = merged_max_complexity_for_scopes(query, [root_complexity.scoped_children])
|
104
|
+
total + total_complexity_for_query
|
50
105
|
end
|
51
106
|
end
|
52
107
|
|
108
|
+
# @param query [GraphQL::Query] Used for `query.possible_types`
|
109
|
+
# @param scoped_children_hashes [Array<Hash>] Array of scoped children hashes
|
53
110
|
# @return [Integer]
|
54
|
-
def
|
55
|
-
|
56
|
-
|
111
|
+
def merged_max_complexity_for_scopes(query, scoped_children_hashes)
|
112
|
+
# Figure out what scopes are possible here.
|
113
|
+
# Use a hash, but ignore the values; it's just a fast way to work with the keys.
|
114
|
+
all_scopes = {}
|
115
|
+
scoped_children_hashes.each do |h|
|
116
|
+
all_scopes.merge!(h)
|
117
|
+
end
|
57
118
|
|
58
|
-
|
119
|
+
# If an abstract scope is present, but _all_ of its concrete types
|
120
|
+
# are also in the list, remove it from the list of scopes to check,
|
121
|
+
# because every possible type is covered by a concrete type.
|
122
|
+
# (That is, there are no remainder types to check.)
|
123
|
+
prev_keys = all_scopes.keys
|
124
|
+
prev_keys.each do |scope|
|
125
|
+
next unless scope.kind.abstract?
|
126
|
+
|
127
|
+
missing_concrete_types = query.possible_types(scope).select { |t| !all_scopes.key?(t) }
|
128
|
+
# This concrete type is possible _only_ as a member of the abstract type.
|
129
|
+
# So, attribute to it the complexity which belongs to the abstract type.
|
130
|
+
missing_concrete_types.each do |concrete_scope|
|
131
|
+
all_scopes[concrete_scope] = all_scopes[scope]
|
132
|
+
end
|
133
|
+
all_scopes.delete(scope)
|
134
|
+
end
|
59
135
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
#
|
64
|
-
|
65
|
-
|
136
|
+
# This will hold `{ type => int }` pairs, one for each possible branch
|
137
|
+
complexity_by_scope = {}
|
138
|
+
|
139
|
+
# For each scope,
|
140
|
+
# find the lexical selections that might apply to it,
|
141
|
+
# and gather them together into an array.
|
142
|
+
# Then, treat the set of selection hashes
|
143
|
+
# as a set and calculate the complexity for them as a unit
|
144
|
+
all_scopes.each do |scope, _|
|
145
|
+
# These will be the selections on `scope`
|
146
|
+
children_for_scope = []
|
147
|
+
scoped_children_hashes.each do |sc_h|
|
148
|
+
sc_h.each do |inner_scope, children_hash|
|
149
|
+
if applies_to?(query, scope, inner_scope)
|
150
|
+
children_for_scope << children_hash
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
66
154
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
155
|
+
# Calculate the complexity for `scope`, merging all
|
156
|
+
# possible lexical branches.
|
157
|
+
complexity_value = merged_max_complexity(query, children_for_scope)
|
158
|
+
complexity_by_scope[scope] = complexity_value
|
159
|
+
end
|
72
160
|
|
73
|
-
|
161
|
+
# Return the max complexity among all scopes
|
162
|
+
complexity_by_scope.each_value.max
|
163
|
+
end
|
74
164
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
defined_complexity + (child_complexity || 0)
|
165
|
+
def applies_to?(query, left_scope, right_scope)
|
166
|
+
if left_scope == right_scope
|
167
|
+
# This can happen when several branches are being analyzed together
|
168
|
+
true
|
80
169
|
else
|
81
|
-
|
170
|
+
# Check if these two scopes have _any_ types in common.
|
171
|
+
possible_right_types = query.possible_types(right_scope)
|
172
|
+
possible_left_types = query.possible_types(left_scope)
|
173
|
+
!(possible_right_types & possible_left_types).empty?
|
82
174
|
end
|
83
175
|
end
|
84
176
|
|
85
|
-
#
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
177
|
+
# A hook which is called whenever a field's max complexity is calculated.
|
178
|
+
# Override this method to capture individual field complexity details.
|
179
|
+
#
|
180
|
+
# @param scoped_type_complexity [ScopedTypeComplexity]
|
181
|
+
# @param max_complexity [Numeric] Field's maximum complexity including child complexity
|
182
|
+
# @param child_complexity [Numeric, nil] Field's child complexity
|
183
|
+
def field_complexity(scoped_type_complexity, max_complexity:, child_complexity: nil)
|
184
|
+
end
|
91
185
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
max
|
186
|
+
# @param children_for_scope [Array<Hash>] An array of `scoped_children[scope]` hashes
|
187
|
+
# (`{field_key => complexity}`)
|
188
|
+
# @return [Integer] Complexity value for all these selections in the current scope
|
189
|
+
def merged_max_complexity(query, children_for_scope)
|
190
|
+
all_keys = []
|
191
|
+
children_for_scope.each do |c|
|
192
|
+
all_keys.concat(c.keys)
|
100
193
|
end
|
194
|
+
all_keys.uniq!
|
195
|
+
complexity_for_keys = {}
|
196
|
+
|
197
|
+
all_keys.each do |child_key|
|
198
|
+
scoped_children_for_key = nil
|
199
|
+
complexity_for_key = nil
|
200
|
+
children_for_scope.each do |children_hash|
|
201
|
+
next unless children_hash.key?(child_key)
|
202
|
+
|
203
|
+
complexity_for_key = children_hash[child_key]
|
204
|
+
if complexity_for_key.terminal?
|
205
|
+
# Assume that all terminals would return the same complexity
|
206
|
+
# Since it's a terminal, its child complexity is zero.
|
207
|
+
complexity = complexity_for_key.own_complexity(0)
|
208
|
+
complexity_for_keys[child_key] = complexity
|
209
|
+
|
210
|
+
field_complexity(complexity_for_key, max_complexity: complexity, child_complexity: nil)
|
211
|
+
else
|
212
|
+
scoped_children_for_key ||= []
|
213
|
+
scoped_children_for_key << complexity_for_key.scoped_children
|
214
|
+
end
|
215
|
+
end
|
101
216
|
|
102
|
-
|
103
|
-
# Later we will see if this is the max complexity among branches.
|
104
|
-
def merge(type_defn, key, complexity)
|
105
|
-
@types[type_defn][key] = complexity
|
106
|
-
end
|
107
|
-
end
|
217
|
+
next unless scoped_children_for_key
|
108
218
|
|
109
|
-
|
110
|
-
|
219
|
+
child_complexity = merged_max_complexity_for_scopes(query, scoped_children_for_key)
|
220
|
+
# This is the _last_ one we visited; assume it's representative.
|
221
|
+
max_complexity = complexity_for_key.own_complexity(child_complexity)
|
111
222
|
|
112
|
-
|
113
|
-
@max_possible_complexity = 0
|
114
|
-
end
|
223
|
+
field_complexity(complexity_for_key, max_complexity: max_complexity, child_complexity: child_complexity)
|
115
224
|
|
116
|
-
|
117
|
-
@max_possible_complexity += complexity
|
225
|
+
complexity_for_keys[child_key] = max_complexity
|
118
226
|
end
|
227
|
+
|
228
|
+
# Calculate the child complexity by summing the complexity of all selections
|
229
|
+
complexity_for_keys.each_value.inject(0, &:+)
|
119
230
|
end
|
120
231
|
end
|
121
232
|
end
|
@@ -134,7 +134,7 @@ module GraphQL
|
|
134
134
|
argument_defn = if (arg = @argument_definitions.last)
|
135
135
|
arg_type = arg.type.unwrap
|
136
136
|
if arg_type.kind.input_object?
|
137
|
-
arg_type.
|
137
|
+
arg_type.arguments[node.name]
|
138
138
|
else
|
139
139
|
nil
|
140
140
|
end
|
@@ -214,7 +214,7 @@ module GraphQL
|
|
214
214
|
fragment_def = query.fragments[fragment_spread.name]
|
215
215
|
|
216
216
|
object_type = if fragment_def.type
|
217
|
-
query.
|
217
|
+
@query.warden.get_type(fragment_def.type.name)
|
218
218
|
else
|
219
219
|
object_types.last
|
220
220
|
end
|
@@ -245,7 +245,7 @@ module GraphQL
|
|
245
245
|
|
246
246
|
def on_fragment_with_type(node)
|
247
247
|
object_type = if node.type
|
248
|
-
@
|
248
|
+
@query.warden.get_type(node.type.name)
|
249
249
|
else
|
250
250
|
@object_types.last
|
251
251
|
end
|
data/lib/graphql/analysis/ast.rb
CHANGED
@@ -12,9 +12,8 @@ module GraphQL
|
|
12
12
|
module AST
|
13
13
|
module_function
|
14
14
|
|
15
|
-
def use(
|
16
|
-
|
17
|
-
schema.analysis_engine = GraphQL::Analysis::AST
|
15
|
+
def use(schema_class)
|
16
|
+
schema_class.analysis_engine = GraphQL::Analysis::AST
|
18
17
|
end
|
19
18
|
|
20
19
|
# Analyze a multiplex, and all queries within.
|
@@ -60,16 +59,18 @@ module GraphQL
|
|
60
59
|
.select { |analyzer| analyzer.analyze? }
|
61
60
|
|
62
61
|
analyzers_to_run = query_analyzers + multiplex_analyzers
|
63
|
-
|
62
|
+
if analyzers_to_run.any?
|
63
|
+
visitor = GraphQL::Analysis::AST::Visitor.new(
|
64
|
+
query: query,
|
65
|
+
analyzers: analyzers_to_run
|
66
|
+
)
|
64
67
|
|
65
|
-
|
66
|
-
query: query,
|
67
|
-
analyzers: analyzers_to_run
|
68
|
-
)
|
68
|
+
visitor.visit
|
69
69
|
|
70
|
-
|
71
|
-
|
72
|
-
|
70
|
+
query_analyzers.map(&:result)
|
71
|
+
else
|
72
|
+
[]
|
73
|
+
end
|
73
74
|
end
|
74
75
|
end
|
75
76
|
|
data/lib/graphql/argument.rb
CHANGED
@@ -1,48 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# {#name} must be a String.
|
6
|
-
#
|
7
|
-
# @example defining an argument for a field
|
8
|
-
# GraphQL::Field.define do
|
9
|
-
# # ...
|
10
|
-
# argument :favoriteFood, types.String, "Favorite thing to eat", default_value: "pizza"
|
11
|
-
# end
|
12
|
-
#
|
13
|
-
# @example defining an argument for an {InputObjectType}
|
14
|
-
# GraphQL::InputObjectType.define do
|
15
|
-
# argument :newName, !types.String
|
16
|
-
# end
|
17
|
-
#
|
18
|
-
# @example defining an argument with a `prepare` function
|
19
|
-
# GraphQL::Field.define do
|
20
|
-
# argument :userId, types.ID, prepare: ->(userId) do
|
21
|
-
# User.find_by(id: userId)
|
22
|
-
# end
|
23
|
-
# end
|
24
|
-
#
|
25
|
-
# @example returning an {ExecutionError} from a `prepare` function
|
26
|
-
# GraphQL::Field.define do
|
27
|
-
# argument :date do
|
28
|
-
# type !types.String
|
29
|
-
# prepare ->(date) do
|
30
|
-
# return GraphQL::ExecutionError.new("Invalid date format") unless DateValidator.valid?(date)
|
31
|
-
# Time.zone.parse(date)
|
32
|
-
# end
|
33
|
-
# end
|
34
|
-
# end
|
35
|
-
|
3
|
+
# @api deprecated
|
36
4
|
class Argument
|
37
5
|
include GraphQL::Define::InstanceDefinable
|
38
|
-
accepts_definitions :name, :type, :description, :default_value, :as, :prepare, :method_access
|
6
|
+
accepts_definitions :name, :type, :description, :default_value, :as, :prepare, :method_access, :deprecation_reason
|
39
7
|
attr_reader :default_value
|
40
|
-
attr_accessor :description, :name, :as
|
8
|
+
attr_accessor :description, :name, :as, :deprecation_reason
|
41
9
|
attr_accessor :ast_node
|
42
10
|
attr_accessor :method_access
|
43
11
|
alias :graphql_name :name
|
44
12
|
|
45
|
-
ensure_defined(:name, :description, :default_value, :type=, :type, :as, :expose_as, :prepare, :method_access)
|
13
|
+
ensure_defined(:name, :description, :default_value, :type=, :type, :as, :expose_as, :prepare, :method_access, :deprecation_reason)
|
46
14
|
|
47
15
|
# @api private
|
48
16
|
module DefaultPrepare
|
@@ -113,6 +81,10 @@ module GraphQL
|
|
113
81
|
@prepare_proc = BackwardsCompatibility.wrap_arity(prepare_proc, from: 1, to: 2, name: "Argument#prepare(value, ctx)")
|
114
82
|
end
|
115
83
|
|
84
|
+
def type_class
|
85
|
+
metadata[:type_class]
|
86
|
+
end
|
87
|
+
|
116
88
|
NO_DEFAULT_VALUE = Object.new
|
117
89
|
# @api private
|
118
90
|
def self.from_dsl(name, type_or_argument = nil, description = nil, default_value: NO_DEFAULT_VALUE, as: nil, prepare: DefaultPrepare, **kwargs, &block)
|
@@ -134,9 +106,9 @@ module GraphQL
|
|
134
106
|
end
|
135
107
|
|
136
108
|
if type_or_argument.is_a?(GraphQL::Argument)
|
137
|
-
type_or_argument.redefine(kwargs, &block)
|
109
|
+
type_or_argument.redefine(**kwargs, &block)
|
138
110
|
else
|
139
|
-
GraphQL::Argument.define(kwargs, &block)
|
111
|
+
GraphQL::Argument.define(**kwargs, &block)
|
140
112
|
end
|
141
113
|
end
|
142
114
|
|
@@ -84,10 +84,14 @@ module GraphQL
|
|
84
84
|
field_name = "#{ctx.irep_node.owner_type.name}.#{ctx.field.name}"
|
85
85
|
position = "#{ctx.ast_node.line}:#{ctx.ast_node.col}"
|
86
86
|
field_alias = ctx.ast_node.alias
|
87
|
+
object = ctx.object
|
88
|
+
if object.is_a?(GraphQL::Schema::Object)
|
89
|
+
object = object.object
|
90
|
+
end
|
87
91
|
rows << [
|
88
92
|
"#{position}",
|
89
93
|
"#{field_name}#{field_alias ? " as #{field_alias}" : ""}",
|
90
|
-
"#{
|
94
|
+
"#{object.inspect}",
|
91
95
|
ctx.irep_node.arguments.to_h.inspect,
|
92
96
|
Backtrace::InspectResult.inspect_result(top && @override_value ? @override_value : ctx.value),
|
93
97
|
]
|
@@ -104,10 +108,14 @@ module GraphQL
|
|
104
108
|
position = "?:?"
|
105
109
|
end
|
106
110
|
op_name = query.selected_operation_name
|
111
|
+
object = query.root_value
|
112
|
+
if object.is_a?(GraphQL::Schema::Object)
|
113
|
+
object = object.object
|
114
|
+
end
|
107
115
|
rows << [
|
108
116
|
"#{position}",
|
109
117
|
"#{op_type}#{op_name ? " #{op_name}" : ""}",
|
110
|
-
"#{
|
118
|
+
"#{object.inspect}",
|
111
119
|
query.variables.to_h.inspect,
|
112
120
|
Backtrace::InspectResult.inspect_result(query.context.value),
|
113
121
|
]
|
@@ -15,7 +15,8 @@ module GraphQL
|
|
15
15
|
when "validate", "analyze_query", "execute_query", "execute_query_lazy"
|
16
16
|
metadata[:query] || metadata[:queries]
|
17
17
|
when "execute_field", "execute_field_lazy"
|
18
|
-
|
18
|
+
# The interpreter passes `query:`, legacy passes `context:`
|
19
|
+
metadata[:context] || ((q = metadata[:query]) && q.context)
|
19
20
|
else
|
20
21
|
# Custom key, no backtrace data for this
|
21
22
|
nil
|
data/lib/graphql/base_type.rb
CHANGED
@@ -70,15 +70,11 @@ module GraphQL
|
|
70
70
|
")
|
71
71
|
end
|
72
72
|
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
def test_it_parses_blank_queries
|
79
|
-
assert_empty_document("")
|
80
|
-
assert_empty_document(" ")
|
81
|
-
assert_empty_document("\t \t")
|
73
|
+
def test_it_rejects_blank_queries
|
74
|
+
assert_raises_parse_error("")
|
75
|
+
assert_raises_parse_error(" ")
|
76
|
+
assert_raises_parse_error("\t \t")
|
77
|
+
assert_raises_parse_error(" # comment ")
|
82
78
|
end
|
83
79
|
|
84
80
|
def test_it_restricts_on
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module Define
|
4
|
-
#
|
4
|
+
# @api deprecated
|
5
5
|
module AssignEnumValue
|
6
6
|
def self.call(enum_type, name, desc = nil, deprecation_reason: nil, value: name, &block)
|
7
7
|
enum_value = GraphQL::EnumType::EnumValue.define(
|
@@ -2,9 +2,9 @@
|
|
2
2
|
module GraphQL
|
3
3
|
module Define
|
4
4
|
module AssignGlobalIdField
|
5
|
-
def self.call(type_defn, field_name)
|
5
|
+
def self.call(type_defn, field_name, **field_kwargs)
|
6
6
|
resolve = GraphQL::Relay::GlobalIdResolve.new(type: type_defn)
|
7
|
-
GraphQL::Define::AssignObjectField.call(type_defn, field_name, type: GraphQL::ID_TYPE.to_non_null_type, resolve: resolve)
|
7
|
+
GraphQL::Define::AssignObjectField.call(type_defn, field_name, **field_kwargs, type: GraphQL::ID_TYPE.to_non_null_type, resolve: resolve)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module Define
|
4
|
-
#
|
4
|
+
# @api deprecated
|
5
5
|
module AssignObjectField
|
6
6
|
def self.call(owner_type, name, type_or_field = nil, desc = nil, function: nil, field: nil, relay_mutation_function: nil, **kwargs, &block)
|
7
7
|
name_s = name.to_s
|
@@ -28,9 +28,9 @@ module GraphQL
|
|
28
28
|
end
|
29
29
|
|
30
30
|
obj_field = if base_field
|
31
|
-
base_field.redefine(kwargs, &block)
|
31
|
+
base_field.redefine(**kwargs, &block)
|
32
32
|
else
|
33
|
-
GraphQL::Field.define(kwargs, &block)
|
33
|
+
GraphQL::Field.define(**kwargs, &block)
|
34
34
|
end
|
35
35
|
|
36
36
|
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module GraphQL
|
3
4
|
module Define
|
4
5
|
# This object delegates most methods to a dictionary of functions, {@dictionary}.
|
5
6
|
# {@target} is passed to the specified function, along with any arguments and block.
|
6
7
|
# This allows a method-based DSL without adding methods to the defined class.
|
7
8
|
class DefinedObjectProxy
|
9
|
+
extend GraphQL::Ruby2Keywords
|
8
10
|
# The object which will be defined by definition functions
|
9
11
|
attr_reader :target
|
10
12
|
|
@@ -41,6 +43,7 @@ module GraphQL
|
|
41
43
|
raise NoDefinitionError, msg, caller
|
42
44
|
end
|
43
45
|
end
|
46
|
+
ruby2_keywords :method_missing
|
44
47
|
|
45
48
|
def respond_to_missing?(name, include_private = false)
|
46
49
|
@dictionary[name] || super
|