graphql 1.10.1 → 1.13.0
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/core.rb +18 -2
- data/lib/generators/graphql/install_generator.rb +36 -6
- data/lib/generators/graphql/loader_generator.rb +1 -0
- data/lib/generators/graphql/mutation_generator.rb +2 -1
- data/lib/generators/graphql/object_generator.rb +54 -9
- data/lib/generators/graphql/relay.rb +63 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +8 -0
- data/lib/generators/graphql/templates/base_edge.erb +8 -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_mutation.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -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/enum.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
- data/lib/generators/graphql/templates/interface.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/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +3 -1
- data/lib/generators/graphql/templates/query_type.erb +3 -3
- data/lib/generators/graphql/templates/scalar.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +21 -33
- data/lib/generators/graphql/templates/union.erb +3 -1
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyze_query.rb +7 -0
- data/lib/graphql/analysis/ast/field_usage.rb +24 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +126 -109
- data/lib/graphql/analysis/ast/visitor.rb +13 -5
- data/lib/graphql/analysis/ast.rb +11 -2
- data/lib/graphql/argument.rb +3 -3
- data/lib/graphql/backtrace/inspect_result.rb +0 -1
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +34 -3
- data/lib/graphql/backtrace/traced_error.rb +0 -1
- data/lib/graphql/backtrace/tracer.rb +40 -9
- data/lib/graphql/backtrace.rb +28 -19
- data/lib/graphql/backwards_compatibility.rb +2 -1
- data/lib/graphql/base_type.rb +1 -1
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
- data/lib/graphql/compatibility/execution_specification.rb +1 -0
- data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
- data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
- data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
- data/lib/graphql/dataloader/null_dataloader.rb +22 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +155 -0
- data/lib/graphql/dataloader.rb +308 -0
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/define/defined_object_proxy.rb +1 -1
- data/lib/graphql/define/instance_definable.rb +34 -4
- data/lib/graphql/define/type_definer.rb +5 -5
- data/lib/graphql/deprecated_dsl.rb +18 -5
- data/lib/graphql/deprecation.rb +9 -0
- data/lib/graphql/directive.rb +4 -4
- data/lib/graphql/enum_type.rb +7 -1
- data/lib/graphql/execution/errors.rb +110 -7
- data/lib/graphql/execution/execute.rb +8 -1
- data/lib/graphql/execution/instrumentation.rb +1 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +88 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +103 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
- data/lib/graphql/execution/interpreter/resolve.rb +37 -25
- data/lib/graphql/execution/interpreter/runtime.rb +685 -421
- data/lib/graphql/execution/interpreter.rb +42 -13
- data/lib/graphql/execution/lazy.rb +5 -1
- data/lib/graphql/execution/lookahead.rb +25 -110
- data/lib/graphql/execution/multiplex.rb +37 -25
- data/lib/graphql/field.rb +5 -1
- data/lib/graphql/function.rb +4 -0
- data/lib/graphql/input_object_type.rb +6 -0
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/interface_type.rb +7 -0
- data/lib/graphql/internal_representation/document.rb +2 -2
- data/lib/graphql/internal_representation/rewrite.rb +1 -1
- data/lib/graphql/internal_representation/scope.rb +2 -2
- data/lib/graphql/internal_representation/visit.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +8 -4
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +9 -5
- data/lib/graphql/introspection/input_value_type.rb +15 -3
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +4 -4
- data/lib/graphql/introspection/type_type.rb +16 -12
- data/lib/graphql/introspection.rb +96 -0
- data/lib/graphql/invalid_null_error.rb +18 -0
- data/lib/graphql/language/block_string.rb +20 -5
- data/lib/graphql/language/cache.rb +37 -0
- data/lib/graphql/language/document_from_schema_definition.rb +73 -25
- data/lib/graphql/language/lexer.rb +4 -3
- data/lib/graphql/language/lexer.rl +3 -3
- data/lib/graphql/language/nodes.rb +51 -89
- data/lib/graphql/language/parser.rb +552 -530
- data/lib/graphql/language/parser.y +114 -99
- data/lib/graphql/language/printer.rb +7 -2
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/language/visitor.rb +2 -2
- data/lib/graphql/language.rb +2 -0
- data/lib/graphql/name_validator.rb +2 -7
- data/lib/graphql/object_type.rb +44 -35
- data/lib/graphql/pagination/active_record_relation_connection.rb +14 -1
- data/lib/graphql/pagination/array_connection.rb +2 -2
- data/lib/graphql/pagination/connection.rb +75 -20
- data/lib/graphql/pagination/connections.rb +83 -31
- data/lib/graphql/pagination/relation_connection.rb +34 -14
- data/lib/graphql/parse_error.rb +0 -1
- data/lib/graphql/query/arguments.rb +4 -3
- data/lib/graphql/query/arguments_cache.rb +1 -2
- data/lib/graphql/query/context.rb +42 -7
- data/lib/graphql/query/executor.rb +0 -1
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +23 -6
- data/lib/graphql/query/literal_input.rb +1 -1
- data/lib/graphql/query/null_context.rb +24 -8
- data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
- data/lib/graphql/query/serial_execution.rb +1 -0
- data/lib/graphql/query/validation_pipeline.rb +5 -2
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +14 -4
- data/lib/graphql/query.rb +68 -13
- data/lib/graphql/railtie.rb +9 -1
- data/lib/graphql/rake_task.rb +12 -9
- data/lib/graphql/relay/array_connection.rb +10 -12
- data/lib/graphql/relay/base_connection.rb +26 -13
- data/lib/graphql/relay/connection_instrumentation.rb +4 -4
- data/lib/graphql/relay/connection_type.rb +1 -1
- data/lib/graphql/relay/edges_instrumentation.rb +0 -1
- data/lib/graphql/relay/mutation.rb +1 -0
- data/lib/graphql/relay/node.rb +3 -0
- data/lib/graphql/relay/range_add.rb +23 -9
- data/lib/graphql/relay/relation_connection.rb +8 -10
- data/lib/graphql/relay/type_extensions.rb +2 -0
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/scalar_type.rb +16 -1
- data/lib/graphql/schema/addition.rb +247 -0
- data/lib/graphql/schema/argument.rb +210 -12
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +3 -1
- data/lib/graphql/schema/build_from_definition.rb +213 -86
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive/deprecated.rb +1 -1
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/transform.rb +14 -2
- data/lib/graphql/schema/directive.rb +78 -2
- data/lib/graphql/schema/enum.rb +80 -9
- data/lib/graphql/schema/enum_value.rb +17 -6
- data/lib/graphql/schema/field/connection_extension.rb +46 -30
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +285 -133
- data/lib/graphql/schema/find_inherited_value.rb +4 -1
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/input_object.rb +97 -89
- data/lib/graphql/schema/interface.rb +24 -19
- data/lib/graphql/schema/late_bound_type.rb +2 -2
- data/lib/graphql/schema/list.rb +7 -1
- data/lib/graphql/schema/loader.rb +137 -103
- data/lib/graphql/schema/member/accepts_definition.rb +8 -1
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -19
- data/lib/graphql/schema/member/build_type.rb +14 -7
- data/lib/graphql/schema/member/has_arguments.rb +205 -12
- data/lib/graphql/schema/member/has_ast_node.rb +4 -1
- data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
- data/lib/graphql/schema/member/has_directives.rb +98 -0
- data/lib/graphql/schema/member/has_fields.rb +95 -30
- data/lib/graphql/schema/member/has_interfaces.rb +90 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/has_validators.rb +31 -0
- data/lib/graphql/schema/member/instrumentation.rb +0 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/middleware_chain.rb +1 -1
- data/lib/graphql/schema/mutation.rb +4 -0
- data/lib/graphql/schema/non_null.rb +5 -0
- data/lib/graphql/schema/object.rb +47 -46
- data/lib/graphql/schema/possible_types.rb +9 -4
- data/lib/graphql/schema/printer.rb +16 -34
- data/lib/graphql/schema/relay_classic_mutation.rb +32 -4
- data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
- data/lib/graphql/schema/resolver.rb +123 -63
- data/lib/graphql/schema/scalar.rb +11 -1
- data/lib/graphql/schema/subscription.rb +57 -21
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/timeout_middleware.rb +3 -1
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +18 -4
- data/lib/graphql/schema/union.rb +41 -1
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +12 -2
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/format_validator.rb +48 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
- data/lib/graphql/schema/validator/length_validator.rb +59 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
- data/lib/graphql/schema/validator/required_validator.rb +68 -0
- data/lib/graphql/schema/validator.rb +174 -0
- data/lib/graphql/schema/warden.rb +153 -28
- data/lib/graphql/schema.rb +364 -330
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +8 -5
- data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +51 -26
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +44 -87
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +28 -22
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +79 -43
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +6 -7
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +9 -10
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +8 -8
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +4 -2
- data/lib/graphql/static_validation/validation_context.rb +9 -3
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +42 -8
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +118 -19
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
- data/lib/graphql/subscriptions/event.rb +81 -30
- data/lib/graphql/subscriptions/instrumentation.rb +0 -1
- data/lib/graphql/subscriptions/serialize.rb +33 -6
- data/lib/graphql/subscriptions/subscription_root.rb +15 -4
- data/lib/graphql/subscriptions.rb +88 -45
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +2 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
- data/lib/graphql/tracing/platform_tracing.rb +43 -17
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/scout_tracing.rb +11 -0
- data/lib/graphql/tracing/skylight_tracing.rb +1 -1
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +9 -33
- data/lib/graphql/types/big_int.rb +5 -1
- data/lib/graphql/types/int.rb +10 -3
- data/lib/graphql/types/iso_8601_date.rb +3 -3
- data/lib/graphql/types/iso_8601_date_time.rb +25 -10
- data/lib/graphql/types/relay/base_connection.rb +6 -90
- data/lib/graphql/types/relay/base_edge.rb +2 -34
- data/lib/graphql/types/relay/connection_behaviors.rb +156 -0
- data/lib/graphql/types/relay/default_relay.rb +27 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +53 -0
- data/lib/graphql/types/relay/has_node_field.rb +41 -0
- data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
- data/lib/graphql/types/relay/node.rb +2 -4
- data/lib/graphql/types/relay/node_behaviors.rb +15 -0
- data/lib/graphql/types/relay/node_field.rb +2 -20
- data/lib/graphql/types/relay/nodes_field.rb +2 -20
- data/lib/graphql/types/relay/page_info.rb +2 -14
- data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
- data/lib/graphql/types/relay.rb +11 -3
- data/lib/graphql/types/string.rb +8 -2
- data/lib/graphql/unauthorized_error.rb +2 -2
- data/lib/graphql/union_type.rb +2 -0
- data/lib/graphql/upgrader/member.rb +1 -0
- data/lib/graphql/upgrader/schema.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +65 -31
- data/readme.md +3 -6
- metadata +77 -112
- data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
- data/lib/graphql/literal_validation_error.rb +0 -6
- data/lib/graphql/types/relay/base_field.rb +0 -22
- data/lib/graphql/types/relay/base_interface.rb +0 -29
- data/lib/graphql/types/relay/base_object.rb +0 -26
data/lib/graphql/schema/field.rb
CHANGED
@@ -1,22 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../object.rb
|
3
2
|
require "graphql/schema/field/connection_extension"
|
4
3
|
require "graphql/schema/field/scope_extension"
|
5
4
|
|
6
5
|
module GraphQL
|
7
6
|
class Schema
|
8
7
|
class Field
|
9
|
-
if !String.method_defined?(:-@)
|
10
|
-
using GraphQL::StringDedupBackport
|
11
|
-
end
|
12
|
-
|
13
8
|
include GraphQL::Schema::Member::CachedGraphQLDefinition
|
14
9
|
include GraphQL::Schema::Member::AcceptsDefinition
|
15
10
|
include GraphQL::Schema::Member::HasArguments
|
16
11
|
include GraphQL::Schema::Member::HasAstNode
|
17
12
|
include GraphQL::Schema::Member::HasPath
|
13
|
+
include GraphQL::Schema::Member::HasValidators
|
18
14
|
extend GraphQL::Schema::FindInheritedValue
|
19
15
|
include GraphQL::Schema::FindInheritedValue::EmptyObjects
|
16
|
+
include GraphQL::Schema::Member::HasDirectives
|
17
|
+
include GraphQL::Schema::Member::HasDeprecationReason
|
20
18
|
|
21
19
|
# @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
|
22
20
|
attr_reader :name
|
@@ -24,9 +22,6 @@ module GraphQL
|
|
24
22
|
|
25
23
|
attr_writer :description
|
26
24
|
|
27
|
-
# @return [String, nil] If present, the field is marked as deprecated with this documentation
|
28
|
-
attr_accessor :deprecation_reason
|
29
|
-
|
30
25
|
# @return [Symbol] Method or hash key on the underlying object to look up
|
31
26
|
attr_reader :method_sym
|
32
27
|
|
@@ -36,9 +31,18 @@ module GraphQL
|
|
36
31
|
# @return [Symbol] The method on the type to look up
|
37
32
|
attr_reader :resolver_method
|
38
33
|
|
39
|
-
# @return [Class] The
|
34
|
+
# @return [Class] The thing this field was defined on (type, mutation, resolver)
|
40
35
|
attr_accessor :owner
|
41
36
|
|
37
|
+
# @return [Class] The GraphQL type this field belongs to. (For fields defined on mutations, it's the payload type)
|
38
|
+
def owner_type
|
39
|
+
@owner_type ||= if owner < GraphQL::Schema::Mutation
|
40
|
+
owner.payload_type
|
41
|
+
else
|
42
|
+
owner
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
42
46
|
# @return [Symbol] the original name of the field, passed in by the user
|
43
47
|
attr_reader :original_name
|
44
48
|
|
@@ -47,6 +51,15 @@ module GraphQL
|
|
47
51
|
@resolver_class
|
48
52
|
end
|
49
53
|
|
54
|
+
# @return [Boolean] Is this field a predefined introspection field?
|
55
|
+
def introspection?
|
56
|
+
@introspection
|
57
|
+
end
|
58
|
+
|
59
|
+
def inspect
|
60
|
+
"#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
|
61
|
+
end
|
62
|
+
|
50
63
|
alias :mutation :resolver
|
51
64
|
|
52
65
|
# @return [Boolean] Apply tracing to this field? (Default: skip scalars, this is the override value)
|
@@ -68,11 +81,11 @@ module GraphQL
|
|
68
81
|
# @see {.initialize} for other options
|
69
82
|
def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
|
70
83
|
if kwargs[:field]
|
71
|
-
if kwargs[:field] == GraphQL::Relay::
|
72
|
-
warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
|
84
|
+
if kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodeField.graphql_definition
|
85
|
+
GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
|
73
86
|
return GraphQL::Types::Relay::NodeField
|
74
|
-
elsif kwargs[:field] == GraphQL::Relay::
|
75
|
-
warn("Legacy-style `GraphQL::Relay::Node.plural_field` is being added to a class-based type. See `GraphQL::Types::Relay::NodesField` for a replacement.")
|
87
|
+
elsif kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodesField.graphql_definition
|
88
|
+
GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.plural_field` is being added to a class-based type. See `GraphQL::Types::Relay::NodesField` for a replacement.")
|
76
89
|
return GraphQL::Types::Relay::NodesField
|
77
90
|
end
|
78
91
|
end
|
@@ -105,6 +118,9 @@ module GraphQL
|
|
105
118
|
else
|
106
119
|
kwargs[:type] = type
|
107
120
|
end
|
121
|
+
if type.is_a?(Class) && type < GraphQL::Schema::Mutation
|
122
|
+
raise ArgumentError, "Use `field #{name.inspect}, mutation: Mutation, ...` to provide a mutation to this field instead"
|
123
|
+
end
|
108
124
|
end
|
109
125
|
new(**kwargs, &block)
|
110
126
|
end
|
@@ -172,7 +188,8 @@ module GraphQL
|
|
172
188
|
# @param hash_key [String, Symbol] The hash key to lookup on the underlying object (if its a Hash) to resolve this field (defaults to `name` or `name.to_s`)
|
173
189
|
# @param resolver_method [Symbol] The method on the type to call to resolve this field (defaults to `name`)
|
174
190
|
# @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
|
175
|
-
# @param
|
191
|
+
# @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
|
192
|
+
# @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
|
176
193
|
# @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
|
177
194
|
# @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
|
178
195
|
# @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
|
@@ -184,10 +201,14 @@ module GraphQL
|
|
184
201
|
# @param scope [Boolean] If true, the return type's `.scope_items` method will be called on the return value
|
185
202
|
# @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
|
186
203
|
# @param extensions [Array<Class, Hash<Class => Object>>] Named extensions to apply to this field (see also {#extension})
|
204
|
+
# @param directives [Hash{Class => Hash}] Directives to apply to this field
|
187
205
|
# @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
|
206
|
+
# @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
|
188
207
|
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
189
208
|
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
190
|
-
|
209
|
+
# @param validates [Array<Hash>] Configurations for validating this field
|
210
|
+
# @param legacy_edge_class [Class, nil] (DEPRECATED) If present, pass this along to the legacy field definition
|
211
|
+
def initialize(type: nil, name: nil, owner: nil, null: true, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, legacy_edge_class: nil, &definition_block)
|
191
212
|
if name.nil?
|
192
213
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
193
214
|
end
|
@@ -195,9 +216,6 @@ module GraphQL
|
|
195
216
|
if type.nil?
|
196
217
|
raise ArgumentError, "missing second `type` argument or keyword `type:`"
|
197
218
|
end
|
198
|
-
if null.nil?
|
199
|
-
raise ArgumentError, "missing keyword argument null:"
|
200
|
-
end
|
201
219
|
end
|
202
220
|
if (field || function || resolve) && extras.any?
|
203
221
|
raise ArgumentError, "keyword `extras:` may only be used with method-based resolve and class-based field such as mutation class, please remove `field:`, `function:` or `resolve:`"
|
@@ -214,7 +232,7 @@ module GraphQL
|
|
214
232
|
end
|
215
233
|
@function = function
|
216
234
|
@resolve = resolve
|
217
|
-
|
235
|
+
self.deprecation_reason = deprecation_reason
|
218
236
|
|
219
237
|
if method && hash_key
|
220
238
|
raise ArgumentError, "Provide `method:` _or_ `hash_key:`, not both. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}`)"
|
@@ -231,19 +249,21 @@ module GraphQL
|
|
231
249
|
end
|
232
250
|
|
233
251
|
# TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
|
234
|
-
method_name = method || hash_key ||
|
235
|
-
resolver_method ||=
|
252
|
+
method_name = method || hash_key || name_s
|
253
|
+
resolver_method ||= name_s.to_sym
|
236
254
|
|
237
|
-
@method_str = method_name.to_s
|
255
|
+
@method_str = -method_name.to_s
|
238
256
|
@method_sym = method_name.to_sym
|
239
257
|
@resolver_method = resolver_method
|
240
258
|
@complexity = complexity
|
241
259
|
@return_type_expr = type
|
242
260
|
@return_type_null = null
|
243
261
|
@connection = connection
|
244
|
-
@
|
262
|
+
@has_max_page_size = max_page_size != :not_given
|
263
|
+
@max_page_size = max_page_size == :not_given ? nil : max_page_size
|
245
264
|
@introspection = introspection
|
246
265
|
@extras = extras
|
266
|
+
@broadcastable = broadcastable
|
247
267
|
@resolver_class = resolver_class
|
248
268
|
@scope = scope
|
249
269
|
@trace = trace
|
@@ -251,34 +271,50 @@ module GraphQL
|
|
251
271
|
@relay_nodes_field = relay_nodes_field
|
252
272
|
@ast_node = ast_node
|
253
273
|
@method_conflict_warning = method_conflict_warning
|
274
|
+
@legacy_edge_class = legacy_edge_class
|
254
275
|
|
255
276
|
arguments.each do |name, arg|
|
256
|
-
|
277
|
+
case arg
|
278
|
+
when Hash
|
257
279
|
argument(name: name, **arg)
|
280
|
+
when GraphQL::Schema::Argument
|
281
|
+
add_argument(arg)
|
282
|
+
when Array
|
283
|
+
arg.each { |a| add_argument(a) }
|
258
284
|
else
|
259
|
-
|
285
|
+
raise ArgumentError, "Unexpected argument config (#{arg.class}): #{arg.inspect}"
|
260
286
|
end
|
261
287
|
end
|
262
288
|
|
263
289
|
@owner = owner
|
264
290
|
@subscription_scope = subscription_scope
|
265
291
|
|
266
|
-
|
267
|
-
@extensions = []
|
268
|
-
if extensions.any?
|
269
|
-
self.extensions(extensions)
|
270
|
-
end
|
292
|
+
@extensions = EMPTY_ARRAY
|
271
293
|
# This should run before connection extension,
|
272
294
|
# but should it run after the definition block?
|
273
295
|
if scoped?
|
274
296
|
self.extension(ScopeExtension)
|
275
297
|
end
|
298
|
+
|
276
299
|
# The problem with putting this after the definition_block
|
277
300
|
# is that it would override arguments
|
278
|
-
if connection?
|
279
|
-
self.extension(
|
301
|
+
if connection? && connection_extension
|
302
|
+
self.extension(connection_extension)
|
280
303
|
end
|
281
304
|
|
305
|
+
# Do this last so we have as much context as possible when initializing them:
|
306
|
+
if extensions.any?
|
307
|
+
self.extensions(extensions)
|
308
|
+
end
|
309
|
+
|
310
|
+
if directives.any?
|
311
|
+
directives.each do |(dir_class, options)|
|
312
|
+
self.directive(dir_class, **options)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
self.validates(validates)
|
317
|
+
|
282
318
|
if definition_block
|
283
319
|
if definition_block.arity == 1
|
284
320
|
yield self
|
@@ -288,6 +324,13 @@ module GraphQL
|
|
288
324
|
end
|
289
325
|
end
|
290
326
|
|
327
|
+
# If true, subscription updates with this field can be shared between viewers
|
328
|
+
# @return [Boolean, nil]
|
329
|
+
# @see GraphQL::Subscriptions::BroadcastAnalyzer
|
330
|
+
def broadcastable?
|
331
|
+
@broadcastable
|
332
|
+
end
|
333
|
+
|
291
334
|
# @param text [String]
|
292
335
|
# @return [String]
|
293
336
|
def description(text = nil)
|
@@ -318,6 +361,9 @@ module GraphQL
|
|
318
361
|
# Read the value
|
319
362
|
@extensions
|
320
363
|
else
|
364
|
+
if @extensions.frozen?
|
365
|
+
@extensions = @extensions.dup
|
366
|
+
end
|
321
367
|
new_extensions.each do |extension|
|
322
368
|
if extension.is_a?(Hash)
|
323
369
|
extension = extension.to_a[0]
|
@@ -355,11 +401,65 @@ module GraphQL
|
|
355
401
|
# Read the value
|
356
402
|
@extras
|
357
403
|
else
|
404
|
+
if @extras.frozen?
|
405
|
+
@extras = @extras.dup
|
406
|
+
end
|
358
407
|
# Append to the set of extras on this field
|
359
408
|
@extras.concat(new_extras)
|
360
409
|
end
|
361
410
|
end
|
362
411
|
|
412
|
+
def calculate_complexity(query:, nodes:, child_complexity:)
|
413
|
+
if respond_to?(:complexity_for)
|
414
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
415
|
+
complexity_for(child_complexity: child_complexity, query: query, lookahead: lookahead)
|
416
|
+
elsif connection?
|
417
|
+
arguments = query.arguments_for(nodes.first, self)
|
418
|
+
max_possible_page_size = nil
|
419
|
+
if arguments[:first]
|
420
|
+
max_possible_page_size = arguments[:first]
|
421
|
+
end
|
422
|
+
if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
|
423
|
+
max_possible_page_size = arguments[:last]
|
424
|
+
end
|
425
|
+
|
426
|
+
if max_possible_page_size.nil?
|
427
|
+
max_possible_page_size = max_page_size || query.schema.default_max_page_size
|
428
|
+
end
|
429
|
+
|
430
|
+
if max_possible_page_size.nil?
|
431
|
+
raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `max_page_size` or `default_max_page_size`"
|
432
|
+
else
|
433
|
+
metadata_complexity = 0
|
434
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
435
|
+
|
436
|
+
if (page_info_lookahead = lookahead.selection(:page_info)).selected?
|
437
|
+
metadata_complexity += 1 # pageInfo
|
438
|
+
metadata_complexity += page_info_lookahead.selections.size # subfields
|
439
|
+
end
|
440
|
+
|
441
|
+
if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
|
442
|
+
metadata_complexity += 1
|
443
|
+
end
|
444
|
+
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
445
|
+
items_complexity = child_complexity - metadata_complexity
|
446
|
+
# Add 1 for _this_ field
|
447
|
+
1 + (max_possible_page_size * items_complexity) + metadata_complexity
|
448
|
+
end
|
449
|
+
else
|
450
|
+
defined_complexity = complexity
|
451
|
+
case defined_complexity
|
452
|
+
when Proc
|
453
|
+
arguments = query.arguments_for(nodes.first, self)
|
454
|
+
defined_complexity.call(query.context, arguments.keyword_arguments, child_complexity)
|
455
|
+
when Numeric
|
456
|
+
defined_complexity + child_complexity
|
457
|
+
else
|
458
|
+
raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
363
463
|
def complexity(new_complexity = nil)
|
364
464
|
case new_complexity
|
365
465
|
when Proc
|
@@ -380,7 +480,12 @@ module GraphQL
|
|
380
480
|
end
|
381
481
|
end
|
382
482
|
|
383
|
-
# @return [
|
483
|
+
# @return [Boolean] True if this field's {#max_page_size} should override the schema default.
|
484
|
+
def has_max_page_size?
|
485
|
+
@has_max_page_size
|
486
|
+
end
|
487
|
+
|
488
|
+
# @return [Integer, nil] Applied to connections if {#has_max_page_size?}
|
384
489
|
attr_reader :max_page_size
|
385
490
|
|
386
491
|
# @return [GraphQL::Field]
|
@@ -402,8 +507,8 @@ module GraphQL
|
|
402
507
|
field_defn.description = @description
|
403
508
|
end
|
404
509
|
|
405
|
-
if
|
406
|
-
field_defn.deprecation_reason =
|
510
|
+
if self.deprecation_reason
|
511
|
+
field_defn.deprecation_reason = self.deprecation_reason
|
407
512
|
end
|
408
513
|
|
409
514
|
if @resolver_class
|
@@ -425,6 +530,10 @@ module GraphQL
|
|
425
530
|
field_defn.relay_nodes_field = @relay_nodes_field
|
426
531
|
end
|
427
532
|
|
533
|
+
if @legacy_edge_class
|
534
|
+
field_defn.edge_class = @legacy_edge_class
|
535
|
+
end
|
536
|
+
|
428
537
|
field_defn.resolve = self.method(:resolve_field)
|
429
538
|
field_defn.connection = connection?
|
430
539
|
field_defn.connection_max_page_size = max_page_size
|
@@ -433,9 +542,9 @@ module GraphQL
|
|
433
542
|
field_defn.subscription_scope = @subscription_scope
|
434
543
|
field_defn.ast_node = ast_node
|
435
544
|
|
436
|
-
|
545
|
+
all_argument_definitions.each do |defn|
|
437
546
|
arg_graphql = defn.to_graphql
|
438
|
-
field_defn.arguments[arg_graphql.name] = arg_graphql
|
547
|
+
field_defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
439
548
|
end
|
440
549
|
|
441
550
|
# Support a passed-in proc, one way or another
|
@@ -453,6 +562,7 @@ module GraphQL
|
|
453
562
|
field_defn
|
454
563
|
end
|
455
564
|
|
565
|
+
class MissingReturnTypeError < GraphQL::Error; end
|
456
566
|
attr_writer :type
|
457
567
|
|
458
568
|
def type
|
@@ -460,14 +570,21 @@ module GraphQL
|
|
460
570
|
Member::BuildType.parse_type(@function.type, null: false)
|
461
571
|
elsif @field
|
462
572
|
Member::BuildType.parse_type(@field.type, null: false)
|
573
|
+
elsif @return_type_expr.nil?
|
574
|
+
# Not enough info to determine type
|
575
|
+
message = "Can't determine the return type for #{self.path}"
|
576
|
+
if @resolver_class
|
577
|
+
message += " (it has `resolver: #{@resolver_class}`, consider configuration a `type ...` for that class)"
|
578
|
+
end
|
579
|
+
raise MissingReturnTypeError, message
|
463
580
|
else
|
464
581
|
Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
465
582
|
end
|
466
|
-
rescue GraphQL::Schema::InvalidDocumentError => err
|
583
|
+
rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
|
467
584
|
# Let this propagate up
|
468
585
|
raise err
|
469
586
|
rescue StandardError => err
|
470
|
-
raise
|
587
|
+
raise MissingReturnTypeError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: (#{err.class}) #{err.message}", err.backtrace
|
471
588
|
end
|
472
589
|
|
473
590
|
def visible?(context)
|
@@ -491,10 +608,36 @@ module GraphQL
|
|
491
608
|
# The resolver will check itself during `resolve()`
|
492
609
|
@resolver_class.authorized?(object, context)
|
493
610
|
else
|
611
|
+
if (arg_values = context[:current_arguments])
|
612
|
+
# ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
|
613
|
+
using_arg_values = true
|
614
|
+
arg_values = arg_values.argument_values
|
615
|
+
else
|
616
|
+
arg_values = args
|
617
|
+
using_arg_values = false
|
618
|
+
end
|
494
619
|
# Faster than `.any?`
|
495
|
-
arguments.each_value do |arg|
|
496
|
-
|
497
|
-
|
620
|
+
arguments(context).each_value do |arg|
|
621
|
+
arg_key = arg.keyword
|
622
|
+
if arg_values.key?(arg_key)
|
623
|
+
arg_value = arg_values[arg_key]
|
624
|
+
if using_arg_values
|
625
|
+
if arg_value.default_used?
|
626
|
+
# pass -- no auth required for default used
|
627
|
+
next
|
628
|
+
else
|
629
|
+
application_arg_value = arg_value.value
|
630
|
+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
|
631
|
+
application_arg_value.keyword_arguments
|
632
|
+
end
|
633
|
+
end
|
634
|
+
else
|
635
|
+
application_arg_value = arg_value
|
636
|
+
end
|
637
|
+
|
638
|
+
if !arg.authorized?(object, application_arg_value, context)
|
639
|
+
return false
|
640
|
+
end
|
498
641
|
end
|
499
642
|
end
|
500
643
|
true
|
@@ -522,7 +665,7 @@ module GraphQL
|
|
522
665
|
@resolve_proc.call(extended_obj, args, ctx)
|
523
666
|
end
|
524
667
|
else
|
525
|
-
public_send_field(after_obj, ruby_args,
|
668
|
+
public_send_field(after_obj, ruby_args, query_ctx)
|
526
669
|
end
|
527
670
|
else
|
528
671
|
err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
|
@@ -544,34 +687,15 @@ module GraphQL
|
|
544
687
|
begin
|
545
688
|
# Unwrap the GraphQL object to get the application object.
|
546
689
|
application_object = object.object
|
547
|
-
if self.authorized?(application_object, args, ctx)
|
548
|
-
# Apply field extensions
|
549
|
-
with_extensions(object, args, ctx) do |extended_obj, extended_args|
|
550
|
-
field_receiver = if @resolver_class
|
551
|
-
resolver_obj = if extended_obj.is_a?(GraphQL::Schema::Object)
|
552
|
-
extended_obj.object
|
553
|
-
else
|
554
|
-
extended_obj
|
555
|
-
end
|
556
|
-
@resolver_class.new(object: resolver_obj, context: ctx, field: self)
|
557
|
-
else
|
558
|
-
extended_obj
|
559
|
-
end
|
560
690
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
else
|
569
|
-
resolve_field_method(field_receiver, extended_args, ctx)
|
570
|
-
end
|
691
|
+
Schema::Validator.validate!(validators, application_object, ctx, args)
|
692
|
+
|
693
|
+
ctx.schema.after_lazy(self.authorized?(application_object, args, ctx)) do |is_authorized|
|
694
|
+
if is_authorized
|
695
|
+
public_send_field(object, args, ctx)
|
696
|
+
else
|
697
|
+
raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
|
571
698
|
end
|
572
|
-
else
|
573
|
-
err = GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
|
574
|
-
ctx.schema.unauthorized_field(err)
|
575
699
|
end
|
576
700
|
rescue GraphQL::UnauthorizedFieldError => err
|
577
701
|
err.field ||= self
|
@@ -583,43 +707,6 @@ module GraphQL
|
|
583
707
|
err
|
584
708
|
end
|
585
709
|
|
586
|
-
# Find a way to resolve this field, checking:
|
587
|
-
#
|
588
|
-
# - Hash keys, if the wrapped object is a hash;
|
589
|
-
# - A method on the wrapped object;
|
590
|
-
# - Or, raise not implemented.
|
591
|
-
#
|
592
|
-
# This can be overridden by defining a method on the object type.
|
593
|
-
# @param obj [GraphQL::Schema::Object]
|
594
|
-
# @param ruby_kwargs [Hash<Symbol => Object>]
|
595
|
-
# @param ctx [GraphQL::Query::Context]
|
596
|
-
def resolve_field_method(obj, ruby_kwargs, ctx)
|
597
|
-
if obj.object.is_a?(Hash)
|
598
|
-
inner_object = obj.object
|
599
|
-
if inner_object.key?(@method_sym)
|
600
|
-
inner_object[@method_sym]
|
601
|
-
else
|
602
|
-
inner_object[@method_str]
|
603
|
-
end
|
604
|
-
elsif obj.object.respond_to?(@method_sym)
|
605
|
-
if ruby_kwargs.any?
|
606
|
-
obj.object.public_send(@method_sym, **ruby_kwargs)
|
607
|
-
else
|
608
|
-
obj.object.public_send(@method_sym)
|
609
|
-
end
|
610
|
-
else
|
611
|
-
raise <<-ERR
|
612
|
-
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
613
|
-
|
614
|
-
- `#{obj.class}##{@resolver_method}`, which did not exist
|
615
|
-
- `#{obj.object.class}##{@method_sym}`, which did not exist
|
616
|
-
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
|
617
|
-
|
618
|
-
To implement this field, define one of the methods above (and check for typos)
|
619
|
-
ERR
|
620
|
-
end
|
621
|
-
end
|
622
|
-
|
623
710
|
# @param ctx [GraphQL::Query::Context::FieldResolutionContext]
|
624
711
|
def fetch_extra(extra_name, ctx)
|
625
712
|
if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
|
@@ -645,11 +732,36 @@ module GraphQL
|
|
645
732
|
if graphql_args.any? || @extras.any?
|
646
733
|
# Splat the GraphQL::Arguments to Ruby keyword arguments
|
647
734
|
ruby_kwargs = graphql_args.to_kwargs
|
735
|
+
maybe_lazies = []
|
648
736
|
# Apply any `prepare` methods. Not great code organization, can this go somewhere better?
|
649
|
-
arguments.each do |name, arg_defn|
|
737
|
+
arguments(field_ctx).each do |name, arg_defn|
|
650
738
|
ruby_kwargs_key = arg_defn.keyword
|
651
|
-
|
652
|
-
|
739
|
+
|
740
|
+
if ruby_kwargs.key?(ruby_kwargs_key)
|
741
|
+
loads = arg_defn.loads
|
742
|
+
value = ruby_kwargs[ruby_kwargs_key]
|
743
|
+
loaded_value = if loads && !arg_defn.from_resolver?
|
744
|
+
if arg_defn.type.list?
|
745
|
+
loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
|
746
|
+
field_ctx.schema.after_any_lazies(loaded_values) { |result| result }
|
747
|
+
else
|
748
|
+
load_application_object(arg_defn, loads, value, field_ctx.query.context)
|
749
|
+
end
|
750
|
+
elsif arg_defn.type.list? && value.is_a?(Array)
|
751
|
+
field_ctx.schema.after_any_lazies(value, &:itself)
|
752
|
+
else
|
753
|
+
value
|
754
|
+
end
|
755
|
+
|
756
|
+
maybe_lazies << field_ctx.schema.after_lazy(loaded_value) do |loaded_value|
|
757
|
+
prepared_value = if arg_defn.prepare
|
758
|
+
arg_defn.prepare_value(obj, loaded_value)
|
759
|
+
else
|
760
|
+
loaded_value
|
761
|
+
end
|
762
|
+
|
763
|
+
ruby_kwargs[ruby_kwargs_key] = prepared_value
|
764
|
+
end
|
653
765
|
end
|
654
766
|
end
|
655
767
|
|
@@ -657,30 +769,60 @@ module GraphQL
|
|
657
769
|
ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
|
658
770
|
end
|
659
771
|
|
660
|
-
|
772
|
+
field_ctx.schema.after_any_lazies(maybe_lazies) do
|
773
|
+
ruby_kwargs
|
774
|
+
end
|
661
775
|
else
|
662
776
|
NO_ARGS
|
663
777
|
end
|
664
778
|
end
|
665
779
|
|
666
|
-
def public_send_field(
|
667
|
-
query_ctx
|
668
|
-
with_extensions(obj, ruby_kwargs, query_ctx) do |extended_obj, extended_args|
|
780
|
+
def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
|
781
|
+
with_extensions(unextended_obj, unextended_ruby_kwargs, query_ctx) do |obj, ruby_kwargs|
|
669
782
|
if @resolver_class
|
670
|
-
if
|
671
|
-
|
783
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
784
|
+
obj = obj.object
|
672
785
|
end
|
673
|
-
|
786
|
+
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
674
787
|
end
|
675
788
|
|
676
|
-
|
677
|
-
|
678
|
-
|
789
|
+
# Find a way to resolve this field, checking:
|
790
|
+
#
|
791
|
+
# - A method on the type instance;
|
792
|
+
# - Hash keys, if the wrapped object is a hash;
|
793
|
+
# - A method on the wrapped object;
|
794
|
+
# - Or, raise not implemented.
|
795
|
+
#
|
796
|
+
if obj.respond_to?(@resolver_method)
|
797
|
+
# Call the method with kwargs, if there are any
|
798
|
+
if ruby_kwargs.any?
|
799
|
+
obj.public_send(@resolver_method, **ruby_kwargs)
|
679
800
|
else
|
680
|
-
|
801
|
+
obj.public_send(@resolver_method)
|
802
|
+
end
|
803
|
+
elsif obj.object.is_a?(Hash)
|
804
|
+
inner_object = obj.object
|
805
|
+
if inner_object.key?(@method_sym)
|
806
|
+
inner_object[@method_sym]
|
807
|
+
else
|
808
|
+
inner_object[@method_str]
|
809
|
+
end
|
810
|
+
elsif obj.object.respond_to?(@method_sym)
|
811
|
+
if ruby_kwargs.any?
|
812
|
+
obj.object.public_send(@method_sym, **ruby_kwargs)
|
813
|
+
else
|
814
|
+
obj.object.public_send(@method_sym)
|
681
815
|
end
|
682
816
|
else
|
683
|
-
|
817
|
+
raise <<-ERR
|
818
|
+
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
819
|
+
|
820
|
+
- `#{obj.class}##{@resolver_method}`, which did not exist
|
821
|
+
- `#{obj.object.class}##{@method_sym}`, which did not exist
|
822
|
+
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
|
823
|
+
|
824
|
+
To implement this field, define one of the methods above (and check for typos)
|
825
|
+
ERR
|
684
826
|
end
|
685
827
|
end
|
686
828
|
end
|
@@ -692,32 +834,42 @@ module GraphQL
|
|
692
834
|
if @extensions.empty?
|
693
835
|
yield(obj, args)
|
694
836
|
else
|
695
|
-
#
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
yield(extended_obj, extended_args)
|
837
|
+
# This is a hack to get the _last_ value for extended obj and args,
|
838
|
+
# in case one of the extensions doesn't `yield`.
|
839
|
+
# (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
|
840
|
+
extended = { args: args, obj: obj, memos: nil }
|
841
|
+
value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
|
842
|
+
yield(obj, args)
|
702
843
|
end
|
703
844
|
|
845
|
+
extended_obj = extended[:obj]
|
846
|
+
extended_args = extended[:args]
|
847
|
+
memos = extended[:memos] || EMPTY_HASH
|
848
|
+
|
704
849
|
ctx.schema.after_lazy(value) do |resolved_value|
|
705
|
-
|
850
|
+
idx = 0
|
851
|
+
@extensions.each do |ext|
|
706
852
|
memo = memos[idx]
|
707
853
|
# TODO after_lazy?
|
708
|
-
resolved_value = ext.after_resolve(object:
|
854
|
+
resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
|
855
|
+
idx += 1
|
709
856
|
end
|
710
857
|
resolved_value
|
711
858
|
end
|
712
859
|
end
|
713
860
|
end
|
714
861
|
|
715
|
-
def run_extensions_before_resolve(
|
862
|
+
def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
|
716
863
|
extension = @extensions[idx]
|
717
864
|
if extension
|
718
865
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
719
|
-
|
720
|
-
|
866
|
+
if memo
|
867
|
+
memos = extended[:memos] ||= {}
|
868
|
+
memos[idx] = memo
|
869
|
+
end
|
870
|
+
extended[:obj] = extended_obj
|
871
|
+
extended[:args] = extended_args
|
872
|
+
run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
|
721
873
|
end
|
722
874
|
else
|
723
875
|
yield(obj, args)
|