graphql 2.0.5 → 2.0.8
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/graphql/execution/interpreter/resolve.rb +7 -0
- data/lib/graphql/execution/interpreter/runtime.rb +23 -3
- data/lib/graphql/execution/lazy.rb +0 -1
- data/lib/graphql/introspection/type_type.rb +1 -1
- data/lib/graphql/introspection.rb +1 -1
- data/lib/graphql/language/parser.rb +338 -327
- data/lib/graphql/language/parser.y +12 -8
- data/lib/graphql/language/printer.rb +9 -5
- data/lib/graphql/pagination/array_connection.rb +4 -2
- data/lib/graphql/schema/field.rb +41 -22
- data/lib/graphql/schema/loader.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +1 -1
- data/lib/graphql/schema/resolver.rb +1 -1
- data/lib/graphql/schema/warden.rb +6 -2
- data/lib/graphql/schema.rb +17 -8
- data/lib/graphql/subscriptions.rb +15 -3
- data/lib/graphql/tracing/data_dog_tracing.rb +16 -1
- data/lib/graphql/tracing/platform_tracing.rb +4 -0
- 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/version.rb +1 -1
- metadata +2 -3
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
@@ -321,13 +321,13 @@ rule
|
|
321
321
|
|
322
322
|
object_type_extension:
|
323
323
|
/* TODO - This first one shouldn't be necessary but parser is getting confused */
|
324
|
-
EXTEND TYPE name implements
|
325
|
-
| EXTEND TYPE name implements_opt directives_list_opt
|
324
|
+
EXTEND TYPE name implements field_definition_list_opt { result = make_node(:ObjectTypeExtension, name: val[2], interfaces: val[3], directives: [], fields: val[4], position_source: val[0]) }
|
325
|
+
| EXTEND TYPE name implements_opt directives_list_opt field_definition_list_opt { result = make_node(:ObjectTypeExtension, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], position_source: val[0]) }
|
326
326
|
| EXTEND TYPE name implements_opt directives_list { result = make_node(:ObjectTypeExtension, name: val[2], interfaces: val[3], directives: val[4], fields: [], position_source: val[0]) }
|
327
327
|
| EXTEND TYPE name implements { result = make_node(:ObjectTypeExtension, name: val[2], interfaces: val[3], directives: [], fields: [], position_source: val[0]) }
|
328
328
|
|
329
329
|
interface_type_extension:
|
330
|
-
EXTEND INTERFACE name implements_opt directives_list_opt
|
330
|
+
EXTEND INTERFACE name implements_opt directives_list_opt field_definition_list_opt { result = make_node(:InterfaceTypeExtension, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], position_source: val[0]) }
|
331
331
|
| EXTEND INTERFACE name implements_opt directives_list { result = make_node(:InterfaceTypeExtension, name: val[2], interfaces: val[3], directives: val[4], fields: [], position_source: val[0]) }
|
332
332
|
| EXTEND INTERFACE name implements { result = make_node(:InterfaceTypeExtension, name: val[2], interfaces: val[3], directives: [], fields: [], position_source: val[0]) }
|
333
333
|
|
@@ -355,8 +355,8 @@ rule
|
|
355
355
|
}
|
356
356
|
|
357
357
|
object_type_definition:
|
358
|
-
description_opt TYPE name implements_opt directives_list_opt
|
359
|
-
result = make_node(:ObjectTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[
|
358
|
+
description_opt TYPE name implements_opt directives_list_opt field_definition_list_opt {
|
359
|
+
result = make_node(:ObjectTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
|
360
360
|
}
|
361
361
|
|
362
362
|
implements_opt:
|
@@ -394,14 +394,18 @@ rule
|
|
394
394
|
result = make_node(:FieldDefinition, name: val[1], arguments: val[2], type: val[4], directives: val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
|
395
395
|
}
|
396
396
|
|
397
|
-
|
397
|
+
field_definition_list_opt:
|
398
398
|
/* none */ { result = EMPTY_ARRAY }
|
399
|
+
| LCURLY field_definition_list RCURLY { result = val[1] }
|
400
|
+
|
401
|
+
field_definition_list:
|
402
|
+
/* none - this is not actually valid but graphql-ruby used to print this */ { result = EMPTY_ARRAY }
|
399
403
|
| field_definition { result = [val[0]] }
|
400
404
|
| field_definition_list field_definition { val[0] << val[1] }
|
401
405
|
|
402
406
|
interface_type_definition:
|
403
|
-
description_opt INTERFACE name implements_opt directives_list_opt
|
404
|
-
result = make_node(:InterfaceTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[
|
407
|
+
description_opt INTERFACE name implements_opt directives_list_opt field_definition_list_opt {
|
408
|
+
result = make_node(:InterfaceTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
|
405
409
|
}
|
406
410
|
|
407
411
|
union_members:
|
@@ -267,12 +267,16 @@ module GraphQL
|
|
267
267
|
end
|
268
268
|
|
269
269
|
def print_field_definitions(fields)
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
out
|
270
|
+
if fields.empty?
|
271
|
+
""
|
272
|
+
else
|
273
|
+
out = " {\n".dup
|
274
|
+
fields.each.with_index do |field, i|
|
275
|
+
out << print_description(field, indent: ' ', first_in_block: i == 0)
|
276
|
+
out << " #{print_field_definition(field)}\n"
|
277
|
+
end
|
278
|
+
out << "}"
|
274
279
|
end
|
275
|
-
out << "}"
|
276
280
|
end
|
277
281
|
|
278
282
|
def print_directives(directives)
|
@@ -35,9 +35,11 @@ module GraphQL
|
|
35
35
|
def load_nodes
|
36
36
|
@nodes ||= begin
|
37
37
|
sliced_nodes = if before && after
|
38
|
-
|
38
|
+
end_idx = index_from_cursor(before)-1
|
39
|
+
end_idx < 0 ? [] : items[index_from_cursor(after)..end_idx] || []
|
39
40
|
elsif before
|
40
|
-
|
41
|
+
end_idx = index_from_cursor(before)-2
|
42
|
+
end_idx < 0 ? [] : items[0..end_idx] || []
|
41
43
|
elsif after
|
42
44
|
items[index_from_cursor(after)..-1] || []
|
43
45
|
else
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -28,6 +28,9 @@ module GraphQL
|
|
28
28
|
# @return [String] Method or hash key on the underlying object to look up
|
29
29
|
attr_reader :method_str
|
30
30
|
|
31
|
+
attr_reader :hash_key
|
32
|
+
attr_reader :dig_keys
|
33
|
+
|
31
34
|
# @return [Symbol] The method on the type to look up
|
32
35
|
def resolver_method
|
33
36
|
if @resolver_class
|
@@ -211,7 +214,8 @@ module GraphQL
|
|
211
214
|
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
212
215
|
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
213
216
|
# @param validates [Array<Hash>] Configurations for validating this field
|
214
|
-
|
217
|
+
# @fallback_value [Object] A fallback value if the method is not defined
|
218
|
+
def initialize(type: nil, name: nil, owner: nil, null: nil, description: :not_given, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: :not_given, &definition_block)
|
215
219
|
if name.nil?
|
216
220
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
217
221
|
end
|
@@ -243,14 +247,16 @@ module GraphQL
|
|
243
247
|
end
|
244
248
|
end
|
245
249
|
|
246
|
-
# TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
|
247
250
|
method_name = method || hash_key || name_s
|
248
251
|
@dig_keys = dig
|
249
|
-
|
252
|
+
if hash_key
|
253
|
+
@hash_key = hash_key
|
254
|
+
@hash_key_str = hash_key.to_s
|
255
|
+
end
|
250
256
|
|
251
257
|
@method_str = -method_name.to_s
|
252
258
|
@method_sym = method_name.to_sym
|
253
|
-
@resolver_method = resolver_method
|
259
|
+
@resolver_method = (resolver_method || name_s).to_sym
|
254
260
|
@complexity = complexity
|
255
261
|
@return_type_expr = type
|
256
262
|
@return_type_null = if !null.nil?
|
@@ -275,6 +281,7 @@ module GraphQL
|
|
275
281
|
@relay_nodes_field = relay_nodes_field
|
276
282
|
@ast_node = ast_node
|
277
283
|
@method_conflict_warning = method_conflict_warning
|
284
|
+
@fallback_value = fallback_value
|
278
285
|
|
279
286
|
arguments.each do |name, arg|
|
280
287
|
case arg
|
@@ -635,14 +642,11 @@ module GraphQL
|
|
635
642
|
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
636
643
|
end
|
637
644
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
# - Or, raise not implemented.
|
644
|
-
#
|
645
|
-
if obj.respond_to?(resolver_method)
|
645
|
+
inner_object = obj.object
|
646
|
+
|
647
|
+
if defined?(@hash_key)
|
648
|
+
inner_object[@hash_key] || inner_object[@hash_key_str] || (@fallback_value != :not_given ? @fallback_value : nil)
|
649
|
+
elsif obj.respond_to?(resolver_method)
|
646
650
|
method_to_call = resolver_method
|
647
651
|
method_receiver = obj
|
648
652
|
# Call the method with kwargs, if there are any
|
@@ -651,32 +655,47 @@ module GraphQL
|
|
651
655
|
else
|
652
656
|
obj.public_send(resolver_method)
|
653
657
|
end
|
654
|
-
elsif
|
655
|
-
inner_object = obj.object
|
658
|
+
elsif inner_object.is_a?(Hash)
|
656
659
|
if @dig_keys
|
657
660
|
inner_object.dig(*@dig_keys)
|
661
|
+
elsif defined?(@hash_key)
|
662
|
+
if inner_object.key?(@hash_key)
|
663
|
+
inner_object[@hash_key]
|
664
|
+
elsif inner_object.key?(@hash_key_str)
|
665
|
+
inner_object[@hash_key_str]
|
666
|
+
elsif @fallback_value != :not_given
|
667
|
+
@fallback_value
|
668
|
+
else
|
669
|
+
nil
|
670
|
+
end
|
658
671
|
elsif inner_object.key?(@method_sym)
|
659
672
|
inner_object[@method_sym]
|
660
|
-
|
673
|
+
elsif inner_object.key?(@method_str)
|
661
674
|
inner_object[@method_str]
|
675
|
+
elsif @fallback_value != :not_given
|
676
|
+
@fallback_value
|
677
|
+
else
|
678
|
+
nil
|
662
679
|
end
|
663
|
-
elsif
|
680
|
+
elsif inner_object.respond_to?(@method_sym)
|
664
681
|
method_to_call = @method_sym
|
665
682
|
method_receiver = obj.object
|
666
683
|
if ruby_kwargs.any?
|
667
|
-
|
684
|
+
inner_object.public_send(@method_sym, **ruby_kwargs)
|
668
685
|
else
|
669
|
-
|
686
|
+
inner_object.public_send(@method_sym)
|
670
687
|
end
|
688
|
+
elsif @fallback_value != :not_given
|
689
|
+
@fallback_value
|
671
690
|
else
|
672
691
|
raise <<-ERR
|
673
692
|
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
674
693
|
|
675
694
|
- `#{obj.class}##{resolver_method}`, which did not exist
|
676
|
-
- `#{
|
677
|
-
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{
|
695
|
+
- `#{inner_object.class}##{@method_sym}`, which did not exist
|
696
|
+
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{inner_object}`, but it wasn't a Hash
|
678
697
|
|
679
|
-
To implement this field, define one of the methods above (and check for typos)
|
698
|
+
To implement this field, define one of the methods above (and check for typos), or supply a `fallback_value`.
|
680
699
|
ERR
|
681
700
|
end
|
682
701
|
end
|
@@ -748,7 +767,7 @@ module GraphQL
|
|
748
767
|
|
749
768
|
if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
|
750
769
|
raise FieldImplementationFailed.new, <<-ERR
|
751
|
-
Failed to call
|
770
|
+
Failed to call `#{method_name.inspect}` on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
|
752
771
|
|
753
772
|
#{ unsatisfied_ruby_kwargs
|
754
773
|
.map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
|
@@ -72,7 +72,7 @@ module GraphQL
|
|
72
72
|
def add_field(field_defn, method_conflict_warning: field_defn.method_conflict_warning?)
|
73
73
|
# Check that `field_defn.original_name` equals `resolver_method` and `method_sym` --
|
74
74
|
# that shows that no override value was given manually.
|
75
|
-
if method_conflict_warning && CONFLICT_FIELD_NAMES.include?(field_defn.resolver_method) && field_defn.original_name == field_defn.resolver_method && field_defn.original_name == field_defn.method_sym
|
75
|
+
if method_conflict_warning && CONFLICT_FIELD_NAMES.include?(field_defn.resolver_method) && field_defn.original_name == field_defn.resolver_method && field_defn.original_name == field_defn.method_sym && field_defn.hash_key.nil? && field_defn.dig_keys.nil?
|
76
76
|
warn(conflict_field_name_warning(field_defn))
|
77
77
|
end
|
78
78
|
prev_defn = own_fields[field_defn.name]
|
@@ -73,7 +73,7 @@ module GraphQL
|
|
73
73
|
context.schema.after_lazy(ready_val) do |is_ready, ready_early_return|
|
74
74
|
if ready_early_return
|
75
75
|
if is_ready != false
|
76
|
-
raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{
|
76
|
+
raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{is_ready.inspect}, #{ready_early_return.inspect}]"
|
77
77
|
else
|
78
78
|
ready_early_return
|
79
79
|
end
|
@@ -55,7 +55,9 @@ module GraphQL
|
|
55
55
|
if visible_item.nil?
|
56
56
|
visible_item = item
|
57
57
|
else
|
58
|
-
raise
|
58
|
+
raise DuplicateNamesError.new(
|
59
|
+
duplicated_name: item.path, duplicated_definition_1: visible_item.inspect, duplicated_definition_2: item.inspect
|
60
|
+
)
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
@@ -362,7 +364,9 @@ module GraphQL
|
|
362
364
|
if @reachable_type_set.add?(type)
|
363
365
|
type_by_name = rt_hash[type.graphql_name] ||= type
|
364
366
|
if type_by_name != type
|
365
|
-
raise DuplicateNamesError
|
367
|
+
raise DuplicateNamesError.new(
|
368
|
+
duplicated_name: type.graphql_name, duplicated_definition_1: type.inspect, duplicated_definition_2: type_by_name.inspect
|
369
|
+
)
|
366
370
|
end
|
367
371
|
if type.kind.input_object?
|
368
372
|
# recurse into visible arguments
|
data/lib/graphql/schema.rb
CHANGED
@@ -73,14 +73,16 @@ module GraphQL
|
|
73
73
|
extend GraphQL::Schema::Member::HasAstNode
|
74
74
|
extend GraphQL::Schema::FindInheritedValue
|
75
75
|
|
76
|
-
class
|
77
|
-
|
78
|
-
|
76
|
+
class DuplicateNamesError < GraphQL::Error
|
77
|
+
attr_reader :duplicated_name
|
78
|
+
def initialize(duplicated_name:, duplicated_definition_1:, duplicated_definition_2:)
|
79
|
+
@duplicated_name = duplicated_name
|
80
|
+
super(
|
81
|
+
"Found two visible definitions for `#{duplicated_name}`: #{duplicated_definition_1}, #{duplicated_definition_2}"
|
82
|
+
)
|
79
83
|
end
|
80
84
|
end
|
81
85
|
|
82
|
-
class DuplicateNamesError < GraphQL::Error; end
|
83
|
-
|
84
86
|
class UnresolvedLateBoundTypeError < GraphQL::Error
|
85
87
|
attr_reader :type
|
86
88
|
def initialize(type:)
|
@@ -225,7 +227,9 @@ module GraphQL
|
|
225
227
|
if visible_t.nil?
|
226
228
|
visible_t = t
|
227
229
|
else
|
228
|
-
raise DuplicateNamesError
|
230
|
+
raise DuplicateNamesError.new(
|
231
|
+
duplicated_name: k, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
232
|
+
)
|
229
233
|
end
|
230
234
|
end
|
231
235
|
end
|
@@ -252,7 +256,9 @@ module GraphQL
|
|
252
256
|
if visible_t.nil?
|
253
257
|
visible_t = t
|
254
258
|
else
|
255
|
-
raise DuplicateNamesError
|
259
|
+
raise DuplicateNamesError.new(
|
260
|
+
duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
261
|
+
)
|
256
262
|
end
|
257
263
|
end
|
258
264
|
end
|
@@ -932,6 +938,7 @@ module GraphQL
|
|
932
938
|
{
|
933
939
|
backtrace: ctx[:backtrace],
|
934
940
|
tracers: ctx[:tracers],
|
941
|
+
dataloader: ctx[:dataloader],
|
935
942
|
}
|
936
943
|
else
|
937
944
|
{}
|
@@ -976,7 +983,9 @@ module GraphQL
|
|
976
983
|
if !defined?(@subscription_extension_added) && subscription && self.subscriptions
|
977
984
|
@subscription_extension_added = true
|
978
985
|
subscription.all_field_definitions.each do |field|
|
979
|
-
field.
|
986
|
+
if !field.extensions.any? { |ext| ext.is_a?(Subscriptions::DefaultSubscriptionResolveExtension) }
|
987
|
+
field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
|
988
|
+
end
|
980
989
|
end
|
981
990
|
end
|
982
991
|
end
|
@@ -39,12 +39,14 @@ module GraphQL
|
|
39
39
|
end
|
40
40
|
|
41
41
|
# @param schema [Class] the GraphQL schema this manager belongs to
|
42
|
-
|
42
|
+
# @param validate_update [Boolean] If false, then validation is skipped when executing updates
|
43
|
+
def initialize(schema:, validate_update: true, broadcast: false, default_broadcastable: false, **rest)
|
43
44
|
if broadcast
|
44
45
|
schema.query_analyzer(Subscriptions::BroadcastAnalyzer)
|
45
46
|
end
|
46
47
|
@default_broadcastable = default_broadcastable
|
47
48
|
@schema = schema
|
49
|
+
@validate_update = validate_update
|
48
50
|
end
|
49
51
|
|
50
52
|
# @return [Boolean] Used when fields don't have `broadcastable:` explicitly set
|
@@ -117,14 +119,16 @@ module GraphQL
|
|
117
119
|
variables = query_data.fetch(:variables)
|
118
120
|
context = query_data.fetch(:context)
|
119
121
|
operation_name = query_data.fetch(:operation_name)
|
120
|
-
|
122
|
+
execute_options = {
|
121
123
|
query: query_string,
|
122
124
|
context: context,
|
123
125
|
subscription_topic: event.topic,
|
124
126
|
operation_name: operation_name,
|
125
127
|
variables: variables,
|
126
128
|
root_value: object,
|
127
|
-
|
129
|
+
}
|
130
|
+
execute_options[:validate] = validate_update?(**execute_options)
|
131
|
+
result = @schema.execute(**execute_options)
|
128
132
|
subscriptions_context = result.context.namespace(:subscriptions)
|
129
133
|
if subscriptions_context[:no_update]
|
130
134
|
result = nil
|
@@ -142,6 +146,14 @@ module GraphQL
|
|
142
146
|
result
|
143
147
|
end
|
144
148
|
|
149
|
+
# Define this method to customize whether to validate
|
150
|
+
# this subscription when executing an update.
|
151
|
+
#
|
152
|
+
# @return [Boolean] defaults to `true`, or false if `validate: false` is provided.
|
153
|
+
def validate_update?(query:, context:, root_value:, subscription_topic:, operation_name:, variables:)
|
154
|
+
@validate_update
|
155
|
+
end
|
156
|
+
|
145
157
|
# Run the update query for this subscription and deliver it
|
146
158
|
# @see {#execute_update}
|
147
159
|
# @see {#deliver}
|
@@ -17,15 +17,21 @@ module GraphQL
|
|
17
17
|
def platform_trace(platform_key, key, data)
|
18
18
|
tracer.trace(platform_key, service: service_name) do |span|
|
19
19
|
span.span_type = 'custom'
|
20
|
+
if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
|
21
|
+
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
|
22
|
+
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, key)
|
23
|
+
end
|
20
24
|
|
21
25
|
if key == 'execute_multiplex'
|
22
26
|
operations = data[:multiplex].queries.map(&:selected_operation_name).join(', ')
|
23
|
-
|
27
|
+
|
28
|
+
resource = if operations.empty?
|
24
29
|
first_query = data[:multiplex].queries.first
|
25
30
|
fallback_transaction_name(first_query && first_query.context)
|
26
31
|
else
|
27
32
|
operations
|
28
33
|
end
|
34
|
+
span.resource = resource if resource
|
29
35
|
|
30
36
|
# For top span of query, set the analytics sample rate tag, if available.
|
31
37
|
if analytics_enabled?
|
@@ -39,6 +45,8 @@ module GraphQL
|
|
39
45
|
span.set_tag(:query_string, data[:query].query_string)
|
40
46
|
end
|
41
47
|
|
48
|
+
prepare_span(key, data, span)
|
49
|
+
|
42
50
|
yield
|
43
51
|
end
|
44
52
|
end
|
@@ -47,6 +55,13 @@ module GraphQL
|
|
47
55
|
options.fetch(:service, 'ruby-graphql')
|
48
56
|
end
|
49
57
|
|
58
|
+
# Implement this method in a subclass to apply custom tags to datadog spans
|
59
|
+
# @param key [String] The event being traced
|
60
|
+
# @param data [Hash] The runtime data for this event (@see GraphQL::Tracing for keys for each event)
|
61
|
+
# @param span [Datadog::Tracing::SpanOperation] The datadog span for this event
|
62
|
+
def prepare_span(key, data, span)
|
63
|
+
end
|
64
|
+
|
50
65
|
def tracer
|
51
66
|
default_tracer = defined?(Datadog::Tracing) ? Datadog::Tracing : Datadog.tracer
|
52
67
|
|
@@ -14,6 +14,7 @@ module GraphQL
|
|
14
14
|
# own Date type.
|
15
15
|
class ISO8601Date < GraphQL::Schema::Scalar
|
16
16
|
description "An ISO 8601-encoded date"
|
17
|
+
specified_by_url "https://tools.ietf.org/html/rfc3339"
|
17
18
|
|
18
19
|
# @param value [Date,Time,DateTime,String]
|
19
20
|
# @return [String]
|
@@ -22,7 +23,7 @@ module GraphQL
|
|
22
23
|
end
|
23
24
|
|
24
25
|
# @param str_value [String, Date, DateTime, Time]
|
25
|
-
# @return [Date]
|
26
|
+
# @return [Date, nil]
|
26
27
|
def self.coerce_input(value, ctx)
|
27
28
|
if value.is_a?(::Date)
|
28
29
|
value
|
@@ -30,6 +31,8 @@ module GraphQL
|
|
30
31
|
value.to_date
|
31
32
|
elsif value.is_a?(::Time)
|
32
33
|
value.to_date
|
34
|
+
elsif value.nil?
|
35
|
+
nil
|
33
36
|
else
|
34
37
|
Date.iso8601(value)
|
35
38
|
end
|
@@ -17,6 +17,7 @@ module GraphQL
|
|
17
17
|
# own DateTime type.
|
18
18
|
class ISO8601DateTime < GraphQL::Schema::Scalar
|
19
19
|
description "An ISO 8601-encoded datetime"
|
20
|
+
specified_by_url "https://tools.ietf.org/html/rfc3339"
|
20
21
|
|
21
22
|
# It's not compatible with Rails' default,
|
22
23
|
# i.e. ActiveSupport::JSON::Encoder.time_precision (3 by default)
|
@@ -59,6 +60,9 @@ module GraphQL
|
|
59
60
|
# But without this, it would zero out given any time part of `str_value` (hours and/or minutes)
|
60
61
|
if dt.iso8601.start_with?(str_value)
|
61
62
|
dt
|
63
|
+
elsif str_value.length == 8 && str_value.match?(/\A\d{8}\Z/)
|
64
|
+
# Allow dates that are missing the "-". eg. "20220404"
|
65
|
+
dt
|
62
66
|
else
|
63
67
|
nil
|
64
68
|
end
|
@@ -10,6 +10,8 @@ module GraphQL
|
|
10
10
|
# so you can extend your own `BaseObject` instead of `GraphQL::Schema::Object`.
|
11
11
|
#
|
12
12
|
# @example Implementation a connection and edge
|
13
|
+
# class BaseObject < GraphQL::Schema::Object; end
|
14
|
+
#
|
13
15
|
# # Given some object in your app ...
|
14
16
|
# class Types::Post < BaseObject
|
15
17
|
# end
|
@@ -20,14 +22,22 @@ module GraphQL
|
|
20
22
|
#
|
21
23
|
# # Then extend them for the object in your app
|
22
24
|
# class Types::PostEdge < Types::BaseEdge
|
23
|
-
# node_type
|
25
|
+
# node_type Types::Post
|
24
26
|
# end
|
27
|
+
#
|
25
28
|
# class Types::PostConnection < Types::BaseConnection
|
26
|
-
# edge_type
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
29
|
+
# edge_type Types::PostEdge,
|
30
|
+
# edges_nullable: true,
|
31
|
+
# edge_nullable: true,
|
32
|
+
# node_nullable: true,
|
33
|
+
# nodes_field: true
|
34
|
+
#
|
35
|
+
# # Alternatively, you can call the class methods followed by your edge type
|
36
|
+
# # edges_nullable true
|
37
|
+
# # edge_nullable true
|
38
|
+
# # nodes_nullable true
|
39
|
+
# # has_nodes_field true
|
40
|
+
# # edge_type Types::PostEdge
|
31
41
|
# end
|
32
42
|
#
|
33
43
|
# @see Relay::BaseEdge for edge types
|
data/lib/graphql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -314,7 +314,6 @@ files:
|
|
314
314
|
- lib/graphql/execution/interpreter/runtime.rb
|
315
315
|
- lib/graphql/execution/lazy.rb
|
316
316
|
- lib/graphql/execution/lazy/lazy_method_map.rb
|
317
|
-
- lib/graphql/execution/lazy/resolve.rb
|
318
317
|
- lib/graphql/execution/lookahead.rb
|
319
318
|
- lib/graphql/execution/multiplex.rb
|
320
319
|
- lib/graphql/execution_error.rb
|
@@ -1,91 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module GraphQL
|
3
|
-
module Execution
|
4
|
-
class Lazy
|
5
|
-
# Helpers for dealing with data structures containing {Lazy} instances
|
6
|
-
# @api private
|
7
|
-
module Resolve
|
8
|
-
# Mutate `value`, replacing {Lazy} instances in place with their resolved values
|
9
|
-
# @return [void]
|
10
|
-
|
11
|
-
# This object can be passed like an array, but it doesn't allocate an
|
12
|
-
# array until it's used.
|
13
|
-
#
|
14
|
-
# There's one crucial difference: you have to _capture_ the result
|
15
|
-
# of `#<<`. (This _works_ with arrays but isn't required, since it has a side-effect.)
|
16
|
-
# @api private
|
17
|
-
module NullAccumulator
|
18
|
-
def self.<<(item)
|
19
|
-
[item]
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.empty?
|
23
|
-
true
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.resolve(value)
|
28
|
-
lazies = resolve_in_place(value)
|
29
|
-
deep_sync(lazies)
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.resolve_in_place(value)
|
33
|
-
acc = each_lazy(NullAccumulator, value)
|
34
|
-
|
35
|
-
if acc.empty?
|
36
|
-
Lazy::NullResult
|
37
|
-
else
|
38
|
-
Lazy.new {
|
39
|
-
acc.each_with_index { |ctx, idx|
|
40
|
-
acc[idx] = ctx.value.value
|
41
|
-
}
|
42
|
-
resolve_in_place(acc)
|
43
|
-
}
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# If `value` is a collection,
|
48
|
-
# add any {Lazy} instances in the collection
|
49
|
-
# to `acc`
|
50
|
-
# @return [void]
|
51
|
-
def self.each_lazy(acc, value)
|
52
|
-
case value
|
53
|
-
when Hash
|
54
|
-
value.each do |key, field_result|
|
55
|
-
acc = each_lazy(acc, field_result)
|
56
|
-
end
|
57
|
-
when Array
|
58
|
-
value.each do |field_result|
|
59
|
-
acc = each_lazy(acc, field_result)
|
60
|
-
end
|
61
|
-
when Query::Context::SharedMethods
|
62
|
-
field_value = value.value
|
63
|
-
case field_value
|
64
|
-
when Lazy
|
65
|
-
acc = acc << value
|
66
|
-
when Enumerable # shortcut for Hash & Array
|
67
|
-
acc = each_lazy(acc, field_value)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
acc
|
72
|
-
end
|
73
|
-
|
74
|
-
# Traverse `val`, triggering resolution for each {Lazy}.
|
75
|
-
# These {Lazy}s are expected to mutate their owner data structures
|
76
|
-
# during resolution! (They're created with the `.then` calls in `resolve_in_place`).
|
77
|
-
# @return [void]
|
78
|
-
def self.deep_sync(val)
|
79
|
-
case val
|
80
|
-
when Lazy
|
81
|
-
deep_sync(val.value)
|
82
|
-
when Array
|
83
|
-
val.each { |v| deep_sync(v.value) }
|
84
|
-
when Hash
|
85
|
-
val.each { |k, v| deep_sync(v.value) }
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|