graphql 2.5.19 → 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/graphql/dashboard/application_controller.rb +41 -0
- data/lib/graphql/dashboard/landings_controller.rb +9 -0
- data/lib/graphql/dashboard/statics_controller.rb +31 -0
- data/lib/graphql/dashboard/subscriptions.rb +2 -1
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +3 -3
- data/lib/graphql/dashboard.rb +9 -74
- data/lib/graphql/dataloader/null_dataloader.rb +7 -3
- data/lib/graphql/execution/multiplex.rb +1 -1
- 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_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_null_error.rb +11 -5
- data/lib/graphql/pagination/connection.rb +2 -0
- data/lib/graphql/pagination/connections.rb +32 -0
- data/lib/graphql/query/context.rb +3 -2
- data/lib/graphql/query/null_context.rb +9 -3
- data/lib/graphql/schema/argument.rb +5 -0
- data/lib/graphql/schema/build_from_definition.rb +7 -0
- 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 +70 -1
- data/lib/graphql/schema/field_extension.rb +33 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -1
- data/lib/graphql/schema/member/has_authorization.rb +35 -0
- data/lib/graphql/schema/member/has_dataloader.rb +17 -0
- data/lib/graphql/schema/member/has_fields.rb +5 -1
- data/lib/graphql/schema/member.rb +5 -0
- data/lib/graphql/schema/object.rb +1 -0
- data/lib/graphql/schema/resolver.rb +45 -1
- data/lib/graphql/schema/visibility.rb +1 -1
- data/lib/graphql/schema.rb +33 -7
- data/lib/graphql/subscriptions.rb +1 -1
- data/lib/graphql/tracing/perfetto_trace.rb +1 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +8 -6
- data/lib/graphql/types/relay/edge_behaviors.rb +4 -3
- 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 +3 -0
- metadata +12 -2
|
@@ -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
|
|
@@ -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,7 +2,7 @@
|
|
|
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
|
|
|
@@ -10,17 +10,23 @@ module GraphQL
|
|
|
10
10
|
attr_reader :field
|
|
11
11
|
|
|
12
12
|
# @return [GraphQL::Language::Nodes::Field] the field where the error occurred
|
|
13
|
-
|
|
13
|
+
def ast_node
|
|
14
|
+
@ast_nodes.first
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_reader :ast_nodes
|
|
14
18
|
|
|
15
19
|
# @return [Boolean] indicates an array result caused the error
|
|
16
20
|
attr_reader :is_from_array
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
attr_accessor :path
|
|
23
|
+
|
|
24
|
+
def initialize(parent_type, field, ast_node_or_nodes, is_from_array: false, path: nil)
|
|
19
25
|
@parent_type = parent_type
|
|
20
26
|
@field = field
|
|
21
|
-
@
|
|
27
|
+
@ast_nodes = Array(ast_node_or_nodes)
|
|
22
28
|
@is_from_array = is_from_array
|
|
23
|
-
|
|
29
|
+
@path = path
|
|
24
30
|
# For List elements, identify the non-null error is for an
|
|
25
31
|
# element and the required element type so it's not ambiguous
|
|
26
32
|
# whether it was caused by a null instead of the list or a
|
|
@@ -83,6 +83,38 @@ module GraphQL
|
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
+
def populate_connection(field, object, value, original_arguments, context)
|
|
87
|
+
if value.is_a? GraphQL::ExecutionError
|
|
88
|
+
# This isn't even going to work because context doesn't have ast_node anymore
|
|
89
|
+
context.add_error(value)
|
|
90
|
+
nil
|
|
91
|
+
elsif value.nil?
|
|
92
|
+
nil
|
|
93
|
+
elsif value.is_a?(GraphQL::Pagination::Connection)
|
|
94
|
+
# update the connection with some things that may not have been provided
|
|
95
|
+
value.context ||= context
|
|
96
|
+
value.parent ||= object
|
|
97
|
+
value.first_value ||= original_arguments[:first]
|
|
98
|
+
value.after_value ||= original_arguments[:after]
|
|
99
|
+
value.last_value ||= original_arguments[:last]
|
|
100
|
+
value.before_value ||= original_arguments[:before]
|
|
101
|
+
value.arguments ||= original_arguments # rubocop:disable Development/ContextIsPassedCop -- unrelated .arguments method
|
|
102
|
+
value.field ||= field
|
|
103
|
+
if field.has_max_page_size? && !value.has_max_page_size_override?
|
|
104
|
+
value.max_page_size = field.max_page_size
|
|
105
|
+
end
|
|
106
|
+
if field.has_default_page_size? && !value.has_default_page_size_override?
|
|
107
|
+
value.default_page_size = field.default_page_size
|
|
108
|
+
end
|
|
109
|
+
if (custom_t = context.schema.connections.edge_class_for_field(field))
|
|
110
|
+
value.edge_class = custom_t
|
|
111
|
+
end
|
|
112
|
+
value
|
|
113
|
+
else
|
|
114
|
+
context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
|
|
115
|
+
context.schema.connections.wrap(field, object, value, original_arguments, context)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
86
118
|
# use an override if there is one
|
|
87
119
|
# @api private
|
|
88
120
|
def edge_class_for_field(field)
|
|
@@ -29,6 +29,7 @@ module GraphQL
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
extend Forwardable
|
|
32
|
+
include Schema::Member::HasDataloader
|
|
32
33
|
|
|
33
34
|
# @return [Array<GraphQL::ExecutionError>] errors returned during execution
|
|
34
35
|
attr_reader :errors
|
|
@@ -118,8 +119,8 @@ module GraphQL
|
|
|
118
119
|
# @param error [GraphQL::ExecutionError] an execution error
|
|
119
120
|
# @return [void]
|
|
120
121
|
def add_error(error)
|
|
121
|
-
if !error.is_a?(
|
|
122
|
-
raise TypeError, "expected error to be a
|
|
122
|
+
if !error.is_a?(GraphQL::RuntimeError)
|
|
123
|
+
raise TypeError, "expected error to be a GraphQL::RuntimeError, but was #{error.class}"
|
|
123
124
|
end
|
|
124
125
|
errors << error
|
|
125
126
|
nil
|
|
@@ -4,7 +4,13 @@ module GraphQL
|
|
|
4
4
|
class Query
|
|
5
5
|
# This object can be `ctx` in places where there is no query
|
|
6
6
|
class NullContext < Context
|
|
7
|
-
|
|
7
|
+
def self.instance
|
|
8
|
+
@instance ||= self.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.instance=(new_inst)
|
|
12
|
+
@instance = new_inst
|
|
13
|
+
end
|
|
8
14
|
|
|
9
15
|
class NullQuery
|
|
10
16
|
def after_lazy(value)
|
|
@@ -20,10 +26,10 @@ module GraphQL
|
|
|
20
26
|
attr_reader :schema, :query, :warden, :dataloader
|
|
21
27
|
def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key?, :to_h
|
|
22
28
|
|
|
23
|
-
def initialize
|
|
29
|
+
def initialize(schema: NullSchema)
|
|
24
30
|
@query = NullQuery.new
|
|
25
31
|
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
|
26
|
-
@schema =
|
|
32
|
+
@schema = schema
|
|
27
33
|
@warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
|
|
28
34
|
@types = @warden.visibility_profile
|
|
29
35
|
freeze
|
|
@@ -4,6 +4,7 @@ module GraphQL
|
|
|
4
4
|
class Argument
|
|
5
5
|
include GraphQL::Schema::Member::HasPath
|
|
6
6
|
include GraphQL::Schema::Member::HasAstNode
|
|
7
|
+
include GraphQL::Schema::Member::HasAuthorization
|
|
7
8
|
include GraphQL::Schema::Member::HasDirectives
|
|
8
9
|
include GraphQL::Schema::Member::HasDeprecationReason
|
|
9
10
|
include GraphQL::Schema::Member::HasValidators
|
|
@@ -164,6 +165,10 @@ module GraphQL
|
|
|
164
165
|
true
|
|
165
166
|
end
|
|
166
167
|
|
|
168
|
+
def authorizes?(_context)
|
|
169
|
+
self.method(:authorized?).owner != GraphQL::Schema::Argument
|
|
170
|
+
end
|
|
171
|
+
|
|
167
172
|
def authorized?(obj, value, ctx)
|
|
168
173
|
authorized_as_type?(obj, value, ctx, as_type: type)
|
|
169
174
|
end
|
|
@@ -512,6 +512,7 @@ module GraphQL
|
|
|
512
512
|
camelize: false,
|
|
513
513
|
directives: prepare_directives(field_definition, type_resolver),
|
|
514
514
|
resolver_method: resolve_method_name,
|
|
515
|
+
resolve_batch: resolve_method_name,
|
|
515
516
|
)
|
|
516
517
|
|
|
517
518
|
builder.build_arguments(schema_field_defn, field_definition.arguments, type_resolver)
|
|
@@ -528,6 +529,12 @@ module GraphQL
|
|
|
528
529
|
field_instance = context.types.field(owner, field_name)
|
|
529
530
|
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
|
530
531
|
}
|
|
532
|
+
owner.define_singleton_method(method_name) { |objects, context, **args|
|
|
533
|
+
field_instance = context.types.field(owner, field_name)
|
|
534
|
+
objects.map do |object|
|
|
535
|
+
context.schema.definition_default_resolve.call(self, field_instance, object, args, context)
|
|
536
|
+
end
|
|
537
|
+
}
|
|
531
538
|
end
|
|
532
539
|
|
|
533
540
|
def build_resolve_type(lookup_hash, directives, missing_type_handler)
|
|
@@ -21,45 +21,25 @@ module GraphQL
|
|
|
21
21
|
yield(object, next_args, arguments)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
def resolve_next(objects:, arguments:, context:)
|
|
25
|
+
next_args = arguments.dup
|
|
26
|
+
next_args.delete(:first)
|
|
27
|
+
next_args.delete(:last)
|
|
28
|
+
next_args.delete(:before)
|
|
29
|
+
next_args.delete(:after)
|
|
30
|
+
yield(objects, next_args, arguments)
|
|
31
|
+
end
|
|
32
|
+
|
|
24
33
|
def after_resolve(value:, object:, arguments:, context:, memo:)
|
|
25
34
|
original_arguments = memo
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
value = nil
|
|
29
|
-
context.query.after_lazy(maybe_lazy) do |resolved_value|
|
|
30
|
-
value = resolved_value
|
|
31
|
-
if value.is_a? GraphQL::ExecutionError
|
|
32
|
-
# This isn't even going to work because context doesn't have ast_node anymore
|
|
33
|
-
context.add_error(value)
|
|
34
|
-
nil
|
|
35
|
-
elsif value.nil?
|
|
36
|
-
nil
|
|
37
|
-
elsif value.is_a?(GraphQL::Pagination::Connection)
|
|
38
|
-
# update the connection with some things that may not have been provided
|
|
39
|
-
value.context ||= context
|
|
40
|
-
value.parent ||= object.object
|
|
41
|
-
value.first_value ||= original_arguments[:first]
|
|
42
|
-
value.after_value ||= original_arguments[:after]
|
|
43
|
-
value.last_value ||= original_arguments[:last]
|
|
44
|
-
value.before_value ||= original_arguments[:before]
|
|
45
|
-
value.arguments ||= original_arguments # rubocop:disable Development/ContextIsPassedCop -- unrelated .arguments method
|
|
46
|
-
value.field ||= field
|
|
47
|
-
if field.has_max_page_size? && !value.has_max_page_size_override?
|
|
48
|
-
value.max_page_size = field.max_page_size
|
|
49
|
-
end
|
|
50
|
-
if field.has_default_page_size? && !value.has_default_page_size_override?
|
|
51
|
-
value.default_page_size = field.default_page_size
|
|
52
|
-
end
|
|
53
|
-
if (custom_t = context.schema.connections.edge_class_for_field(@field))
|
|
54
|
-
value.edge_class = custom_t
|
|
55
|
-
end
|
|
56
|
-
value
|
|
57
|
-
else
|
|
58
|
-
context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
|
|
59
|
-
context.schema.connections.wrap(field, object.object, value, original_arguments, context)
|
|
60
|
-
end
|
|
35
|
+
context.query.after_lazy(value) do |resolved_value|
|
|
36
|
+
context.schema.connections.populate_connection(field, object.object, resolved_value, original_arguments, context)
|
|
61
37
|
end
|
|
62
38
|
end
|
|
39
|
+
|
|
40
|
+
def after_resolve_next(**kwargs)
|
|
41
|
+
raise "This should never be called -- it's hardcoded in execution instead."
|
|
42
|
+
end
|
|
63
43
|
end
|
|
64
44
|
end
|
|
65
45
|
end
|