graphql 2.0.13 → 2.0.15
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/templates/schema.erb +3 -0
- data/lib/graphql/backtrace/table.rb +2 -2
- data/lib/graphql/dataloader/source.rb +9 -0
- data/lib/graphql/dataloader.rb +4 -1
- data/lib/graphql/execution/interpreter/runtime.rb +23 -10
- data/lib/graphql/execution/interpreter.rb +185 -59
- data/lib/graphql/execution/lookahead.rb +39 -28
- data/lib/graphql/execution/multiplex.rb +1 -116
- data/lib/graphql/execution.rb +0 -1
- data/lib/graphql/introspection/type_type.rb +7 -0
- data/lib/graphql/introspection.rb +3 -2
- data/lib/graphql/language/document_from_schema_definition.rb +18 -18
- data/lib/graphql/language/printer.rb +20 -11
- data/lib/graphql/query/context.rb +19 -5
- data/lib/graphql/query.rb +1 -1
- data/lib/graphql/schema/build_from_definition.rb +32 -17
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/field.rb +3 -3
- data/lib/graphql/schema/input_object.rb +35 -0
- data/lib/graphql/schema/late_bound_type.rb +4 -0
- data/lib/graphql/schema/member/build_type.rb +1 -1
- data/lib/graphql/schema/member/has_directives.rb +71 -56
- data/lib/graphql/schema/resolver/has_payload_type.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema.rb +19 -7
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/literal_validator.rb +4 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/instrumentation_tracing.rb +83 -0
- data/lib/graphql/types/relay/node_behaviors.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +7 -4
- data/lib/graphql/execution/instrumentation.rb +0 -92
data/lib/graphql/schema.rb
CHANGED
@@ -31,6 +31,7 @@ require "graphql/schema/union"
|
|
31
31
|
require "graphql/schema/directive"
|
32
32
|
require "graphql/schema/directive/deprecated"
|
33
33
|
require "graphql/schema/directive/include"
|
34
|
+
require "graphql/schema/directive/one_of"
|
34
35
|
require "graphql/schema/directive/skip"
|
35
36
|
require "graphql/schema/directive/feature"
|
36
37
|
require "graphql/schema/directive/flagged"
|
@@ -109,9 +110,10 @@ module GraphQL
|
|
109
110
|
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
110
111
|
# @return [Class] the schema described by `document`
|
111
112
|
def from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
|
112
|
-
# If the file ends in `.graphql`, treat it like a filepath
|
113
|
-
if definition_or_path.end_with?(".graphql")
|
113
|
+
# If the file ends in `.graphql` or `.graphqls`, treat it like a filepath
|
114
|
+
if definition_or_path.end_with?(".graphql") || definition_or_path.end_with?(".graphqls")
|
114
115
|
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
116
|
+
self,
|
115
117
|
definition_or_path,
|
116
118
|
default_resolve: default_resolve,
|
117
119
|
parser: parser,
|
@@ -119,6 +121,7 @@ module GraphQL
|
|
119
121
|
)
|
120
122
|
else
|
121
123
|
GraphQL::Schema::BuildFromDefinition.from_definition(
|
124
|
+
self,
|
122
125
|
definition_or_path,
|
123
126
|
default_resolve: default_resolve,
|
124
127
|
parser: parser,
|
@@ -737,11 +740,10 @@ module GraphQL
|
|
737
740
|
def handle_or_reraise(context, err)
|
738
741
|
handler = Execution::Errors.find_handler_for(self, err.class)
|
739
742
|
if handler
|
740
|
-
|
741
|
-
|
742
|
-
args = runtime_info[:current_arguments]
|
743
|
+
obj = context[:current_object]
|
744
|
+
args = context[:current_arguments]
|
743
745
|
args = args && args.keyword_arguments
|
744
|
-
field =
|
746
|
+
field = context[:current_field]
|
745
747
|
if obj.is_a?(GraphQL::Schema::Object)
|
746
748
|
obj = obj.object
|
747
749
|
end
|
@@ -815,6 +817,15 @@ module GraphQL
|
|
815
817
|
member.accessible?(ctx)
|
816
818
|
end
|
817
819
|
|
820
|
+
def schema_directive(dir_class, **options)
|
821
|
+
@own_schema_directives ||= []
|
822
|
+
Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
|
823
|
+
end
|
824
|
+
|
825
|
+
def schema_directives
|
826
|
+
Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
|
827
|
+
end
|
828
|
+
|
818
829
|
# This hook is called when a client tries to access one or more
|
819
830
|
# fields that fail the `accessible?` check.
|
820
831
|
#
|
@@ -913,6 +924,7 @@ module GraphQL
|
|
913
924
|
"include" => GraphQL::Schema::Directive::Include,
|
914
925
|
"skip" => GraphQL::Schema::Directive::Skip,
|
915
926
|
"deprecated" => GraphQL::Schema::Directive::Deprecated,
|
927
|
+
"oneOf" => GraphQL::Schema::Directive::OneOf,
|
916
928
|
}.freeze
|
917
929
|
end
|
918
930
|
|
@@ -990,7 +1002,7 @@ module GraphQL
|
|
990
1002
|
# @param context [Hash] Multiplex-level context
|
991
1003
|
# @return [Array<Hash>] One result for each query in the input
|
992
1004
|
def multiplex(queries, **kwargs)
|
993
|
-
GraphQL::Execution::
|
1005
|
+
GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
|
994
1006
|
end
|
995
1007
|
|
996
1008
|
def instrumenters
|
@@ -108,6 +108,10 @@ module GraphQL
|
|
108
108
|
arg_type = @warden.get_argument(type, name).type
|
109
109
|
recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
|
110
110
|
end
|
111
|
+
|
112
|
+
if type.one_of? && ast_node.arguments.size != 1
|
113
|
+
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})")
|
114
|
+
end
|
111
115
|
merge_results(results)
|
112
116
|
end
|
113
117
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
module OneOfInputObjectsAreValid
|
5
|
+
def on_input_object(node, parent)
|
6
|
+
return super unless parent.is_a?(GraphQL::Language::Nodes::Argument)
|
7
|
+
|
8
|
+
parent_type = get_parent_type(context, parent)
|
9
|
+
return super unless parent_type && parent_type.kind.input_object? && parent_type.one_of?
|
10
|
+
|
11
|
+
validate_one_of_input_object(node, context, parent_type)
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def validate_one_of_input_object(ast_node, context, parent_type)
|
18
|
+
present_fields = ast_node.arguments.map(&:name)
|
19
|
+
input_object_type = parent_type.to_type_signature
|
20
|
+
|
21
|
+
if present_fields.count != 1
|
22
|
+
add_error(
|
23
|
+
OneOfInputObjectsAreValidError.new(
|
24
|
+
"OneOf Input Object '#{input_object_type}' must specify exactly one key.",
|
25
|
+
path: context.path,
|
26
|
+
nodes: ast_node,
|
27
|
+
input_object_type: input_object_type
|
28
|
+
)
|
29
|
+
)
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
field = present_fields.first
|
34
|
+
value = ast_node.arguments.first.value
|
35
|
+
|
36
|
+
if value.is_a?(GraphQL::Language::Nodes::NullValue)
|
37
|
+
add_error(
|
38
|
+
OneOfInputObjectsAreValidError.new(
|
39
|
+
"Argument '#{input_object_type}.#{field}' must be non-null.",
|
40
|
+
path: [*context.path, field],
|
41
|
+
nodes: ast_node.arguments.first,
|
42
|
+
input_object_type: input_object_type
|
43
|
+
)
|
44
|
+
)
|
45
|
+
return
|
46
|
+
end
|
47
|
+
|
48
|
+
if value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
49
|
+
variable_name = value.name
|
50
|
+
variable_type = @declared_variables[variable_name].type
|
51
|
+
|
52
|
+
unless variable_type.is_a?(GraphQL::Language::Nodes::NonNullType)
|
53
|
+
add_error(
|
54
|
+
OneOfInputObjectsAreValidError.new(
|
55
|
+
"Variable '#{variable_name}' must be non-nullable to be used for OneOf Input Object '#{input_object_type}'.",
|
56
|
+
path: [*context.path, field],
|
57
|
+
nodes: ast_node,
|
58
|
+
input_object_type: input_object_type
|
59
|
+
)
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class OneOfInputObjectsAreValidError < StaticValidation::Error
|
5
|
+
attr_reader :input_object_type
|
6
|
+
|
7
|
+
def initialize(message, path:, nodes:, input_object_type:)
|
8
|
+
super(message, path: path, nodes: nodes)
|
9
|
+
@input_object_type = input_object_type
|
10
|
+
end
|
11
|
+
|
12
|
+
# A hash representation of this Message
|
13
|
+
def to_h
|
14
|
+
extensions = {
|
15
|
+
"code" => code,
|
16
|
+
"inputObjectType" => input_object_type
|
17
|
+
}
|
18
|
+
|
19
|
+
super.merge({
|
20
|
+
"extensions" => extensions
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
def code
|
25
|
+
"invalidOneOfInputObject"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -23,7 +23,7 @@ module GraphQL
|
|
23
23
|
problems = validation_result.problems
|
24
24
|
first_problem = problems && problems.first
|
25
25
|
if first_problem
|
26
|
-
error_message = first_problem["
|
26
|
+
error_message = first_problem["explanation"]
|
27
27
|
end
|
28
28
|
|
29
29
|
error_message ||= "Default value for $#{node.name} doesn't match type #{type.to_type_signature}"
|
@@ -75,10 +75,12 @@ module GraphQL
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def analytics_enabled?
|
78
|
+
# [Deprecated] options[:analytics_enabled] will be removed in the future
|
78
79
|
analytics_available? && Datadog::Contrib::Analytics.enabled?(options.fetch(:analytics_enabled, false))
|
79
80
|
end
|
80
81
|
|
81
82
|
def analytics_sample_rate
|
83
|
+
# [Deprecated] options[:analytics_sample_rate] will be removed in the future
|
82
84
|
options.fetch(:analytics_sample_rate, 1.0)
|
83
85
|
end
|
84
86
|
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module Tracing
|
3
|
+
class InstrumentationTracing
|
4
|
+
def initialize(schema)
|
5
|
+
@schema = schema
|
6
|
+
end
|
7
|
+
|
8
|
+
def trace(event, data)
|
9
|
+
instrumenters = nil
|
10
|
+
query_instrumenters = nil
|
11
|
+
case event
|
12
|
+
when "execute_multiplex"
|
13
|
+
instrumenters = @schema.instrumenters
|
14
|
+
multiplex_instrumenters = instrumenters[:multiplex]
|
15
|
+
query_instrumenters = instrumenters[:query]
|
16
|
+
call_hooks(multiplex_instrumenters, data[:multiplex], :before_multiplex, :after_multiplex) {
|
17
|
+
each_query_call_hooks(query_instrumenters, data[:multiplex].queries) {
|
18
|
+
yield
|
19
|
+
}
|
20
|
+
}
|
21
|
+
else
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Call the before_ hooks of each query,
|
29
|
+
# Then yield if no errors.
|
30
|
+
# `call_hooks` takes care of appropriate cleanup.
|
31
|
+
def each_query_call_hooks(instrumenters, queries, i = 0)
|
32
|
+
if i >= queries.length
|
33
|
+
yield
|
34
|
+
else
|
35
|
+
query = queries[i]
|
36
|
+
call_hooks(instrumenters, query, :before_query, :after_query) {
|
37
|
+
each_query_call_hooks(instrumenters, queries, i + 1) {
|
38
|
+
yield
|
39
|
+
}
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Call each before hook, and if they all succeed, yield.
|
45
|
+
# If they don't all succeed, call after_ for each one that succeeded.
|
46
|
+
def call_hooks(instrumenters, object, before_hook_name, after_hook_name)
|
47
|
+
begin
|
48
|
+
successful = []
|
49
|
+
instrumenters.each do |instrumenter|
|
50
|
+
instrumenter.public_send(before_hook_name, object)
|
51
|
+
successful << instrumenter
|
52
|
+
end
|
53
|
+
|
54
|
+
# if any before hooks raise an exception, quit calling before hooks,
|
55
|
+
# but call the after hooks on anything that succeeded but also
|
56
|
+
# raise the exception that came from the before hook.
|
57
|
+
rescue GraphQL::ExecutionError => err
|
58
|
+
object.context.errors << err
|
59
|
+
rescue => e
|
60
|
+
raise call_after_hooks(successful, object, after_hook_name, e)
|
61
|
+
end
|
62
|
+
|
63
|
+
begin
|
64
|
+
yield # Call the user code
|
65
|
+
ensure
|
66
|
+
ex = call_after_hooks(successful, object, after_hook_name, nil)
|
67
|
+
raise ex if ex
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def call_after_hooks(instrumenters, object, after_hook_name, ex)
|
72
|
+
instrumenters.reverse_each do |instrumenter|
|
73
|
+
begin
|
74
|
+
instrumenter.public_send(after_hook_name, object)
|
75
|
+
rescue => e
|
76
|
+
ex = e
|
77
|
+
end
|
78
|
+
end
|
79
|
+
ex
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
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.15
|
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-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -303,7 +303,6 @@ files:
|
|
303
303
|
- lib/graphql/execution.rb
|
304
304
|
- lib/graphql/execution/directive_checks.rb
|
305
305
|
- lib/graphql/execution/errors.rb
|
306
|
-
- lib/graphql/execution/instrumentation.rb
|
307
306
|
- lib/graphql/execution/interpreter.rb
|
308
307
|
- lib/graphql/execution/interpreter/argument_value.rb
|
309
308
|
- lib/graphql/execution/interpreter/arguments.rb
|
@@ -394,6 +393,7 @@ files:
|
|
394
393
|
- lib/graphql/schema/directive/feature.rb
|
395
394
|
- lib/graphql/schema/directive/flagged.rb
|
396
395
|
- lib/graphql/schema/directive/include.rb
|
396
|
+
- lib/graphql/schema/directive/one_of.rb
|
397
397
|
- lib/graphql/schema/directive/skip.rb
|
398
398
|
- lib/graphql/schema/directive/transform.rb
|
399
399
|
- lib/graphql/schema/enum.rb
|
@@ -497,6 +497,8 @@ files:
|
|
497
497
|
- lib/graphql/static_validation/rules/mutation_root_exists_error.rb
|
498
498
|
- lib/graphql/static_validation/rules/no_definitions_are_present.rb
|
499
499
|
- lib/graphql/static_validation/rules/no_definitions_are_present_error.rb
|
500
|
+
- lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb
|
501
|
+
- lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb
|
500
502
|
- lib/graphql/static_validation/rules/operation_names_are_valid.rb
|
501
503
|
- lib/graphql/static_validation/rules/operation_names_are_valid_error.rb
|
502
504
|
- lib/graphql/static_validation/rules/query_root_exists.rb
|
@@ -536,6 +538,7 @@ files:
|
|
536
538
|
- lib/graphql/tracing/appoptics_tracing.rb
|
537
539
|
- lib/graphql/tracing/appsignal_tracing.rb
|
538
540
|
- lib/graphql/tracing/data_dog_tracing.rb
|
541
|
+
- lib/graphql/tracing/instrumentation_tracing.rb
|
539
542
|
- lib/graphql/tracing/new_relic_tracing.rb
|
540
543
|
- lib/graphql/tracing/notifications_tracing.rb
|
541
544
|
- lib/graphql/tracing/platform_tracing.rb
|
@@ -595,7 +598,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
595
598
|
- !ruby/object:Gem::Version
|
596
599
|
version: '0'
|
597
600
|
requirements: []
|
598
|
-
rubygems_version: 3.2.
|
601
|
+
rubygems_version: 3.2.33
|
599
602
|
signing_key:
|
600
603
|
specification_version: 4
|
601
604
|
summary: A GraphQL language and runtime for Ruby
|
@@ -1,92 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module GraphQL
|
3
|
-
module Execution
|
4
|
-
module Instrumentation
|
5
|
-
# This function implements the instrumentation policy:
|
6
|
-
#
|
7
|
-
# - Instrumenters are a stack; the first `before_query` will have the last `after_query`
|
8
|
-
# - If a `before_` hook returned without an error, its corresponding `after_` hook will run.
|
9
|
-
# - If the `before_` hook did _not_ run, the `after_` hook will not be called.
|
10
|
-
#
|
11
|
-
# When errors are raised from `after_` hooks:
|
12
|
-
# - Subsequent `after_` hooks _are_ called
|
13
|
-
# - The first raised error is captured; later errors are ignored
|
14
|
-
# - If an error was capture, it's re-raised after all hooks are finished
|
15
|
-
#
|
16
|
-
# Partial runs of instrumentation are possible:
|
17
|
-
# - If a `before_multiplex` hook raises an error, no `before_query` hooks will run
|
18
|
-
# - If a `before_query` hook raises an error, subsequent `before_query` hooks will not run (on any query)
|
19
|
-
def self.apply_instrumenters(multiplex)
|
20
|
-
schema = multiplex.schema
|
21
|
-
queries = multiplex.queries
|
22
|
-
query_instrumenters = schema.instrumenters[:query]
|
23
|
-
multiplex_instrumenters = schema.instrumenters[:multiplex]
|
24
|
-
|
25
|
-
# First, run multiplex instrumentation, then query instrumentation for each query
|
26
|
-
call_hooks(multiplex_instrumenters, multiplex, :before_multiplex, :after_multiplex) do
|
27
|
-
each_query_call_hooks(query_instrumenters, queries) do
|
28
|
-
# Let them be executed
|
29
|
-
yield
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class << self
|
35
|
-
private
|
36
|
-
# Call the before_ hooks of each query,
|
37
|
-
# Then yield if no errors.
|
38
|
-
# `call_hooks` takes care of appropriate cleanup.
|
39
|
-
def each_query_call_hooks(instrumenters, queries, i = 0)
|
40
|
-
if i >= queries.length
|
41
|
-
yield
|
42
|
-
else
|
43
|
-
query = queries[i]
|
44
|
-
call_hooks(instrumenters, query, :before_query, :after_query) {
|
45
|
-
each_query_call_hooks(instrumenters, queries, i + 1) {
|
46
|
-
yield
|
47
|
-
}
|
48
|
-
}
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Call each before hook, and if they all succeed, yield.
|
53
|
-
# If they don't all succeed, call after_ for each one that succeeded.
|
54
|
-
def call_hooks(instrumenters, object, before_hook_name, after_hook_name)
|
55
|
-
begin
|
56
|
-
successful = []
|
57
|
-
instrumenters.each do |instrumenter|
|
58
|
-
instrumenter.public_send(before_hook_name, object)
|
59
|
-
successful << instrumenter
|
60
|
-
end
|
61
|
-
|
62
|
-
# if any before hooks raise an exception, quit calling before hooks,
|
63
|
-
# but call the after hooks on anything that succeeded but also
|
64
|
-
# raise the exception that came from the before hook.
|
65
|
-
rescue GraphQL::ExecutionError => err
|
66
|
-
object.context.errors << err
|
67
|
-
rescue => e
|
68
|
-
raise call_after_hooks(successful, object, after_hook_name, e)
|
69
|
-
end
|
70
|
-
|
71
|
-
begin
|
72
|
-
yield # Call the user code
|
73
|
-
ensure
|
74
|
-
ex = call_after_hooks(successful, object, after_hook_name, nil)
|
75
|
-
raise ex if ex
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def call_after_hooks(instrumenters, object, after_hook_name, ex)
|
80
|
-
instrumenters.reverse_each do |instrumenter|
|
81
|
-
begin
|
82
|
-
instrumenter.public_send(after_hook_name, object)
|
83
|
-
rescue => e
|
84
|
-
ex = e
|
85
|
-
end
|
86
|
-
end
|
87
|
-
ex
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|