graphql 2.4.5 → 2.5.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/graphql/detailed_trace_generator.rb +77 -0
- data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
- data/lib/graphql/analysis/analyzer.rb +2 -1
- data/lib/graphql/analysis/query_complexity.rb +87 -7
- data/lib/graphql/analysis/visitor.rb +37 -40
- data/lib/graphql/analysis.rb +12 -9
- data/lib/graphql/autoload.rb +1 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +6 -1
- data/lib/graphql/dashboard/application_controller.rb +41 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/landings_controller.rb +9 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/statics_controller.rb +31 -0
- data/lib/graphql/dashboard/subscriptions.rb +97 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +24 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +96 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +38 -15
- data/lib/graphql/dataloader/null_dataloader.rb +55 -10
- data/lib/graphql/dataloader/source.rb +18 -6
- data/lib/graphql/dataloader.rb +110 -26
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/execution/interpreter/resolve.rb +10 -16
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +58 -5
- data/lib/graphql/execution/interpreter/runtime.rb +229 -93
- data/lib/graphql/execution/interpreter.rb +15 -24
- data/lib/graphql/execution/multiplex.rb +7 -6
- data/lib/graphql/execution/next/field_resolve_step.rb +690 -0
- data/lib/graphql/execution/next/load_argument_step.rb +60 -0
- data/lib/graphql/execution/next/prepare_object_step.rb +129 -0
- data/lib/graphql/execution/next/runner.rb +389 -0
- data/lib/graphql/execution/next/selections_step.rb +37 -0
- data/lib/graphql/execution/next.rb +69 -0
- data/lib/graphql/execution.rb +1 -0
- data/lib/graphql/execution_error.rb +13 -10
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +7 -3
- data/lib/graphql/introspection/dynamic_fields.rb +5 -1
- data/lib/graphql/introspection/entry_points.rb +11 -3
- data/lib/graphql/introspection/enum_value_type.rb +5 -5
- data/lib/graphql/introspection/field_type.rb +13 -5
- data/lib/graphql/introspection/input_value_type.rb +21 -13
- data/lib/graphql/introspection/type_type.rb +64 -28
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +25 -16
- data/lib/graphql/language/document_from_schema_definition.rb +2 -1
- data/lib/graphql/language/lexer.rb +16 -5
- data/lib/graphql/language/nodes.rb +8 -1
- data/lib/graphql/language/parser.rb +16 -8
- data/lib/graphql/language/static_visitor.rb +37 -33
- data/lib/graphql/language/visitor.rb +59 -55
- data/lib/graphql/language.rb +21 -12
- data/lib/graphql/pagination/connection.rb +2 -0
- data/lib/graphql/pagination/connections.rb +32 -0
- data/lib/graphql/query/context.rb +6 -10
- data/lib/graphql/query/null_context.rb +9 -3
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query.rb +64 -64
- data/lib/graphql/railtie.rb +1 -1
- data/lib/graphql/schema/addition.rb +3 -1
- data/lib/graphql/schema/always_visible.rb +1 -0
- data/lib/graphql/schema/argument.rb +24 -8
- data/lib/graphql/schema/build_from_definition.rb +113 -54
- data/lib/graphql/schema/directive/flagged.rb +2 -0
- data/lib/graphql/schema/directive.rb +52 -2
- data/lib/graphql/schema/enum.rb +36 -1
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field/connection_extension.rb +15 -35
- data/lib/graphql/schema/field/scope_extension.rb +22 -13
- data/lib/graphql/schema/field.rb +101 -51
- data/lib/graphql/schema/field_extension.rb +33 -0
- data/lib/graphql/schema/input_object.rb +45 -38
- data/lib/graphql/schema/interface.rb +2 -1
- data/lib/graphql/schema/list.rb +1 -1
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +56 -19
- data/lib/graphql/schema/member/has_authorization.rb +35 -0
- data/lib/graphql/schema/member/has_dataloader.rb +79 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +81 -5
- data/lib/graphql/schema/member/has_interfaces.rb +3 -3
- data/lib/graphql/schema/member/scoped.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -3
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/object.rb +18 -8
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/resolver.rb +52 -6
- data/lib/graphql/schema/scalar.rb +1 -6
- data/lib/graphql/schema/subscription.rb +50 -4
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/validator/required_validator.rb +71 -14
- data/lib/graphql/schema/visibility/migration.rb +3 -2
- data/lib/graphql/schema/visibility/profile.rb +115 -23
- data/lib/graphql/schema/visibility.rb +49 -32
- data/lib/graphql/schema/warden.rb +23 -2
- data/lib/graphql/schema.rb +333 -68
- data/lib/graphql/static_validation/all_rules.rb +2 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +79 -17
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +6 -2
- data/lib/graphql/static_validation/validator.rb +6 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +12 -1
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/subscriptions.rb +1 -1
- data/lib/graphql/testing/helpers.rb +17 -11
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +1 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +9 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
- data/lib/graphql/tracing/appsignal_trace.rb +32 -55
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +46 -158
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +156 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +184 -34
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +864 -0
- data/lib/graphql/tracing/platform_trace.rb +5 -0
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- data/lib/graphql/tracing/prometheus_trace.rb +72 -68
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -55
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +64 -94
- data/lib/graphql/tracing/statsd_trace.rb +33 -41
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +111 -1
- data/lib/graphql/tracing.rb +31 -30
- data/lib/graphql/type_kinds.rb +1 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +9 -7
- data/lib/graphql/types/relay/edge_behaviors.rb +5 -4
- data/lib/graphql/types/relay/has_node_field.rb +13 -8
- data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
- data/lib/graphql/types/relay/node_behaviors.rb +13 -2
- data/lib/graphql/unauthorized_error.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +12 -31
- metadata +174 -11
- data/lib/graphql/backtrace/inspect_result.rb +0 -38
- data/lib/graphql/backtrace/trace.rb +0 -93
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
|
@@ -3,9 +3,17 @@ module GraphQL
|
|
|
3
3
|
# If a field's resolve function returns a {ExecutionError},
|
|
4
4
|
# the error will be inserted into the response's `"errors"` key
|
|
5
5
|
# and the field will resolve to `nil`.
|
|
6
|
-
class ExecutionError < GraphQL::
|
|
6
|
+
class ExecutionError < GraphQL::RuntimeError
|
|
7
7
|
# @return [GraphQL::Language::Nodes::Field] the field where the error occurred
|
|
8
|
-
|
|
8
|
+
def ast_node
|
|
9
|
+
ast_nodes.first
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def ast_node=(new_node)
|
|
13
|
+
@ast_nodes = [new_node]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attr_accessor :ast_nodes
|
|
9
17
|
|
|
10
18
|
# @return [String] an array describing the JSON-path into the execution
|
|
11
19
|
# response which corresponds to this error.
|
|
@@ -21,8 +29,8 @@ module GraphQL
|
|
|
21
29
|
# under the `extensions` key.
|
|
22
30
|
attr_accessor :extensions
|
|
23
31
|
|
|
24
|
-
def initialize(message, ast_node: nil, options: nil, extensions: nil)
|
|
25
|
-
@
|
|
32
|
+
def initialize(message, ast_node: nil, ast_nodes: nil, options: nil, extensions: nil)
|
|
33
|
+
@ast_nodes = ast_nodes || [ast_node]
|
|
26
34
|
@options = options
|
|
27
35
|
@extensions = extensions
|
|
28
36
|
super(message)
|
|
@@ -34,12 +42,7 @@ module GraphQL
|
|
|
34
42
|
"message" => message,
|
|
35
43
|
}
|
|
36
44
|
if ast_node
|
|
37
|
-
hash["locations"] =
|
|
38
|
-
{
|
|
39
|
-
"line" => ast_node.line,
|
|
40
|
-
"column" => ast_node.col,
|
|
41
|
-
}
|
|
42
|
-
]
|
|
45
|
+
hash["locations"] = @ast_nodes.map { |a| { "line" => a.line, "column" => a.col } }
|
|
43
46
|
end
|
|
44
47
|
if path
|
|
45
48
|
hash["path"] = path
|
|
@@ -7,7 +7,7 @@ module GraphQL
|
|
|
7
7
|
"a __DirectiveLocation describes one such possible adjacencies."
|
|
8
8
|
|
|
9
9
|
GraphQL::Schema::Directive::LOCATIONS.each do |location|
|
|
10
|
-
value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location)
|
|
10
|
+
value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location, value_method: false)
|
|
11
11
|
end
|
|
12
12
|
introspection true
|
|
13
13
|
end
|
|
@@ -12,7 +12,7 @@ module GraphQL
|
|
|
12
12
|
field :name, String, null: false, method: :graphql_name
|
|
13
13
|
field :description, String
|
|
14
14
|
field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false, scope: false
|
|
15
|
-
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
|
|
15
|
+
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false, resolve_each: :resolve_args do
|
|
16
16
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
|
17
17
|
end
|
|
18
18
|
field :on_operation, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_operation?
|
|
@@ -21,11 +21,15 @@ module GraphQL
|
|
|
21
21
|
|
|
22
22
|
field :is_repeatable, Boolean, method: :repeatable?
|
|
23
23
|
|
|
24
|
-
def
|
|
25
|
-
args =
|
|
24
|
+
def self.resolve_args(object, context, include_deprecated:)
|
|
25
|
+
args = context.types.arguments(object)
|
|
26
26
|
args = args.reject(&:deprecation_reason) unless include_deprecated
|
|
27
27
|
args
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
def args(include_deprecated:)
|
|
31
|
+
self.class.resolve_args(object, context, include_deprecated: include_deprecated)
|
|
32
|
+
end
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
end
|
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
module GraphQL
|
|
3
3
|
module Introspection
|
|
4
4
|
class DynamicFields < Introspection::BaseObject
|
|
5
|
-
field :__typename, String, "The name of this type", null: false, dynamic_introspection: true
|
|
5
|
+
field :__typename, String, "The name of this type", null: false, dynamic_introspection: true, resolve_each: true
|
|
6
6
|
|
|
7
7
|
def __typename
|
|
8
|
+
self.class.__typename(object, context)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.__typename(object, context)
|
|
8
12
|
object.class.graphql_name
|
|
9
13
|
end
|
|
10
14
|
end
|
|
@@ -2,19 +2,27 @@
|
|
|
2
2
|
module GraphQL
|
|
3
3
|
module Introspection
|
|
4
4
|
class EntryPoints < Introspection::BaseObject
|
|
5
|
-
field :__schema, GraphQL::Schema::LateBoundType.new("__Schema"), "This GraphQL schema", null: false, dynamic_introspection: true
|
|
6
|
-
field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system", dynamic_introspection: true do
|
|
5
|
+
field :__schema, GraphQL::Schema::LateBoundType.new("__Schema"), "This GraphQL schema", null: false, dynamic_introspection: true, resolve_static: :__schema
|
|
6
|
+
field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system", dynamic_introspection: true, resolve_static: :__type do
|
|
7
7
|
argument :name, String
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def __schema
|
|
10
|
+
def self.__schema(context)
|
|
11
11
|
# Apply wrapping manually since this field isn't wrapped by instrumentation
|
|
12
12
|
schema = context.schema
|
|
13
13
|
schema_type = schema.introspection_system.types["__Schema"]
|
|
14
14
|
schema_type.wrap(schema, context)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
def __schema
|
|
18
|
+
self.class.__schema(context)
|
|
19
|
+
end
|
|
20
|
+
|
|
17
21
|
def __type(name:)
|
|
22
|
+
self.class.__type(context, name: name)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.__type(context, name:)
|
|
18
26
|
if context.types.reachable_type?(name) && (type = context.types.type(name))
|
|
19
27
|
type
|
|
20
28
|
elsif (type = context.schema.extra_types.find { |t| t.graphql_name == name })
|
|
@@ -6,17 +6,17 @@ module GraphQL
|
|
|
6
6
|
description "One possible value for a given Enum. Enum values are unique values, not a "\
|
|
7
7
|
"placeholder for a string or numeric value. However an Enum value is returned in "\
|
|
8
8
|
"a JSON response as a string."
|
|
9
|
-
field :name, String, null: false
|
|
9
|
+
field :name, String, null: false, method: :graphql_name
|
|
10
10
|
field :description, String
|
|
11
|
-
field :is_deprecated, Boolean, null: false
|
|
11
|
+
field :is_deprecated, Boolean, null: false, resolve_each: :resolve_is_deprecated
|
|
12
12
|
field :deprecation_reason, String
|
|
13
13
|
|
|
14
|
-
def
|
|
15
|
-
object.
|
|
14
|
+
def self.resolve_is_deprecated(object, context)
|
|
15
|
+
!!object.deprecation_reason
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def is_deprecated
|
|
19
|
-
|
|
19
|
+
self.class.resolve_is_deprecated(object, context)
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
end
|
|
@@ -7,22 +7,30 @@ module GraphQL
|
|
|
7
7
|
"a name, potentially a list of arguments, and a return type."
|
|
8
8
|
field :name, String, null: false
|
|
9
9
|
field :description, String
|
|
10
|
-
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
|
|
10
|
+
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false, resolve_each: :resolve_args do
|
|
11
11
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
|
12
12
|
end
|
|
13
13
|
field :type, GraphQL::Schema::LateBoundType.new("__Type"), null: false
|
|
14
|
-
field :is_deprecated, Boolean, null: false
|
|
14
|
+
field :is_deprecated, Boolean, null: false, resolve_each: :resolve_is_deprecated
|
|
15
15
|
field :deprecation_reason, String
|
|
16
16
|
|
|
17
|
+
def self.resolve_is_deprecated(object, _context)
|
|
18
|
+
!!object.deprecation_reason
|
|
19
|
+
end
|
|
20
|
+
|
|
17
21
|
def is_deprecated
|
|
18
|
-
|
|
22
|
+
self.class.resolve_is_deprecated(object, context)
|
|
19
23
|
end
|
|
20
24
|
|
|
21
|
-
def
|
|
22
|
-
args =
|
|
25
|
+
def self.resolve_args(object, context, include_deprecated:)
|
|
26
|
+
args = context.types.arguments(object)
|
|
23
27
|
args = args.reject(&:deprecation_reason) unless include_deprecated
|
|
24
28
|
args
|
|
25
29
|
end
|
|
30
|
+
|
|
31
|
+
def args(include_deprecated:)
|
|
32
|
+
self.class.resolve_args(object, context, include_deprecated: include_deprecated)
|
|
33
|
+
end
|
|
26
34
|
end
|
|
27
35
|
end
|
|
28
36
|
end
|
|
@@ -9,53 +9,61 @@ module GraphQL
|
|
|
9
9
|
field :name, String, null: false
|
|
10
10
|
field :description, String
|
|
11
11
|
field :type, GraphQL::Schema::LateBoundType.new("__Type"), null: false
|
|
12
|
-
field :default_value, String, "A GraphQL-formatted string representing the default value for this input value."
|
|
13
|
-
field :is_deprecated, Boolean, null: false
|
|
12
|
+
field :default_value, String, "A GraphQL-formatted string representing the default value for this input value.", resolve_each: :resolve_default_value
|
|
13
|
+
field :is_deprecated, Boolean, null: false, resolve_each: :resolve_is_deprecated
|
|
14
14
|
field :deprecation_reason, String
|
|
15
15
|
|
|
16
|
+
def self.resolve_is_deprecated(object, context)
|
|
17
|
+
!!object.deprecation_reason
|
|
18
|
+
end
|
|
19
|
+
|
|
16
20
|
def is_deprecated
|
|
17
|
-
|
|
21
|
+
self.class.resolve_is_deprecated(object, context)
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
def
|
|
21
|
-
if
|
|
22
|
-
value =
|
|
24
|
+
def self.resolve_default_value(object, context)
|
|
25
|
+
if object.default_value?
|
|
26
|
+
value = object.default_value
|
|
23
27
|
if value.nil?
|
|
24
28
|
'null'
|
|
25
29
|
else
|
|
26
|
-
if (
|
|
30
|
+
if (object.type.kind.list? || (object.type.kind.non_null? && object.type.of_type.kind.list?)) && !value.respond_to?(:map)
|
|
27
31
|
# This is a bit odd -- we expect the default value to be an application-style value, so we use coerce result below.
|
|
28
32
|
# But coerce_result doesn't wrap single-item lists, which are valid inputs to list types.
|
|
29
33
|
# So, apply that wrapper here if needed.
|
|
30
34
|
value = [value]
|
|
31
35
|
end
|
|
32
|
-
coerced_default_value =
|
|
33
|
-
serialize_default_value(coerced_default_value,
|
|
36
|
+
coerced_default_value = object.type.coerce_result(value, context)
|
|
37
|
+
serialize_default_value(coerced_default_value, object.type, context)
|
|
34
38
|
end
|
|
35
39
|
else
|
|
36
40
|
nil
|
|
37
41
|
end
|
|
38
42
|
end
|
|
39
43
|
|
|
44
|
+
def default_value
|
|
45
|
+
self.class.resolve_default_value(object, context)
|
|
46
|
+
end
|
|
47
|
+
|
|
40
48
|
|
|
41
49
|
private
|
|
42
50
|
|
|
43
51
|
# Recursively serialize, taking care not to add quotes to enum values
|
|
44
|
-
def serialize_default_value(value, type)
|
|
52
|
+
def self.serialize_default_value(value, type, context)
|
|
45
53
|
if value.nil?
|
|
46
54
|
'null'
|
|
47
55
|
elsif type.kind.list?
|
|
48
56
|
inner_type = type.of_type
|
|
49
|
-
"[" + value.map { |v| serialize_default_value(v, inner_type) }.join(", ") + "]"
|
|
57
|
+
"[" + value.map { |v| serialize_default_value(v, inner_type, context) }.join(", ") + "]"
|
|
50
58
|
elsif type.kind.non_null?
|
|
51
|
-
serialize_default_value(value, type.of_type)
|
|
59
|
+
serialize_default_value(value, type.of_type, context)
|
|
52
60
|
elsif type.kind.enum?
|
|
53
61
|
value
|
|
54
62
|
elsif type.kind.input_object?
|
|
55
63
|
"{" +
|
|
56
64
|
value.map do |k, v|
|
|
57
65
|
arg_defn = type.get_argument(k, context)
|
|
58
|
-
"#{k}: #{serialize_default_value(v, arg_defn.type)}"
|
|
66
|
+
"#{k}: #{serialize_default_value(v, arg_defn.type, context)}"
|
|
59
67
|
end.join(", ") +
|
|
60
68
|
"}"
|
|
61
69
|
else
|
|
@@ -11,32 +11,36 @@ module GraphQL
|
|
|
11
11
|
"they describe. Abstract types, Union and Interface, provide the Object types "\
|
|
12
12
|
"possible at runtime. List and NonNull types compose other types."
|
|
13
13
|
|
|
14
|
-
field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false
|
|
14
|
+
field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false, resolve_each: :resolve_kind
|
|
15
15
|
field :name, String, method: :graphql_name
|
|
16
16
|
field :description, String
|
|
17
|
-
field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], scope: false do
|
|
17
|
+
field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], scope: false, resolve_each: :resolve_fields do
|
|
18
18
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
|
19
19
|
end
|
|
20
|
-
field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
|
|
21
|
-
field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
|
|
22
|
-
field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], scope: false do
|
|
20
|
+
field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false, resolve_each: :resolve_interfaces
|
|
21
|
+
field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false, resolve_each: :resolve_possible_types
|
|
22
|
+
field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], scope: false, resolve_each: :resolve_enum_values do
|
|
23
23
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
|
24
24
|
end
|
|
25
|
-
field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], scope: false do
|
|
25
|
+
field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], scope: false, resolve_each: :resolve_input_fields do
|
|
26
26
|
argument :include_deprecated, Boolean, required: false, default_value: false
|
|
27
27
|
end
|
|
28
|
-
field :of_type, GraphQL::Schema::LateBoundType.new("__Type")
|
|
28
|
+
field :of_type, GraphQL::Schema::LateBoundType.new("__Type"), resolve_each: :resolve_of_type
|
|
29
29
|
|
|
30
|
-
field :specifiedByURL, String, resolver_method: :specified_by_url
|
|
30
|
+
field :specifiedByURL, String, resolve_each: :resolve_specified_by_url, resolver_method: :specified_by_url
|
|
31
31
|
|
|
32
|
-
field :is_one_of, Boolean, null: false
|
|
32
|
+
field :is_one_of, Boolean, null: false, resolve_each: :resolve_is_one_of
|
|
33
33
|
|
|
34
|
-
def
|
|
34
|
+
def self.resolve_is_one_of(object, _ctx)
|
|
35
35
|
object.kind.input_object? &&
|
|
36
36
|
object.directives.any? { |d| d.graphql_name == "oneOf" }
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def
|
|
39
|
+
def is_one_of
|
|
40
|
+
self.class.resolve_is_one_of(object, context)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.resolve_specified_by_url(object, _ctx)
|
|
40
44
|
if object.kind.scalar?
|
|
41
45
|
object.specified_by_url
|
|
42
46
|
else
|
|
@@ -44,15 +48,23 @@ module GraphQL
|
|
|
44
48
|
end
|
|
45
49
|
end
|
|
46
50
|
|
|
51
|
+
def specified_by_url
|
|
52
|
+
self.class.resolve_specified_by_url(object, context)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.resolve_kind(object, context)
|
|
56
|
+
object.kind.name
|
|
57
|
+
end
|
|
58
|
+
|
|
47
59
|
def kind
|
|
48
|
-
|
|
60
|
+
self.class.resolve_kind(object, context)
|
|
49
61
|
end
|
|
50
62
|
|
|
51
|
-
def
|
|
52
|
-
if
|
|
63
|
+
def self.resolve_enum_values(object, context, include_deprecated:)
|
|
64
|
+
if !object.kind.enum?
|
|
53
65
|
nil
|
|
54
66
|
else
|
|
55
|
-
enum_values =
|
|
67
|
+
enum_values = context.types.enum_values(object)
|
|
56
68
|
|
|
57
69
|
if !include_deprecated
|
|
58
70
|
enum_values = enum_values.select {|f| !f.deprecation_reason }
|
|
@@ -62,17 +74,25 @@ module GraphQL
|
|
|
62
74
|
end
|
|
63
75
|
end
|
|
64
76
|
|
|
65
|
-
def
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
def enum_values(include_deprecated:)
|
|
78
|
+
self.class.resolve_enum_values(object, context, include_deprecated: include_deprecated)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.resolve_interfaces(object, context)
|
|
82
|
+
if object.kind.object? || object.kind.interface?
|
|
83
|
+
context.types.interfaces(object).sort_by(&:graphql_name)
|
|
68
84
|
else
|
|
69
85
|
nil
|
|
70
86
|
end
|
|
71
87
|
end
|
|
72
88
|
|
|
73
|
-
def
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
def interfaces
|
|
90
|
+
self.class.resolve_interfaces(object, context)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def self.resolve_input_fields(object, context, include_deprecated:)
|
|
94
|
+
if object.kind.input_object?
|
|
95
|
+
args = context.types.arguments(object)
|
|
76
96
|
args = args.reject(&:deprecation_reason) unless include_deprecated
|
|
77
97
|
args
|
|
78
98
|
else
|
|
@@ -80,19 +100,27 @@ module GraphQL
|
|
|
80
100
|
end
|
|
81
101
|
end
|
|
82
102
|
|
|
83
|
-
def
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
def input_fields(include_deprecated:)
|
|
104
|
+
self.class.resolve_input_fields(object, context, include_deprecated: include_deprecated)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.resolve_possible_types(object, context)
|
|
108
|
+
if object.kind.abstract?
|
|
109
|
+
context.types.possible_types(object).sort_by(&:graphql_name)
|
|
86
110
|
else
|
|
87
111
|
nil
|
|
88
112
|
end
|
|
89
113
|
end
|
|
90
114
|
|
|
91
|
-
def
|
|
92
|
-
|
|
115
|
+
def possible_types
|
|
116
|
+
self.class.resolve_possible_types(object, context)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def self.resolve_fields(object, context, include_deprecated:)
|
|
120
|
+
if !object.kind.fields?
|
|
93
121
|
nil
|
|
94
122
|
else
|
|
95
|
-
fields =
|
|
123
|
+
fields = context.types.fields(object)
|
|
96
124
|
if !include_deprecated
|
|
97
125
|
fields = fields.select {|f| !f.deprecation_reason }
|
|
98
126
|
end
|
|
@@ -100,8 +128,16 @@ module GraphQL
|
|
|
100
128
|
end
|
|
101
129
|
end
|
|
102
130
|
|
|
131
|
+
def fields(include_deprecated:)
|
|
132
|
+
self.class.resolve_fields(object, context, include_deprecated: include_deprecated)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def self.resolve_of_type(object, _ctx)
|
|
136
|
+
object.kind.wraps? ? object.of_type : nil
|
|
137
|
+
end
|
|
138
|
+
|
|
103
139
|
def of_type
|
|
104
|
-
|
|
140
|
+
self.class.resolve_of_type(object, context)
|
|
105
141
|
end
|
|
106
142
|
end
|
|
107
143
|
end
|
|
@@ -2,31 +2,40 @@
|
|
|
2
2
|
module GraphQL
|
|
3
3
|
# Raised automatically when a field's resolve function returns `nil`
|
|
4
4
|
# for a non-null field.
|
|
5
|
-
class InvalidNullError < GraphQL::
|
|
5
|
+
class InvalidNullError < GraphQL::RuntimeError
|
|
6
6
|
# @return [GraphQL::BaseType] The owner of {#field}
|
|
7
7
|
attr_reader :parent_type
|
|
8
8
|
|
|
9
9
|
# @return [GraphQL::Field] The field which failed to return a value
|
|
10
10
|
attr_reader :field
|
|
11
11
|
|
|
12
|
-
# @return [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def initialize(parent_type, field, value)
|
|
16
|
-
@parent_type = parent_type
|
|
17
|
-
@field = field
|
|
18
|
-
@value = value
|
|
19
|
-
super("Cannot return null for non-nullable field #{@parent_type.graphql_name}.#{@field.graphql_name}")
|
|
12
|
+
# @return [GraphQL::Language::Nodes::Field] the field where the error occurred
|
|
13
|
+
def ast_node
|
|
14
|
+
@ast_nodes.first
|
|
20
15
|
end
|
|
21
16
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
attr_reader :ast_nodes
|
|
18
|
+
|
|
19
|
+
# @return [Boolean] indicates an array result caused the error
|
|
20
|
+
attr_reader :is_from_array
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
attr_accessor :path
|
|
23
|
+
|
|
24
|
+
def initialize(parent_type, field, ast_node_or_nodes, is_from_array: false, path: nil)
|
|
25
|
+
@parent_type = parent_type
|
|
26
|
+
@field = field
|
|
27
|
+
@ast_nodes = Array(ast_node_or_nodes)
|
|
28
|
+
@is_from_array = is_from_array
|
|
29
|
+
@path = path
|
|
30
|
+
# For List elements, identify the non-null error is for an
|
|
31
|
+
# element and the required element type so it's not ambiguous
|
|
32
|
+
# whether it was caused by a null instead of the list or a
|
|
33
|
+
# null element.
|
|
34
|
+
if @is_from_array
|
|
35
|
+
super("Cannot return null for non-nullable element of type '#{@field.type.of_type.of_type.to_type_signature}' for #{@parent_type.graphql_name}.#{@field.graphql_name}")
|
|
36
|
+
else
|
|
37
|
+
super("Cannot return null for non-nullable field #{@parent_type.graphql_name}.#{@field.graphql_name}")
|
|
38
|
+
end
|
|
30
39
|
end
|
|
31
40
|
|
|
32
41
|
class << self
|
|
@@ -52,8 +52,9 @@ module GraphQL
|
|
|
52
52
|
|
|
53
53
|
def build_object_type_node(object_type)
|
|
54
54
|
ints = @types.interfaces(object_type)
|
|
55
|
+
|
|
55
56
|
if !ints.empty?
|
|
56
|
-
ints.sort_by
|
|
57
|
+
ints = ints.sort_by(&:graphql_name)
|
|
57
58
|
ints.map! { |iface| build_type_name_node(iface) }
|
|
58
59
|
end
|
|
59
60
|
|
|
@@ -13,17 +13,26 @@ module GraphQL
|
|
|
13
13
|
@pos = nil
|
|
14
14
|
@max_tokens = max_tokens || Float::INFINITY
|
|
15
15
|
@tokens_count = 0
|
|
16
|
+
@finished = false
|
|
16
17
|
end
|
|
17
18
|
|
|
18
|
-
def
|
|
19
|
-
@
|
|
19
|
+
def finished?
|
|
20
|
+
@finished
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def freeze
|
|
24
|
+
@scanner = nil
|
|
25
|
+
super
|
|
20
26
|
end
|
|
21
27
|
|
|
22
28
|
attr_reader :pos, :tokens_count
|
|
23
29
|
|
|
24
30
|
def advance
|
|
25
31
|
@scanner.skip(IGNORE_REGEXP)
|
|
26
|
-
|
|
32
|
+
if @scanner.eos?
|
|
33
|
+
@finished = true
|
|
34
|
+
return false
|
|
35
|
+
end
|
|
27
36
|
@tokens_count += 1
|
|
28
37
|
if @tokens_count > @max_tokens
|
|
29
38
|
raise_parse_error("This query is too large to execute.")
|
|
@@ -238,7 +247,7 @@ module GraphQL
|
|
|
238
247
|
:SCALAR,
|
|
239
248
|
nil,
|
|
240
249
|
:FRAGMENT
|
|
241
|
-
]
|
|
250
|
+
].freeze
|
|
242
251
|
|
|
243
252
|
# This produces a unique integer for bytes 2 and 3 of each keyword string
|
|
244
253
|
# See https://tenderlovemaking.com/2023/09/02/fast-tokenizers-with-stringscanner.html
|
|
@@ -267,7 +276,8 @@ module GraphQL
|
|
|
267
276
|
PUNCTUATION_NAME_FOR_BYTE = Punctuation.constants.each_with_object([]) { |name, arr|
|
|
268
277
|
punct = Punctuation.const_get(name)
|
|
269
278
|
arr[punct.ord] = name
|
|
270
|
-
}
|
|
279
|
+
}.freeze
|
|
280
|
+
|
|
271
281
|
|
|
272
282
|
QUOTE = '"'
|
|
273
283
|
UNICODE_DIGIT = /[0-9A-Za-z]/
|
|
@@ -317,6 +327,7 @@ module GraphQL
|
|
|
317
327
|
punct = Punctuation.const_get(punct_name)
|
|
318
328
|
FIRST_BYTES[punct.ord] = ByteFor::PUNCTUATION
|
|
319
329
|
end
|
|
330
|
+
FIRST_BYTES.freeze
|
|
320
331
|
|
|
321
332
|
|
|
322
333
|
# Replace any escaped unicode or whitespace with the _actual_ characters
|
|
@@ -83,7 +83,11 @@ module GraphQL
|
|
|
83
83
|
|
|
84
84
|
def to_query_string(printer: GraphQL::Language::Printer.new)
|
|
85
85
|
if printer.is_a?(GraphQL::Language::Printer)
|
|
86
|
-
|
|
86
|
+
if frozen?
|
|
87
|
+
@query_string || printer.print(self)
|
|
88
|
+
else
|
|
89
|
+
@query_string ||= printer.print(self)
|
|
90
|
+
end
|
|
87
91
|
else
|
|
88
92
|
printer.print(self)
|
|
89
93
|
end
|
|
@@ -141,6 +145,8 @@ module GraphQL
|
|
|
141
145
|
end
|
|
142
146
|
|
|
143
147
|
class << self
|
|
148
|
+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
|
149
|
+
|
|
144
150
|
# Add a default `#visit_method` and `#children_method_name` using the class name
|
|
145
151
|
def inherited(child_class)
|
|
146
152
|
super
|
|
@@ -343,6 +349,7 @@ module GraphQL
|
|
|
343
349
|
RUBY
|
|
344
350
|
end
|
|
345
351
|
end
|
|
352
|
+
# rubocop:enable Development/NoEvalCop
|
|
346
353
|
end
|
|
347
354
|
end
|
|
348
355
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "strscan"
|
|
4
4
|
require "graphql/language/nodes"
|
|
5
|
+
require "graphql/tracing/null_trace"
|
|
5
6
|
|
|
6
7
|
module GraphQL
|
|
7
8
|
module Language
|
|
@@ -110,7 +111,7 @@ module GraphQL
|
|
|
110
111
|
# Only ignored characters is not a valid document
|
|
111
112
|
raise GraphQL::ParseError.new("Unexpected end of document", nil, nil, @graphql_str)
|
|
112
113
|
end
|
|
113
|
-
while !@lexer.
|
|
114
|
+
while !@lexer.finished?
|
|
114
115
|
defns << definition
|
|
115
116
|
end
|
|
116
117
|
Document.new(pos: 0, definitions: defns, filename: @filename, source: self)
|
|
@@ -161,7 +162,7 @@ module GraphQL
|
|
|
161
162
|
expect_token(:VAR_SIGN)
|
|
162
163
|
var_name = parse_name
|
|
163
164
|
expect_token(:COLON)
|
|
164
|
-
var_type = self.type
|
|
165
|
+
var_type = self.type || raise_parse_error("Missing type definition for variable: $#{var_name}")
|
|
165
166
|
default_value = if at?(:EQUALS)
|
|
166
167
|
advance_token
|
|
167
168
|
value
|
|
@@ -488,26 +489,33 @@ module GraphQL
|
|
|
488
489
|
end
|
|
489
490
|
|
|
490
491
|
def type
|
|
491
|
-
|
|
492
|
+
parsed_type = case token_name
|
|
492
493
|
when :IDENTIFIER
|
|
493
494
|
parse_type_name
|
|
494
495
|
when :LBRACKET
|
|
495
496
|
list_type
|
|
497
|
+
else
|
|
498
|
+
nil
|
|
496
499
|
end
|
|
497
500
|
|
|
498
|
-
if at?(:BANG)
|
|
499
|
-
|
|
501
|
+
if at?(:BANG) && parsed_type
|
|
502
|
+
parsed_type = Nodes::NonNullType.new(pos: pos, of_type: parsed_type, source: self)
|
|
500
503
|
expect_token(:BANG)
|
|
501
504
|
end
|
|
502
|
-
|
|
505
|
+
parsed_type
|
|
503
506
|
end
|
|
504
507
|
|
|
505
508
|
def list_type
|
|
506
509
|
loc = pos
|
|
507
510
|
expect_token(:LBRACKET)
|
|
508
|
-
|
|
511
|
+
inner_type = self.type
|
|
512
|
+
parsed_list_type = if inner_type
|
|
513
|
+
Nodes::ListType.new(pos: loc, of_type: inner_type, source: self)
|
|
514
|
+
else
|
|
515
|
+
nil
|
|
516
|
+
end
|
|
509
517
|
expect_token(:RBRACKET)
|
|
510
|
-
|
|
518
|
+
parsed_list_type
|
|
511
519
|
end
|
|
512
520
|
|
|
513
521
|
def parse_operation_type
|