graphql 1.12.17 → 1.12.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/graphql/object_generator.rb +2 -1
- data/lib/generators/graphql/relay.rb +19 -11
- data/lib/generators/graphql/templates/schema.erb +14 -2
- data/lib/graphql/analysis/ast/field_usage.rb +7 -3
- data/lib/graphql/dataloader/source.rb +32 -2
- data/lib/graphql/dataloader.rb +13 -0
- data/lib/graphql/deprecated_dsl.rb +11 -3
- data/lib/graphql/deprecation.rb +1 -5
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/language/nodes.rb +13 -1
- data/lib/graphql/pagination/connections.rb +35 -16
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/schema/argument.rb +58 -31
- data/lib/graphql/schema/build_from_definition.rb +8 -7
- data/lib/graphql/schema/directive.rb +4 -0
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field.rb +15 -4
- data/lib/graphql/schema/input_object.rb +10 -11
- data/lib/graphql/schema/member/has_arguments.rb +90 -44
- data/lib/graphql/schema/resolver.rb +20 -57
- data/lib/graphql/schema/subscription.rb +4 -4
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/format_validator.rb +4 -1
- data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/length_validator.rb +5 -3
- data/lib/graphql/schema/validator/numericality_validator.rb +7 -1
- data/lib/graphql/schema/validator.rb +36 -25
- data/lib/graphql/schema.rb +18 -5
- data/lib/graphql/static_validation/base_visitor.rb +3 -0
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +51 -25
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -0
- data/lib/graphql/static_validation/validation_context.rb +8 -2
- data/lib/graphql/static_validation/validator.rb +15 -12
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
- data/lib/graphql/subscriptions/event.rb +47 -2
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
- data/lib/graphql/types/int.rb +1 -1
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +5 -6
|
@@ -10,6 +10,7 @@ module GraphQL
|
|
|
10
10
|
#
|
|
11
11
|
# Original Algorithm: https://github.com/graphql/graphql-js/blob/master/src/validation/rules/OverlappingFieldsCanBeMerged.js
|
|
12
12
|
NO_ARGS = {}.freeze
|
|
13
|
+
|
|
13
14
|
Field = Struct.new(:node, :definition, :owner_type, :parents)
|
|
14
15
|
FragmentSpread = Struct.new(:name, :parents)
|
|
15
16
|
|
|
@@ -17,24 +18,47 @@ module GraphQL
|
|
|
17
18
|
super
|
|
18
19
|
@visited_fragments = {}
|
|
19
20
|
@compared_fragments = {}
|
|
21
|
+
@conflict_count = 0
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def on_operation_definition(node, _parent)
|
|
23
|
-
conflicts_within_selection_set(node, type_definition)
|
|
25
|
+
setting_errors { conflicts_within_selection_set(node, type_definition) }
|
|
24
26
|
super
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def on_field(node, _parent)
|
|
28
|
-
conflicts_within_selection_set(node, type_definition)
|
|
30
|
+
setting_errors { conflicts_within_selection_set(node, type_definition) }
|
|
29
31
|
super
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
private
|
|
33
35
|
|
|
36
|
+
def field_conflicts
|
|
37
|
+
@field_conflicts ||= Hash.new do |errors, field|
|
|
38
|
+
errors[field] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: :field, field_name: field)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def arg_conflicts
|
|
43
|
+
@arg_conflicts ||= Hash.new do |errors, field|
|
|
44
|
+
errors[field] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: :argument, field_name: field)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def setting_errors
|
|
49
|
+
@field_conflicts = nil
|
|
50
|
+
@arg_conflicts = nil
|
|
51
|
+
|
|
52
|
+
yield
|
|
53
|
+
# don't initialize these if they weren't initialized in the block:
|
|
54
|
+
@field_conflicts && @field_conflicts.each_value { |error| add_error(error) }
|
|
55
|
+
@arg_conflicts && @arg_conflicts.each_value { |error| add_error(error) }
|
|
56
|
+
end
|
|
57
|
+
|
|
34
58
|
def conflicts_within_selection_set(node, parent_type)
|
|
35
59
|
return if parent_type.nil?
|
|
36
60
|
|
|
37
|
-
fields, fragment_spreads = fields_and_fragments_from_selection(node, owner_type: parent_type, parents:
|
|
61
|
+
fields, fragment_spreads = fields_and_fragments_from_selection(node, owner_type: parent_type, parents: nil)
|
|
38
62
|
|
|
39
63
|
# (A) Find find all conflicts "within" the fields of this selection set.
|
|
40
64
|
find_conflicts_within(fields)
|
|
@@ -174,15 +198,21 @@ module GraphQL
|
|
|
174
198
|
response_keys.each do |key, fields|
|
|
175
199
|
next if fields.size < 2
|
|
176
200
|
# find conflicts within nodes
|
|
177
|
-
|
|
178
|
-
|
|
201
|
+
i = 0
|
|
202
|
+
while i < fields.size
|
|
203
|
+
j = i + 1
|
|
204
|
+
while j < fields.size
|
|
179
205
|
find_conflict(key, fields[i], fields[j])
|
|
206
|
+
j += 1
|
|
180
207
|
end
|
|
208
|
+
i += 1
|
|
181
209
|
end
|
|
182
210
|
end
|
|
183
211
|
end
|
|
184
212
|
|
|
185
213
|
def find_conflict(response_key, field1, field2, mutually_exclusive: false)
|
|
214
|
+
return if @conflict_count >= context.max_errors
|
|
215
|
+
|
|
186
216
|
node1 = field1.node
|
|
187
217
|
node2 = field2.node
|
|
188
218
|
|
|
@@ -191,28 +221,21 @@ module GraphQL
|
|
|
191
221
|
|
|
192
222
|
if !are_mutually_exclusive
|
|
193
223
|
if node1.name != node2.name
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
field_name: response_key,
|
|
201
|
-
conflicts: errored_nodes
|
|
202
|
-
)
|
|
224
|
+
conflict = field_conflicts[response_key]
|
|
225
|
+
|
|
226
|
+
conflict.add_conflict(node1, node1.name)
|
|
227
|
+
conflict.add_conflict(node2, node2.name)
|
|
228
|
+
|
|
229
|
+
@conflict_count += 1
|
|
203
230
|
end
|
|
204
231
|
|
|
205
232
|
if !same_arguments?(node1, node2)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
path: [],
|
|
213
|
-
field_name: response_key,
|
|
214
|
-
conflicts: conflicts
|
|
215
|
-
)
|
|
233
|
+
conflict = arg_conflicts[response_key]
|
|
234
|
+
|
|
235
|
+
conflict.add_conflict(node1, GraphQL::Language.serialize(serialize_field_args(node1)))
|
|
236
|
+
conflict.add_conflict(node2, GraphQL::Language.serialize(serialize_field_args(node2)))
|
|
237
|
+
|
|
238
|
+
@conflict_count += 1
|
|
216
239
|
end
|
|
217
240
|
end
|
|
218
241
|
|
|
@@ -224,7 +247,9 @@ module GraphQL
|
|
|
224
247
|
end
|
|
225
248
|
|
|
226
249
|
def find_conflicts_between_sub_selection_sets(field1, field2, mutually_exclusive:)
|
|
227
|
-
return if field1.definition.nil? ||
|
|
250
|
+
return if field1.definition.nil? ||
|
|
251
|
+
field2.definition.nil? ||
|
|
252
|
+
(field1.node.selections.empty? && field2.node.selections.empty?)
|
|
228
253
|
|
|
229
254
|
return_type1 = field1.definition.type.unwrap
|
|
230
255
|
return_type2 = field2.definition.type.unwrap
|
|
@@ -304,6 +329,7 @@ module GraphQL
|
|
|
304
329
|
if node.selections.empty?
|
|
305
330
|
NO_SELECTIONS
|
|
306
331
|
else
|
|
332
|
+
parents ||= []
|
|
307
333
|
fields, fragment_spreads = find_fields_and_fragments(node.selections, owner_type: owner_type, parents: parents, fields: [], fragment_spreads: [])
|
|
308
334
|
response_keys = fields.group_by { |f| f.node.alias || f.node.name }
|
|
309
335
|
[response_keys, fragment_spreads]
|
|
@@ -3,12 +3,33 @@ module GraphQL
|
|
|
3
3
|
module StaticValidation
|
|
4
4
|
class FieldsWillMergeError < StaticValidation::Error
|
|
5
5
|
attr_reader :field_name
|
|
6
|
-
attr_reader :
|
|
6
|
+
attr_reader :kind
|
|
7
|
+
|
|
8
|
+
def initialize(kind:, field_name:)
|
|
9
|
+
super(nil)
|
|
7
10
|
|
|
8
|
-
def initialize(message, path: nil, nodes: [], field_name:, conflicts:)
|
|
9
|
-
super(message, path: path, nodes: nodes)
|
|
10
11
|
@field_name = field_name
|
|
11
|
-
@
|
|
12
|
+
@kind = kind
|
|
13
|
+
@conflicts = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def message
|
|
17
|
+
"Field '#{field_name}' has #{kind == :argument ? 'an' : 'a'} #{kind} conflict: #{conflicts}?"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def path
|
|
21
|
+
[]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def conflicts
|
|
25
|
+
@conflicts.join(' or ')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def add_conflict(node, conflict_str)
|
|
29
|
+
return if nodes.include?(node)
|
|
30
|
+
|
|
31
|
+
@nodes << node
|
|
32
|
+
@conflicts << conflict_str
|
|
12
33
|
end
|
|
13
34
|
|
|
14
35
|
# A hash representation of this Message
|
|
@@ -7,12 +7,12 @@ module GraphQL
|
|
|
7
7
|
dependency_map = context.dependencies
|
|
8
8
|
dependency_map.cyclical_definitions.each do |defn|
|
|
9
9
|
if defn.node.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
|
|
10
|
-
|
|
10
|
+
add_error(GraphQL::StaticValidation::FragmentsAreFiniteError.new(
|
|
11
11
|
"Fragment #{defn.name} contains an infinite loop",
|
|
12
12
|
nodes: defn.node,
|
|
13
13
|
path: defn.path,
|
|
14
14
|
name: defn.name
|
|
15
|
-
)
|
|
15
|
+
))
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
end
|
|
@@ -16,6 +16,8 @@ module GraphQL
|
|
|
16
16
|
private
|
|
17
17
|
|
|
18
18
|
def assert_required_args(ast_node, defn)
|
|
19
|
+
args = defn.arguments
|
|
20
|
+
return if args.empty?
|
|
19
21
|
present_argument_names = ast_node.arguments.map(&:name)
|
|
20
22
|
required_argument_names = defn.arguments.each_value
|
|
21
23
|
.select { |a| a.type.kind.non_null? && !a.default_value? && context.warden.get_argument(defn, a.name) }
|
|
@@ -15,14 +15,16 @@ module GraphQL
|
|
|
15
15
|
extend Forwardable
|
|
16
16
|
|
|
17
17
|
attr_reader :query, :errors, :visitor,
|
|
18
|
-
:on_dependency_resolve_handlers
|
|
18
|
+
:on_dependency_resolve_handlers,
|
|
19
|
+
:max_errors
|
|
19
20
|
|
|
20
21
|
def_delegators :@query, :schema, :document, :fragments, :operations, :warden
|
|
21
22
|
|
|
22
|
-
def initialize(query, visitor_class)
|
|
23
|
+
def initialize(query, visitor_class, max_errors)
|
|
23
24
|
@query = query
|
|
24
25
|
@literal_validator = LiteralValidator.new(context: query.context)
|
|
25
26
|
@errors = []
|
|
27
|
+
@max_errors = max_errors || Float::INFINITY
|
|
26
28
|
@on_dependency_resolve_handlers = []
|
|
27
29
|
@visitor = visitor_class.new(document, self)
|
|
28
30
|
end
|
|
@@ -38,6 +40,10 @@ module GraphQL
|
|
|
38
40
|
def validate_literal(ast_value, type)
|
|
39
41
|
@literal_validator.validate(ast_value, type)
|
|
40
42
|
end
|
|
43
|
+
|
|
44
|
+
def too_many_errors?
|
|
45
|
+
@errors.length >= @max_errors
|
|
46
|
+
end
|
|
41
47
|
end
|
|
42
48
|
end
|
|
43
49
|
end
|
|
@@ -24,8 +24,9 @@ module GraphQL
|
|
|
24
24
|
# @param query [GraphQL::Query]
|
|
25
25
|
# @param validate [Boolean]
|
|
26
26
|
# @param timeout [Float] Number of seconds to wait before aborting validation. Any positive number may be used, including Floats to specify fractional seconds.
|
|
27
|
+
# @param max_errors [Integer] Maximum number of errors before aborting validation. Any positive number will limit the number of errors. Defaults to nil for no limit.
|
|
27
28
|
# @return [Array<Hash>]
|
|
28
|
-
def validate(query, validate: true, timeout: nil)
|
|
29
|
+
def validate(query, validate: true, timeout: nil, max_errors: nil)
|
|
29
30
|
query.trace("validate", { validate: validate, query: query }) do
|
|
30
31
|
can_skip_rewrite = query.context.interpreter? && query.schema.using_ast_analysis? && query.schema.is_a?(Class)
|
|
31
32
|
errors = if validate == false && can_skip_rewrite
|
|
@@ -34,25 +35,27 @@ module GraphQL
|
|
|
34
35
|
rules_to_use = validate ? @rules : []
|
|
35
36
|
visitor_class = BaseVisitor.including_rules(rules_to_use, rewrite: !can_skip_rewrite)
|
|
36
37
|
|
|
37
|
-
context = GraphQL::StaticValidation::ValidationContext.new(query, visitor_class)
|
|
38
|
+
context = GraphQL::StaticValidation::ValidationContext.new(query, visitor_class, max_errors)
|
|
38
39
|
|
|
39
40
|
begin
|
|
40
41
|
# CAUTION: Usage of the timeout module makes the assumption that validation rules are stateless Ruby code that requires no cleanup if process was interrupted. This means no blocking IO calls, native gems, locks, or `rescue` clauses that must be reached.
|
|
41
42
|
# A timeout value of 0 or nil will execute the block without any timeout.
|
|
42
43
|
Timeout::timeout(timeout) do
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
legacy_rules
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
catch(:too_many_validation_errors) do
|
|
45
|
+
# Attach legacy-style rules.
|
|
46
|
+
# Only loop through rules if it has legacy-style rules
|
|
47
|
+
unless (legacy_rules = rules_to_use - GraphQL::StaticValidation::ALL_RULES).empty?
|
|
48
|
+
legacy_rules.each do |rule_class_or_module|
|
|
49
|
+
if rule_class_or_module.method_defined?(:validate)
|
|
50
|
+
GraphQL::Deprecation.warn "Legacy validator rules will be removed from GraphQL-Ruby 2.0, use a module instead (see the built-in rules: https://github.com/rmosolgo/graphql-ruby/tree/master/lib/graphql/static_validation/rules)"
|
|
51
|
+
GraphQL::Deprecation.warn " -> Legacy validator: #{rule_class_or_module}"
|
|
52
|
+
rule_class_or_module.new.validate(context)
|
|
53
|
+
end
|
|
51
54
|
end
|
|
52
55
|
end
|
|
53
|
-
end
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
context.visitor.visit
|
|
58
|
+
end
|
|
56
59
|
end
|
|
57
60
|
rescue Timeout::Error
|
|
58
61
|
handle_timeout(query, context)
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module GraphQL
|
|
3
3
|
class StringEncodingError < GraphQL::RuntimeTypeError
|
|
4
|
-
attr_reader :string
|
|
5
|
-
def initialize(str)
|
|
4
|
+
attr_reader :string, :field, :path
|
|
5
|
+
def initialize(str, context:)
|
|
6
6
|
@string = str
|
|
7
|
-
|
|
7
|
+
@field = context[:current_field]
|
|
8
|
+
@path = context[:current_path]
|
|
9
|
+
message = "String #{str.inspect} was encoded as #{str.encoding}".dup
|
|
10
|
+
if @path
|
|
11
|
+
message << " @ #{@path.join(".")}"
|
|
12
|
+
end
|
|
13
|
+
if @field
|
|
14
|
+
message << " (#{@field.path})"
|
|
15
|
+
end
|
|
16
|
+
message << ". GraphQL requires an encoding compatible with UTF-8."
|
|
17
|
+
super(message)
|
|
8
18
|
end
|
|
9
19
|
end
|
|
10
20
|
end
|
|
@@ -127,7 +127,13 @@ module GraphQL
|
|
|
127
127
|
# It will receive notifications when events come in
|
|
128
128
|
# and re-evaluate the query locally.
|
|
129
129
|
def write_subscription(query, events)
|
|
130
|
-
channel = query.context
|
|
130
|
+
unless (channel = query.context[:channel])
|
|
131
|
+
raise GraphQL::Error, "This GraphQL Subscription client does not support the transport protocol expected"\
|
|
132
|
+
"by the backend Subscription Server implementation (graphql-ruby ActionCableSubscriptions in this case)."\
|
|
133
|
+
"Some official client implementation including Apollo (https://graphql-ruby.org/javascript_client/apollo_subscriptions.html), "\
|
|
134
|
+
"Relay Modern (https://graphql-ruby.org/javascript_client/relay_subscriptions.html#actioncable)."\
|
|
135
|
+
"GraphiQL via `graphiql-rails` may not work out of box (#1051)."
|
|
136
|
+
end
|
|
131
137
|
subscription_id = query.context[:subscription_id] ||= build_id
|
|
132
138
|
stream = stream_subscription_name(subscription_id)
|
|
133
139
|
channel.stream_from(stream)
|
|
@@ -53,7 +53,38 @@ module GraphQL
|
|
|
53
53
|
|
|
54
54
|
class << self
|
|
55
55
|
private
|
|
56
|
+
|
|
57
|
+
# This method does not support cyclic references in the Hash,
|
|
58
|
+
# nor does it support Hashes whose keys are not sortable
|
|
59
|
+
# with respect to their peers ( cases where a <=> b might throw an error )
|
|
60
|
+
def deep_sort_hash_keys(hash_to_sort)
|
|
61
|
+
raise ArgumentError.new("Argument must be a Hash") unless hash_to_sort.is_a?(Hash)
|
|
62
|
+
hash_to_sort.keys.sort.map do |k|
|
|
63
|
+
if hash_to_sort[k].is_a?(Hash)
|
|
64
|
+
[k, deep_sort_hash_keys(hash_to_sort[k])]
|
|
65
|
+
elsif hash_to_sort[k].is_a?(Array)
|
|
66
|
+
[k, deep_sort_array_hashes(hash_to_sort[k])]
|
|
67
|
+
else
|
|
68
|
+
[k, hash_to_sort[k]]
|
|
69
|
+
end
|
|
70
|
+
end.to_h
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def deep_sort_array_hashes(array_to_inspect)
|
|
74
|
+
raise ArgumentError.new("Argument must be an Array") unless array_to_inspect.is_a?(Array)
|
|
75
|
+
array_to_inspect.map do |v|
|
|
76
|
+
if v.is_a?(Hash)
|
|
77
|
+
deep_sort_hash_keys(v)
|
|
78
|
+
elsif v.is_a?(Array)
|
|
79
|
+
deep_sort_array_hashes(v)
|
|
80
|
+
else
|
|
81
|
+
v
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
56
86
|
def stringify_args(arg_owner, args)
|
|
87
|
+
arg_owner = arg_owner.respond_to?(:unwrap) ? arg_owner.unwrap : arg_owner # remove list and non-null wrappers
|
|
57
88
|
case args
|
|
58
89
|
when Hash
|
|
59
90
|
next_args = {}
|
|
@@ -68,8 +99,22 @@ module GraphQL
|
|
|
68
99
|
normalized_arg_name = arg_name
|
|
69
100
|
arg_defn = get_arg_definition(arg_owner, normalized_arg_name)
|
|
70
101
|
end
|
|
71
|
-
|
|
72
|
-
|
|
102
|
+
arg_base_type = arg_defn.type.unwrap
|
|
103
|
+
# In the case where the value being emitted is seen as a "JSON"
|
|
104
|
+
# type, treat the value as one atomic unit of serialization
|
|
105
|
+
is_json_definition = arg_base_type && arg_base_type <= GraphQL::Types::JSON
|
|
106
|
+
if is_json_definition
|
|
107
|
+
sorted_value = if v.is_a?(Hash)
|
|
108
|
+
deep_sort_hash_keys(v)
|
|
109
|
+
elsif v.is_a?(Array)
|
|
110
|
+
deep_sort_array_hashes(v)
|
|
111
|
+
else
|
|
112
|
+
v
|
|
113
|
+
end
|
|
114
|
+
next_args[normalized_arg_name] = sorted_value.respond_to?(:to_json) ? sorted_value.to_json : sorted_value
|
|
115
|
+
else
|
|
116
|
+
next_args[normalized_arg_name] = stringify_args(arg_base_type, v)
|
|
117
|
+
end
|
|
73
118
|
end
|
|
74
119
|
# Make sure they're deeply sorted
|
|
75
120
|
next_args.sort.to_h
|
|
@@ -9,7 +9,7 @@ module GraphQL
|
|
|
9
9
|
SYMBOL_KEY = "__sym__"
|
|
10
10
|
SYMBOL_KEYS_KEY = "__sym_keys__"
|
|
11
11
|
TIMESTAMP_KEY = "__timestamp__"
|
|
12
|
-
TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S.%N%
|
|
12
|
+
TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S.%N%z" # eg '2020-01-01 23:59:59.123456789+05:00'
|
|
13
13
|
OPEN_STRUCT_KEY = "__ostruct__"
|
|
14
14
|
|
|
15
15
|
module_function
|
|
@@ -14,7 +14,22 @@ module GraphQL
|
|
|
14
14
|
"execute_query_lazy" => "execute.graphql",
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
# @param set_action_name [Boolean] If true, the GraphQL operation name will be used as the transaction name.
|
|
18
|
+
# This is not advised if you run more than one query per HTTP request, for example, with `graphql-client` or multiplexing.
|
|
19
|
+
# It can also be specified per-query with `context[:set_appsignal_action_name]`.
|
|
20
|
+
def initialize(options = {})
|
|
21
|
+
@set_action_name = options.fetch(:set_action_name, false)
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
|
|
17
25
|
def platform_trace(platform_key, key, data)
|
|
26
|
+
if key == "execute_query"
|
|
27
|
+
set_this_txn_name = data[:query].context[:set_appsignal_action_name]
|
|
28
|
+
if set_this_txn_name == true || (set_this_txn_name.nil? && @set_action_name)
|
|
29
|
+
Appsignal::Transaction.current.set_action(transaction_name(data[:query]))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
18
33
|
Appsignal.instrument(platform_key) do
|
|
19
34
|
yield
|
|
20
35
|
end
|
data/lib/graphql/types/int.rb
CHANGED
data/lib/graphql/types/string.rb
CHANGED
|
@@ -12,7 +12,7 @@ module GraphQL
|
|
|
12
12
|
attr_reader :type
|
|
13
13
|
|
|
14
14
|
# @return [GraphQL::Query::Context] the context for the current query
|
|
15
|
-
|
|
15
|
+
attr_accessor :context
|
|
16
16
|
|
|
17
17
|
def initialize(message = nil, object: nil, type: nil, context: nil)
|
|
18
18
|
if message.nil? && object.nil? && type.nil?
|
data/lib/graphql/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: graphql
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.12.
|
|
4
|
+
version: 1.12.25
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Mosolgo
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 2025-03-12 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: benchmark-ips
|
|
@@ -544,6 +543,8 @@ files:
|
|
|
544
543
|
- lib/graphql/schema/unique_within_type.rb
|
|
545
544
|
- lib/graphql/schema/validation.rb
|
|
546
545
|
- lib/graphql/schema/validator.rb
|
|
546
|
+
- lib/graphql/schema/validator/allow_blank_validator.rb
|
|
547
|
+
- lib/graphql/schema/validator/allow_null_validator.rb
|
|
547
548
|
- lib/graphql/schema/validator/exclusion_validator.rb
|
|
548
549
|
- lib/graphql/schema/validator/format_validator.rb
|
|
549
550
|
- lib/graphql/schema/validator/inclusion_validator.rb
|
|
@@ -685,7 +686,6 @@ metadata:
|
|
|
685
686
|
source_code_uri: https://github.com/rmosolgo/graphql-ruby
|
|
686
687
|
bug_tracker_uri: https://github.com/rmosolgo/graphql-ruby/issues
|
|
687
688
|
mailing_list_uri: https://tinyletter.com/graphql-ruby
|
|
688
|
-
post_install_message:
|
|
689
689
|
rdoc_options: []
|
|
690
690
|
require_paths:
|
|
691
691
|
- lib
|
|
@@ -700,8 +700,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
700
700
|
- !ruby/object:Gem::Version
|
|
701
701
|
version: '0'
|
|
702
702
|
requirements: []
|
|
703
|
-
rubygems_version: 3.
|
|
704
|
-
signing_key:
|
|
703
|
+
rubygems_version: 3.6.3
|
|
705
704
|
specification_version: 4
|
|
706
705
|
summary: A GraphQL language and runtime for Ruby
|
|
707
706
|
test_files: []
|