graphql 2.0.5 → 2.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|