graphql 2.0.13 → 2.3.10
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/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +3 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/generators/graphql/relay.rb +18 -1
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +6 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +8 -0
- data/lib/graphql/analysis/analyzer.rb +89 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +183 -0
- data/lib/graphql/analysis/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +283 -0
- data/lib/graphql/analysis.rb +92 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/backtrace/table.rb +2 -2
- data/lib/graphql/backtrace/trace.rb +93 -0
- data/lib/graphql/backtrace/tracer.rb +1 -1
- data/lib/graphql/backtrace.rb +2 -1
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +88 -0
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +89 -45
- data/lib/graphql/dataloader.rb +115 -142
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
- data/lib/graphql/execution/interpreter/resolve.rb +19 -0
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
- data/lib/graphql/execution/interpreter/runtime.rb +331 -455
- data/lib/graphql/execution/interpreter.rb +125 -61
- data/lib/graphql/execution/lazy.rb +6 -12
- data/lib/graphql/execution/lookahead.rb +124 -46
- data/lib/graphql/execution/multiplex.rb +3 -117
- data/lib/graphql/execution.rb +0 -1
- data/lib/graphql/introspection/directive_type.rb +3 -3
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +11 -5
- data/lib/graphql/introspection/field_type.rb +2 -2
- data/lib/graphql/introspection/schema_type.rb +10 -13
- data/lib/graphql/introspection/type_type.rb +17 -10
- data/lib/graphql/introspection.rb +3 -2
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +75 -59
- data/lib/graphql/language/lexer.rb +358 -1506
- data/lib/graphql/language/nodes.rb +166 -93
- data/lib/graphql/language/parser.rb +795 -1953
- data/lib/graphql/language/printer.rb +340 -160
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +188 -141
- data/lib/graphql/language.rb +61 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +33 -6
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +117 -112
- data/lib/graphql/query/null_context.rb +12 -25
- data/lib/graphql/query/validation_pipeline.rb +6 -5
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +86 -30
- data/lib/graphql/railtie.rb +9 -6
- data/lib/graphql/rake_task.rb +29 -11
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/schema/addition.rb +59 -23
- data/lib/graphql/schema/always_visible.rb +11 -0
- data/lib/graphql/schema/argument.rb +55 -26
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +56 -32
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +15 -3
- data/lib/graphql/schema/enum.rb +35 -24
- data/lib/graphql/schema/enum_value.rb +2 -3
- data/lib/graphql/schema/field/connection_extension.rb +2 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +147 -107
- data/lib/graphql/schema/field_extension.rb +1 -4
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/has_single_input_argument.rb +158 -0
- data/lib/graphql/schema/input_object.rb +47 -11
- data/lib/graphql/schema/interface.rb +15 -21
- data/lib/graphql/schema/introspection_system.rb +7 -17
- data/lib/graphql/schema/late_bound_type.rb +10 -0
- data/lib/graphql/schema/list.rb +2 -2
- data/lib/graphql/schema/loader.rb +2 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -14
- data/lib/graphql/schema/member/build_type.rb +11 -3
- data/lib/graphql/schema/member/has_arguments.rb +170 -130
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +100 -38
- data/lib/graphql/schema/member/has_interfaces.rb +65 -10
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +16 -5
- data/lib/graphql/schema/printer.rb +11 -8
- data/lib/graphql/schema/relay_classic_mutation.rb +7 -129
- data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
- data/lib/graphql/schema/resolver.rb +47 -32
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/subset.rb +397 -0
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +11 -2
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +60 -0
- data/lib/graphql/schema/validator.rb +4 -2
- data/lib/graphql/schema/warden.rb +238 -93
- data/lib/graphql/schema.rb +498 -103
- data/lib/graphql/static_validation/all_rules.rb +2 -1
- data/lib/graphql/static_validation/base_visitor.rb +7 -6
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/literal_validator.rb +24 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +10 -10
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- 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/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +5 -5
- data/lib/graphql/static_validation/validator.rb +4 -1
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +11 -4
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/event.rb +11 -10
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +20 -13
- data/lib/graphql/testing/helpers.rb +151 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +251 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/data_dog_trace.rb +183 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +9 -21
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
- data/lib/graphql/tracing/legacy_trace.rb +69 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +45 -0
- data/lib/graphql/tracing/platform_trace.rb +118 -0
- data/lib/graphql/tracing/platform_tracing.rb +17 -3
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/trace.rb +76 -0
- data/lib/graphql/tracing.rb +20 -40
- data/lib/graphql/type_kinds.rb +7 -4
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +1 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +68 -6
- data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
- data/lib/graphql/types/relay/node_behaviors.rb +8 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
- data/lib/graphql/types/relay.rb +0 -1
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +27 -20
- data/readme.md +13 -3
- metadata +96 -47
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -269
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/language/lexer.rl +0 -280
- data/lib/graphql/language/parser.y +0 -554
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
- data/lib/graphql/types/relay/default_relay.rb +0 -21
@@ -1,51 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "graphql/query/context"
|
2
3
|
module GraphQL
|
3
4
|
class Query
|
4
5
|
# This object can be `ctx` in places where there is no query
|
5
|
-
class NullContext
|
6
|
-
|
7
|
-
def visible_field?(field, ctx); true; end
|
8
|
-
def visible_argument?(arg, ctx); true; end
|
9
|
-
def visible_type?(type, ctx); true; end
|
10
|
-
def visible_enum_value?(ev, ctx); true; end
|
11
|
-
def visible_type_membership?(tm, ctx); true; end
|
12
|
-
end
|
6
|
+
class NullContext < Context
|
7
|
+
include Singleton
|
13
8
|
|
14
9
|
class NullQuery
|
10
|
+
def after_lazy(value)
|
11
|
+
yield(value)
|
12
|
+
end
|
15
13
|
end
|
16
14
|
|
17
15
|
class NullSchema < GraphQL::Schema
|
18
16
|
end
|
19
17
|
|
18
|
+
extend Forwardable
|
19
|
+
|
20
20
|
attr_reader :schema, :query, :warden, :dataloader
|
21
|
+
def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key?
|
21
22
|
|
22
23
|
def initialize
|
23
24
|
@query = NullQuery.new
|
24
25
|
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
25
26
|
@schema = NullSchema
|
26
|
-
@warden = NullWarden.new(
|
27
|
-
GraphQL::Filter.new,
|
28
|
-
context: self,
|
29
|
-
schema: @schema,
|
30
|
-
)
|
27
|
+
@warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
|
31
28
|
end
|
32
29
|
|
33
|
-
def [](key); end
|
34
|
-
|
35
30
|
def interpreter?
|
36
31
|
true
|
37
32
|
end
|
38
33
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
def [](key); end
|
43
|
-
|
44
|
-
def instance
|
45
|
-
@instance ||= self.new
|
46
|
-
end
|
47
|
-
|
48
|
-
def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader
|
34
|
+
def types
|
35
|
+
@types ||= GraphQL::Schema::Warden::SchemaSubset.new(@warden)
|
49
36
|
end
|
50
37
|
end
|
51
38
|
end
|
@@ -14,7 +14,7 @@ module GraphQL
|
|
14
14
|
#
|
15
15
|
# @api private
|
16
16
|
class ValidationPipeline
|
17
|
-
attr_reader :max_depth, :max_complexity
|
17
|
+
attr_reader :max_depth, :max_complexity, :validate_timeout_remaining
|
18
18
|
|
19
19
|
def initialize(query:, parse_error:, operation_name_error:, max_depth:, max_complexity:)
|
20
20
|
@validation_errors = []
|
@@ -68,9 +68,10 @@ module GraphQL
|
|
68
68
|
elsif @operation_name_error
|
69
69
|
@validation_errors << @operation_name_error
|
70
70
|
else
|
71
|
-
|
71
|
+
validator = @query.static_validator || @schema.static_validator
|
72
|
+
validation_result = validator.validate(@query, validate: @query.validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
|
72
73
|
@validation_errors.concat(validation_result[:errors])
|
73
|
-
|
74
|
+
@validate_timeout_remaining = validation_result[:remaining_timeout]
|
74
75
|
if @validation_errors.empty?
|
75
76
|
@validation_errors.concat(@query.variables.errors)
|
76
77
|
end
|
@@ -99,10 +100,10 @@ module GraphQL
|
|
99
100
|
# Depending on the analysis engine, we must use different analyzers
|
100
101
|
# remove this once everything has switched over to AST analyzers
|
101
102
|
if max_depth
|
102
|
-
qa << GraphQL::Analysis::
|
103
|
+
qa << GraphQL::Analysis::MaxQueryDepth
|
103
104
|
end
|
104
105
|
if max_complexity
|
105
|
-
qa << GraphQL::Analysis::
|
106
|
+
qa << GraphQL::Analysis::MaxQueryComplexity
|
106
107
|
end
|
107
108
|
qa
|
108
109
|
else
|
@@ -26,7 +26,7 @@ module GraphQL
|
|
26
26
|
# - Then, fall back to the default value from the query string
|
27
27
|
# If it's still nil, raise an error if it's required.
|
28
28
|
variable_type = schema.type_from_ast(ast_variable.type, context: ctx)
|
29
|
-
if variable_type.nil?
|
29
|
+
if variable_type.nil? || !variable_type.unwrap.kind.input?
|
30
30
|
# Pass -- it will get handled by a validator
|
31
31
|
else
|
32
32
|
variable_name = ast_variable.name
|
@@ -80,12 +80,12 @@ module GraphQL
|
|
80
80
|
else
|
81
81
|
val
|
82
82
|
end
|
83
|
-
end
|
83
|
+
end
|
84
84
|
|
85
85
|
def add_max_errors_reached_message
|
86
86
|
message = "Too many errors processing variables, max validation error limit reached. Execution aborted"
|
87
87
|
validation_result = GraphQL::Query::InputValidationResult.from_problem(message)
|
88
|
-
errors << GraphQL::Query::VariableValidationError.new(nil, nil, nil, validation_result, msg: message)
|
88
|
+
errors << GraphQL::Query::VariableValidationError.new(nil, nil, nil, validation_result, msg: message)
|
89
89
|
end
|
90
90
|
end
|
91
91
|
end
|
data/lib/graphql/query.rb
CHANGED
@@ -45,6 +45,20 @@ module GraphQL
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
# @return [GraphQL::StaticValidation::Validator] if present, the query will validate with these rules.
|
49
|
+
attr_reader :static_validator
|
50
|
+
|
51
|
+
# @param new_validate [GraphQL::StaticValidation::Validator] if present, the query will validate with these rules. This can't be reasssigned after validation.
|
52
|
+
def static_validator=(new_validator)
|
53
|
+
if defined?(@validation_pipeline) && @validation_pipeline && @validation_pipeline.has_validated?
|
54
|
+
raise ArgumentError, "Can't reassign Query#static_validator= after validation has run, remove this assignment."
|
55
|
+
elsif !new_validator.is_a?(GraphQL::StaticValidation::Validator)
|
56
|
+
raise ArgumentError, "Expected a `GraphQL::StaticValidation::Validator` instance."
|
57
|
+
else
|
58
|
+
@static_validator = new_validator
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
48
62
|
attr_writer :query_string
|
49
63
|
|
50
64
|
# @return [GraphQL::Language::Nodes::Document]
|
@@ -81,24 +95,43 @@ module GraphQL
|
|
81
95
|
# @param root_value [Object] the object used to resolve fields on the root type
|
82
96
|
# @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
|
83
97
|
# @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
|
84
|
-
|
85
|
-
# @param only [<#call(schema_member, context)>] If provided, objects will be hidden from the schema when `.call(schema_member, context)` returns false
|
86
|
-
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, except: nil, only: nil, warden: nil)
|
98
|
+
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil, use_schema_subset: nil)
|
87
99
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
88
100
|
variables ||= {}
|
89
101
|
@schema = schema
|
90
|
-
@
|
91
|
-
|
92
|
-
|
102
|
+
@context = schema.context_class.new(query: self, values: context)
|
103
|
+
|
104
|
+
if use_schema_subset.nil?
|
105
|
+
use_schema_subset = warden ? false : schema.use_schema_subset?
|
106
|
+
end
|
107
|
+
|
108
|
+
if use_schema_subset
|
109
|
+
@schema_subset = @schema.subset_class.new(self)
|
110
|
+
@warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
|
111
|
+
else
|
112
|
+
@schema_subset = nil
|
113
|
+
@warden = warden
|
114
|
+
end
|
115
|
+
|
93
116
|
@subscription_topic = subscription_topic
|
94
117
|
@root_value = root_value
|
95
118
|
@fragments = nil
|
96
119
|
@operations = nil
|
97
120
|
@validate = validate
|
98
|
-
|
121
|
+
self.static_validator = static_validator if static_validator
|
122
|
+
context_tracers = (context ? context.fetch(:tracers, []) : [])
|
123
|
+
@tracers = schema.tracers + context_tracers
|
124
|
+
|
99
125
|
# Support `ctx[:backtrace] = true` for wrapping backtraces
|
100
126
|
if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
|
101
|
-
|
127
|
+
if schema.trace_class <= GraphQL::Tracing::CallLegacyTracers
|
128
|
+
context_tracers += [GraphQL::Backtrace::Tracer]
|
129
|
+
@tracers << GraphQL::Backtrace::Tracer
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
if context_tracers.any? && !(schema.trace_class <= GraphQL::Tracing::CallLegacyTracers)
|
134
|
+
raise ArgumentError, "context[:tracers] are not supported without `trace_with(GraphQL::Tracing::CallLegacyTracers)` in the schema configuration, please add it."
|
102
135
|
end
|
103
136
|
|
104
137
|
@analysis_errors = []
|
@@ -140,9 +173,12 @@ module GraphQL
|
|
140
173
|
@result_values = nil
|
141
174
|
@executed = false
|
142
175
|
|
143
|
-
|
144
|
-
|
145
|
-
|
176
|
+
@logger = if context && context[:logger] == false
|
177
|
+
Logger.new(IO::NULL)
|
178
|
+
elsif context && (l = context[:logger])
|
179
|
+
l
|
180
|
+
else
|
181
|
+
schema.default_logger
|
146
182
|
end
|
147
183
|
end
|
148
184
|
|
@@ -157,6 +193,11 @@ module GraphQL
|
|
157
193
|
|
158
194
|
attr_accessor :multiplex
|
159
195
|
|
196
|
+
# @return [GraphQL::Tracing::Trace]
|
197
|
+
def current_trace
|
198
|
+
@current_trace ||= context[:trace] || (multiplex ? multiplex.current_trace : schema.new_trace(multiplex: multiplex, query: self))
|
199
|
+
end
|
200
|
+
|
160
201
|
def subscription_update?
|
161
202
|
@subscription_topic && subscription?
|
162
203
|
end
|
@@ -166,7 +207,14 @@ module GraphQL
|
|
166
207
|
def lookahead
|
167
208
|
@lookahead ||= begin
|
168
209
|
ast_node = selected_operation
|
169
|
-
root_type =
|
210
|
+
root_type = case ast_node.operation_type
|
211
|
+
when nil, "query"
|
212
|
+
types.query_root # rubocop:disable Development/ContextIsPassedCop
|
213
|
+
when "mutation"
|
214
|
+
types.mutation_root # rubocop:disable Development/ContextIsPassedCop
|
215
|
+
when "subscription"
|
216
|
+
types.subscription_root # rubocop:disable Development/ContextIsPassedCop
|
217
|
+
end
|
170
218
|
GraphQL::Execution::Lookahead.new(query: self, root_type: root_type, ast_nodes: [ast_node])
|
171
219
|
end
|
172
220
|
end
|
@@ -193,10 +241,10 @@ module GraphQL
|
|
193
241
|
end
|
194
242
|
|
195
243
|
# Get the result for this query, executing it once
|
196
|
-
# @return [
|
244
|
+
# @return [GraphQL::Query::Result] A Hash-like GraphQL response, with `"data"` and/or `"errors"` keys
|
197
245
|
def result
|
198
246
|
if !@executed
|
199
|
-
Execution::
|
247
|
+
Execution::Interpreter.run_all(@schema, [self], context: @context)
|
200
248
|
end
|
201
249
|
@result ||= Query::Result.new(query: self, values: @result_values)
|
202
250
|
end
|
@@ -275,7 +323,7 @@ module GraphQL
|
|
275
323
|
|
276
324
|
# @return [String] An opaque hash for identifying this query's given query string and selected operation
|
277
325
|
def operation_fingerprint
|
278
|
-
@operation_fingerprint ||= "#{selected_operation_name || "anonymous"}/#{Fingerprint.generate(query_string)}"
|
326
|
+
@operation_fingerprint ||= "#{selected_operation_name || "anonymous"}/#{Fingerprint.generate(query_string || "")}"
|
279
327
|
end
|
280
328
|
|
281
329
|
# @return [String] An opaque hash for identifying this query's given a variable values (not including defaults)
|
@@ -288,7 +336,7 @@ module GraphQL
|
|
288
336
|
end
|
289
337
|
|
290
338
|
def_delegators :validation_pipeline, :validation_errors,
|
291
|
-
:analyzers, :ast_analyzers, :max_depth, :max_complexity
|
339
|
+
:analyzers, :ast_analyzers, :max_depth, :max_complexity, :validate_timeout_remaining
|
292
340
|
|
293
341
|
attr_accessor :analysis_errors
|
294
342
|
def valid?
|
@@ -301,12 +349,16 @@ module GraphQL
|
|
301
349
|
|
302
350
|
def_delegators :warden, :get_type, :get_field, :possible_types, :root_type_for_operation
|
303
351
|
|
352
|
+
def types
|
353
|
+
@schema_subset || warden.schema_subset
|
354
|
+
end
|
355
|
+
|
304
356
|
# @param abstract_type [GraphQL::UnionType, GraphQL::InterfaceType]
|
305
357
|
# @param value [Object] Any runtime value
|
306
358
|
# @return [GraphQL::ObjectType, nil] The runtime type of `value` from {Schema#resolve_type}
|
307
359
|
# @see {#possible_types} to apply filtering from `only` / `except`
|
308
|
-
def resolve_type(abstract_type, value =
|
309
|
-
if value.is_a?(Symbol) && value ==
|
360
|
+
def resolve_type(abstract_type, value = NOT_CONFIGURED)
|
361
|
+
if value.is_a?(Symbol) && value == NOT_CONFIGURED
|
310
362
|
# Old method signature
|
311
363
|
value = abstract_type
|
312
364
|
abstract_type = nil
|
@@ -325,16 +377,6 @@ module GraphQL
|
|
325
377
|
with_prepared_ast { @query }
|
326
378
|
end
|
327
379
|
|
328
|
-
# @return [void]
|
329
|
-
def merge_filters(only: nil, except: nil)
|
330
|
-
if @prepared_ast
|
331
|
-
raise "Can't add filters after preparing the query"
|
332
|
-
else
|
333
|
-
@filter = @filter.merge(only: only, except: except)
|
334
|
-
end
|
335
|
-
nil
|
336
|
-
end
|
337
|
-
|
338
380
|
def subscription?
|
339
381
|
with_prepared_ast { @subscription }
|
340
382
|
end
|
@@ -344,6 +386,20 @@ module GraphQL
|
|
344
386
|
schema.handle_or_reraise(context, err)
|
345
387
|
end
|
346
388
|
|
389
|
+
def after_lazy(value, &block)
|
390
|
+
if !defined?(@runtime_instance)
|
391
|
+
@runtime_instance = context.namespace(:interpreter_runtime)[:runtime]
|
392
|
+
end
|
393
|
+
|
394
|
+
if @runtime_instance
|
395
|
+
@runtime_instance.minimal_after_lazy(value, &block)
|
396
|
+
else
|
397
|
+
@schema.after_lazy(value, &block)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
attr_reader :logger
|
402
|
+
|
347
403
|
private
|
348
404
|
|
349
405
|
def find_operation(operations, operation_name)
|
@@ -358,11 +414,11 @@ module GraphQL
|
|
358
414
|
|
359
415
|
def prepare_ast
|
360
416
|
@prepared_ast = true
|
361
|
-
@warden ||=
|
417
|
+
@warden ||= @schema.warden_class.new(schema: @schema, context: @context)
|
362
418
|
parse_error = nil
|
363
419
|
@document ||= begin
|
364
420
|
if query_string
|
365
|
-
GraphQL.parse(query_string,
|
421
|
+
GraphQL.parse(query_string, trace: self.current_trace, max_tokens: @schema.max_query_string_tokens)
|
366
422
|
end
|
367
423
|
rescue GraphQL::ParseError => err
|
368
424
|
parse_error = err
|
data/lib/graphql/railtie.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module GraphQL
|
3
4
|
class Railtie < Rails::Railtie
|
4
|
-
config.
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
if
|
9
|
-
Language::Parser.cache ||= Language::Cache.new(
|
5
|
+
config.graphql = ActiveSupport::OrderedOptions.new
|
6
|
+
config.graphql.parser_cache = false
|
7
|
+
|
8
|
+
initializer("graphql.cache") do |app|
|
9
|
+
if config.graphql.parser_cache
|
10
|
+
Language::Parser.cache ||= Language::Cache.new(
|
11
|
+
app.root.join("tmp/cache/graphql")
|
12
|
+
)
|
10
13
|
end
|
11
14
|
end
|
12
15
|
end
|
data/lib/graphql/rake_task.rb
CHANGED
@@ -9,8 +9,7 @@ module GraphQL
|
|
9
9
|
# By default, schemas are looked up by name as constants using `schema_name:`.
|
10
10
|
# You can provide a `load_schema` function to return your schema another way.
|
11
11
|
#
|
12
|
-
# `load_context
|
13
|
-
# you can keep an eye on how filters affect your schema.
|
12
|
+
# Use `load_context:` and `visible?` to dump schemas under certain visibility constraints.
|
14
13
|
#
|
15
14
|
# @example Dump a Schema to .graphql + .json files
|
16
15
|
# require "graphql/rake_task"
|
@@ -23,6 +22,10 @@ module GraphQL
|
|
23
22
|
# @example Invoking the task from Ruby
|
24
23
|
# require "rake"
|
25
24
|
# Rake::Task["graphql:schema:dump"].invoke
|
25
|
+
#
|
26
|
+
# @example Providing arguments to build the introspection query
|
27
|
+
# require "graphql/rake_task"
|
28
|
+
# GraphQL::RakeTask.new(schema_name: "MySchema", include_is_one_of: true)
|
26
29
|
class RakeTask
|
27
30
|
include Rake::DSL
|
28
31
|
|
@@ -32,11 +35,14 @@ module GraphQL
|
|
32
35
|
schema_name: nil,
|
33
36
|
load_schema: ->(task) { Object.const_get(task.schema_name) },
|
34
37
|
load_context: ->(task) { {} },
|
35
|
-
only: nil,
|
36
|
-
except: nil,
|
37
38
|
directory: ".",
|
38
39
|
idl_outfile: "schema.graphql",
|
39
40
|
json_outfile: "schema.json",
|
41
|
+
include_deprecated_args: true,
|
42
|
+
include_schema_description: false,
|
43
|
+
include_is_repeatable: false,
|
44
|
+
include_specified_by_url: false,
|
45
|
+
include_is_one_of: false
|
40
46
|
}
|
41
47
|
|
42
48
|
# @return [String] Namespace for generated tasks
|
@@ -59,12 +65,6 @@ module GraphQL
|
|
59
65
|
# @return [<#call(task)>] A callable for loading the query context
|
60
66
|
attr_accessor :load_context
|
61
67
|
|
62
|
-
# @return [<#call(member, ctx)>, nil] A filter for this task
|
63
|
-
attr_accessor :only
|
64
|
-
|
65
|
-
# @return [<#call(member, ctx)>, nil] A filter for this task
|
66
|
-
attr_accessor :except
|
67
|
-
|
68
68
|
# @return [String] target for IDL task
|
69
69
|
attr_accessor :idl_outfile
|
70
70
|
|
@@ -74,6 +74,10 @@ module GraphQL
|
|
74
74
|
# @return [String] directory for IDL & JSON files
|
75
75
|
attr_accessor :directory
|
76
76
|
|
77
|
+
# @return [Boolean] Options for additional fields in the introspection query JSON response
|
78
|
+
# @see GraphQL::Schema.as_json
|
79
|
+
attr_accessor :include_deprecated_args, :include_schema_description, :include_is_repeatable, :include_specified_by_url, :include_is_one_of
|
80
|
+
|
77
81
|
# Set the parameters of this task by passing keyword arguments
|
78
82
|
# or assigning attributes inside the block
|
79
83
|
def initialize(options = {})
|
@@ -96,7 +100,21 @@ module GraphQL
|
|
96
100
|
def write_outfile(method_name, file)
|
97
101
|
schema = @load_schema.call(self)
|
98
102
|
context = @load_context.call(self)
|
99
|
-
result =
|
103
|
+
result = case method_name
|
104
|
+
when :to_json
|
105
|
+
schema.to_json(
|
106
|
+
include_is_one_of: include_is_one_of,
|
107
|
+
include_deprecated_args: include_deprecated_args,
|
108
|
+
include_is_repeatable: include_is_repeatable,
|
109
|
+
include_specified_by_url: include_specified_by_url,
|
110
|
+
include_schema_description: include_schema_description,
|
111
|
+
context: context
|
112
|
+
)
|
113
|
+
when :to_definition
|
114
|
+
schema.to_definition(context: context)
|
115
|
+
else
|
116
|
+
raise ArgumentError, "Unexpected schema dump method: #{method_name.inspect}"
|
117
|
+
end
|
100
118
|
dir = File.dirname(file)
|
101
119
|
FileUtils.mkdir_p(dir)
|
102
120
|
if !result.end_with?("\n")
|
@@ -9,7 +9,7 @@ module GraphQL
|
|
9
9
|
|
10
10
|
# Return the source of `send_node`, but without the keyword argument represented by `pair_node`
|
11
11
|
def source_without_keyword_argument(send_node, pair_node)
|
12
|
-
# work back to the
|
12
|
+
# work back to the preceding comma
|
13
13
|
first_pos = pair_node.location.expression.begin_pos
|
14
14
|
end_pos = pair_node.location.expression.end_pos
|
15
15
|
node_source = send_node.source_range.source
|
@@ -12,7 +12,7 @@ module GraphQL
|
|
12
12
|
@possible_types = {}
|
13
13
|
@types = {}
|
14
14
|
@union_memberships = {}
|
15
|
-
@references = Hash.new { |h, k| h[k] =
|
15
|
+
@references = Hash.new { |h, k| h[k] = Set.new }
|
16
16
|
@arguments_with_default_values = []
|
17
17
|
add_type_and_traverse(new_types)
|
18
18
|
end
|
@@ -20,7 +20,7 @@ module GraphQL
|
|
20
20
|
private
|
21
21
|
|
22
22
|
def references_to(thing, from:)
|
23
|
-
@references[thing]
|
23
|
+
@references[thing].add(from)
|
24
24
|
end
|
25
25
|
|
26
26
|
def get_type(name)
|
@@ -40,14 +40,21 @@ module GraphQL
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def add_directives_from(owner)
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
if (dir_instances = owner.directives).any?
|
44
|
+
dirs = dir_instances.map(&:class)
|
45
|
+
@directives.merge(dirs)
|
46
|
+
add_type_and_traverse(dirs)
|
47
|
+
end
|
46
48
|
end
|
47
49
|
|
48
50
|
def add_type_and_traverse(new_types)
|
49
51
|
late_types = []
|
50
|
-
|
52
|
+
path = []
|
53
|
+
new_types.each do |t|
|
54
|
+
path.push(t.graphql_name)
|
55
|
+
add_type(t, owner: nil, late_types: late_types, path: path)
|
56
|
+
path.pop
|
57
|
+
end
|
51
58
|
missed_late_types = 0
|
52
59
|
while (late_type_vals = late_types.shift)
|
53
60
|
type_owner, lt = late_type_vals
|
@@ -88,7 +95,7 @@ module GraphQL
|
|
88
95
|
# It's a union with possible_types
|
89
96
|
# Replace the item by class name
|
90
97
|
owner.assign_type_membership_object_type(type)
|
91
|
-
@possible_types[owner
|
98
|
+
@possible_types[owner] = owner.possible_types
|
92
99
|
elsif type.kind.interface? && (owner.kind.object? || owner.kind.interface?)
|
93
100
|
new_interfaces = []
|
94
101
|
owner.interfaces.each do |int_t|
|
@@ -103,7 +110,7 @@ module GraphQL
|
|
103
110
|
end
|
104
111
|
owner.implements(*new_interfaces)
|
105
112
|
new_interfaces.each do |int|
|
106
|
-
pt = @possible_types[int
|
113
|
+
pt = @possible_types[int] ||= []
|
107
114
|
if !pt.include?(owner) && owner.is_a?(Class)
|
108
115
|
pt << owner
|
109
116
|
end
|
@@ -119,6 +126,7 @@ module GraphQL
|
|
119
126
|
@types[type.graphql_name] = type
|
120
127
|
when GraphQL::Schema::Field, GraphQL::Schema::Argument
|
121
128
|
orig_type = owner.type
|
129
|
+
unwrapped_t = type
|
122
130
|
# Apply list/non-null wrapper as needed
|
123
131
|
if orig_type.respond_to?(:of_type)
|
124
132
|
transforms = []
|
@@ -135,6 +143,7 @@ module GraphQL
|
|
135
143
|
transforms.reverse_each { |t| type = type.public_send(t) }
|
136
144
|
end
|
137
145
|
owner.type = type
|
146
|
+
references_to(unwrapped_t, from: owner)
|
138
147
|
else
|
139
148
|
raise "Unexpected update: #{owner.inspect} #{type.inspect}"
|
140
149
|
end
|
@@ -157,8 +166,12 @@ module GraphQL
|
|
157
166
|
@directives << type
|
158
167
|
type.all_argument_definitions.each do |arg|
|
159
168
|
arg_type = arg.type.unwrap
|
160
|
-
|
161
|
-
|
169
|
+
if !arg_type.is_a?(GraphQL::Schema::LateBoundType)
|
170
|
+
references_to(arg_type, from: arg)
|
171
|
+
end
|
172
|
+
path.push(arg.graphql_name)
|
173
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: path)
|
174
|
+
path.pop
|
162
175
|
if arg.default_value?
|
163
176
|
@arguments_with_default_values << arg
|
164
177
|
end
|
@@ -178,56 +191,72 @@ module GraphQL
|
|
178
191
|
type.all_field_definitions.each do |field|
|
179
192
|
name = field.graphql_name
|
180
193
|
field_type = field.type.unwrap
|
181
|
-
|
182
|
-
|
183
|
-
|
194
|
+
if !field_type.is_a?(GraphQL::Schema::LateBoundType)
|
195
|
+
references_to(field_type, from: field)
|
196
|
+
end
|
197
|
+
path.push(name)
|
198
|
+
add_type(field_type, owner: field, late_types: late_types, path: path)
|
184
199
|
add_directives_from(field)
|
185
200
|
field.all_argument_definitions.each do |arg|
|
186
201
|
add_directives_from(arg)
|
187
202
|
arg_type = arg.type.unwrap
|
188
|
-
|
189
|
-
|
203
|
+
if !arg_type.is_a?(GraphQL::Schema::LateBoundType)
|
204
|
+
references_to(arg_type, from: arg)
|
205
|
+
end
|
206
|
+
path.push(arg.graphql_name)
|
207
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: path)
|
208
|
+
path.pop
|
190
209
|
if arg.default_value?
|
191
210
|
@arguments_with_default_values << arg
|
192
211
|
end
|
193
212
|
end
|
213
|
+
path.pop
|
194
214
|
end
|
195
215
|
end
|
196
216
|
if type.kind.input_object?
|
197
217
|
type.all_argument_definitions.each do |arg|
|
198
218
|
add_directives_from(arg)
|
199
219
|
arg_type = arg.type.unwrap
|
200
|
-
|
201
|
-
|
220
|
+
if !arg_type.is_a?(GraphQL::Schema::LateBoundType)
|
221
|
+
references_to(arg_type, from: arg)
|
222
|
+
end
|
223
|
+
path.push(arg.graphql_name)
|
224
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: path)
|
225
|
+
path.pop
|
202
226
|
if arg.default_value?
|
203
227
|
@arguments_with_default_values << arg
|
204
228
|
end
|
205
229
|
end
|
206
230
|
end
|
207
231
|
if type.kind.union?
|
208
|
-
@possible_types[type
|
232
|
+
@possible_types[type] = type.all_possible_types
|
233
|
+
path.push("possible_types")
|
209
234
|
type.all_possible_types.each do |t|
|
210
|
-
add_type(t, owner: type, late_types: late_types, path: path
|
235
|
+
add_type(t, owner: type, late_types: late_types, path: path)
|
211
236
|
end
|
237
|
+
path.pop
|
212
238
|
end
|
213
239
|
if type.kind.interface?
|
240
|
+
path.push("orphan_types")
|
214
241
|
type.orphan_types.each do |t|
|
215
|
-
add_type(t, owner: type, late_types: late_types, path: path
|
242
|
+
add_type(t, owner: type, late_types: late_types, path: path)
|
216
243
|
end
|
244
|
+
path.pop
|
217
245
|
end
|
218
246
|
if type.kind.object?
|
219
|
-
possible_types_for_this_name = @possible_types[type
|
247
|
+
possible_types_for_this_name = @possible_types[type] ||= []
|
220
248
|
possible_types_for_this_name << type
|
221
249
|
end
|
222
250
|
|
223
251
|
if type.kind.object? || type.kind.interface?
|
252
|
+
path.push("implements")
|
224
253
|
type.interface_type_memberships.each do |interface_type_membership|
|
225
254
|
case interface_type_membership
|
226
255
|
when Schema::TypeMembership
|
227
256
|
interface_type = interface_type_membership.abstract_type
|
228
257
|
# We can get these now; we'll have to get late-bound types later
|
229
258
|
if interface_type.is_a?(Module) && type.is_a?(Class)
|
230
|
-
implementers = @possible_types[interface_type
|
259
|
+
implementers = @possible_types[interface_type] ||= []
|
231
260
|
implementers << type
|
232
261
|
end
|
233
262
|
when String, Schema::LateBoundType
|
@@ -235,7 +264,14 @@ module GraphQL
|
|
235
264
|
else
|
236
265
|
raise ArgumentError, "Invariant: unexpected type membership for #{type.graphql_name}: #{interface_type_membership.class} (#{interface_type_membership.inspect})"
|
237
266
|
end
|
238
|
-
add_type(interface_type, owner: type, late_types: late_types, path: path
|
267
|
+
add_type(interface_type, owner: type, late_types: late_types, path: path)
|
268
|
+
end
|
269
|
+
path.pop
|
270
|
+
end
|
271
|
+
|
272
|
+
if type.kind.enum?
|
273
|
+
type.all_enum_value_definitions.each do |value_definition|
|
274
|
+
add_directives_from(value_definition)
|
239
275
|
end
|
240
276
|
end
|
241
277
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Schema
|
4
|
+
class AlwaysVisible
|
5
|
+
def self.use(schema, **opts)
|
6
|
+
schema.warden_class = GraphQL::Schema::Warden::NullWarden
|
7
|
+
schema.subset_class = GraphQL::Schema::Warden::NullWarden::NullSubset
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|