graphql 2.2.5 → 2.2.12
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/graphql/analysis/ast/field_usage.rb +32 -7
- data/lib/graphql/analysis/ast.rb +10 -1
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/execution/interpreter/runtime.rb +9 -0
- data/lib/graphql/execution/interpreter.rb +90 -150
- data/lib/graphql/introspection/entry_points.rb +9 -3
- data/lib/graphql/introspection/schema_type.rb +3 -1
- data/lib/graphql/language/document_from_schema_definition.rb +1 -2
- data/lib/graphql/language/nodes.rb +1 -1
- data/lib/graphql/language/parser.rb +11 -1
- data/lib/graphql/language/printer.rb +4 -0
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +1 -1
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/field.rb +33 -30
- data/lib/graphql/schema/interface.rb +5 -1
- data/lib/graphql/schema/member/has_arguments.rb +2 -2
- data/lib/graphql/schema/resolver.rb +9 -5
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema.rb +88 -27
- data/lib/graphql/static_validation/literal_validator.rb +1 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
- data/lib/graphql/static_validation/validator.rb +3 -0
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +0 -3
- data/lib/graphql/testing/helpers.rb +8 -4
- data/lib/graphql/tracing/data_dog_trace.rb +21 -34
- data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +2 -0
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing.rb +3 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -2
- metadata +24 -23
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
data/lib/graphql/schema/field.rb
CHANGED
|
@@ -471,6 +471,8 @@ module GraphQL
|
|
|
471
471
|
if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
|
|
472
472
|
max_possible_page_size = arguments[:last]
|
|
473
473
|
end
|
|
474
|
+
elsif arguments.is_a?(GraphQL::UnauthorizedError)
|
|
475
|
+
raise arguments
|
|
474
476
|
end
|
|
475
477
|
|
|
476
478
|
if max_possible_page_size.nil?
|
|
@@ -483,41 +485,24 @@ module GraphQL
|
|
|
483
485
|
metadata_complexity = 0
|
|
484
486
|
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
|
485
487
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
488
|
+
lookahead.selections.each do |next_lookahead|
|
|
489
|
+
# this includes `pageInfo`, `nodes` and `edges` and any custom fields
|
|
490
|
+
# TODO this doesn't support procs yet -- unlikely to need it.
|
|
491
|
+
metadata_complexity += next_lookahead.field.complexity
|
|
492
|
+
if next_lookahead.name != :nodes && next_lookahead.name != :edges
|
|
493
|
+
# subfields, eg, for pageInfo -- assumes no subselections
|
|
494
|
+
metadata_complexity += next_lookahead.selections.size
|
|
495
|
+
end
|
|
493
496
|
end
|
|
494
497
|
|
|
495
|
-
nodes_edges_complexity = 0
|
|
496
|
-
nodes_edges_complexity += 1 if lookahead.selects?(:edges)
|
|
497
|
-
nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
|
|
498
|
-
|
|
499
498
|
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
|
500
|
-
items_complexity = child_complexity - metadata_complexity
|
|
501
|
-
|
|
502
|
-
|
|
499
|
+
items_complexity = child_complexity - metadata_complexity
|
|
500
|
+
subfields_complexity = (max_possible_page_size * items_complexity) + metadata_complexity
|
|
501
|
+
# Apply this field's own complexity
|
|
502
|
+
apply_own_complexity_to(subfields_complexity, query, nodes)
|
|
503
503
|
end
|
|
504
504
|
else
|
|
505
|
-
|
|
506
|
-
case defined_complexity
|
|
507
|
-
when Proc
|
|
508
|
-
arguments = query.arguments_for(nodes.first, self)
|
|
509
|
-
if arguments.is_a?(GraphQL::ExecutionError)
|
|
510
|
-
return child_complexity
|
|
511
|
-
elsif arguments.respond_to?(:keyword_arguments)
|
|
512
|
-
arguments = arguments.keyword_arguments
|
|
513
|
-
end
|
|
514
|
-
|
|
515
|
-
defined_complexity.call(query.context, arguments, child_complexity)
|
|
516
|
-
when Numeric
|
|
517
|
-
defined_complexity + child_complexity
|
|
518
|
-
else
|
|
519
|
-
raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
|
|
520
|
-
end
|
|
505
|
+
apply_own_complexity_to(child_complexity, query, nodes)
|
|
521
506
|
end
|
|
522
507
|
end
|
|
523
508
|
|
|
@@ -882,6 +867,24 @@ ERR
|
|
|
882
867
|
yield(obj, args)
|
|
883
868
|
end
|
|
884
869
|
end
|
|
870
|
+
|
|
871
|
+
def apply_own_complexity_to(child_complexity, query, nodes)
|
|
872
|
+
case (own_complexity = complexity)
|
|
873
|
+
when Numeric
|
|
874
|
+
own_complexity + child_complexity
|
|
875
|
+
when Proc
|
|
876
|
+
arguments = query.arguments_for(nodes.first, self)
|
|
877
|
+
if arguments.is_a?(GraphQL::ExecutionError)
|
|
878
|
+
return child_complexity
|
|
879
|
+
elsif arguments.respond_to?(:keyword_arguments)
|
|
880
|
+
arguments = arguments.keyword_arguments
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
own_complexity.call(query.context, arguments, child_complexity)
|
|
884
|
+
else
|
|
885
|
+
raise ArgumentError, "Invalid complexity for #{self.path}: #{own_complexity.inspect}"
|
|
886
|
+
end
|
|
887
|
+
end
|
|
885
888
|
end
|
|
886
889
|
end
|
|
887
890
|
end
|
|
@@ -69,7 +69,11 @@ module GraphQL
|
|
|
69
69
|
end
|
|
70
70
|
elsif child_class < GraphQL::Schema::Object
|
|
71
71
|
# This is being included into an object type, make sure it's using `implements(...)`
|
|
72
|
-
backtrace_line =
|
|
72
|
+
backtrace_line = caller_locations(0, 10).find do |location|
|
|
73
|
+
location.base_label == "implements" &&
|
|
74
|
+
location.path.end_with?("schema/member/has_interfaces.rb")
|
|
75
|
+
end
|
|
76
|
+
|
|
73
77
|
if !backtrace_line
|
|
74
78
|
raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
|
|
75
79
|
end
|
|
@@ -50,7 +50,7 @@ module GraphQL
|
|
|
50
50
|
if loads && arg_defn.type.list?
|
|
51
51
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
52
52
|
def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
|
|
53
|
-
argument = get_argument("#{arg_defn.graphql_name}")
|
|
53
|
+
argument = get_argument("#{arg_defn.graphql_name}", context || self.context)
|
|
54
54
|
(context || self.context).query.after_lazy(values) do |values2|
|
|
55
55
|
GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
|
|
56
56
|
end
|
|
@@ -59,7 +59,7 @@ module GraphQL
|
|
|
59
59
|
elsif loads
|
|
60
60
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
61
61
|
def #{method_owner}load_#{arg_defn.keyword}(value, context = nil)
|
|
62
|
-
argument = get_argument("#{arg_defn.graphql_name}")
|
|
62
|
+
argument = get_argument("#{arg_defn.graphql_name}", context || self.context)
|
|
63
63
|
load_application_object(argument, value, context || self.context)
|
|
64
64
|
end
|
|
65
65
|
RUBY
|
|
@@ -166,11 +166,15 @@ module GraphQL
|
|
|
166
166
|
args.each_value do |argument|
|
|
167
167
|
arg_keyword = argument.keyword
|
|
168
168
|
if inputs.key?(arg_keyword) && !(arg_value = inputs[arg_keyword]).nil? && (arg_value != argument.default_value)
|
|
169
|
-
|
|
170
|
-
if
|
|
171
|
-
return
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
auth_result = argument.authorized?(self, arg_value, context)
|
|
170
|
+
if auth_result.is_a?(Array)
|
|
171
|
+
# only return this second value if the application returned a second value
|
|
172
|
+
arg_auth, err = auth_result
|
|
173
|
+
if !arg_auth
|
|
174
|
+
return arg_auth, err
|
|
175
|
+
end
|
|
176
|
+
elsif auth_result == false
|
|
177
|
+
return auth_result
|
|
174
178
|
end
|
|
175
179
|
else
|
|
176
180
|
true
|
data/lib/graphql/schema.rb
CHANGED
|
@@ -63,10 +63,6 @@ module GraphQL
|
|
|
63
63
|
# Schemas can restrict large incoming queries with `max_depth` and `max_complexity` configurations.
|
|
64
64
|
# (These configurations can be overridden by specific calls to {Schema#execute})
|
|
65
65
|
#
|
|
66
|
-
# Schemas can specify how queries should be executed against them.
|
|
67
|
-
# `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
|
|
68
|
-
# each apply to corresponding root types.
|
|
69
|
-
#
|
|
70
66
|
# @example defining a schema
|
|
71
67
|
# class MySchema < GraphQL::Schema
|
|
72
68
|
# query QueryType
|
|
@@ -167,13 +163,20 @@ module GraphQL
|
|
|
167
163
|
backtrace_class.include(GraphQL::Backtrace::Trace)
|
|
168
164
|
trace_mode(:default_backtrace, backtrace_class)
|
|
169
165
|
end
|
|
170
|
-
trace_class_for(:default)
|
|
166
|
+
trace_class_for(:default, build: true)
|
|
171
167
|
end
|
|
172
168
|
|
|
173
169
|
# @return [Class] Return the trace class to use for this mode, looking one up on the superclass if this Schema doesn't have one defined.
|
|
174
|
-
def trace_class_for(mode, build:
|
|
175
|
-
own_trace_modes[mode]
|
|
176
|
-
|
|
170
|
+
def trace_class_for(mode, build: false)
|
|
171
|
+
if (trace_class = own_trace_modes[mode])
|
|
172
|
+
trace_class
|
|
173
|
+
elsif superclass.respond_to?(:trace_class_for) && (trace_class = superclass.trace_class_for(mode, build: false))
|
|
174
|
+
trace_class
|
|
175
|
+
elsif build
|
|
176
|
+
own_trace_modes[mode] = build_trace_mode(mode)
|
|
177
|
+
else
|
|
178
|
+
nil
|
|
179
|
+
end
|
|
177
180
|
end
|
|
178
181
|
|
|
179
182
|
# Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
|
|
@@ -211,20 +214,24 @@ module GraphQL
|
|
|
211
214
|
include DefaultTraceClass
|
|
212
215
|
end
|
|
213
216
|
when :default_backtrace
|
|
214
|
-
schema_base_class = trace_class_for(:default)
|
|
217
|
+
schema_base_class = trace_class_for(:default, build: true)
|
|
215
218
|
Class.new(schema_base_class) do
|
|
216
219
|
include(GraphQL::Backtrace::Trace)
|
|
217
220
|
end
|
|
218
221
|
else
|
|
219
222
|
# First, see if the superclass has a custom-defined class for this.
|
|
220
223
|
# Then, if it doesn't, use this class's default trace
|
|
221
|
-
base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode
|
|
224
|
+
base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || trace_class_for(:default, build: true)
|
|
222
225
|
# Prepare the default trace class if it hasn't been initialized yet
|
|
223
226
|
base_class ||= (own_trace_modes[:default] = build_trace_mode(:default))
|
|
224
227
|
mods = trace_modules_for(mode)
|
|
225
228
|
if base_class < DefaultTraceClass
|
|
226
229
|
mods = trace_modules_for(:default) + mods
|
|
227
230
|
end
|
|
231
|
+
# Copy the existing default options into this mode's options
|
|
232
|
+
default_options = trace_options_for(:default)
|
|
233
|
+
add_trace_options_for(mode, default_options)
|
|
234
|
+
|
|
228
235
|
Class.new(base_class) do
|
|
229
236
|
mods.any? && include(*mods)
|
|
230
237
|
end
|
|
@@ -640,27 +647,39 @@ module GraphQL
|
|
|
640
647
|
end
|
|
641
648
|
end
|
|
642
649
|
|
|
643
|
-
def query_execution_strategy(new_query_execution_strategy = nil)
|
|
650
|
+
def query_execution_strategy(new_query_execution_strategy = nil, deprecation_warning: true)
|
|
651
|
+
if deprecation_warning
|
|
652
|
+
warn "GraphQL::Schema.query_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
|
|
653
|
+
warn " #{caller(1, 1).first}"
|
|
654
|
+
end
|
|
644
655
|
if new_query_execution_strategy
|
|
645
656
|
@query_execution_strategy = new_query_execution_strategy
|
|
646
657
|
else
|
|
647
|
-
@query_execution_strategy ||
|
|
658
|
+
@query_execution_strategy || (superclass.respond_to?(:query_execution_strategy) ? superclass.query_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
|
|
648
659
|
end
|
|
649
660
|
end
|
|
650
661
|
|
|
651
|
-
def mutation_execution_strategy(new_mutation_execution_strategy = nil)
|
|
662
|
+
def mutation_execution_strategy(new_mutation_execution_strategy = nil, deprecation_warning: true)
|
|
663
|
+
if deprecation_warning
|
|
664
|
+
warn "GraphQL::Schema.mutation_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
|
|
665
|
+
warn " #{caller(1, 1).first}"
|
|
666
|
+
end
|
|
652
667
|
if new_mutation_execution_strategy
|
|
653
668
|
@mutation_execution_strategy = new_mutation_execution_strategy
|
|
654
669
|
else
|
|
655
|
-
@mutation_execution_strategy ||
|
|
670
|
+
@mutation_execution_strategy || (superclass.respond_to?(:mutation_execution_strategy) ? superclass.mutation_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
|
|
656
671
|
end
|
|
657
672
|
end
|
|
658
673
|
|
|
659
|
-
def subscription_execution_strategy(new_subscription_execution_strategy = nil)
|
|
674
|
+
def subscription_execution_strategy(new_subscription_execution_strategy = nil, deprecation_warning: true)
|
|
675
|
+
if deprecation_warning
|
|
676
|
+
warn "GraphQL::Schema.subscription_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
|
|
677
|
+
warn " #{caller(1, 1).first}"
|
|
678
|
+
end
|
|
660
679
|
if new_subscription_execution_strategy
|
|
661
680
|
@subscription_execution_strategy = new_subscription_execution_strategy
|
|
662
681
|
else
|
|
663
|
-
@subscription_execution_strategy ||
|
|
682
|
+
@subscription_execution_strategy || (superclass.respond_to?(:subscription_execution_strategy) ? superclass.subscription_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
|
|
664
683
|
end
|
|
665
684
|
end
|
|
666
685
|
|
|
@@ -743,6 +762,7 @@ module GraphQL
|
|
|
743
762
|
|
|
744
763
|
def error_bubbling(new_error_bubbling = nil)
|
|
745
764
|
if !new_error_bubbling.nil?
|
|
765
|
+
warn("error_bubbling(#{new_error_bubbling.inspect}) is deprecated; the default value of `false` will be the only option in GraphQL-Ruby 3.0")
|
|
746
766
|
@error_bubbling = new_error_bubbling
|
|
747
767
|
else
|
|
748
768
|
@error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
|
|
@@ -814,6 +834,26 @@ module GraphQL
|
|
|
814
834
|
end
|
|
815
835
|
end
|
|
816
836
|
|
|
837
|
+
# @param new_extra_types [Module] Type definitions to include in printing and introspection, even though they aren't referenced in the schema
|
|
838
|
+
# @return [Array<Module>] Type definitions added to this schema
|
|
839
|
+
def extra_types(*new_extra_types)
|
|
840
|
+
if new_extra_types.any?
|
|
841
|
+
new_extra_types = new_extra_types.flatten
|
|
842
|
+
@own_extra_types ||= []
|
|
843
|
+
@own_extra_types.concat(new_extra_types)
|
|
844
|
+
end
|
|
845
|
+
inherited_et = find_inherited_value(:extra_types, nil)
|
|
846
|
+
if inherited_et
|
|
847
|
+
if @own_extra_types
|
|
848
|
+
inherited_et + @own_extra_types
|
|
849
|
+
else
|
|
850
|
+
inherited_et
|
|
851
|
+
end
|
|
852
|
+
else
|
|
853
|
+
@own_extra_types || EMPTY_ARRAY
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
|
|
817
857
|
def orphan_types(*new_orphan_types)
|
|
818
858
|
if new_orphan_types.any?
|
|
819
859
|
new_orphan_types = new_orphan_types.flatten
|
|
@@ -1044,6 +1084,12 @@ module GraphQL
|
|
|
1044
1084
|
end
|
|
1045
1085
|
|
|
1046
1086
|
def instrument(instrument_step, instrumenter, options = {})
|
|
1087
|
+
warn <<~WARN
|
|
1088
|
+
Schema.instrument is deprecated, use `trace_with` instead: https://graphql-ruby.org/queries/tracing.html"
|
|
1089
|
+
(From `#{self}.instrument(#{instrument_step}, #{instrumenter})` at #{caller(1, 1).first})
|
|
1090
|
+
|
|
1091
|
+
WARN
|
|
1092
|
+
trace_with(Tracing::LegacyHooksTrace)
|
|
1047
1093
|
own_instrumenters[instrument_step] << instrumenter
|
|
1048
1094
|
end
|
|
1049
1095
|
|
|
@@ -1080,7 +1126,7 @@ module GraphQL
|
|
|
1080
1126
|
end
|
|
1081
1127
|
|
|
1082
1128
|
def tracer(new_tracer)
|
|
1083
|
-
default_trace = trace_class_for(:default)
|
|
1129
|
+
default_trace = trace_class_for(:default, build: true)
|
|
1084
1130
|
if default_trace.nil? || !(default_trace < GraphQL::Tracing::CallLegacyTracers)
|
|
1085
1131
|
trace_with(GraphQL::Tracing::CallLegacyTracers)
|
|
1086
1132
|
end
|
|
@@ -1106,20 +1152,23 @@ module GraphQL
|
|
|
1106
1152
|
tc = own_trace_modes[mode] ||= build_trace_mode(mode)
|
|
1107
1153
|
tc.include(trace_mod)
|
|
1108
1154
|
own_trace_modules[mode] << trace_mod
|
|
1109
|
-
|
|
1155
|
+
add_trace_options_for(mode, options)
|
|
1110
1156
|
if mode == :default
|
|
1111
1157
|
# This module is being added as a default tracer. If any other mode classes
|
|
1112
1158
|
# have already been created, but get their default behavior from a superclass,
|
|
1113
1159
|
# Then mix this into this schema's subclass.
|
|
1114
1160
|
# (But don't mix it into mode classes that aren't default-based.)
|
|
1115
1161
|
own_trace_modes.each do |other_mode_name, other_mode_class|
|
|
1116
|
-
if other_mode_class < DefaultTraceClass
|
|
1117
|
-
|
|
1162
|
+
if other_mode_class < DefaultTraceClass
|
|
1163
|
+
# Don't add it back to the inheritance tree if it's already there
|
|
1164
|
+
if !(other_mode_class < trace_mod)
|
|
1165
|
+
other_mode_class.include(trace_mod)
|
|
1166
|
+
end
|
|
1167
|
+
# Add any options so they'll be available
|
|
1168
|
+
add_trace_options_for(other_mode_name, options)
|
|
1118
1169
|
end
|
|
1119
1170
|
end
|
|
1120
1171
|
end
|
|
1121
|
-
t_opts = trace_options_for(mode)
|
|
1122
|
-
t_opts.merge!(options)
|
|
1123
1172
|
end
|
|
1124
1173
|
nil
|
|
1125
1174
|
end
|
|
@@ -1129,10 +1178,14 @@ module GraphQL
|
|
|
1129
1178
|
def trace_options_for(mode)
|
|
1130
1179
|
@trace_options_for_mode ||= {}
|
|
1131
1180
|
@trace_options_for_mode[mode] ||= begin
|
|
1181
|
+
# It may be time to create an options hash for a mode that wasn't registered yet.
|
|
1182
|
+
# Mix in the default options in that case.
|
|
1183
|
+
default_options = mode == :default ? EMPTY_HASH : trace_options_for(:default)
|
|
1184
|
+
# Make sure this returns a new object so that other hashes aren't modified later
|
|
1132
1185
|
if superclass.respond_to?(:trace_options_for)
|
|
1133
|
-
superclass.trace_options_for(mode).
|
|
1186
|
+
superclass.trace_options_for(mode).merge(default_options)
|
|
1134
1187
|
else
|
|
1135
|
-
|
|
1188
|
+
default_options.dup
|
|
1136
1189
|
end
|
|
1137
1190
|
end
|
|
1138
1191
|
end
|
|
@@ -1155,15 +1208,17 @@ module GraphQL
|
|
|
1155
1208
|
raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
|
|
1156
1209
|
else
|
|
1157
1210
|
own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
|
|
1211
|
+
options_trace_mode = :default
|
|
1158
1212
|
:default_backtrace
|
|
1159
1213
|
end
|
|
1160
1214
|
else
|
|
1161
1215
|
default_trace_mode
|
|
1162
1216
|
end
|
|
1163
1217
|
|
|
1164
|
-
|
|
1218
|
+
options_trace_mode ||= trace_mode
|
|
1219
|
+
base_trace_options = trace_options_for(options_trace_mode)
|
|
1165
1220
|
trace_options = base_trace_options.merge(options)
|
|
1166
|
-
trace_class_for_mode = trace_class_for(trace_mode
|
|
1221
|
+
trace_class_for_mode = trace_class_for(trace_mode, build: true)
|
|
1167
1222
|
trace_class_for_mode.new(**trace_options)
|
|
1168
1223
|
end
|
|
1169
1224
|
|
|
@@ -1317,6 +1372,12 @@ module GraphQL
|
|
|
1317
1372
|
|
|
1318
1373
|
private
|
|
1319
1374
|
|
|
1375
|
+
def add_trace_options_for(mode, new_options)
|
|
1376
|
+
t_opts = trace_options_for(mode)
|
|
1377
|
+
t_opts.merge!(new_options)
|
|
1378
|
+
nil
|
|
1379
|
+
end
|
|
1380
|
+
|
|
1320
1381
|
# @param t [Module, Array<Module>]
|
|
1321
1382
|
# @return [void]
|
|
1322
1383
|
def add_type_and_traverse(t, root:)
|
|
@@ -1378,7 +1439,7 @@ module GraphQL
|
|
|
1378
1439
|
else
|
|
1379
1440
|
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
|
1380
1441
|
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
|
1381
|
-
@lazy_methods.set(GraphQL::Dataloader::Request, :
|
|
1442
|
+
@lazy_methods.set(GraphQL::Dataloader::Request, :load_with_deprecation_warning)
|
|
1382
1443
|
end
|
|
1383
1444
|
end
|
|
1384
1445
|
@lazy_methods
|
|
@@ -110,7 +110,7 @@ module GraphQL
|
|
|
110
110
|
# TODO - would be nice to use these to create an error message so the caller knows
|
|
111
111
|
# that required fields are missing
|
|
112
112
|
required_field_names = @warden.arguments(type)
|
|
113
|
-
.select { |argument| argument.type.kind.non_null? &&
|
|
113
|
+
.select { |argument| argument.type.kind.non_null? && !argument.default_value? }
|
|
114
114
|
.map!(&:name)
|
|
115
115
|
|
|
116
116
|
present_field_names = ast_node.arguments.map(&:name)
|
|
@@ -122,7 +122,6 @@ module GraphQL
|
|
|
122
122
|
arg_type = @warden.get_argument(type, name).type
|
|
123
123
|
recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
|
|
124
124
|
end
|
|
125
|
-
|
|
126
125
|
if type.one_of? && ast_node.arguments.size != 1
|
|
127
126
|
results << Query::InputValidationResult.from_problem("`#{type.graphql_name}` is a OneOf type, so only one argument may be given (instead of #{ast_node.arguments.size})")
|
|
128
127
|
end
|
|
@@ -35,7 +35,7 @@ module GraphQL
|
|
|
35
35
|
return unless parent_type && parent_type.kind.input_object?
|
|
36
36
|
|
|
37
37
|
required_fields = context.warden.arguments(parent_type)
|
|
38
|
-
.select{|arg| arg.type.kind.non_null?}
|
|
38
|
+
.select{ |arg| arg.type.kind.non_null? && !arg.default_value? }
|
|
39
39
|
.map!(&:graphql_name)
|
|
40
40
|
|
|
41
41
|
present_fields = ast_node.arguments.map(&:name)
|
|
@@ -28,6 +28,7 @@ module GraphQL
|
|
|
28
28
|
# @return [Array<Hash>]
|
|
29
29
|
def validate(query, validate: true, timeout: nil, max_errors: nil)
|
|
30
30
|
query.current_trace.validate(validate: validate, query: query) do
|
|
31
|
+
begin_t = Time.now
|
|
31
32
|
errors = if validate == false
|
|
32
33
|
[]
|
|
33
34
|
else
|
|
@@ -52,11 +53,13 @@ module GraphQL
|
|
|
52
53
|
end
|
|
53
54
|
|
|
54
55
|
{
|
|
56
|
+
remaining_timeout: timeout ? (timeout - (Time.now - begin_t)) : nil,
|
|
55
57
|
errors: errors,
|
|
56
58
|
}
|
|
57
59
|
end
|
|
58
60
|
rescue GraphQL::ExecutionError => e
|
|
59
61
|
{
|
|
62
|
+
remaining_timeout: nil,
|
|
60
63
|
errors: [e],
|
|
61
64
|
}
|
|
62
65
|
end
|
|
@@ -148,6 +148,8 @@ module GraphQL
|
|
|
148
148
|
{ TIMESTAMP_KEY => [obj.class.name, obj.strftime(TIMESTAMP_FORMAT)] }
|
|
149
149
|
elsif obj.is_a?(OpenStruct)
|
|
150
150
|
{ OPEN_STRUCT_KEY => dump_value(obj.to_h) }
|
|
151
|
+
elsif defined?(ActiveRecord::Relation) && obj.is_a?(ActiveRecord::Relation)
|
|
152
|
+
dump_value(obj.to_a)
|
|
151
153
|
else
|
|
152
154
|
obj
|
|
153
155
|
end
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
require "securerandom"
|
|
3
3
|
require "graphql/subscriptions/broadcast_analyzer"
|
|
4
4
|
require "graphql/subscriptions/event"
|
|
5
|
-
require "graphql/subscriptions/instrumentation"
|
|
6
5
|
require "graphql/subscriptions/serialize"
|
|
7
6
|
require "graphql/subscriptions/action_cable_subscriptions"
|
|
8
7
|
require "graphql/subscriptions/default_subscription_resolve_extension"
|
|
@@ -30,8 +29,6 @@ module GraphQL
|
|
|
30
29
|
raise ArgumentError, "Can't reinstall subscriptions. #{schema} is using #{schema.subscriptions}, can't also add #{self}"
|
|
31
30
|
end
|
|
32
31
|
|
|
33
|
-
instrumentation = Subscriptions::Instrumentation.new(schema: schema)
|
|
34
|
-
defn.instrument(:query, instrumentation)
|
|
35
32
|
options[:schema] = schema
|
|
36
33
|
schema.subscriptions = self.new(**options)
|
|
37
34
|
schema.add_subscription_extension_if_necessary
|
|
@@ -5,10 +5,7 @@ module GraphQL
|
|
|
5
5
|
# @param schema_class [Class<GraphQL::Schema>]
|
|
6
6
|
# @return [Module] A helpers module which always uses the given schema
|
|
7
7
|
def self.for(schema_class)
|
|
8
|
-
|
|
9
|
-
include SchemaHelpers
|
|
10
|
-
@@schema_class_for_helpers = schema_class
|
|
11
|
-
end
|
|
8
|
+
SchemaHelpers.for(schema_class)
|
|
12
9
|
end
|
|
13
10
|
|
|
14
11
|
class Error < GraphQL::Error
|
|
@@ -119,6 +116,13 @@ module GraphQL
|
|
|
119
116
|
# schema will be added later
|
|
120
117
|
super(nil, *args, **kwargs, &block)
|
|
121
118
|
end
|
|
119
|
+
|
|
120
|
+
def self.for(schema_class)
|
|
121
|
+
Module.new do
|
|
122
|
+
include SchemaHelpers
|
|
123
|
+
@@schema_class_for_helpers = schema_class
|
|
124
|
+
end
|
|
125
|
+
end
|
|
122
126
|
end
|
|
123
127
|
end
|
|
124
128
|
end
|
|
@@ -3,20 +3,18 @@
|
|
|
3
3
|
module GraphQL
|
|
4
4
|
module Tracing
|
|
5
5
|
module DataDogTrace
|
|
6
|
+
# @param tracer [#trace] Deprecated
|
|
6
7
|
# @param analytics_enabled [Boolean] Deprecated
|
|
7
8
|
# @param analytics_sample_rate [Float] Deprecated
|
|
8
|
-
def initialize(tracer: nil, analytics_enabled: false, analytics_sample_rate: 1.0, service:
|
|
9
|
+
def initialize(tracer: nil, analytics_enabled: false, analytics_sample_rate: 1.0, service: nil, **rest)
|
|
9
10
|
if tracer.nil?
|
|
10
11
|
tracer = defined?(Datadog::Tracing) ? Datadog::Tracing : Datadog.tracer
|
|
11
12
|
end
|
|
12
13
|
@tracer = tracer
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
&& Datadog::Contrib::Analytics.respond_to?(:enabled?) \
|
|
16
|
-
&& Datadog::Contrib::Analytics.respond_to?(:set_sample_rate)
|
|
17
|
-
|
|
18
|
-
@analytics_enabled = analytics_available && Datadog::Contrib::Analytics.enabled?(analytics_enabled)
|
|
15
|
+
@analytics_enabled = analytics_enabled
|
|
19
16
|
@analytics_sample_rate = analytics_sample_rate
|
|
17
|
+
|
|
20
18
|
@service_name = service
|
|
21
19
|
@has_prepare_span = respond_to?(:prepare_span)
|
|
22
20
|
super
|
|
@@ -34,12 +32,9 @@ module GraphQL
|
|
|
34
32
|
}.each do |trace_method, trace_key|
|
|
35
33
|
module_eval <<-RUBY, __FILE__, __LINE__
|
|
36
34
|
def #{trace_method}(**data)
|
|
37
|
-
@tracer.trace("#{trace_key}", service: @service_name) do |span|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
|
|
41
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, '#{trace_method}')
|
|
42
|
-
end
|
|
35
|
+
@tracer.trace("#{trace_key}", service: @service_name, type: 'custom') do |span|
|
|
36
|
+
span.set_tag('component', 'graphql')
|
|
37
|
+
span.set_tag('operation', '#{trace_method}')
|
|
43
38
|
|
|
44
39
|
#{
|
|
45
40
|
if trace_method == 'execute_multiplex'
|
|
@@ -54,10 +49,8 @@ module GraphQL
|
|
|
54
49
|
end
|
|
55
50
|
span.resource = resource if resource
|
|
56
51
|
|
|
57
|
-
#
|
|
58
|
-
if @analytics_enabled
|
|
59
|
-
Datadog::Contrib::Analytics.set_sample_rate(span, @analytics_sample_rate)
|
|
60
|
-
end
|
|
52
|
+
# [Deprecated] will be removed in the future
|
|
53
|
+
span.set_metric('_dd1.sr.eausr', @analytics_sample_rate) if @analytics_enabled
|
|
61
54
|
RUBY
|
|
62
55
|
elsif trace_method == 'execute_query'
|
|
63
56
|
<<-RUBY
|
|
@@ -89,12 +82,10 @@ module GraphQL
|
|
|
89
82
|
nil
|
|
90
83
|
end
|
|
91
84
|
if platform_key && trace_field
|
|
92
|
-
@tracer.trace(platform_key, service: @service_name) do |span|
|
|
93
|
-
span.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
|
|
97
|
-
end
|
|
85
|
+
@tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
|
|
86
|
+
span.set_tag('component', 'graphql')
|
|
87
|
+
span.set_tag('operation', span_key)
|
|
88
|
+
|
|
98
89
|
if @has_prepare_span
|
|
99
90
|
prepare_span_data = { query: query, field: field, ast_node: ast_node, arguments: arguments, object: object }
|
|
100
91
|
prepare_span(span_key, prepare_span_data, span)
|
|
@@ -125,12 +116,10 @@ module GraphQL
|
|
|
125
116
|
|
|
126
117
|
def authorized_span(span_key, object, type, query)
|
|
127
118
|
platform_key = @platform_key_cache[DataDogTrace].platform_authorized_key_cache[type]
|
|
128
|
-
@tracer.trace(platform_key, service: @service_name) do |span|
|
|
129
|
-
span.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
|
|
133
|
-
end
|
|
119
|
+
@tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
|
|
120
|
+
span.set_tag('component', 'graphql')
|
|
121
|
+
span.set_tag('operation', span_key)
|
|
122
|
+
|
|
134
123
|
if @has_prepare_span
|
|
135
124
|
prepare_span(span_key, {object: object, type: type, query: query}, span)
|
|
136
125
|
end
|
|
@@ -158,12 +147,10 @@ module GraphQL
|
|
|
158
147
|
|
|
159
148
|
def resolve_type_span(span_key, object, type, query)
|
|
160
149
|
platform_key = @platform_key_cache[DataDogTrace].platform_resolve_type_key_cache[type]
|
|
161
|
-
@tracer.trace(platform_key, service: @service_name) do |span|
|
|
162
|
-
span.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
|
|
166
|
-
end
|
|
150
|
+
@tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
|
|
151
|
+
span.set_tag('component', 'graphql')
|
|
152
|
+
span.set_tag('operation', span_key)
|
|
153
|
+
|
|
167
154
|
if @has_prepare_span
|
|
168
155
|
prepare_span(span_key, {object: object, type: type, query: query}, span)
|
|
169
156
|
end
|