graphql 1.9.18 → 1.13.24
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/core.rb +21 -10
- data/lib/generators/graphql/enum_generator.rb +4 -10
- data/lib/generators/graphql/field_extractor.rb +31 -0
- data/lib/generators/graphql/input_generator.rb +50 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
- data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
- data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +44 -7
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/loader_generator.rb +1 -0
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +6 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +28 -12
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +63 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- 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_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 +7 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +6 -2
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +3 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +7 -3
- data/lib/generators/graphql/templates/query_type.erb +3 -3
- data/lib/generators/graphql/templates/scalar.erb +5 -1
- data/lib/generators/graphql/templates/schema.erb +22 -27
- data/lib/generators/graphql/templates/union.erb +6 -2
- data/lib/generators/graphql/type_generator.rb +47 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/analyze_query.rb +7 -0
- data/lib/graphql/analysis/ast/field_usage.rb +29 -2
- data/lib/graphql/analysis/ast/query_complexity.rb +174 -67
- data/lib/graphql/analysis/ast/visitor.rb +16 -7
- data/lib/graphql/analysis/ast.rb +21 -11
- data/lib/graphql/argument.rb +8 -36
- data/lib/graphql/backtrace/inspect_result.rb +0 -1
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +44 -5
- 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 +10 -4
- data/lib/graphql/boolean_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/parse_error_specification.rb +5 -9
- 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/date_encoding_error.rb +16 -0
- data/lib/graphql/define/assign_enum_value.rb +1 -1
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/define/assign_object_field.rb +1 -1
- data/lib/graphql/define/defined_object_proxy.rb +5 -8
- data/lib/graphql/define/instance_definable.rb +60 -110
- 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/deprecated_directive.rb +1 -12
- data/lib/graphql/directive/include_directive.rb +1 -1
- data/lib/graphql/directive/skip_directive.rb +1 -1
- data/lib/graphql/directive.rb +9 -6
- data/lib/graphql/enum_type.rb +14 -74
- data/lib/graphql/execution/directive_checks.rb +2 -2
- data/lib/graphql/execution/errors.rb +110 -8
- 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 +105 -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 +721 -386
- data/lib/graphql/execution/interpreter.rb +42 -19
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lazy.rb +5 -1
- data/lib/graphql/execution/lookahead.rb +39 -114
- data/lib/graphql/execution/multiplex.rb +50 -25
- data/lib/graphql/field.rb +15 -119
- data/lib/graphql/filter.rb +1 -1
- data/lib/graphql/float_type.rb +1 -1
- data/lib/graphql/function.rb +5 -30
- data/lib/graphql/id_type.rb +1 -1
- data/lib/graphql/input_object_type.rb +9 -25
- data/lib/graphql/int_type.rb +1 -1
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/interface_type.rb +10 -24
- 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/base_object.rb +2 -5
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +12 -6
- data/lib/graphql/introspection/entry_points.rb +9 -9
- 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 +41 -11
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +12 -12
- data/lib/graphql/introspection/type_type.rb +27 -17
- data/lib/graphql/introspection.rb +99 -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/definition_slice.rb +21 -10
- data/lib/graphql/language/document_from_schema_definition.rb +116 -63
- data/lib/graphql/language/lexer.rb +53 -27
- data/lib/graphql/language/lexer.rl +5 -3
- data/lib/graphql/language/nodes.rb +67 -93
- data/lib/graphql/language/parser.rb +929 -896
- data/lib/graphql/language/parser.y +125 -102
- data/lib/graphql/language/printer.rb +11 -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 +3 -1
- data/lib/graphql/name_validator.rb +2 -7
- data/lib/graphql/non_null_type.rb +0 -10
- data/lib/graphql/object_type.rb +47 -58
- data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
- data/lib/graphql/pagination/array_connection.rb +77 -0
- data/lib/graphql/pagination/connection.rb +226 -0
- data/lib/graphql/pagination/connections.rb +160 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +226 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/parse_error.rb +0 -1
- data/lib/graphql/query/arguments.rb +6 -4
- data/lib/graphql/query/arguments_cache.rb +1 -2
- data/lib/graphql/query/context.rb +52 -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 +32 -6
- data/lib/graphql/query/literal_input.rb +31 -11
- 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 +6 -4
- data/lib/graphql/query/variable_validation_error.rb +3 -3
- data/lib/graphql/query/variables.rb +50 -10
- data/lib/graphql/query.rb +77 -18
- data/lib/graphql/railtie.rb +9 -1
- data/lib/graphql/rake_task/validate.rb +3 -0
- data/lib/graphql/rake_task.rb +12 -9
- data/lib/graphql/relay/array_connection.rb +10 -12
- data/lib/graphql/relay/base_connection.rb +30 -13
- data/lib/graphql/relay/connection_instrumentation.rb +4 -4
- data/lib/graphql/relay/connection_type.rb +18 -4
- data/lib/graphql/relay/edge_type.rb +1 -0
- data/lib/graphql/relay/edges_instrumentation.rb +1 -2
- data/lib/graphql/relay/global_id_resolve.rb +1 -2
- data/lib/graphql/relay/mutation.rb +3 -87
- data/lib/graphql/relay/node.rb +3 -0
- data/lib/graphql/relay/page_info.rb +1 -1
- data/lib/graphql/relay/range_add.rb +27 -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 +18 -60
- data/lib/graphql/schema/addition.rb +247 -0
- data/lib/graphql/schema/argument.rb +274 -18
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
- data/lib/graphql/schema/build_from_definition.rb +320 -219
- data/lib/graphql/schema/built_in_types.rb +5 -5
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- 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 +2 -2
- data/lib/graphql/schema/directive/skip.rb +2 -2
- data/lib/graphql/schema/directive/transform.rb +14 -2
- data/lib/graphql/schema/directive.rb +130 -6
- data/lib/graphql/schema/enum.rb +121 -12
- data/lib/graphql/schema/enum_value.rb +24 -7
- data/lib/graphql/schema/field/connection_extension.rb +46 -20
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +465 -181
- data/lib/graphql/schema/field_extension.rb +89 -2
- data/lib/graphql/schema/find_inherited_value.rb +17 -1
- data/lib/graphql/schema/finder.rb +16 -14
- data/lib/graphql/schema/input_object.rb +172 -37
- data/lib/graphql/schema/interface.rb +39 -25
- data/lib/graphql/schema/introspection_system.rb +106 -38
- data/lib/graphql/schema/late_bound_type.rb +3 -2
- data/lib/graphql/schema/list.rb +65 -1
- data/lib/graphql/schema/loader.rb +145 -102
- data/lib/graphql/schema/member/accepts_definition.rb +15 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +34 -28
- data/lib/graphql/schema/member/build_type.rb +19 -8
- data/lib/graphql/schema/member/cached_graphql_definition.rb +34 -2
- data/lib/graphql/schema/member/has_arguments.rb +206 -13
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- 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 +97 -32
- data/lib/graphql/schema/member/has_interfaces.rb +100 -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/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +11 -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 +37 -1
- data/lib/graphql/schema/object.rb +51 -38
- data/lib/graphql/schema/possible_types.rb +9 -4
- data/lib/graphql/schema/printer.rb +16 -35
- data/lib/graphql/schema/relay_classic_mutation.rb +40 -4
- data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
- data/lib/graphql/schema/resolver.rb +133 -79
- data/lib/graphql/schema/scalar.rb +43 -3
- 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/traversal.rb +2 -2
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +19 -5
- data/lib/graphql/schema/union.rb +44 -3
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +14 -4
- 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 +82 -0
- data/lib/graphql/schema/validator.rb +171 -0
- data/lib/graphql/schema/warden.rb +193 -34
- data/lib/graphql/schema.rb +882 -247
- data/lib/graphql/static_validation/all_rules.rb +2 -0
- data/lib/graphql/static_validation/base_visitor.rb +17 -10
- 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 +45 -83
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
- 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/directives_are_in_valid_locations.rb +2 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +94 -51
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- 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/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +13 -3
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +43 -9
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/string_type.rb +1 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +123 -22
- 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 +84 -30
- data/lib/graphql/subscriptions/instrumentation.rb +10 -6
- data/lib/graphql/subscriptions/serialize.rb +53 -6
- data/lib/graphql/subscriptions/subscription_root.rb +15 -5
- data/lib/graphql/subscriptions.rb +117 -49
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +32 -15
- data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_tracing.rb +66 -10
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
- data/lib/graphql/tracing/scout_tracing.rb +19 -0
- data/lib/graphql/tracing/skylight_tracing.rb +9 -1
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +15 -35
- 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 +16 -8
- data/lib/graphql/types/iso_8601_date_time.rb +32 -10
- data/lib/graphql/types/relay/base_connection.rb +6 -88
- data/lib/graphql/types/relay/base_edge.rb +2 -34
- data/lib/graphql/types/relay/connection_behaviors.rb +174 -0
- data/lib/graphql/types/relay/default_relay.rb +31 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +64 -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 +3 -22
- data/lib/graphql/types/relay/nodes_field.rb +16 -18
- 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 +5 -25
- data/lib/graphql/unresolved_type_error.rb +2 -2
- 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 +87 -31
- data/readme.md +3 -6
- metadata +126 -124
- 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,20 +1,22 @@
|
|
|
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
|
|
11
|
+
include GraphQL::Schema::Member::HasAstNode
|
|
16
12
|
include GraphQL::Schema::Member::HasPath
|
|
13
|
+
include GraphQL::Schema::Member::HasValidators
|
|
17
14
|
extend GraphQL::Schema::FindInheritedValue
|
|
15
|
+
include GraphQL::Schema::FindInheritedValue::EmptyObjects
|
|
16
|
+
include GraphQL::Schema::Member::HasDirectives
|
|
17
|
+
include GraphQL::Schema::Member::HasDeprecationReason
|
|
18
|
+
|
|
19
|
+
class FieldImplementationFailed < GraphQL::Error; end
|
|
18
20
|
|
|
19
21
|
# @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
|
|
20
22
|
attr_reader :name
|
|
@@ -22,9 +24,6 @@ module GraphQL
|
|
|
22
24
|
|
|
23
25
|
attr_writer :description
|
|
24
26
|
|
|
25
|
-
# @return [String, nil] If present, the field is marked as deprecated with this documentation
|
|
26
|
-
attr_accessor :deprecation_reason
|
|
27
|
-
|
|
28
27
|
# @return [Symbol] Method or hash key on the underlying object to look up
|
|
29
28
|
attr_reader :method_sym
|
|
30
29
|
|
|
@@ -34,10 +33,21 @@ module GraphQL
|
|
|
34
33
|
# @return [Symbol] The method on the type to look up
|
|
35
34
|
attr_reader :resolver_method
|
|
36
35
|
|
|
37
|
-
# @return [Class] The
|
|
38
|
-
|
|
36
|
+
# @return [Class] The thing this field was defined on (type, mutation, resolver)
|
|
37
|
+
attr_accessor :owner
|
|
38
|
+
|
|
39
|
+
# @return [Class] The GraphQL type this field belongs to. (For fields defined on mutations, it's the payload type)
|
|
40
|
+
def owner_type
|
|
41
|
+
@owner_type ||= if owner.nil?
|
|
42
|
+
raise GraphQL::InvariantError, "Field #{original_name.inspect} (graphql name: #{graphql_name.inspect}) has no owner, but all fields should have an owner. How did this happen?!"
|
|
43
|
+
elsif owner < GraphQL::Schema::Mutation
|
|
44
|
+
owner.payload_type
|
|
45
|
+
else
|
|
46
|
+
owner
|
|
47
|
+
end
|
|
48
|
+
end
|
|
39
49
|
|
|
40
|
-
# @return [
|
|
50
|
+
# @return [Symbol] the original name of the field, passed in by the user
|
|
41
51
|
attr_reader :original_name
|
|
42
52
|
|
|
43
53
|
# @return [Class, nil] The {Schema::Resolver} this field was derived from, if there is one
|
|
@@ -45,13 +55,22 @@ module GraphQL
|
|
|
45
55
|
@resolver_class
|
|
46
56
|
end
|
|
47
57
|
|
|
58
|
+
# @return [Boolean] Is this field a predefined introspection field?
|
|
59
|
+
def introspection?
|
|
60
|
+
@introspection
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def inspect
|
|
64
|
+
"#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
|
|
65
|
+
end
|
|
66
|
+
|
|
48
67
|
alias :mutation :resolver
|
|
49
68
|
|
|
50
69
|
# @return [Boolean] Apply tracing to this field? (Default: skip scalars, this is the override value)
|
|
51
70
|
attr_reader :trace
|
|
52
71
|
|
|
53
72
|
# @return [String, nil]
|
|
54
|
-
|
|
73
|
+
attr_accessor :subscription_scope
|
|
55
74
|
|
|
56
75
|
# Create a field instance from a list of arguments, keyword arguments, and a block.
|
|
57
76
|
#
|
|
@@ -66,11 +85,11 @@ module GraphQL
|
|
|
66
85
|
# @see {.initialize} for other options
|
|
67
86
|
def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
|
|
68
87
|
if kwargs[:field]
|
|
69
|
-
if kwargs[:field] == GraphQL::Relay::
|
|
70
|
-
warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
|
|
88
|
+
if kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodeField.graphql_definition
|
|
89
|
+
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.")
|
|
71
90
|
return GraphQL::Types::Relay::NodeField
|
|
72
|
-
elsif kwargs[:field] == GraphQL::Relay::
|
|
73
|
-
warn("Legacy-style `GraphQL::Relay::Node.plural_field` is being added to a class-based type. See `GraphQL::Types::Relay::NodesField` for a replacement.")
|
|
91
|
+
elsif kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodesField.graphql_definition
|
|
92
|
+
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.")
|
|
74
93
|
return GraphQL::Types::Relay::NodesField
|
|
75
94
|
end
|
|
76
95
|
end
|
|
@@ -103,6 +122,9 @@ module GraphQL
|
|
|
103
122
|
else
|
|
104
123
|
kwargs[:type] = type
|
|
105
124
|
end
|
|
125
|
+
if type.is_a?(Class) && type < GraphQL::Schema::Mutation
|
|
126
|
+
raise ArgumentError, "Use `field #{name.inspect}, mutation: Mutation, ...` to provide a mutation to this field instead"
|
|
127
|
+
end
|
|
106
128
|
end
|
|
107
129
|
new(**kwargs, &block)
|
|
108
130
|
end
|
|
@@ -152,6 +174,16 @@ module GraphQL
|
|
|
152
174
|
end
|
|
153
175
|
end
|
|
154
176
|
|
|
177
|
+
# @return Boolean
|
|
178
|
+
attr_reader :relay_node_field
|
|
179
|
+
# @return Boolean
|
|
180
|
+
attr_reader :relay_nodes_field
|
|
181
|
+
|
|
182
|
+
# @return [Boolean] Should we warn if this field's name conflicts with a built-in method?
|
|
183
|
+
def method_conflict_warning?
|
|
184
|
+
@method_conflict_warning
|
|
185
|
+
end
|
|
186
|
+
|
|
155
187
|
# @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
|
|
156
188
|
# @param type [Class, GraphQL::BaseType, Array] The return type of this field
|
|
157
189
|
# @param owner [Class] The type that this field belongs to
|
|
@@ -160,9 +192,11 @@ module GraphQL
|
|
|
160
192
|
# @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
|
|
161
193
|
# @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
|
|
162
194
|
# @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`)
|
|
195
|
+
# @param dig [Array<String, Symbol>] The nested hash keys to lookup on the underlying hash to resolve this field using dig
|
|
163
196
|
# @param resolver_method [Symbol] The method on the type to call to resolve this field (defaults to `name`)
|
|
164
197
|
# @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
|
|
165
|
-
# @param
|
|
198
|
+
# @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
|
|
199
|
+
# @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
|
|
166
200
|
# @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
|
|
167
201
|
# @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
|
|
168
202
|
# @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
|
|
@@ -174,8 +208,14 @@ module GraphQL
|
|
|
174
208
|
# @param scope [Boolean] If true, the return type's `.scope_items` method will be called on the return value
|
|
175
209
|
# @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
|
|
176
210
|
# @param extensions [Array<Class, Hash<Class => Object>>] Named extensions to apply to this field (see also {#extension})
|
|
211
|
+
# @param directives [Hash{Class => Hash}] Directives to apply to this field
|
|
177
212
|
# @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
|
|
178
|
-
|
|
213
|
+
# @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
|
|
214
|
+
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
|
215
|
+
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
|
216
|
+
# @param validates [Array<Hash>] Configurations for validating this field
|
|
217
|
+
# @param legacy_edge_class [Class, nil] (DEPRECATED) If present, pass this along to the legacy field definition
|
|
218
|
+
def initialize(type: nil, name: nil, owner: nil, null: true, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, dig: 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)
|
|
179
219
|
if name.nil?
|
|
180
220
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
|
181
221
|
end
|
|
@@ -183,16 +223,16 @@ module GraphQL
|
|
|
183
223
|
if type.nil?
|
|
184
224
|
raise ArgumentError, "missing second `type` argument or keyword `type:`"
|
|
185
225
|
end
|
|
186
|
-
if null.nil?
|
|
187
|
-
raise ArgumentError, "missing keyword argument null:"
|
|
188
|
-
end
|
|
189
226
|
end
|
|
190
227
|
if (field || function || resolve) && extras.any?
|
|
191
228
|
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:`"
|
|
192
229
|
end
|
|
193
230
|
@original_name = name
|
|
194
|
-
|
|
195
|
-
|
|
231
|
+
name_s = -name.to_s
|
|
232
|
+
|
|
233
|
+
@underscored_name = -Member::BuildType.underscore(name_s)
|
|
234
|
+
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
|
235
|
+
NameValidator.validate!(@name)
|
|
196
236
|
@description = description
|
|
197
237
|
if field.is_a?(GraphQL::Schema::Field)
|
|
198
238
|
raise ArgumentError, "Instead of passing a field as `field:`, use `add_field(field)` to add an already-defined field."
|
|
@@ -201,10 +241,10 @@ module GraphQL
|
|
|
201
241
|
end
|
|
202
242
|
@function = function
|
|
203
243
|
@resolve = resolve
|
|
204
|
-
|
|
244
|
+
self.deprecation_reason = deprecation_reason
|
|
205
245
|
|
|
206
|
-
if method && hash_key
|
|
207
|
-
raise ArgumentError, "Provide `method:` _or_ `
|
|
246
|
+
if method && hash_key && dig
|
|
247
|
+
raise ArgumentError, "Provide `method:`, `hash_key:` _or_ `dig:`, not multiple. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}, dig: #{dig.inspect}`)"
|
|
208
248
|
end
|
|
209
249
|
|
|
210
250
|
if resolver_method
|
|
@@ -212,60 +252,84 @@ module GraphQL
|
|
|
212
252
|
raise ArgumentError, "Provide `method:` _or_ `resolver_method:`, not both. (called with: `method: #{method.inspect}, resolver_method: #{resolver_method.inspect}`)"
|
|
213
253
|
end
|
|
214
254
|
|
|
215
|
-
if hash_key
|
|
216
|
-
raise ArgumentError, "Provide `hash_key
|
|
255
|
+
if hash_key || dig
|
|
256
|
+
raise ArgumentError, "Provide `hash_key:`, `dig:`, _or_ `resolver_method:`, not multiple. (called with: `hash_key: #{hash_key.inspect}, dig: #{dig.inspect}, resolver_method: #{resolver_method.inspect}`)"
|
|
217
257
|
end
|
|
218
258
|
end
|
|
219
259
|
|
|
220
260
|
# TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
|
|
221
|
-
method_name = method || hash_key ||
|
|
222
|
-
|
|
261
|
+
method_name = method || hash_key || name_s
|
|
262
|
+
@dig_keys = dig
|
|
263
|
+
if hash_key
|
|
264
|
+
@hash_key = hash_key
|
|
265
|
+
end
|
|
223
266
|
|
|
224
|
-
|
|
267
|
+
resolver_method ||= name_s.to_sym
|
|
268
|
+
|
|
269
|
+
@method_str = -method_name.to_s
|
|
225
270
|
@method_sym = method_name.to_sym
|
|
226
271
|
@resolver_method = resolver_method
|
|
227
272
|
@complexity = complexity
|
|
228
273
|
@return_type_expr = type
|
|
229
274
|
@return_type_null = null
|
|
230
275
|
@connection = connection
|
|
231
|
-
@
|
|
276
|
+
@has_max_page_size = max_page_size != :not_given
|
|
277
|
+
@max_page_size = max_page_size == :not_given ? nil : max_page_size
|
|
232
278
|
@introspection = introspection
|
|
233
279
|
@extras = extras
|
|
280
|
+
@broadcastable = broadcastable
|
|
234
281
|
@resolver_class = resolver_class
|
|
235
282
|
@scope = scope
|
|
236
283
|
@trace = trace
|
|
237
284
|
@relay_node_field = relay_node_field
|
|
238
285
|
@relay_nodes_field = relay_nodes_field
|
|
286
|
+
@ast_node = ast_node
|
|
287
|
+
@method_conflict_warning = method_conflict_warning
|
|
288
|
+
@legacy_edge_class = legacy_edge_class
|
|
239
289
|
|
|
240
|
-
# Override the default from HasArguments
|
|
241
|
-
@own_arguments = {}
|
|
242
290
|
arguments.each do |name, arg|
|
|
243
|
-
|
|
291
|
+
case arg
|
|
292
|
+
when Hash
|
|
244
293
|
argument(name: name, **arg)
|
|
294
|
+
when GraphQL::Schema::Argument
|
|
295
|
+
add_argument(arg)
|
|
296
|
+
when Array
|
|
297
|
+
arg.each { |a| add_argument(a) }
|
|
245
298
|
else
|
|
246
|
-
|
|
299
|
+
raise ArgumentError, "Unexpected argument config (#{arg.class}): #{arg.inspect}"
|
|
247
300
|
end
|
|
248
301
|
end
|
|
249
302
|
|
|
250
303
|
@owner = owner
|
|
251
304
|
@subscription_scope = subscription_scope
|
|
252
305
|
|
|
253
|
-
|
|
254
|
-
@
|
|
255
|
-
if extensions.any?
|
|
256
|
-
self.extensions(extensions)
|
|
257
|
-
end
|
|
306
|
+
@extensions = EMPTY_ARRAY
|
|
307
|
+
@call_after_define = false
|
|
258
308
|
# This should run before connection extension,
|
|
259
309
|
# but should it run after the definition block?
|
|
260
310
|
if scoped?
|
|
261
311
|
self.extension(ScopeExtension)
|
|
262
312
|
end
|
|
313
|
+
|
|
263
314
|
# The problem with putting this after the definition_block
|
|
264
315
|
# is that it would override arguments
|
|
265
|
-
if connection?
|
|
266
|
-
self.extension(
|
|
316
|
+
if connection? && connection_extension
|
|
317
|
+
self.extension(connection_extension)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
# Do this last so we have as much context as possible when initializing them:
|
|
321
|
+
if extensions.any?
|
|
322
|
+
self.extensions(extensions)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
if directives.any?
|
|
326
|
+
directives.each do |(dir_class, options)|
|
|
327
|
+
self.directive(dir_class, **options)
|
|
328
|
+
end
|
|
267
329
|
end
|
|
268
330
|
|
|
331
|
+
self.validates(validates)
|
|
332
|
+
|
|
269
333
|
if definition_block
|
|
270
334
|
if definition_block.arity == 1
|
|
271
335
|
yield self
|
|
@@ -273,6 +337,16 @@ module GraphQL
|
|
|
273
337
|
instance_eval(&definition_block)
|
|
274
338
|
end
|
|
275
339
|
end
|
|
340
|
+
|
|
341
|
+
self.extensions.each(&:after_define_apply)
|
|
342
|
+
@call_after_define = true
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# If true, subscription updates with this field can be shared between viewers
|
|
346
|
+
# @return [Boolean, nil]
|
|
347
|
+
# @see GraphQL::Subscriptions::BroadcastAnalyzer
|
|
348
|
+
def broadcastable?
|
|
349
|
+
@broadcastable
|
|
276
350
|
end
|
|
277
351
|
|
|
278
352
|
# @param text [String]
|
|
@@ -298,24 +372,20 @@ module GraphQL
|
|
|
298
372
|
# @example adding an extension with options
|
|
299
373
|
# extensions([MyExtensionClass, { AnotherExtensionClass => { filter: true } }])
|
|
300
374
|
#
|
|
301
|
-
# @param extensions [Array<Class, Hash<Class =>
|
|
375
|
+
# @param extensions [Array<Class, Hash<Class => Hash>>] Add extensions to this field. For hash elements, only the first key/value is used.
|
|
302
376
|
# @return [Array<GraphQL::Schema::FieldExtension>] extensions to apply to this field
|
|
303
377
|
def extensions(new_extensions = nil)
|
|
304
|
-
if new_extensions
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
if extension.is_a?(Hash)
|
|
310
|
-
extension = extension.to_a[0]
|
|
311
|
-
extension_class, options = *extension
|
|
312
|
-
@extensions << extension_class.new(field: self, options: options)
|
|
378
|
+
if new_extensions
|
|
379
|
+
new_extensions.each do |extension_config|
|
|
380
|
+
if extension_config.is_a?(Hash)
|
|
381
|
+
extension_class, options = *extension_config.to_a[0]
|
|
382
|
+
self.extension(extension_class, options)
|
|
313
383
|
else
|
|
314
|
-
|
|
315
|
-
@extensions << extension_class.new(field: self, options: nil)
|
|
384
|
+
self.extension(extension_config)
|
|
316
385
|
end
|
|
317
386
|
end
|
|
318
387
|
end
|
|
388
|
+
@extensions
|
|
319
389
|
end
|
|
320
390
|
|
|
321
391
|
# Add `extension` to this field, initialized with `options` if provided.
|
|
@@ -326,10 +396,19 @@ module GraphQL
|
|
|
326
396
|
# @example adding an extension with options
|
|
327
397
|
# extension(MyExtensionClass, filter: true)
|
|
328
398
|
#
|
|
329
|
-
# @param
|
|
330
|
-
# @param options [
|
|
331
|
-
|
|
332
|
-
|
|
399
|
+
# @param extension_class [Class] subclass of {Schema::FieldExtension}
|
|
400
|
+
# @param options [Hash] if provided, given as `options:` when initializing `extension`.
|
|
401
|
+
# @return [void]
|
|
402
|
+
def extension(extension_class, options = nil)
|
|
403
|
+
extension_inst = extension_class.new(field: self, options: options)
|
|
404
|
+
if @extensions.frozen?
|
|
405
|
+
@extensions = @extensions.dup
|
|
406
|
+
end
|
|
407
|
+
if @call_after_define
|
|
408
|
+
extension_inst.after_define_apply
|
|
409
|
+
end
|
|
410
|
+
@extensions << extension_inst
|
|
411
|
+
nil
|
|
333
412
|
end
|
|
334
413
|
|
|
335
414
|
# Read extras (as symbols) from this field,
|
|
@@ -342,12 +421,80 @@ module GraphQL
|
|
|
342
421
|
# Read the value
|
|
343
422
|
@extras
|
|
344
423
|
else
|
|
424
|
+
if @extras.frozen?
|
|
425
|
+
@extras = @extras.dup
|
|
426
|
+
end
|
|
345
427
|
# Append to the set of extras on this field
|
|
346
428
|
@extras.concat(new_extras)
|
|
347
429
|
end
|
|
348
430
|
end
|
|
349
431
|
|
|
350
|
-
def
|
|
432
|
+
def calculate_complexity(query:, nodes:, child_complexity:)
|
|
433
|
+
if respond_to?(:complexity_for)
|
|
434
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
|
435
|
+
complexity_for(child_complexity: child_complexity, query: query, lookahead: lookahead)
|
|
436
|
+
elsif connection?
|
|
437
|
+
arguments = query.arguments_for(nodes.first, self)
|
|
438
|
+
max_possible_page_size = nil
|
|
439
|
+
if arguments.respond_to?(:[]) # It might have been an error
|
|
440
|
+
if arguments[:first]
|
|
441
|
+
max_possible_page_size = arguments[:first]
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
|
|
445
|
+
max_possible_page_size = arguments[:last]
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
if max_possible_page_size.nil?
|
|
450
|
+
max_possible_page_size = max_page_size || query.schema.default_max_page_size
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
if max_possible_page_size.nil?
|
|
454
|
+
raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `max_page_size` or `default_max_page_size`"
|
|
455
|
+
else
|
|
456
|
+
metadata_complexity = 0
|
|
457
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
|
458
|
+
|
|
459
|
+
if (page_info_lookahead = lookahead.selection(:page_info)).selected?
|
|
460
|
+
metadata_complexity += 1 # pageInfo
|
|
461
|
+
metadata_complexity += page_info_lookahead.selections.size # subfields
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
|
|
465
|
+
metadata_complexity += 1
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
nodes_edges_complexity = 0
|
|
469
|
+
nodes_edges_complexity += 1 if lookahead.selects?(:edges)
|
|
470
|
+
nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
|
|
471
|
+
|
|
472
|
+
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
|
473
|
+
items_complexity = child_complexity - metadata_complexity - nodes_edges_complexity
|
|
474
|
+
# Add 1 for _this_ field
|
|
475
|
+
1 + (max_possible_page_size * items_complexity) + metadata_complexity + nodes_edges_complexity
|
|
476
|
+
end
|
|
477
|
+
else
|
|
478
|
+
defined_complexity = complexity
|
|
479
|
+
case defined_complexity
|
|
480
|
+
when Proc
|
|
481
|
+
arguments = query.arguments_for(nodes.first, self)
|
|
482
|
+
if arguments.is_a?(GraphQL::ExecutionError)
|
|
483
|
+
return child_complexity
|
|
484
|
+
elsif arguments.respond_to?(:keyword_arguments)
|
|
485
|
+
arguments = arguments.keyword_arguments
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
defined_complexity.call(query.context, arguments, child_complexity)
|
|
489
|
+
when Numeric
|
|
490
|
+
defined_complexity + child_complexity
|
|
491
|
+
else
|
|
492
|
+
raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def complexity(new_complexity = nil)
|
|
351
498
|
case new_complexity
|
|
352
499
|
when Proc
|
|
353
500
|
if new_complexity.parameters.size != 3
|
|
@@ -360,14 +507,23 @@ module GraphQL
|
|
|
360
507
|
end
|
|
361
508
|
when Numeric
|
|
362
509
|
@complexity = new_complexity
|
|
510
|
+
when nil
|
|
511
|
+
@complexity
|
|
363
512
|
else
|
|
364
513
|
raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
|
|
365
514
|
end
|
|
366
515
|
end
|
|
367
516
|
|
|
368
|
-
# @return [
|
|
517
|
+
# @return [Boolean] True if this field's {#max_page_size} should override the schema default.
|
|
518
|
+
def has_max_page_size?
|
|
519
|
+
@has_max_page_size
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
# @return [Integer, nil] Applied to connections if {#has_max_page_size?}
|
|
369
523
|
attr_reader :max_page_size
|
|
370
524
|
|
|
525
|
+
prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
|
|
526
|
+
|
|
371
527
|
# @return [GraphQL::Field]
|
|
372
528
|
def to_graphql
|
|
373
529
|
field_defn = if @field
|
|
@@ -387,8 +543,8 @@ module GraphQL
|
|
|
387
543
|
field_defn.description = @description
|
|
388
544
|
end
|
|
389
545
|
|
|
390
|
-
if
|
|
391
|
-
field_defn.deprecation_reason =
|
|
546
|
+
if self.deprecation_reason
|
|
547
|
+
field_defn.deprecation_reason = self.deprecation_reason
|
|
392
548
|
end
|
|
393
549
|
|
|
394
550
|
if @resolver_class
|
|
@@ -410,16 +566,21 @@ module GraphQL
|
|
|
410
566
|
field_defn.relay_nodes_field = @relay_nodes_field
|
|
411
567
|
end
|
|
412
568
|
|
|
569
|
+
if @legacy_edge_class
|
|
570
|
+
field_defn.edge_class = @legacy_edge_class
|
|
571
|
+
end
|
|
572
|
+
|
|
413
573
|
field_defn.resolve = self.method(:resolve_field)
|
|
414
574
|
field_defn.connection = connection?
|
|
415
575
|
field_defn.connection_max_page_size = max_page_size
|
|
416
576
|
field_defn.introspection = @introspection
|
|
417
577
|
field_defn.complexity = @complexity
|
|
418
578
|
field_defn.subscription_scope = @subscription_scope
|
|
579
|
+
field_defn.ast_node = ast_node
|
|
419
580
|
|
|
420
|
-
|
|
421
|
-
arg_graphql = defn.
|
|
422
|
-
field_defn.arguments[arg_graphql.name] = arg_graphql
|
|
581
|
+
all_argument_definitions.each do |defn|
|
|
582
|
+
arg_graphql = defn.deprecated_to_graphql
|
|
583
|
+
field_defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
|
423
584
|
end
|
|
424
585
|
|
|
425
586
|
# Support a passed-in proc, one way or another
|
|
@@ -433,14 +594,33 @@ module GraphQL
|
|
|
433
594
|
|
|
434
595
|
# Ok, `self` isn't a class, but this is for consistency with the classes
|
|
435
596
|
field_defn.metadata[:type_class] = self
|
|
436
|
-
|
|
597
|
+
field_defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(field_defn)
|
|
437
598
|
field_defn
|
|
438
599
|
end
|
|
439
600
|
|
|
601
|
+
class MissingReturnTypeError < GraphQL::Error; end
|
|
602
|
+
attr_writer :type
|
|
603
|
+
|
|
440
604
|
def type
|
|
441
|
-
@type ||=
|
|
442
|
-
|
|
443
|
-
|
|
605
|
+
@type ||= if @function
|
|
606
|
+
Member::BuildType.parse_type(@function.type, null: false)
|
|
607
|
+
elsif @field
|
|
608
|
+
Member::BuildType.parse_type(@field.type, null: false)
|
|
609
|
+
elsif @return_type_expr.nil?
|
|
610
|
+
# Not enough info to determine type
|
|
611
|
+
message = "Can't determine the return type for #{self.path}"
|
|
612
|
+
if @resolver_class
|
|
613
|
+
message += " (it has `resolver: #{@resolver_class}`, consider configuration a `type ...` for that class)"
|
|
614
|
+
end
|
|
615
|
+
raise MissingReturnTypeError, message
|
|
616
|
+
else
|
|
617
|
+
Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
|
618
|
+
end
|
|
619
|
+
rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
|
|
620
|
+
# Let this propagate up
|
|
621
|
+
raise err
|
|
622
|
+
rescue StandardError => err
|
|
623
|
+
raise MissingReturnTypeError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: (#{err.class}) #{err.message}", err.backtrace
|
|
444
624
|
end
|
|
445
625
|
|
|
446
626
|
def visible?(context)
|
|
@@ -459,15 +639,43 @@ module GraphQL
|
|
|
459
639
|
end
|
|
460
640
|
end
|
|
461
641
|
|
|
462
|
-
def authorized?(object, context)
|
|
642
|
+
def authorized?(object, args, context)
|
|
463
643
|
if @resolver_class
|
|
464
|
-
# The resolver will check itself during `resolve()`
|
|
644
|
+
# The resolver _instance_ will check itself during `resolve()`
|
|
465
645
|
@resolver_class.authorized?(object, context)
|
|
466
646
|
else
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
647
|
+
if (arg_values = context[:current_arguments])
|
|
648
|
+
# ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
|
|
649
|
+
using_arg_values = true
|
|
650
|
+
arg_values = arg_values.argument_values
|
|
651
|
+
else
|
|
652
|
+
arg_values = args
|
|
653
|
+
using_arg_values = false
|
|
654
|
+
end
|
|
655
|
+
if args.size > 0
|
|
656
|
+
args = context.warden.arguments(self)
|
|
657
|
+
args.each do |arg|
|
|
658
|
+
arg_key = arg.keyword
|
|
659
|
+
if arg_values.key?(arg_key)
|
|
660
|
+
arg_value = arg_values[arg_key]
|
|
661
|
+
if using_arg_values
|
|
662
|
+
if arg_value.default_used?
|
|
663
|
+
# pass -- no auth required for default used
|
|
664
|
+
next
|
|
665
|
+
else
|
|
666
|
+
application_arg_value = arg_value.value
|
|
667
|
+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
|
|
668
|
+
application_arg_value.keyword_arguments
|
|
669
|
+
end
|
|
670
|
+
end
|
|
671
|
+
else
|
|
672
|
+
application_arg_value = arg_value
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
if !arg.authorized?(object, application_arg_value, context)
|
|
676
|
+
return false
|
|
677
|
+
end
|
|
678
|
+
end
|
|
471
679
|
end
|
|
472
680
|
end
|
|
473
681
|
true
|
|
@@ -485,21 +693,22 @@ module GraphQL
|
|
|
485
693
|
# Some legacy fields can have `nil` here, not exactly sure why.
|
|
486
694
|
# @see https://github.com/rmosolgo/graphql-ruby/issues/1990 before removing
|
|
487
695
|
inner_obj = after_obj && after_obj.object
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
696
|
+
ctx.schema.after_lazy(to_ruby_args(after_obj, args, ctx)) do |ruby_args|
|
|
697
|
+
if authorized?(inner_obj, ruby_args, query_ctx)
|
|
698
|
+
# Then if it passed, resolve the field
|
|
699
|
+
if @resolve_proc
|
|
700
|
+
# Might be nil, still want to call the func in that case
|
|
701
|
+
with_extensions(inner_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
|
|
702
|
+
# Pass the GraphQL args here for compatibility:
|
|
703
|
+
@resolve_proc.call(extended_obj, args, ctx)
|
|
704
|
+
end
|
|
705
|
+
else
|
|
706
|
+
public_send_field(after_obj, ruby_args, query_ctx)
|
|
496
707
|
end
|
|
497
708
|
else
|
|
498
|
-
|
|
709
|
+
err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
|
|
710
|
+
query_ctx.schema.unauthorized_field(err)
|
|
499
711
|
end
|
|
500
|
-
else
|
|
501
|
-
err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
|
|
502
|
-
query_ctx.schema.unauthorized_field(err)
|
|
503
712
|
end
|
|
504
713
|
end
|
|
505
714
|
end
|
|
@@ -516,34 +725,15 @@ module GraphQL
|
|
|
516
725
|
begin
|
|
517
726
|
# Unwrap the GraphQL object to get the application object.
|
|
518
727
|
application_object = object.object
|
|
519
|
-
if self.authorized?(application_object, ctx)
|
|
520
|
-
# Apply field extensions
|
|
521
|
-
with_extensions(object, args, ctx) do |extended_obj, extended_args|
|
|
522
|
-
field_receiver = if @resolver_class
|
|
523
|
-
resolver_obj = if extended_obj.is_a?(GraphQL::Schema::Object)
|
|
524
|
-
extended_obj.object
|
|
525
|
-
else
|
|
526
|
-
extended_obj
|
|
527
|
-
end
|
|
528
|
-
@resolver_class.new(object: resolver_obj, context: ctx, field: self)
|
|
529
|
-
else
|
|
530
|
-
extended_obj
|
|
531
|
-
end
|
|
532
728
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
else
|
|
541
|
-
resolve_field_method(field_receiver, extended_args, ctx)
|
|
542
|
-
end
|
|
729
|
+
Schema::Validator.validate!(validators, application_object, ctx, args)
|
|
730
|
+
|
|
731
|
+
ctx.schema.after_lazy(self.authorized?(application_object, args, ctx)) do |is_authorized|
|
|
732
|
+
if is_authorized
|
|
733
|
+
public_send_field(object, args, ctx)
|
|
734
|
+
else
|
|
735
|
+
raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
|
|
543
736
|
end
|
|
544
|
-
else
|
|
545
|
-
err = GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
|
|
546
|
-
ctx.schema.unauthorized_field(err)
|
|
547
737
|
end
|
|
548
738
|
rescue GraphQL::UnauthorizedFieldError => err
|
|
549
739
|
err.field ||= self
|
|
@@ -555,46 +745,9 @@ module GraphQL
|
|
|
555
745
|
err
|
|
556
746
|
end
|
|
557
747
|
|
|
558
|
-
# Find a way to resolve this field, checking:
|
|
559
|
-
#
|
|
560
|
-
# - Hash keys, if the wrapped object is a hash;
|
|
561
|
-
# - A method on the wrapped object;
|
|
562
|
-
# - Or, raise not implemented.
|
|
563
|
-
#
|
|
564
|
-
# This can be overridden by defining a method on the object type.
|
|
565
|
-
# @param obj [GraphQL::Schema::Object]
|
|
566
|
-
# @param ruby_kwargs [Hash<Symbol => Object>]
|
|
567
|
-
# @param ctx [GraphQL::Query::Context]
|
|
568
|
-
def resolve_field_method(obj, ruby_kwargs, ctx)
|
|
569
|
-
if obj.object.is_a?(Hash)
|
|
570
|
-
inner_object = obj.object
|
|
571
|
-
if inner_object.key?(@method_sym)
|
|
572
|
-
inner_object[@method_sym]
|
|
573
|
-
else
|
|
574
|
-
inner_object[@method_str]
|
|
575
|
-
end
|
|
576
|
-
elsif obj.object.respond_to?(@method_sym)
|
|
577
|
-
if ruby_kwargs.any?
|
|
578
|
-
obj.object.public_send(@method_sym, **ruby_kwargs)
|
|
579
|
-
else
|
|
580
|
-
obj.object.public_send(@method_sym)
|
|
581
|
-
end
|
|
582
|
-
else
|
|
583
|
-
raise <<-ERR
|
|
584
|
-
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
|
585
|
-
|
|
586
|
-
- `#{obj.class}##{@resolver_method}`, which did not exist
|
|
587
|
-
- `#{obj.object.class}##{@method_sym}`, which did not exist
|
|
588
|
-
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
|
|
589
|
-
|
|
590
|
-
To implement this field, define one of the methods above (and check for typos)
|
|
591
|
-
ERR
|
|
592
|
-
end
|
|
593
|
-
end
|
|
594
|
-
|
|
595
748
|
# @param ctx [GraphQL::Query::Context::FieldResolutionContext]
|
|
596
749
|
def fetch_extra(extra_name, ctx)
|
|
597
|
-
if extra_name != :path && respond_to?(extra_name)
|
|
750
|
+
if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
|
|
598
751
|
self.public_send(extra_name)
|
|
599
752
|
elsif ctx.respond_to?(extra_name)
|
|
600
753
|
ctx.public_send(extra_name)
|
|
@@ -617,11 +770,36 @@ module GraphQL
|
|
|
617
770
|
if graphql_args.any? || @extras.any?
|
|
618
771
|
# Splat the GraphQL::Arguments to Ruby keyword arguments
|
|
619
772
|
ruby_kwargs = graphql_args.to_kwargs
|
|
773
|
+
maybe_lazies = []
|
|
620
774
|
# Apply any `prepare` methods. Not great code organization, can this go somewhere better?
|
|
621
|
-
arguments.each do |name, arg_defn|
|
|
775
|
+
arguments(field_ctx).each do |name, arg_defn|
|
|
622
776
|
ruby_kwargs_key = arg_defn.keyword
|
|
623
|
-
|
|
624
|
-
|
|
777
|
+
|
|
778
|
+
if ruby_kwargs.key?(ruby_kwargs_key)
|
|
779
|
+
loads = arg_defn.loads
|
|
780
|
+
value = ruby_kwargs[ruby_kwargs_key]
|
|
781
|
+
loaded_value = if loads && !arg_defn.from_resolver?
|
|
782
|
+
if arg_defn.type.list?
|
|
783
|
+
loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
|
|
784
|
+
field_ctx.schema.after_any_lazies(loaded_values) { |result| result }
|
|
785
|
+
else
|
|
786
|
+
load_application_object(arg_defn, loads, value, field_ctx.query.context)
|
|
787
|
+
end
|
|
788
|
+
elsif arg_defn.type.list? && value.is_a?(Array)
|
|
789
|
+
field_ctx.schema.after_any_lazies(value, &:itself)
|
|
790
|
+
else
|
|
791
|
+
value
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
maybe_lazies << field_ctx.schema.after_lazy(loaded_value) do |loaded_value|
|
|
795
|
+
prepared_value = if arg_defn.prepare
|
|
796
|
+
arg_defn.prepare_value(obj, loaded_value)
|
|
797
|
+
else
|
|
798
|
+
loaded_value
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
ruby_kwargs[ruby_kwargs_key] = prepared_value
|
|
802
|
+
end
|
|
625
803
|
end
|
|
626
804
|
end
|
|
627
805
|
|
|
@@ -629,32 +807,118 @@ module GraphQL
|
|
|
629
807
|
ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
|
|
630
808
|
end
|
|
631
809
|
|
|
632
|
-
|
|
810
|
+
field_ctx.schema.after_any_lazies(maybe_lazies) do
|
|
811
|
+
ruby_kwargs
|
|
812
|
+
end
|
|
633
813
|
else
|
|
634
814
|
NO_ARGS
|
|
635
815
|
end
|
|
636
816
|
end
|
|
637
817
|
|
|
638
|
-
def public_send_field(
|
|
639
|
-
query_ctx
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
818
|
+
def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
|
|
819
|
+
with_extensions(unextended_obj, unextended_ruby_kwargs, query_ctx) do |obj, ruby_kwargs|
|
|
820
|
+
begin
|
|
821
|
+
method_receiver = nil
|
|
822
|
+
method_to_call = nil
|
|
823
|
+
if @resolver_class
|
|
824
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
|
825
|
+
obj = obj.object
|
|
826
|
+
end
|
|
827
|
+
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
|
644
828
|
end
|
|
645
|
-
|
|
829
|
+
|
|
830
|
+
# Find a way to resolve this field, checking:
|
|
831
|
+
#
|
|
832
|
+
# - A method on the type instance;
|
|
833
|
+
# - Hash keys, if the wrapped object is a hash or responds to `#[]`
|
|
834
|
+
# - A method on the wrapped object;
|
|
835
|
+
# - Or, raise not implemented.
|
|
836
|
+
#
|
|
837
|
+
if obj.respond_to?(@resolver_method)
|
|
838
|
+
method_to_call = @resolver_method
|
|
839
|
+
method_receiver = obj
|
|
840
|
+
# Call the method with kwargs, if there are any
|
|
841
|
+
if ruby_kwargs.any?
|
|
842
|
+
obj.public_send(@resolver_method, **ruby_kwargs)
|
|
843
|
+
else
|
|
844
|
+
obj.public_send(@resolver_method)
|
|
845
|
+
end
|
|
846
|
+
elsif obj.object.is_a?(Hash)
|
|
847
|
+
inner_object = obj.object
|
|
848
|
+
if @dig_keys
|
|
849
|
+
inner_object.dig(*@dig_keys)
|
|
850
|
+
elsif inner_object.key?(@method_sym)
|
|
851
|
+
inner_object[@method_sym]
|
|
852
|
+
else
|
|
853
|
+
inner_object[@method_str]
|
|
854
|
+
end
|
|
855
|
+
elsif defined?(@hash_key) && obj.object.respond_to?(:[])
|
|
856
|
+
obj.object[@hash_key]
|
|
857
|
+
elsif obj.object.respond_to?(@method_sym)
|
|
858
|
+
method_to_call = @method_sym
|
|
859
|
+
method_receiver = obj.object
|
|
860
|
+
if ruby_kwargs.any?
|
|
861
|
+
obj.object.public_send(@method_sym, **ruby_kwargs)
|
|
862
|
+
else
|
|
863
|
+
obj.object.public_send(@method_sym)
|
|
864
|
+
end
|
|
865
|
+
else
|
|
866
|
+
raise <<-ERR
|
|
867
|
+
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
|
868
|
+
|
|
869
|
+
- `#{obj.class}##{@resolver_method}`, which did not exist
|
|
870
|
+
- `#{obj.object.class}##{@method_sym}`, which did not exist
|
|
871
|
+
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
|
|
872
|
+
|
|
873
|
+
To implement this field, define one of the methods above (and check for typos)
|
|
874
|
+
ERR
|
|
875
|
+
end
|
|
876
|
+
rescue ArgumentError
|
|
877
|
+
assert_satisfactory_implementation(method_receiver, method_to_call, ruby_kwargs)
|
|
878
|
+
# if the line above doesn't raise, re-raise
|
|
879
|
+
raise
|
|
646
880
|
end
|
|
881
|
+
end
|
|
882
|
+
end
|
|
647
883
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
884
|
+
def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
|
|
885
|
+
method_defn = receiver.method(method_name)
|
|
886
|
+
unsatisfied_ruby_kwargs = ruby_kwargs.dup
|
|
887
|
+
unsatisfied_method_params = []
|
|
888
|
+
encountered_keyrest = false
|
|
889
|
+
method_defn.parameters.each do |(param_type, param_name)|
|
|
890
|
+
case param_type
|
|
891
|
+
when :key
|
|
892
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
|
893
|
+
when :keyreq
|
|
894
|
+
if unsatisfied_ruby_kwargs.key?(param_name)
|
|
895
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
|
651
896
|
else
|
|
652
|
-
|
|
897
|
+
unsatisfied_method_params << "- `#{param_name}:` is required by Ruby, but not by GraphQL. Consider `#{param_name}: nil` instead, or making this argument required in GraphQL."
|
|
653
898
|
end
|
|
654
|
-
|
|
655
|
-
|
|
899
|
+
when :keyrest
|
|
900
|
+
encountered_keyrest = true
|
|
901
|
+
when :req
|
|
902
|
+
unsatisfied_method_params << "- `#{param_name}` is required by Ruby, but GraphQL doesn't pass positional arguments. If it's meant to be a GraphQL argument, use `#{param_name}:` instead. Otherwise, remove it."
|
|
903
|
+
when :opt, :rest
|
|
904
|
+
# This is fine, although it will never be present
|
|
656
905
|
end
|
|
657
906
|
end
|
|
907
|
+
|
|
908
|
+
if encountered_keyrest
|
|
909
|
+
unsatisfied_ruby_kwargs.clear
|
|
910
|
+
end
|
|
911
|
+
|
|
912
|
+
if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
|
|
913
|
+
raise FieldImplementationFailed.new, <<-ERR
|
|
914
|
+
Failed to call #{method_name} on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
|
|
915
|
+
|
|
916
|
+
#{ unsatisfied_ruby_kwargs
|
|
917
|
+
.map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
|
|
918
|
+
.concat(unsatisfied_method_params)
|
|
919
|
+
.join("\n") }
|
|
920
|
+
ERR
|
|
921
|
+
end
|
|
658
922
|
end
|
|
659
923
|
|
|
660
924
|
# Wrap execution with hooks.
|
|
@@ -664,32 +928,52 @@ module GraphQL
|
|
|
664
928
|
if @extensions.empty?
|
|
665
929
|
yield(obj, args)
|
|
666
930
|
else
|
|
667
|
-
#
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
931
|
+
# This is a hack to get the _last_ value for extended obj and args,
|
|
932
|
+
# in case one of the extensions doesn't `yield`.
|
|
933
|
+
# (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
|
|
934
|
+
extended = { args: args, obj: obj, memos: nil, added_extras: nil }
|
|
935
|
+
value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
|
|
936
|
+
if (added_extras = extended[:added_extras])
|
|
937
|
+
args = args.dup
|
|
938
|
+
added_extras.each { |e| args.delete(e) }
|
|
939
|
+
end
|
|
940
|
+
yield(obj, args)
|
|
674
941
|
end
|
|
675
942
|
|
|
943
|
+
extended_obj = extended[:obj]
|
|
944
|
+
extended_args = extended[:args]
|
|
945
|
+
memos = extended[:memos] || EMPTY_HASH
|
|
946
|
+
|
|
676
947
|
ctx.schema.after_lazy(value) do |resolved_value|
|
|
677
|
-
|
|
948
|
+
idx = 0
|
|
949
|
+
@extensions.each do |ext|
|
|
678
950
|
memo = memos[idx]
|
|
679
951
|
# TODO after_lazy?
|
|
680
|
-
resolved_value = ext.after_resolve(object:
|
|
952
|
+
resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
|
|
953
|
+
idx += 1
|
|
681
954
|
end
|
|
682
955
|
resolved_value
|
|
683
956
|
end
|
|
684
957
|
end
|
|
685
958
|
end
|
|
686
959
|
|
|
687
|
-
def run_extensions_before_resolve(
|
|
960
|
+
def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
|
|
688
961
|
extension = @extensions[idx]
|
|
689
962
|
if extension
|
|
690
963
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
|
691
|
-
|
|
692
|
-
|
|
964
|
+
if memo
|
|
965
|
+
memos = extended[:memos] ||= {}
|
|
966
|
+
memos[idx] = memo
|
|
967
|
+
end
|
|
968
|
+
|
|
969
|
+
if (extras = extension.added_extras)
|
|
970
|
+
ae = extended[:added_extras] ||= []
|
|
971
|
+
ae.concat(extras)
|
|
972
|
+
end
|
|
973
|
+
|
|
974
|
+
extended[:obj] = extended_obj
|
|
975
|
+
extended[:args] = extended_args
|
|
976
|
+
run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
|
|
693
977
|
end
|
|
694
978
|
else
|
|
695
979
|
yield(obj, args)
|