graphql 1.13.14 → 2.0.19
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_generator.rb +1 -1
- data/lib/generators/graphql/relay.rb +3 -17
- data/lib/generators/graphql/templates/schema.erb +3 -0
- data/lib/graphql/analysis/ast/field_usage.rb +3 -1
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
- data/lib/graphql/analysis/ast/query_depth.rb +0 -1
- data/lib/graphql/analysis/ast/visitor.rb +43 -36
- data/lib/graphql/analysis/ast.rb +2 -12
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/table.rb +2 -20
- data/lib/graphql/backtrace/tracer.rb +2 -3
- data/lib/graphql/backtrace.rb +2 -8
- data/lib/graphql/dataloader/null_dataloader.rb +3 -1
- data/lib/graphql/dataloader/source.rb +9 -0
- data/lib/graphql/dataloader.rb +4 -1
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/execution/errors.rb +12 -82
- data/lib/graphql/execution/interpreter/resolve.rb +26 -0
- data/lib/graphql/execution/interpreter/runtime.rb +163 -120
- data/lib/graphql/execution/interpreter.rb +187 -78
- data/lib/graphql/execution/lazy.rb +7 -21
- data/lib/graphql/execution/lookahead.rb +44 -40
- data/lib/graphql/execution/multiplex.rb +3 -174
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/introspection/directive_type.rb +2 -2
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +2 -15
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +2 -2
- data/lib/graphql/introspection/type_type.rb +13 -6
- data/lib/graphql/introspection.rb +4 -3
- data/lib/graphql/language/document_from_schema_definition.rb +18 -35
- data/lib/graphql/language/lexer.rb +216 -1488
- data/lib/graphql/language/lexer.ri +744 -0
- data/lib/graphql/language/nodes.rb +41 -33
- data/lib/graphql/language/parser.rb +375 -363
- data/lib/graphql/language/parser.y +48 -43
- data/lib/graphql/language/printer.rb +37 -21
- data/lib/graphql/language/visitor.rb +191 -83
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +4 -2
- data/lib/graphql/pagination/connection.rb +31 -4
- data/lib/graphql/pagination/connections.rb +3 -28
- data/lib/graphql/pagination/relation_connection.rb +2 -0
- data/lib/graphql/query/context.rb +155 -196
- data/lib/graphql/query/input_validation_result.rb +10 -1
- data/lib/graphql/query/null_context.rb +0 -3
- data/lib/graphql/query/validation_pipeline.rb +12 -37
- data/lib/graphql/query/variable_validation_error.rb +2 -2
- data/lib/graphql/query/variables.rb +35 -21
- data/lib/graphql/query.rb +32 -43
- data/lib/graphql/railtie.rb +0 -104
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +29 -1
- data/lib/graphql/relay/range_add.rb +9 -20
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/schema/addition.rb +7 -9
- data/lib/graphql/schema/argument.rb +36 -43
- data/lib/graphql/schema/build_from_definition.rb +32 -18
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +12 -23
- data/lib/graphql/schema/enum.rb +29 -41
- data/lib/graphql/schema/enum_value.rb +5 -25
- data/lib/graphql/schema/field/connection_extension.rb +4 -0
- data/lib/graphql/schema/field.rb +245 -343
- data/lib/graphql/schema/input_object.rb +57 -69
- data/lib/graphql/schema/interface.rb +0 -35
- data/lib/graphql/schema/introspection_system.rb +3 -8
- data/lib/graphql/schema/late_bound_type.rb +8 -2
- data/lib/graphql/schema/list.rb +18 -9
- data/lib/graphql/schema/loader.rb +1 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -19
- data/lib/graphql/schema/member/build_type.rb +5 -7
- data/lib/graphql/schema/member/has_arguments.rb +146 -55
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +71 -56
- data/lib/graphql/schema/member/has_fields.rb +16 -4
- data/lib/graphql/schema/member/has_interfaces.rb +49 -10
- data/lib/graphql/schema/member/has_validators.rb +31 -5
- data/lib/graphql/schema/member/relay_shortcuts.rb +28 -2
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/member.rb +0 -6
- data/lib/graphql/schema/mutation.rb +0 -9
- data/lib/graphql/schema/non_null.rb +3 -9
- data/lib/graphql/schema/object.rb +15 -52
- data/lib/graphql/schema/relay_classic_mutation.rb +53 -42
- data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
- data/lib/graphql/schema/resolver.rb +41 -42
- data/lib/graphql/schema/scalar.rb +8 -23
- data/lib/graphql/schema/subscription.rb +0 -7
- data/lib/graphql/schema/timeout.rb +24 -28
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +10 -17
- data/lib/graphql/schema/warden.rb +34 -8
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +240 -968
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +4 -21
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/error.rb +2 -2
- data/lib/graphql/static_validation/literal_validator.rb +19 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +12 -12
- 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/unique_directives_per_location.rb +12 -6
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
- data/lib/graphql/static_validation/validator.rb +3 -25
- data/lib/graphql/static_validation.rb +0 -2
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
- data/lib/graphql/subscriptions/event.rb +3 -8
- data/lib/graphql/subscriptions/instrumentation.rb +0 -51
- data/lib/graphql/subscriptions.rb +32 -20
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +231 -0
- data/lib/graphql/tracing/appsignal_trace.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +148 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +41 -0
- data/lib/graphql/tracing/platform_trace.rb +107 -0
- data/lib/graphql/tracing/platform_tracing.rb +26 -40
- 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/statsd_trace.rb +56 -0
- data/lib/graphql/tracing.rb +136 -41
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/iso_8601_date.rb +4 -1
- data/lib/graphql/types/iso_8601_date_time.rb +4 -0
- data/lib/graphql/types/relay/base_connection.rb +16 -6
- data/lib/graphql/types/relay/connection_behaviors.rb +5 -25
- data/lib/graphql/types/relay/default_relay.rb +5 -9
- data/lib/graphql/types/relay/edge_behaviors.rb +1 -4
- data/lib/graphql/types/relay/node_behaviors.rb +5 -1
- data/lib/graphql/types/relay.rb +0 -2
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +11 -72
- metadata +31 -133
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/field_usage.rb +0 -45
- data/lib/graphql/analysis/max_query_complexity.rb +0 -26
- data/lib/graphql/analysis/max_query_depth.rb +0 -26
- data/lib/graphql/analysis/query_complexity.rb +0 -88
- data/lib/graphql/analysis/query_depth.rb +0 -43
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -232
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -255
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -55
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -107
- data/lib/graphql/enum_type.rb +0 -133
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/instrumentation.rb +0 -92
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -260
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -54
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -39
- data/lib/graphql/relay/global_id_resolve.rb +0 -17
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/member/accepts_definition.rb +0 -164
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/opentelemetry_tracing.rb +0 -101
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/node_field.rb +0 -24
- data/lib/graphql/types/relay/nodes_field.rb +0 -43
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
@@ -11,98 +11,207 @@ require "graphql/execution/interpreter/handles_raw_value"
|
|
11
11
|
module GraphQL
|
12
12
|
module Execution
|
13
13
|
class Interpreter
|
14
|
-
|
15
|
-
|
14
|
+
class << self
|
15
|
+
# Used internally to signal that the query shouldn't be executed
|
16
|
+
# @api private
|
17
|
+
NO_OPERATION = {}.freeze
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
# @param schema [GraphQL::Schema]
|
20
|
+
# @param queries [Array<GraphQL::Query, Hash>]
|
21
|
+
# @param context [Hash]
|
22
|
+
# @param max_complexity [Integer, nil]
|
23
|
+
# @return [Array<Hash>] One result per query
|
24
|
+
def run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
|
25
|
+
queries = query_options.map do |opts|
|
26
|
+
case opts
|
27
|
+
when Hash
|
28
|
+
GraphQL::Query.new(schema, nil, **opts)
|
29
|
+
when GraphQL::Query
|
30
|
+
opts
|
31
|
+
else
|
32
|
+
raise "Expected Hash or GraphQL::Query, not #{opts.class} (#{opts.inspect})"
|
33
|
+
end
|
34
|
+
end
|
23
35
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
schema_class.subscription_execution_strategy(self)
|
32
|
-
schema_class.add_subscription_extension_if_necessary
|
33
|
-
end
|
34
|
-
end
|
36
|
+
multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
|
37
|
+
multiplex.current_trace.execute_multiplex(multiplex: multiplex) do
|
38
|
+
schema = multiplex.schema
|
39
|
+
queries = multiplex.queries
|
40
|
+
query_instrumenters = schema.instrumenters[:query]
|
41
|
+
multiplex_instrumenters = schema.instrumenters[:multiplex]
|
42
|
+
lazies_at_depth = Hash.new { |h, k| h[k] = [] }
|
35
43
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
44
|
+
# First, run multiplex instrumentation, then query instrumentation for each query
|
45
|
+
call_hooks(multiplex_instrumenters, multiplex, :before_multiplex, :after_multiplex) do
|
46
|
+
each_query_call_hooks(query_instrumenters, queries) do
|
47
|
+
schema = multiplex.schema
|
48
|
+
multiplex_analyzers = schema.multiplex_analyzers
|
49
|
+
queries = multiplex.queries
|
50
|
+
if multiplex.max_complexity
|
51
|
+
multiplex_analyzers += [GraphQL::Analysis::AST::MaxQueryComplexity]
|
52
|
+
end
|
41
53
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
54
|
+
schema.analysis_engine.analyze_multiplex(multiplex, multiplex_analyzers)
|
55
|
+
begin
|
56
|
+
# Since this is basically the batching context,
|
57
|
+
# share it for a whole multiplex
|
58
|
+
multiplex.context[:interpreter_instance] ||= multiplex.schema.query_execution_strategy.new
|
59
|
+
# Do as much eager evaluation of the query as possible
|
60
|
+
results = []
|
61
|
+
queries.each_with_index do |query, idx|
|
62
|
+
multiplex.dataloader.append_job {
|
63
|
+
operation = query.selected_operation
|
64
|
+
result = if operation.nil? || !query.valid? || query.context.errors.any?
|
65
|
+
NO_OPERATION
|
66
|
+
else
|
67
|
+
begin
|
68
|
+
# Although queries in a multiplex _share_ an Interpreter instance,
|
69
|
+
# they also have another item of state, which is private to that query
|
70
|
+
# in particular, assign it here:
|
71
|
+
runtime = Runtime.new(query: query, lazies_at_depth: lazies_at_depth)
|
72
|
+
query.context.namespace(:interpreter_runtime)[:runtime] = runtime
|
51
73
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
74
|
+
query.current_trace.execute_query(query: query) do
|
75
|
+
runtime.run_eager
|
76
|
+
end
|
77
|
+
rescue GraphQL::ExecutionError => err
|
78
|
+
query.context.errors << err
|
79
|
+
NO_OPERATION
|
80
|
+
end
|
81
|
+
end
|
82
|
+
results[idx] = result
|
83
|
+
}
|
84
|
+
end
|
56
85
|
|
57
|
-
|
58
|
-
{
|
59
|
-
"data" => query.context.namespace(:interpreter)[:runtime].final_result
|
60
|
-
}
|
61
|
-
end
|
86
|
+
multiplex.dataloader.run
|
62
87
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
88
|
+
# Then, work through lazy results in a breadth-first way
|
89
|
+
multiplex.dataloader.append_job {
|
90
|
+
tracer = multiplex
|
91
|
+
query = multiplex.queries.length == 1 ? multiplex.queries[0] : nil
|
92
|
+
queries = multiplex ? multiplex.queries : [query]
|
93
|
+
final_values = queries.map do |query|
|
94
|
+
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
95
|
+
# it might not be present if the query has an error
|
96
|
+
runtime ? runtime.final_result : nil
|
97
|
+
end
|
98
|
+
final_values.compact!
|
99
|
+
tracer.current_trace.execute_query_lazy(multiplex: multiplex, query: query) do
|
100
|
+
Interpreter::Resolve.resolve_each_depth(lazies_at_depth, multiplex.dataloader)
|
101
|
+
end
|
102
|
+
queries.each do |query|
|
103
|
+
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
104
|
+
if runtime
|
105
|
+
runtime.delete_all_interpreter_context
|
106
|
+
end
|
107
|
+
end
|
108
|
+
}
|
109
|
+
multiplex.dataloader.run
|
75
110
|
|
76
|
-
|
77
|
-
|
111
|
+
# Then, find all errors and assign the result to the query object
|
112
|
+
results.each_with_index do |data_result, idx|
|
113
|
+
query = queries[idx]
|
114
|
+
# Assign the result so that it can be accessed in instrumentation
|
115
|
+
query.result_values = if data_result.equal?(NO_OPERATION)
|
116
|
+
if !query.valid? || query.context.errors.any?
|
117
|
+
# A bit weird, but `Query#static_errors` _includes_ `query.context.errors`
|
118
|
+
{ "errors" => query.static_errors.map(&:to_h) }
|
119
|
+
else
|
120
|
+
data_result
|
121
|
+
end
|
122
|
+
else
|
123
|
+
result = {
|
124
|
+
"data" => query.context.namespace(:interpreter_runtime)[:runtime].final_result
|
125
|
+
}
|
126
|
+
|
127
|
+
if query.context.errors.any?
|
128
|
+
error_result = query.context.errors.map(&:to_h)
|
129
|
+
result["errors"] = error_result
|
130
|
+
end
|
78
131
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
132
|
+
result
|
133
|
+
end
|
134
|
+
if query.context.namespace?(:__query_result_extensions__)
|
135
|
+
query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__)
|
136
|
+
end
|
137
|
+
# Get the Query::Result, not the Hash
|
138
|
+
results[idx] = query.result
|
139
|
+
end
|
140
|
+
|
141
|
+
results
|
142
|
+
rescue Exception
|
143
|
+
# TODO rescue at a higher level so it will catch errors in analysis, too
|
144
|
+
# Assign values here so that the query's `@executed` becomes true
|
145
|
+
queries.map { |q| q.result_values ||= {} }
|
146
|
+
raise
|
147
|
+
ensure
|
148
|
+
queries.map { |query|
|
149
|
+
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
150
|
+
if runtime
|
151
|
+
runtime.delete_all_interpreter_context
|
152
|
+
end
|
153
|
+
}
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
85
158
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
# Call the before_ hooks of each query,
|
163
|
+
# Then yield if no errors.
|
164
|
+
# `call_hooks` takes care of appropriate cleanup.
|
165
|
+
def each_query_call_hooks(instrumenters, queries, i = 0)
|
166
|
+
if i >= queries.length
|
167
|
+
yield
|
168
|
+
else
|
169
|
+
query = queries[i]
|
170
|
+
call_hooks(instrumenters, query, :before_query, :after_query) {
|
171
|
+
each_query_call_hooks(instrumenters, queries, i + 1) {
|
172
|
+
yield
|
173
|
+
}
|
174
|
+
}
|
175
|
+
end
|
91
176
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
177
|
+
|
178
|
+
# Call each before hook, and if they all succeed, yield.
|
179
|
+
# If they don't all succeed, call after_ for each one that succeeded.
|
180
|
+
def call_hooks(instrumenters, object, before_hook_name, after_hook_name)
|
181
|
+
begin
|
182
|
+
successful = []
|
183
|
+
instrumenters.each do |instrumenter|
|
184
|
+
instrumenter.public_send(before_hook_name, object)
|
185
|
+
successful << instrumenter
|
186
|
+
end
|
187
|
+
|
188
|
+
# if any before hooks raise an exception, quit calling before hooks,
|
189
|
+
# but call the after hooks on anything that succeeded but also
|
190
|
+
# raise the exception that came from the before hook.
|
191
|
+
rescue GraphQL::ExecutionError => err
|
192
|
+
object.context.errors << err
|
193
|
+
rescue => e
|
194
|
+
raise call_after_hooks(successful, object, after_hook_name, e)
|
195
|
+
end
|
196
|
+
|
197
|
+
begin
|
198
|
+
yield # Call the user code
|
199
|
+
ensure
|
200
|
+
ex = call_after_hooks(successful, object, after_hook_name, nil)
|
201
|
+
raise ex if ex
|
202
|
+
end
|
95
203
|
end
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
204
|
+
|
205
|
+
def call_after_hooks(instrumenters, object, after_hook_name, ex)
|
206
|
+
instrumenters.reverse_each do |instrumenter|
|
207
|
+
begin
|
208
|
+
instrumenter.public_send(after_hook_name, object)
|
209
|
+
rescue => e
|
210
|
+
ex = e
|
211
|
+
end
|
103
212
|
end
|
213
|
+
ex
|
104
214
|
end
|
105
|
-
nil
|
106
215
|
end
|
107
216
|
|
108
217
|
class ListResultFailedError < GraphQL::Error
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "graphql/execution/lazy/lazy_method_map"
|
3
|
-
require "graphql/execution/lazy/resolve"
|
4
3
|
|
5
4
|
module GraphQL
|
6
5
|
module Execution
|
@@ -13,23 +12,14 @@ module GraphQL
|
|
13
12
|
# - It has no error-catching functionality
|
14
13
|
# @api private
|
15
14
|
class Lazy
|
16
|
-
|
17
|
-
# @param val [Object] A data structure containing mixed plain values and `Lazy` instances
|
18
|
-
# @return void
|
19
|
-
def self.resolve(val)
|
20
|
-
Resolve.resolve(val)
|
21
|
-
end
|
22
|
-
|
23
|
-
attr_reader :path, :field
|
15
|
+
attr_reader :field
|
24
16
|
|
25
17
|
# Create a {Lazy} which will get its inner value by calling the block
|
26
|
-
# @param path [Array<String, Integer>]
|
27
18
|
# @param field [GraphQL::Schema::Field]
|
28
19
|
# @param get_value_func [Proc] a block to get the inner value (later)
|
29
|
-
def initialize(
|
20
|
+
def initialize(field: nil, &get_value_func)
|
30
21
|
@get_value_func = get_value_func
|
31
22
|
@resolved = false
|
32
|
-
@path = path
|
33
23
|
@field = field
|
34
24
|
end
|
35
25
|
|
@@ -37,22 +27,18 @@ module GraphQL
|
|
37
27
|
def value
|
38
28
|
if !@resolved
|
39
29
|
@resolved = true
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
v = v.value
|
44
|
-
end
|
45
|
-
v
|
46
|
-
rescue GraphQL::ExecutionError => err
|
47
|
-
err
|
30
|
+
v = @get_value_func.call
|
31
|
+
if v.is_a?(Lazy)
|
32
|
+
v = v.value
|
48
33
|
end
|
34
|
+
@value = v
|
49
35
|
end
|
50
36
|
|
51
37
|
# `SKIP` was made into a subclass of `GraphQL::Error` to improve runtime performance
|
52
38
|
# (fewer clauses in a hot `case` block), but now it requires special handling here.
|
53
39
|
# I think it's still worth it for the performance win, but if the number of special
|
54
40
|
# cases grows, then maybe it's worth rethinking somehow.
|
55
|
-
if @value.is_a?(StandardError) && @value != GraphQL::Execution::
|
41
|
+
if @value.is_a?(StandardError) && @value != GraphQL::Execution::SKIP
|
56
42
|
raise @value
|
57
43
|
else
|
58
44
|
@value
|
@@ -76,8 +76,8 @@ module GraphQL
|
|
76
76
|
# @param field_name [String, Symbol]
|
77
77
|
# @param arguments [Hash] Arguments which must match in the selection
|
78
78
|
# @return [Boolean]
|
79
|
-
def selects?(field_name, arguments: nil)
|
80
|
-
selection(field_name, arguments: arguments).selected?
|
79
|
+
def selects?(field_name, selected_type: @selected_type, arguments: nil)
|
80
|
+
selection(field_name, selected_type: selected_type, arguments: arguments).selected?
|
81
81
|
end
|
82
82
|
|
83
83
|
# @return [Boolean] True if this lookahead represents a field that was requested
|
@@ -87,16 +87,39 @@ module GraphQL
|
|
87
87
|
|
88
88
|
# Like {#selects?}, but can be used for chaining.
|
89
89
|
# It returns a null object (check with {#selected?})
|
90
|
+
# @param field_name [String, Symbol]
|
90
91
|
# @return [GraphQL::Execution::Lookahead]
|
91
92
|
def selection(field_name, selected_type: @selected_type, arguments: nil)
|
92
|
-
|
93
|
+
next_field_defn = case field_name
|
94
|
+
when String
|
95
|
+
@query.get_field(selected_type, field_name)
|
96
|
+
when Symbol
|
97
|
+
# Try to avoid the `.to_s` below, if possible
|
98
|
+
all_fields = if selected_type.kind.fields?
|
99
|
+
@query.warden.fields(selected_type)
|
100
|
+
else
|
101
|
+
# Handle unions by checking possible
|
102
|
+
@query.warden
|
103
|
+
.possible_types(selected_type)
|
104
|
+
.map { |t| @query.warden.fields(t) }
|
105
|
+
.flatten
|
106
|
+
end
|
107
|
+
|
108
|
+
if (match_by_orig_name = all_fields.find { |f| f.original_name == field_name })
|
109
|
+
match_by_orig_name
|
110
|
+
else
|
111
|
+
# Symbol#name is only present on 3.0+
|
112
|
+
sym_s = field_name.respond_to?(:name) ? field_name.name : field_name.to_s
|
113
|
+
guessed_name = Schema::Member::BuildType.camelize(sym_s)
|
114
|
+
@query.get_field(selected_type, guessed_name)
|
115
|
+
end
|
116
|
+
end
|
93
117
|
|
94
|
-
next_field_defn = get_class_based_field(selected_type, next_field_name)
|
95
118
|
if next_field_defn
|
96
119
|
next_nodes = []
|
97
120
|
@ast_nodes.each do |ast_node|
|
98
121
|
ast_node.selections.each do |selection|
|
99
|
-
find_selected_nodes(selection,
|
122
|
+
find_selected_nodes(selection, next_field_defn, arguments: arguments, matches: next_nodes)
|
100
123
|
end
|
101
124
|
end
|
102
125
|
|
@@ -137,7 +160,7 @@ module GraphQL
|
|
137
160
|
|
138
161
|
subselections_by_type.each do |type, ast_nodes_by_response_key|
|
139
162
|
ast_nodes_by_response_key.each do |response_key, ast_nodes|
|
140
|
-
field_defn =
|
163
|
+
field_defn = @query.get_field(type, ast_nodes.first.name)
|
141
164
|
lookahead = Lookahead.new(query: @query, ast_nodes: ast_nodes, field: field_defn, owner_type: type)
|
142
165
|
subselections.push(lookahead)
|
143
166
|
end
|
@@ -196,34 +219,10 @@ module GraphQL
|
|
196
219
|
|
197
220
|
private
|
198
221
|
|
199
|
-
# If it's a symbol, stringify and camelize it
|
200
|
-
def normalize_name(name)
|
201
|
-
if name.is_a?(Symbol)
|
202
|
-
Schema::Member::BuildType.camelize(name.to_s)
|
203
|
-
else
|
204
|
-
name
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
def normalize_keyword(keyword)
|
209
|
-
if keyword.is_a?(String)
|
210
|
-
Schema::Member::BuildType.underscore(keyword).to_sym
|
211
|
-
else
|
212
|
-
keyword
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
# Wrap get_field and ensure that it returns a GraphQL::Schema::Field.
|
217
|
-
# Remove this when legacy execution is removed.
|
218
|
-
def get_class_based_field(type, name)
|
219
|
-
f = @query.get_field(type, name)
|
220
|
-
f && f.type_class
|
221
|
-
end
|
222
|
-
|
223
222
|
def skipped_by_directive?(ast_selection)
|
224
223
|
ast_selection.directives.each do |directive|
|
225
224
|
dir_defn = @query.schema.directives.fetch(directive.name)
|
226
|
-
directive_class = dir_defn
|
225
|
+
directive_class = dir_defn
|
227
226
|
if directive_class
|
228
227
|
dir_args = @query.arguments_for(directive, dir_defn)
|
229
228
|
return true unless directive_class.static_include?(dir_args, @query.context)
|
@@ -244,7 +243,7 @@ module GraphQL
|
|
244
243
|
elsif arguments.nil? || arguments.empty?
|
245
244
|
selections_on_type[response_key] = [ast_selection]
|
246
245
|
else
|
247
|
-
field_defn =
|
246
|
+
field_defn = @query.get_field(selected_type, ast_selection.name)
|
248
247
|
if arguments_match?(arguments, field_defn, ast_selection)
|
249
248
|
selections_on_type[response_key] = [ast_selection]
|
250
249
|
end
|
@@ -254,14 +253,14 @@ module GraphQL
|
|
254
253
|
subselections_on_type = selections_on_type
|
255
254
|
if (t = ast_selection.type)
|
256
255
|
# Assuming this is valid, that `t` will be found.
|
257
|
-
on_type = @query.get_type(t.name)
|
256
|
+
on_type = @query.get_type(t.name)
|
258
257
|
subselections_on_type = subselections_by_type[on_type] ||= {}
|
259
258
|
end
|
260
259
|
find_selections(subselections_by_type, subselections_on_type, on_type, ast_selection.selections, arguments)
|
261
260
|
when GraphQL::Language::Nodes::FragmentSpread
|
262
261
|
frag_defn = @query.fragments[ast_selection.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{ast_selection.name} (found: #{@query.fragments.keys})")
|
263
262
|
# Again, assuming a valid AST
|
264
|
-
on_type = @query.get_type(frag_defn.type.name)
|
263
|
+
on_type = @query.get_type(frag_defn.type.name)
|
265
264
|
subselections_on_type = subselections_by_type[on_type] ||= {}
|
266
265
|
find_selections(subselections_by_type, subselections_on_type, on_type, frag_defn.selections, arguments)
|
267
266
|
else
|
@@ -272,11 +271,11 @@ module GraphQL
|
|
272
271
|
|
273
272
|
# If a selection on `node` matches `field_name` (which is backed by `field_defn`)
|
274
273
|
# and matches the `arguments:` constraints, then add that node to `matches`
|
275
|
-
def find_selected_nodes(node,
|
274
|
+
def find_selected_nodes(node, field_defn, arguments:, matches:)
|
276
275
|
return if skipped_by_directive?(node)
|
277
276
|
case node
|
278
277
|
when GraphQL::Language::Nodes::Field
|
279
|
-
if node.name ==
|
278
|
+
if node.name == field_defn.graphql_name
|
280
279
|
if arguments.nil? || arguments.empty?
|
281
280
|
# No constraint applied
|
282
281
|
matches << node
|
@@ -285,10 +284,10 @@ module GraphQL
|
|
285
284
|
end
|
286
285
|
end
|
287
286
|
when GraphQL::Language::Nodes::InlineFragment
|
288
|
-
node.selections.each { |s| find_selected_nodes(s,
|
287
|
+
node.selections.each { |s| find_selected_nodes(s, field_defn, arguments: arguments, matches: matches) }
|
289
288
|
when GraphQL::Language::Nodes::FragmentSpread
|
290
289
|
frag_defn = @query.fragments[node.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{node.name} (found: #{@query.fragments.keys})")
|
291
|
-
frag_defn.selections.each { |s| find_selected_nodes(s,
|
290
|
+
frag_defn.selections.each { |s| find_selected_nodes(s, field_defn, arguments: arguments, matches: matches) }
|
292
291
|
else
|
293
292
|
raise "Unexpected selection comparison on #{node.class.name} (#{node})"
|
294
293
|
end
|
@@ -297,9 +296,14 @@ module GraphQL
|
|
297
296
|
def arguments_match?(arguments, field_defn, field_node)
|
298
297
|
query_kwargs = @query.arguments_for(field_node, field_defn)
|
299
298
|
arguments.all? do |arg_name, arg_value|
|
300
|
-
|
299
|
+
arg_name_sym = if arg_name.is_a?(String)
|
300
|
+
Schema::Member::BuildType.underscore(arg_name).to_sym
|
301
|
+
else
|
302
|
+
arg_name
|
303
|
+
end
|
304
|
+
|
301
305
|
# Make sure the constraint is present with a matching value
|
302
|
-
query_kwargs.key?(
|
306
|
+
query_kwargs.key?(arg_name_sym) && query_kwargs[arg_name_sym] == arg_value
|
303
307
|
end
|
304
308
|
end
|
305
309
|
end
|