graphql 1.12.12 → 2.2.14
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 +3 -8
- 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 +14 -4
- data/lib/generators/graphql/interface_generator.rb +7 -7
- 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 +5 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +10 -38
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +23 -12
- 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 +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +6 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +5 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +4 -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 +2 -0
- data/lib/generators/graphql/templates/object.erb +4 -2
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +3 -1
- data/lib/generators/graphql/templates/schema.erb +19 -2
- data/lib/generators/graphql/templates/union.erb +4 -2
- data/lib/generators/graphql/type_generator.rb +46 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/ast/analyzer.rb +7 -0
- data/lib/graphql/analysis/ast/field_usage.rb +55 -1
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +88 -140
- data/lib/graphql/analysis/ast/query_depth.rb +7 -3
- data/lib/graphql/analysis/ast/visitor.rb +50 -42
- data/lib/graphql/analysis/ast.rb +26 -23
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/table.rb +4 -22
- data/lib/graphql/backtrace/trace.rb +93 -0
- data/lib/graphql/backtrace/tracer.rb +8 -6
- data/lib/graphql/backtrace.rb +3 -8
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +85 -0
- data/lib/graphql/dataloader/null_dataloader.rb +3 -1
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +120 -31
- data/lib/graphql/dataloader.rb +168 -142
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/errors.rb +12 -81
- data/lib/graphql/execution/interpreter/arguments.rb +2 -2
- data/lib/graphql/execution/interpreter/arguments_cache.rb +36 -34
- data/lib/graphql/execution/interpreter/resolve.rb +32 -2
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
- data/lib/graphql/execution/interpreter/runtime.rb +414 -341
- data/lib/graphql/execution/interpreter.rb +122 -80
- data/lib/graphql/execution/lazy.rb +11 -21
- data/lib/graphql/execution/lookahead.rb +125 -54
- data/lib/graphql/execution/multiplex.rb +4 -172
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +5 -3
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +11 -18
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +3 -3
- data/lib/graphql/introspection/input_value_type.rb +10 -4
- data/lib/graphql/introspection/schema_type.rb +12 -5
- data/lib/graphql/introspection/type_type.rb +25 -12
- data/lib/graphql/introspection.rb +6 -2
- data/lib/graphql/language/block_string.rb +37 -25
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +78 -65
- data/lib/graphql/language/lexer.rb +345 -1467
- data/lib/graphql/language/nodes.rb +145 -91
- data/lib/graphql/language/parser.rb +701 -1921
- data/lib/graphql/language/printer.rb +351 -155
- data/lib/graphql/language/sanitized_printer.rb +25 -27
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/language/visitor.rb +188 -141
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/name_validator.rb +0 -4
- data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
- data/lib/graphql/pagination/array_connection.rb +8 -6
- data/lib/graphql/pagination/connection.rb +61 -7
- data/lib/graphql/pagination/connections.rb +22 -23
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +60 -28
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +109 -189
- data/lib/graphql/query/input_validation_result.rb +10 -1
- data/lib/graphql/query/null_context.rb +14 -29
- data/lib/graphql/query/validation_pipeline.rb +15 -39
- data/lib/graphql/query/variable_validation_error.rb +2 -2
- data/lib/graphql/query/variables.rb +35 -17
- data/lib/graphql/query.rb +78 -65
- data/lib/graphql/railtie.rb +8 -109
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +30 -11
- data/lib/graphql/relay/range_add.rb +9 -16
- data/lib/graphql/relay.rb +0 -15
- 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/schema/addition.rb +78 -45
- data/lib/graphql/schema/always_visible.rb +10 -0
- data/lib/graphql/schema/argument.rb +134 -80
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +60 -38
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +2 -2
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +2 -2
- data/lib/graphql/schema/directive.rb +33 -21
- data/lib/graphql/schema/enum.rb +93 -46
- data/lib/graphql/schema/enum_value.rb +4 -21
- data/lib/graphql/schema/field/connection_extension.rb +6 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +432 -337
- data/lib/graphql/schema/field_extension.rb +86 -2
- data/lib/graphql/schema/find_inherited_value.rb +3 -7
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/has_single_input_argument.rb +156 -0
- data/lib/graphql/schema/input_object.rb +88 -90
- data/lib/graphql/schema/interface.rb +19 -59
- data/lib/graphql/schema/introspection_system.rb +6 -9
- data/lib/graphql/schema/late_bound_type.rb +8 -2
- data/lib/graphql/schema/list.rb +18 -7
- data/lib/graphql/schema/loader.rb +3 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -19
- data/lib/graphql/schema/member/build_type.rb +16 -13
- data/lib/graphql/schema/member/has_arguments.rb +288 -84
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +149 -31
- data/lib/graphql/schema/member/has_interfaces.rb +143 -0
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
- data/lib/graphql/schema/member/validates_input.rb +6 -6
- data/lib/graphql/schema/member.rb +1 -6
- data/lib/graphql/schema/mutation.rb +0 -9
- data/lib/graphql/schema/non_null.rb +7 -7
- data/lib/graphql/schema/object.rb +30 -119
- data/lib/graphql/schema/printer.rb +23 -25
- data/lib/graphql/schema/relay_classic_mutation.rb +13 -90
- data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
- data/lib/graphql/schema/resolver.rb +101 -102
- data/lib/graphql/schema/scalar.rb +20 -21
- data/lib/graphql/schema/subscription.rb +45 -17
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +21 -4
- data/lib/graphql/schema/union.rb +15 -15
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- 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 +3 -1
- data/lib/graphql/schema/validator/format_validator.rb +4 -5
- data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/length_validator.rb +5 -3
- data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
- data/lib/graphql/schema/validator/required_validator.rb +29 -15
- data/lib/graphql/schema/validator.rb +35 -27
- data/lib/graphql/schema/warden.rb +259 -132
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +658 -989
- data/lib/graphql/static_validation/all_rules.rb +3 -1
- data/lib/graphql/static_validation/base_visitor.rb +14 -28
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +21 -4
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +13 -13
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +54 -28
- 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/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +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 +5 -3
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
- data/lib/graphql/static_validation/validation_context.rb +16 -6
- data/lib/graphql/static_validation/validator.rb +11 -27
- data/lib/graphql/static_validation.rb +0 -3
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +46 -9
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
- data/lib/graphql/subscriptions/event.rb +75 -37
- data/lib/graphql/subscriptions/serialize.rb +25 -3
- data/lib/graphql/subscriptions.rb +59 -47
- data/lib/graphql/testing/helpers.rb +129 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
- data/lib/graphql/tracing/appoptics_trace.rb +251 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
- data/lib/graphql/tracing/data_dog_trace.rb +183 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +25 -15
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
- data/lib/graphql/tracing/legacy_trace.rb +69 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +45 -0
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_trace.rb +118 -0
- data/lib/graphql/tracing/platform_tracing.rb +46 -49
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/trace.rb +76 -0
- data/lib/graphql/tracing.rb +20 -41
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/big_int.rb +5 -1
- data/lib/graphql/types/int.rb +1 -1
- data/lib/graphql/types/iso_8601_date.rb +17 -6
- data/lib/graphql/types/iso_8601_date_time.rb +12 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +16 -6
- data/lib/graphql/types/relay/connection_behaviors.rb +82 -32
- data/lib/graphql/types/relay/edge_behaviors.rb +36 -7
- data/lib/graphql/types/relay/has_node_field.rb +2 -2
- data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
- data/lib/graphql/types/relay/node_behaviors.rb +12 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
- data/lib/graphql/types/relay.rb +0 -3
- data/lib/graphql/types/string.rb +2 -2
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +33 -95
- data/readme.md +13 -6
- metadata +102 -185
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/field_usage.rb +0 -45
- data/lib/graphql/analysis/max_query_complexity.rb +0 -26
- data/lib/graphql/analysis/max_query_depth.rb +0 -26
- data/lib/graphql/analysis/query_complexity.rb +0 -88
- data/lib/graphql/analysis/query_depth.rb +0 -43
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -230
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -240
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -47
- data/lib/graphql/deprecation.rb +0 -13
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -111
- data/lib/graphql/enum_type.rb +0 -129
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -262
- data/lib/graphql/language/parser.y +0 -543
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -41
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -40
- data/lib/graphql/relay/global_id_resolve.rb +0 -18
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/member/accepts_definition.rb +0 -152
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/instrumentation.rb +0 -79
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/default_relay.rb +0 -27
- data/lib/graphql/types/relay/node_field.rb +0 -25
- data/lib/graphql/types/relay/nodes_field.rb +0 -27
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
data/lib/graphql/schema/field.rb
CHANGED
@@ -5,21 +5,18 @@ require "graphql/schema/field/scope_extension"
|
|
5
5
|
module GraphQL
|
6
6
|
class Schema
|
7
7
|
class Field
|
8
|
-
if !String.method_defined?(:-@)
|
9
|
-
using GraphQL::StringDedupBackport
|
10
|
-
end
|
11
|
-
|
12
|
-
include GraphQL::Schema::Member::CachedGraphQLDefinition
|
13
|
-
include GraphQL::Schema::Member::AcceptsDefinition
|
14
8
|
include GraphQL::Schema::Member::HasArguments
|
9
|
+
include GraphQL::Schema::Member::HasArguments::FieldConfigured
|
15
10
|
include GraphQL::Schema::Member::HasAstNode
|
16
11
|
include GraphQL::Schema::Member::HasPath
|
17
12
|
include GraphQL::Schema::Member::HasValidators
|
18
13
|
extend GraphQL::Schema::FindInheritedValue
|
19
|
-
include GraphQL::
|
14
|
+
include GraphQL::EmptyObjects
|
20
15
|
include GraphQL::Schema::Member::HasDirectives
|
21
16
|
include GraphQL::Schema::Member::HasDeprecationReason
|
22
17
|
|
18
|
+
class FieldImplementationFailed < GraphQL::Error; end
|
19
|
+
|
23
20
|
# @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
|
24
21
|
attr_reader :name
|
25
22
|
alias :graphql_name :name
|
@@ -32,15 +29,26 @@ module GraphQL
|
|
32
29
|
# @return [String] Method or hash key on the underlying object to look up
|
33
30
|
attr_reader :method_str
|
34
31
|
|
32
|
+
attr_reader :hash_key
|
33
|
+
attr_reader :dig_keys
|
34
|
+
|
35
35
|
# @return [Symbol] The method on the type to look up
|
36
|
-
|
36
|
+
def resolver_method
|
37
|
+
if @resolver_class
|
38
|
+
@resolver_class.resolver_method
|
39
|
+
else
|
40
|
+
@resolver_method
|
41
|
+
end
|
42
|
+
end
|
37
43
|
|
38
44
|
# @return [Class] The thing this field was defined on (type, mutation, resolver)
|
39
45
|
attr_accessor :owner
|
40
46
|
|
41
47
|
# @return [Class] The GraphQL type this field belongs to. (For fields defined on mutations, it's the payload type)
|
42
48
|
def owner_type
|
43
|
-
@owner_type ||= if owner
|
49
|
+
@owner_type ||= if owner.nil?
|
50
|
+
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?!"
|
51
|
+
elsif owner < GraphQL::Schema::Mutation
|
44
52
|
owner.payload_type
|
45
53
|
else
|
46
54
|
owner
|
@@ -61,7 +69,7 @@ module GraphQL
|
|
61
69
|
end
|
62
70
|
|
63
71
|
def inspect
|
64
|
-
"#<#{self.class} #{path}#{
|
72
|
+
"#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
|
65
73
|
end
|
66
74
|
|
67
75
|
alias :mutation :resolver
|
@@ -70,7 +78,10 @@ module GraphQL
|
|
70
78
|
attr_reader :trace
|
71
79
|
|
72
80
|
# @return [String, nil]
|
73
|
-
|
81
|
+
def subscription_scope
|
82
|
+
@subscription_scope || (@resolver_class.respond_to?(:subscription_scope) ? @resolver_class.subscription_scope : nil)
|
83
|
+
end
|
84
|
+
attr_writer :subscription_scope
|
74
85
|
|
75
86
|
# Create a field instance from a list of arguments, keyword arguments, and a block.
|
76
87
|
#
|
@@ -81,24 +92,12 @@ module GraphQL
|
|
81
92
|
# @param resolver [Class] A {GraphQL::Schema::Resolver} class to use for field configuration
|
82
93
|
# @param mutation [Class] A {GraphQL::Schema::Mutation} class to use for field configuration
|
83
94
|
# @param subscription [Class] A {GraphQL::Schema::Subscription} class to use for field configuration
|
84
|
-
# @return [GraphQL::Schema:Field] an instance of `self
|
95
|
+
# @return [GraphQL::Schema:Field] an instance of `self`
|
85
96
|
# @see {.initialize} for other options
|
86
97
|
def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
|
87
|
-
if
|
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.")
|
90
|
-
return GraphQL::Types::Relay::NodeField
|
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.")
|
93
|
-
return GraphQL::Types::Relay::NodesField
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
if (parent_config = resolver || mutation || subscription)
|
98
|
-
# Get the parent config, merge in local overrides
|
99
|
-
kwargs = parent_config.field_options.merge(kwargs)
|
98
|
+
if (resolver_class = resolver || mutation || subscription)
|
100
99
|
# Add a reference to that parent class
|
101
|
-
kwargs[:resolver_class] =
|
100
|
+
kwargs[:resolver_class] = resolver_class
|
102
101
|
end
|
103
102
|
|
104
103
|
if name
|
@@ -106,9 +105,6 @@ module GraphQL
|
|
106
105
|
end
|
107
106
|
|
108
107
|
if !type.nil?
|
109
|
-
if type.is_a?(GraphQL::Field)
|
110
|
-
raise ArgumentError, "A GraphQL::Field was passed as the second argument, use the `field:` keyword for this instead."
|
111
|
-
end
|
112
108
|
if desc
|
113
109
|
if kwargs[:description]
|
114
110
|
raise ArgumentError, "Provide description as a positional argument or `description:` keyword, but not both (#{desc.inspect}, #{kwargs[:description].inspect})"
|
@@ -116,12 +112,15 @@ module GraphQL
|
|
116
112
|
|
117
113
|
kwargs[:description] = desc
|
118
114
|
kwargs[:type] = type
|
119
|
-
elsif (
|
120
|
-
# The return type should be copied from
|
115
|
+
elsif (resolver || mutation) && type.is_a?(String)
|
116
|
+
# The return type should be copied from the resolver, and the second positional argument is the description
|
121
117
|
kwargs[:description] = type
|
122
118
|
else
|
123
119
|
kwargs[:type] = type
|
124
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
|
125
124
|
end
|
126
125
|
new(**kwargs, &block)
|
127
126
|
end
|
@@ -131,15 +130,15 @@ module GraphQL
|
|
131
130
|
def connection?
|
132
131
|
if @connection.nil?
|
133
132
|
# Provide default based on type name
|
134
|
-
return_type_name = if
|
135
|
-
Member::BuildType.to_type_name(contains_type.type)
|
136
|
-
elsif @return_type_expr
|
133
|
+
return_type_name = if @return_type_expr
|
137
134
|
Member::BuildType.to_type_name(@return_type_expr)
|
135
|
+
elsif @resolver_class && @resolver_class.type
|
136
|
+
Member::BuildType.to_type_name(@resolver_class.type)
|
138
137
|
else
|
139
138
|
# As a last ditch, try to force loading the return type:
|
140
139
|
type.unwrap.name
|
141
140
|
end
|
142
|
-
@connection = return_type_name.end_with?("Connection")
|
141
|
+
@connection = return_type_name.end_with?("Connection") && return_type_name != "Connection"
|
143
142
|
else
|
144
143
|
@connection
|
145
144
|
end
|
@@ -150,8 +149,18 @@ module GraphQL
|
|
150
149
|
if !@scope.nil?
|
151
150
|
# The default was overridden
|
152
151
|
@scope
|
152
|
+
elsif @return_type_expr
|
153
|
+
# Detect a list return type, but don't call `type` since that may eager-load an otherwise lazy-loaded type
|
154
|
+
@return_type_expr.is_a?(Array) ||
|
155
|
+
(@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) ||
|
156
|
+
connection?
|
157
|
+
elsif @resolver_class
|
158
|
+
resolver_type = @resolver_class.type_expr
|
159
|
+
resolver_type.is_a?(Array) ||
|
160
|
+
(resolver_type.is_a?(String) && resolver_type.include?("[")) ||
|
161
|
+
connection?
|
153
162
|
else
|
154
|
-
|
163
|
+
false
|
155
164
|
end
|
156
165
|
end
|
157
166
|
|
@@ -173,6 +182,8 @@ module GraphQL
|
|
173
182
|
|
174
183
|
# @return Boolean
|
175
184
|
attr_reader :relay_node_field
|
185
|
+
# @return Boolean
|
186
|
+
attr_reader :relay_nodes_field
|
176
187
|
|
177
188
|
# @return [Boolean] Should we warn if this field's name conflicts with a built-in method?
|
178
189
|
def method_conflict_warning?
|
@@ -182,19 +193,18 @@ module GraphQL
|
|
182
193
|
# @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
|
183
194
|
# @param type [Class, GraphQL::BaseType, Array] The return type of this field
|
184
195
|
# @param owner [Class] The type that this field belongs to
|
185
|
-
# @param null [Boolean] `true` if this field may return `null`, `false` if it is never `null`
|
196
|
+
# @param null [Boolean] (defaults to `true`) `true` if this field may return `null`, `false` if it is never `null`
|
186
197
|
# @param description [String] Field description
|
187
198
|
# @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
|
188
199
|
# @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
|
189
200
|
# @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`)
|
201
|
+
# @param dig [Array<String, Symbol>] The nested hash keys to lookup on the underlying hash to resolve this field using dig
|
190
202
|
# @param resolver_method [Symbol] The method on the type to call to resolve this field (defaults to `name`)
|
191
203
|
# @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
|
192
204
|
# @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
|
193
205
|
# @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
|
206
|
+
# @param default_page_size [Integer, nil] For connections, the default number of items to return from this field, or `nil` to return unlimited results.
|
194
207
|
# @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
|
195
|
-
# @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
|
196
|
-
# @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
|
197
|
-
# @param function [GraphQL::Function] **deprecated** for compatibility with <1.8.0
|
198
208
|
# @param resolver_class [Class] (Private) A {Schema::Resolver} which this field was derived from. Use `resolver:` to create a field with a resolver.
|
199
209
|
# @param arguments [{String=>GraphQL::Schema::Argument, Hash}] Arguments for this field (may be added in the block, also)
|
200
210
|
# @param camelize [Boolean] If true, the field name will be camelized when building the schema
|
@@ -208,38 +218,29 @@ module GraphQL
|
|
208
218
|
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
209
219
|
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
210
220
|
# @param validates [Array<Hash>] Configurations for validating this field
|
211
|
-
# @param
|
212
|
-
def initialize(type: nil, name: nil, owner: nil, null: nil,
|
221
|
+
# @param fallback_value [Object] A fallback value if the method is not defined
|
222
|
+
def initialize(type: nil, name: nil, owner: nil, null: nil, description: NOT_CONFIGURED, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, 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: NOT_CONFIGURED, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: NOT_CONFIGURED, dynamic_introspection: false, &definition_block)
|
213
223
|
if name.nil?
|
214
224
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
215
225
|
end
|
216
|
-
if !(
|
226
|
+
if !(resolver_class)
|
217
227
|
if type.nil?
|
218
228
|
raise ArgumentError, "missing second `type` argument or keyword `type:`"
|
219
229
|
end
|
220
|
-
if null.nil?
|
221
|
-
raise ArgumentError, "missing keyword argument null:"
|
222
|
-
end
|
223
|
-
end
|
224
|
-
if (field || function || resolve) && extras.any?
|
225
|
-
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:`"
|
226
230
|
end
|
227
231
|
@original_name = name
|
228
232
|
name_s = -name.to_s
|
233
|
+
|
229
234
|
@underscored_name = -Member::BuildType.underscore(name_s)
|
230
235
|
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
236
|
+
|
231
237
|
@description = description
|
232
|
-
if
|
233
|
-
|
234
|
-
else
|
235
|
-
@field = field
|
236
|
-
end
|
237
|
-
@function = function
|
238
|
-
@resolve = resolve
|
238
|
+
@type = @owner_type = @own_validators = @own_directives = @own_arguments = @arguments_statically_coercible = nil # these will be prepared later if necessary
|
239
|
+
|
239
240
|
self.deprecation_reason = deprecation_reason
|
240
241
|
|
241
|
-
if method && hash_key
|
242
|
-
raise ArgumentError, "Provide `method:` _or_ `
|
242
|
+
if method && hash_key && dig
|
243
|
+
raise ArgumentError, "Provide `method:`, `hash_key:` _or_ `dig:`, not multiple. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}, dig: #{dig.inspect}`)"
|
243
244
|
end
|
244
245
|
|
245
246
|
if resolver_method
|
@@ -247,24 +248,37 @@ module GraphQL
|
|
247
248
|
raise ArgumentError, "Provide `method:` _or_ `resolver_method:`, not both. (called with: `method: #{method.inspect}, resolver_method: #{resolver_method.inspect}`)"
|
248
249
|
end
|
249
250
|
|
250
|
-
if hash_key
|
251
|
-
raise ArgumentError, "Provide `hash_key
|
251
|
+
if hash_key || dig
|
252
|
+
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}`)"
|
252
253
|
end
|
253
254
|
end
|
254
255
|
|
255
|
-
# TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
|
256
256
|
method_name = method || hash_key || name_s
|
257
|
-
|
257
|
+
@dig_keys = dig
|
258
|
+
if hash_key
|
259
|
+
@hash_key = hash_key
|
260
|
+
@hash_key_str = hash_key.to_s
|
261
|
+
else
|
262
|
+
@hash_key = NOT_CONFIGURED
|
263
|
+
@hash_key_str = NOT_CONFIGURED
|
264
|
+
end
|
258
265
|
|
259
266
|
@method_str = -method_name.to_s
|
260
267
|
@method_sym = method_name.to_sym
|
261
|
-
@resolver_method = resolver_method
|
268
|
+
@resolver_method = (resolver_method || name_s).to_sym
|
262
269
|
@complexity = complexity
|
270
|
+
@dynamic_introspection = dynamic_introspection
|
263
271
|
@return_type_expr = type
|
264
|
-
@return_type_null = null
|
272
|
+
@return_type_null = if !null.nil?
|
273
|
+
null
|
274
|
+
elsif resolver_class
|
275
|
+
nil
|
276
|
+
else
|
277
|
+
true
|
278
|
+
end
|
265
279
|
@connection = connection
|
266
|
-
@
|
267
|
-
@
|
280
|
+
@max_page_size = max_page_size
|
281
|
+
@default_page_size = default_page_size
|
268
282
|
@introspection = introspection
|
269
283
|
@extras = extras
|
270
284
|
@broadcastable = broadcastable
|
@@ -275,13 +289,18 @@ module GraphQL
|
|
275
289
|
@relay_nodes_field = relay_nodes_field
|
276
290
|
@ast_node = ast_node
|
277
291
|
@method_conflict_warning = method_conflict_warning
|
278
|
-
@
|
292
|
+
@fallback_value = fallback_value
|
279
293
|
|
280
294
|
arguments.each do |name, arg|
|
281
|
-
|
295
|
+
case arg
|
296
|
+
when Hash
|
282
297
|
argument(name: name, **arg)
|
283
|
-
|
298
|
+
when GraphQL::Schema::Argument
|
284
299
|
add_argument(arg)
|
300
|
+
when Array
|
301
|
+
arg.each { |a| add_argument(a) }
|
302
|
+
else
|
303
|
+
raise ArgumentError, "Unexpected argument config (#{arg.class}): #{arg.inspect}"
|
285
304
|
end
|
286
305
|
end
|
287
306
|
|
@@ -289,6 +308,7 @@ module GraphQL
|
|
289
308
|
@subscription_scope = subscription_scope
|
290
309
|
|
291
310
|
@extensions = EMPTY_ARRAY
|
311
|
+
@call_after_define = false
|
292
312
|
# This should run before connection extension,
|
293
313
|
# but should it run after the definition block?
|
294
314
|
if scoped?
|
@@ -306,28 +326,45 @@ module GraphQL
|
|
306
326
|
self.extensions(extensions)
|
307
327
|
end
|
308
328
|
|
329
|
+
if resolver_class && resolver_class.extensions.any?
|
330
|
+
self.extensions(resolver_class.extensions)
|
331
|
+
end
|
332
|
+
|
309
333
|
if directives.any?
|
310
334
|
directives.each do |(dir_class, options)|
|
311
335
|
self.directive(dir_class, **options)
|
312
336
|
end
|
313
337
|
end
|
314
338
|
|
315
|
-
|
339
|
+
if !validates.empty?
|
340
|
+
self.validates(validates)
|
341
|
+
end
|
316
342
|
|
317
|
-
if
|
343
|
+
if block_given?
|
318
344
|
if definition_block.arity == 1
|
319
345
|
yield self
|
320
346
|
else
|
321
347
|
instance_eval(&definition_block)
|
322
348
|
end
|
323
349
|
end
|
350
|
+
|
351
|
+
self.extensions.each(&:after_define_apply)
|
352
|
+
@call_after_define = true
|
324
353
|
end
|
325
354
|
|
355
|
+
attr_accessor :dynamic_introspection
|
356
|
+
|
326
357
|
# If true, subscription updates with this field can be shared between viewers
|
327
358
|
# @return [Boolean, nil]
|
328
359
|
# @see GraphQL::Subscriptions::BroadcastAnalyzer
|
329
360
|
def broadcastable?
|
330
|
-
@broadcastable
|
361
|
+
if !NOT_CONFIGURED.equal?(@broadcastable)
|
362
|
+
@broadcastable
|
363
|
+
elsif @resolver_class
|
364
|
+
@resolver_class.broadcastable?
|
365
|
+
else
|
366
|
+
nil
|
367
|
+
end
|
331
368
|
end
|
332
369
|
|
333
370
|
# @param text [String]
|
@@ -335,8 +372,12 @@ module GraphQL
|
|
335
372
|
def description(text = nil)
|
336
373
|
if text
|
337
374
|
@description = text
|
338
|
-
|
375
|
+
elsif !NOT_CONFIGURED.equal?(@description)
|
339
376
|
@description
|
377
|
+
elsif @resolver_class
|
378
|
+
@resolver_class.description
|
379
|
+
else
|
380
|
+
nil
|
340
381
|
end
|
341
382
|
end
|
342
383
|
|
@@ -353,27 +394,20 @@ module GraphQL
|
|
353
394
|
# @example adding an extension with options
|
354
395
|
# extensions([MyExtensionClass, { AnotherExtensionClass => { filter: true } }])
|
355
396
|
#
|
356
|
-
# @param extensions [Array<Class, Hash<Class =>
|
397
|
+
# @param extensions [Array<Class, Hash<Class => Hash>>] Add extensions to this field. For hash elements, only the first key/value is used.
|
357
398
|
# @return [Array<GraphQL::Schema::FieldExtension>] extensions to apply to this field
|
358
399
|
def extensions(new_extensions = nil)
|
359
|
-
if new_extensions
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
@extensions = @extensions.dup
|
365
|
-
end
|
366
|
-
new_extensions.each do |extension|
|
367
|
-
if extension.is_a?(Hash)
|
368
|
-
extension = extension.to_a[0]
|
369
|
-
extension_class, options = *extension
|
370
|
-
@extensions << extension_class.new(field: self, options: options)
|
400
|
+
if new_extensions
|
401
|
+
new_extensions.each do |extension_config|
|
402
|
+
if extension_config.is_a?(Hash)
|
403
|
+
extension_class, options = *extension_config.to_a[0]
|
404
|
+
self.extension(extension_class, options)
|
371
405
|
else
|
372
|
-
|
373
|
-
@extensions << extension_class.new(field: self, options: nil)
|
406
|
+
self.extension(extension_config)
|
374
407
|
end
|
375
408
|
end
|
376
409
|
end
|
410
|
+
@extensions
|
377
411
|
end
|
378
412
|
|
379
413
|
# Add `extension` to this field, initialized with `options` if provided.
|
@@ -384,10 +418,19 @@ module GraphQL
|
|
384
418
|
# @example adding an extension with options
|
385
419
|
# extension(MyExtensionClass, filter: true)
|
386
420
|
#
|
387
|
-
# @param
|
388
|
-
# @param options [
|
389
|
-
|
390
|
-
|
421
|
+
# @param extension_class [Class] subclass of {Schema::FieldExtension}
|
422
|
+
# @param options [Hash] if provided, given as `options:` when initializing `extension`.
|
423
|
+
# @return [void]
|
424
|
+
def extension(extension_class, options = nil)
|
425
|
+
extension_inst = extension_class.new(field: self, options: options)
|
426
|
+
if @extensions.frozen?
|
427
|
+
@extensions = @extensions.dup
|
428
|
+
end
|
429
|
+
if @call_after_define
|
430
|
+
extension_inst.after_define_apply
|
431
|
+
end
|
432
|
+
@extensions << extension_inst
|
433
|
+
nil
|
391
434
|
end
|
392
435
|
|
393
436
|
# Read extras (as symbols) from this field,
|
@@ -398,7 +441,12 @@ module GraphQL
|
|
398
441
|
def extras(new_extras = nil)
|
399
442
|
if new_extras.nil?
|
400
443
|
# Read the value
|
401
|
-
@extras
|
444
|
+
field_extras = @extras
|
445
|
+
if @resolver_class && @resolver_class.extras.any?
|
446
|
+
field_extras + @resolver_class.extras
|
447
|
+
else
|
448
|
+
field_extras
|
449
|
+
end
|
402
450
|
else
|
403
451
|
if @extras.frozen?
|
404
452
|
@extras = @extras.dup
|
@@ -408,6 +456,56 @@ module GraphQL
|
|
408
456
|
end
|
409
457
|
end
|
410
458
|
|
459
|
+
def calculate_complexity(query:, nodes:, child_complexity:)
|
460
|
+
if respond_to?(:complexity_for)
|
461
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
462
|
+
complexity_for(child_complexity: child_complexity, query: query, lookahead: lookahead)
|
463
|
+
elsif connection?
|
464
|
+
arguments = query.arguments_for(nodes.first, self)
|
465
|
+
max_possible_page_size = nil
|
466
|
+
if arguments.respond_to?(:[]) # It might have been an error
|
467
|
+
if arguments[:first]
|
468
|
+
max_possible_page_size = arguments[:first]
|
469
|
+
end
|
470
|
+
|
471
|
+
if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
|
472
|
+
max_possible_page_size = arguments[:last]
|
473
|
+
end
|
474
|
+
elsif arguments.is_a?(GraphQL::UnauthorizedError)
|
475
|
+
raise arguments
|
476
|
+
end
|
477
|
+
|
478
|
+
if max_possible_page_size.nil?
|
479
|
+
max_possible_page_size = default_page_size || query.schema.default_page_size || max_page_size || query.schema.default_max_page_size
|
480
|
+
end
|
481
|
+
|
482
|
+
if max_possible_page_size.nil?
|
483
|
+
raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `default_page_size`, `max_page_size` or `default_max_page_size`"
|
484
|
+
else
|
485
|
+
metadata_complexity = 0
|
486
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
487
|
+
|
488
|
+
lookahead.selections.each do |next_lookahead|
|
489
|
+
# this includes `pageInfo`, `nodes` and `edges` and any custom fields
|
490
|
+
# TODO this doesn't support procs yet -- unlikely to need it.
|
491
|
+
metadata_complexity += next_lookahead.field.complexity
|
492
|
+
if next_lookahead.name != :nodes && next_lookahead.name != :edges
|
493
|
+
# subfields, eg, for pageInfo -- assumes no subselections
|
494
|
+
metadata_complexity += next_lookahead.selections.size
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
499
|
+
items_complexity = child_complexity - metadata_complexity
|
500
|
+
subfields_complexity = (max_possible_page_size * items_complexity) + metadata_complexity
|
501
|
+
# Apply this field's own complexity
|
502
|
+
apply_own_complexity_to(subfields_complexity, query, nodes)
|
503
|
+
end
|
504
|
+
else
|
505
|
+
apply_own_complexity_to(child_complexity, query, nodes)
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
411
509
|
def complexity(new_complexity = nil)
|
412
510
|
case new_complexity
|
413
511
|
when Proc
|
@@ -422,7 +520,11 @@ module GraphQL
|
|
422
520
|
when Numeric
|
423
521
|
@complexity = new_complexity
|
424
522
|
when nil
|
425
|
-
@
|
523
|
+
if @resolver_class
|
524
|
+
@complexity || @resolver_class.complexity || 1
|
525
|
+
else
|
526
|
+
@complexity || 1
|
527
|
+
end
|
426
528
|
else
|
427
529
|
raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
|
428
530
|
end
|
@@ -430,101 +532,55 @@ module GraphQL
|
|
430
532
|
|
431
533
|
# @return [Boolean] True if this field's {#max_page_size} should override the schema default.
|
432
534
|
def has_max_page_size?
|
433
|
-
@has_max_page_size
|
535
|
+
!NOT_CONFIGURED.equal?(@max_page_size) || (@resolver_class && @resolver_class.has_max_page_size?)
|
434
536
|
end
|
435
537
|
|
436
538
|
# @return [Integer, nil] Applied to connections if {#has_max_page_size?}
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
@field.dup
|
443
|
-
elsif @function
|
444
|
-
GraphQL::Function.build_field(@function)
|
539
|
+
def max_page_size
|
540
|
+
if !NOT_CONFIGURED.equal?(@max_page_size)
|
541
|
+
@max_page_size
|
542
|
+
elsif @resolver_class && @resolver_class.has_max_page_size?
|
543
|
+
@resolver_class.max_page_size
|
445
544
|
else
|
446
|
-
|
447
|
-
end
|
448
|
-
|
449
|
-
field_defn.name = @name
|
450
|
-
if @return_type_expr
|
451
|
-
field_defn.type = -> { type }
|
452
|
-
end
|
453
|
-
|
454
|
-
if @description
|
455
|
-
field_defn.description = @description
|
456
|
-
end
|
457
|
-
|
458
|
-
if self.deprecation_reason
|
459
|
-
field_defn.deprecation_reason = self.deprecation_reason
|
460
|
-
end
|
461
|
-
|
462
|
-
if @resolver_class
|
463
|
-
if @resolver_class < GraphQL::Schema::Mutation
|
464
|
-
field_defn.mutation = @resolver_class
|
465
|
-
end
|
466
|
-
field_defn.metadata[:resolver] = @resolver_class
|
467
|
-
end
|
468
|
-
|
469
|
-
if !@trace.nil?
|
470
|
-
field_defn.trace = @trace
|
471
|
-
end
|
472
|
-
|
473
|
-
if @relay_node_field
|
474
|
-
field_defn.relay_node_field = @relay_node_field
|
475
|
-
end
|
476
|
-
|
477
|
-
if @relay_nodes_field
|
478
|
-
field_defn.relay_nodes_field = @relay_nodes_field
|
545
|
+
nil
|
479
546
|
end
|
547
|
+
end
|
480
548
|
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
field_defn.resolve = self.method(:resolve_field)
|
486
|
-
field_defn.connection = connection?
|
487
|
-
field_defn.connection_max_page_size = max_page_size
|
488
|
-
field_defn.introspection = @introspection
|
489
|
-
field_defn.complexity = @complexity
|
490
|
-
field_defn.subscription_scope = @subscription_scope
|
491
|
-
field_defn.ast_node = ast_node
|
492
|
-
|
493
|
-
arguments.each do |name, defn|
|
494
|
-
arg_graphql = defn.to_graphql
|
495
|
-
field_defn.arguments[arg_graphql.name] = arg_graphql
|
496
|
-
end
|
549
|
+
# @return [Boolean] True if this field's {#default_page_size} should override the schema default.
|
550
|
+
def has_default_page_size?
|
551
|
+
!NOT_CONFIGURED.equal?(@default_page_size) || (@resolver_class && @resolver_class.has_default_page_size?)
|
552
|
+
end
|
497
553
|
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
554
|
+
# @return [Integer, nil] Applied to connections if {#has_default_page_size?}
|
555
|
+
def default_page_size
|
556
|
+
if !NOT_CONFIGURED.equal?(@default_page_size)
|
557
|
+
@default_page_size
|
558
|
+
elsif @resolver_class && @resolver_class.has_default_page_size?
|
559
|
+
@resolver_class.default_page_size
|
560
|
+
else
|
561
|
+
nil
|
505
562
|
end
|
506
|
-
|
507
|
-
# Ok, `self` isn't a class, but this is for consistency with the classes
|
508
|
-
field_defn.metadata[:type_class] = self
|
509
|
-
field_defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(field_defn)
|
510
|
-
field_defn
|
511
563
|
end
|
512
564
|
|
565
|
+
class MissingReturnTypeError < GraphQL::Error; end
|
513
566
|
attr_writer :type
|
514
567
|
|
515
568
|
def type
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
569
|
+
if @resolver_class
|
570
|
+
return_type = @return_type_expr || @resolver_class.type_expr
|
571
|
+
if return_type.nil?
|
572
|
+
raise MissingReturnTypeError, "Can't determine the return type for #{self.path} (it has `resolver: #{@resolver_class}`, perhaps that class is missing a `type ...` declaration, or perhaps its type causes a cyclical loading issue)"
|
573
|
+
end
|
574
|
+
nullable = @return_type_null.nil? ? @resolver_class.null : @return_type_null
|
575
|
+
Member::BuildType.parse_type(return_type, null: nullable)
|
520
576
|
else
|
521
|
-
Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
577
|
+
@type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
522
578
|
end
|
523
|
-
rescue GraphQL::Schema::InvalidDocumentError => err
|
579
|
+
rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
|
524
580
|
# Let this propagate up
|
525
581
|
raise err
|
526
582
|
rescue StandardError => err
|
527
|
-
raise
|
583
|
+
raise MissingReturnTypeError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: (#{err.class}) #{err.message}", err.backtrace
|
528
584
|
end
|
529
585
|
|
530
586
|
def visible?(context)
|
@@ -535,57 +591,47 @@ module GraphQL
|
|
535
591
|
end
|
536
592
|
end
|
537
593
|
|
538
|
-
def accessible?(context)
|
539
|
-
if @resolver_class
|
540
|
-
@resolver_class.accessible?(context)
|
541
|
-
else
|
542
|
-
true
|
543
|
-
end
|
544
|
-
end
|
545
|
-
|
546
594
|
def authorized?(object, args, context)
|
547
595
|
if @resolver_class
|
548
|
-
# The resolver will check itself during `resolve()`
|
596
|
+
# The resolver _instance_ will check itself during `resolve()`
|
549
597
|
@resolver_class.authorized?(object, context)
|
550
598
|
else
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
599
|
+
if args.size > 0
|
600
|
+
if (arg_values = context[:current_arguments])
|
601
|
+
# ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
|
602
|
+
using_arg_values = true
|
603
|
+
arg_values = arg_values.argument_values
|
604
|
+
else
|
605
|
+
arg_values = args
|
606
|
+
using_arg_values = false
|
555
607
|
end
|
556
|
-
end
|
557
|
-
true
|
558
|
-
end
|
559
|
-
end
|
560
608
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
609
|
+
args = context.warden.arguments(self)
|
610
|
+
args.each do |arg|
|
611
|
+
arg_key = arg.keyword
|
612
|
+
if arg_values.key?(arg_key)
|
613
|
+
arg_value = arg_values[arg_key]
|
614
|
+
if using_arg_values
|
615
|
+
if arg_value.default_used?
|
616
|
+
# pass -- no auth required for default used
|
617
|
+
next
|
618
|
+
else
|
619
|
+
application_arg_value = arg_value.value
|
620
|
+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
|
621
|
+
application_arg_value.keyword_arguments
|
622
|
+
end
|
623
|
+
end
|
624
|
+
else
|
625
|
+
application_arg_value = arg_value
|
626
|
+
end
|
627
|
+
|
628
|
+
if !arg.authorized?(object, application_arg_value, context)
|
629
|
+
return false
|
580
630
|
end
|
581
|
-
else
|
582
|
-
public_send_field(after_obj, ruby_args, query_ctx)
|
583
631
|
end
|
584
|
-
else
|
585
|
-
err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
|
586
|
-
query_ctx.schema.unauthorized_field(err)
|
587
632
|
end
|
588
633
|
end
|
634
|
+
true
|
589
635
|
end
|
590
636
|
end
|
591
637
|
|
@@ -594,35 +640,112 @@ module GraphQL
|
|
594
640
|
# @param object [GraphQL::Schema::Object] An instance of some type class, wrapping an application object
|
595
641
|
# @param args [Hash] A symbol-keyed hash of Ruby keyword arguments. (Empty if no args)
|
596
642
|
# @param ctx [GraphQL::Query::Context]
|
597
|
-
def resolve(object, args,
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
643
|
+
def resolve(object, args, query_ctx)
|
644
|
+
# Unwrap the GraphQL object to get the application object.
|
645
|
+
application_object = object.object
|
646
|
+
method_receiver = nil
|
647
|
+
method_to_call = nil
|
648
|
+
method_args = nil
|
649
|
+
|
650
|
+
@own_validators && Schema::Validator.validate!(validators, application_object, query_ctx, args)
|
651
|
+
|
652
|
+
query_ctx.query.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
|
653
|
+
if is_authorized
|
654
|
+
with_extensions(object, args, query_ctx) do |obj, ruby_kwargs|
|
655
|
+
method_args = ruby_kwargs
|
656
|
+
if @resolver_class
|
657
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
658
|
+
obj = obj.object
|
659
|
+
end
|
660
|
+
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
661
|
+
end
|
604
662
|
|
605
|
-
|
663
|
+
inner_object = obj.object
|
606
664
|
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
665
|
+
if !NOT_CONFIGURED.equal?(@hash_key)
|
666
|
+
hash_value = if inner_object.is_a?(Hash)
|
667
|
+
inner_object.key?(@hash_key) ? inner_object[@hash_key] : inner_object[@hash_key_str]
|
668
|
+
elsif inner_object.respond_to?(:[])
|
669
|
+
inner_object[@hash_key]
|
670
|
+
else
|
671
|
+
nil
|
672
|
+
end
|
673
|
+
if hash_value == false
|
674
|
+
hash_value
|
675
|
+
else
|
676
|
+
hash_value || (@fallback_value != NOT_CONFIGURED ? @fallback_value : nil)
|
677
|
+
end
|
678
|
+
elsif obj.respond_to?(resolver_method)
|
679
|
+
method_to_call = resolver_method
|
680
|
+
method_receiver = obj
|
681
|
+
# Call the method with kwargs, if there are any
|
682
|
+
if ruby_kwargs.any?
|
683
|
+
obj.public_send(resolver_method, **ruby_kwargs)
|
684
|
+
else
|
685
|
+
obj.public_send(resolver_method)
|
686
|
+
end
|
687
|
+
elsif inner_object.is_a?(Hash)
|
688
|
+
if @dig_keys
|
689
|
+
inner_object.dig(*@dig_keys)
|
690
|
+
elsif inner_object.key?(@method_sym)
|
691
|
+
inner_object[@method_sym]
|
692
|
+
elsif inner_object.key?(@method_str) || !inner_object.default_proc.nil?
|
693
|
+
inner_object[@method_str]
|
694
|
+
elsif @fallback_value != NOT_CONFIGURED
|
695
|
+
@fallback_value
|
696
|
+
else
|
697
|
+
nil
|
698
|
+
end
|
699
|
+
elsif inner_object.respond_to?(@method_sym)
|
700
|
+
method_to_call = @method_sym
|
701
|
+
method_receiver = obj.object
|
702
|
+
if ruby_kwargs.any?
|
703
|
+
inner_object.public_send(@method_sym, **ruby_kwargs)
|
704
|
+
else
|
705
|
+
inner_object.public_send(@method_sym)
|
706
|
+
end
|
707
|
+
elsif @fallback_value != NOT_CONFIGURED
|
708
|
+
@fallback_value
|
709
|
+
else
|
710
|
+
raise <<-ERR
|
711
|
+
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
712
|
+
|
713
|
+
- `#{obj.class}##{resolver_method}`, which did not exist
|
714
|
+
- `#{inner_object.class}##{@method_sym}`, which did not exist
|
715
|
+
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{inner_object}`, but it wasn't a Hash
|
716
|
+
|
717
|
+
To implement this field, define one of the methods above (and check for typos), or supply a `fallback_value`.
|
718
|
+
ERR
|
719
|
+
end
|
613
720
|
end
|
721
|
+
else
|
722
|
+
raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: query_ctx, field: self)
|
614
723
|
end
|
615
|
-
rescue GraphQL::UnauthorizedFieldError => err
|
616
|
-
err.field ||= self
|
617
|
-
ctx.schema.unauthorized_field(err)
|
618
|
-
rescue GraphQL::UnauthorizedError => err
|
619
|
-
ctx.schema.unauthorized_object(err)
|
620
724
|
end
|
725
|
+
rescue GraphQL::UnauthorizedFieldError => err
|
726
|
+
err.field ||= self
|
727
|
+
begin
|
728
|
+
query_ctx.schema.unauthorized_field(err)
|
729
|
+
rescue GraphQL::ExecutionError => err
|
730
|
+
err
|
731
|
+
end
|
732
|
+
rescue GraphQL::UnauthorizedError => err
|
733
|
+
begin
|
734
|
+
query_ctx.schema.unauthorized_object(err)
|
735
|
+
rescue GraphQL::ExecutionError => err
|
736
|
+
err
|
737
|
+
end
|
738
|
+
rescue ArgumentError
|
739
|
+
if method_receiver && method_to_call
|
740
|
+
assert_satisfactory_implementation(method_receiver, method_to_call, method_args)
|
741
|
+
end
|
742
|
+
# if the line above doesn't raise, re-raise
|
743
|
+
raise
|
621
744
|
rescue GraphQL::ExecutionError => err
|
622
745
|
err
|
623
746
|
end
|
624
747
|
|
625
|
-
# @param ctx [GraphQL::Query::Context
|
748
|
+
# @param ctx [GraphQL::Query::Context]
|
626
749
|
def fetch_extra(extra_name, ctx)
|
627
750
|
if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
|
628
751
|
self.public_send(extra_name)
|
@@ -635,111 +758,55 @@ module GraphQL
|
|
635
758
|
|
636
759
|
private
|
637
760
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
arguments.each do |name, arg_defn|
|
653
|
-
ruby_kwargs_key = arg_defn.keyword
|
654
|
-
|
655
|
-
if ruby_kwargs.key?(ruby_kwargs_key)
|
656
|
-
loads = arg_defn.loads
|
657
|
-
value = ruby_kwargs[ruby_kwargs_key]
|
658
|
-
loaded_value = if loads && !arg_defn.from_resolver?
|
659
|
-
if arg_defn.type.list?
|
660
|
-
loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
|
661
|
-
field_ctx.schema.after_any_lazies(loaded_values) { |result| result }
|
662
|
-
else
|
663
|
-
load_application_object(arg_defn, loads, value, field_ctx.query.context)
|
664
|
-
end
|
665
|
-
elsif arg_defn.type.list? && value.is_a?(Array)
|
666
|
-
field_ctx.schema.after_any_lazies(value, &:itself)
|
667
|
-
else
|
668
|
-
value
|
669
|
-
end
|
670
|
-
|
671
|
-
maybe_lazies << field_ctx.schema.after_lazy(loaded_value) do |loaded_value|
|
672
|
-
prepared_value = if arg_defn.prepare
|
673
|
-
arg_defn.prepare_value(obj, loaded_value)
|
674
|
-
else
|
675
|
-
loaded_value
|
676
|
-
end
|
677
|
-
|
678
|
-
ruby_kwargs[ruby_kwargs_key] = prepared_value
|
679
|
-
end
|
761
|
+
def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
|
762
|
+
method_defn = receiver.method(method_name)
|
763
|
+
unsatisfied_ruby_kwargs = ruby_kwargs.dup
|
764
|
+
unsatisfied_method_params = []
|
765
|
+
encountered_keyrest = false
|
766
|
+
method_defn.parameters.each do |(param_type, param_name)|
|
767
|
+
case param_type
|
768
|
+
when :key
|
769
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
770
|
+
when :keyreq
|
771
|
+
if unsatisfied_ruby_kwargs.key?(param_name)
|
772
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
773
|
+
else
|
774
|
+
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."
|
680
775
|
end
|
776
|
+
when :keyrest
|
777
|
+
encountered_keyrest = true
|
778
|
+
when :req
|
779
|
+
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."
|
780
|
+
when :opt, :rest
|
781
|
+
# This is fine, although it will never be present
|
681
782
|
end
|
682
|
-
|
683
|
-
@extras.each do |extra_arg|
|
684
|
-
ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
|
685
|
-
end
|
686
|
-
|
687
|
-
field_ctx.schema.after_any_lazies(maybe_lazies) do
|
688
|
-
ruby_kwargs
|
689
|
-
end
|
690
|
-
else
|
691
|
-
NO_ARGS
|
692
783
|
end
|
693
|
-
end
|
694
784
|
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
if obj.is_a?(GraphQL::Schema::Object)
|
699
|
-
obj = obj.object
|
700
|
-
end
|
701
|
-
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
702
|
-
end
|
785
|
+
if encountered_keyrest
|
786
|
+
unsatisfied_ruby_kwargs.clear
|
787
|
+
end
|
703
788
|
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
# - Hash keys, if the wrapped object is a hash;
|
708
|
-
# - A method on the wrapped object;
|
709
|
-
# - Or, raise not implemented.
|
710
|
-
#
|
711
|
-
if obj.respond_to?(@resolver_method)
|
712
|
-
# Call the method with kwargs, if there are any
|
713
|
-
if ruby_kwargs.any?
|
714
|
-
obj.public_send(@resolver_method, **ruby_kwargs)
|
715
|
-
else
|
716
|
-
obj.public_send(@resolver_method)
|
717
|
-
end
|
718
|
-
elsif obj.object.is_a?(Hash)
|
719
|
-
inner_object = obj.object
|
720
|
-
if inner_object.key?(@method_sym)
|
721
|
-
inner_object[@method_sym]
|
722
|
-
else
|
723
|
-
inner_object[@method_str]
|
724
|
-
end
|
725
|
-
elsif obj.object.respond_to?(@method_sym)
|
726
|
-
if ruby_kwargs.any?
|
727
|
-
obj.object.public_send(@method_sym, **ruby_kwargs)
|
728
|
-
else
|
729
|
-
obj.object.public_send(@method_sym)
|
730
|
-
end
|
731
|
-
else
|
732
|
-
raise <<-ERR
|
733
|
-
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
789
|
+
if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
|
790
|
+
raise FieldImplementationFailed.new, <<-ERR
|
791
|
+
Failed to call `#{method_name.inspect}` on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
|
734
792
|
|
735
|
-
|
736
|
-
|
737
|
-
|
793
|
+
#{ unsatisfied_ruby_kwargs
|
794
|
+
.map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
|
795
|
+
.concat(unsatisfied_method_params)
|
796
|
+
.join("\n") }
|
797
|
+
ERR
|
798
|
+
end
|
799
|
+
end
|
738
800
|
|
739
|
-
|
740
|
-
|
741
|
-
|
801
|
+
class ExtendedState
|
802
|
+
def initialize(args, object)
|
803
|
+
@arguments = args
|
804
|
+
@object = object
|
805
|
+
@memos = nil
|
806
|
+
@added_extras = nil
|
742
807
|
end
|
808
|
+
|
809
|
+
attr_accessor :arguments, :object, :memos, :added_extras
|
743
810
|
end
|
744
811
|
|
745
812
|
# Wrap execution with hooks.
|
@@ -752,16 +819,20 @@ module GraphQL
|
|
752
819
|
# This is a hack to get the _last_ value for extended obj and args,
|
753
820
|
# in case one of the extensions doesn't `yield`.
|
754
821
|
# (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
|
755
|
-
extended =
|
822
|
+
extended = ExtendedState.new(args, obj)
|
756
823
|
value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
|
824
|
+
if (added_extras = extended.added_extras)
|
825
|
+
args = args.dup
|
826
|
+
added_extras.each { |e| args.delete(e) }
|
827
|
+
end
|
757
828
|
yield(obj, args)
|
758
829
|
end
|
759
830
|
|
760
|
-
extended_obj = extended
|
761
|
-
extended_args = extended
|
762
|
-
memos = extended
|
831
|
+
extended_obj = extended.object
|
832
|
+
extended_args = extended.arguments # rubocop:disable Development/ContextIsPassedCop
|
833
|
+
memos = extended.memos || EMPTY_HASH
|
763
834
|
|
764
|
-
ctx.
|
835
|
+
ctx.query.after_lazy(value) do |resolved_value|
|
765
836
|
idx = 0
|
766
837
|
@extensions.each do |ext|
|
767
838
|
memo = memos[idx]
|
@@ -779,17 +850,41 @@ module GraphQL
|
|
779
850
|
if extension
|
780
851
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
781
852
|
if memo
|
782
|
-
memos = extended
|
853
|
+
memos = extended.memos ||= {}
|
783
854
|
memos[idx] = memo
|
784
855
|
end
|
785
|
-
|
786
|
-
|
856
|
+
|
857
|
+
if (extras = extension.added_extras)
|
858
|
+
ae = extended.added_extras ||= []
|
859
|
+
ae.concat(extras)
|
860
|
+
end
|
861
|
+
|
862
|
+
extended.object = extended_obj
|
863
|
+
extended.arguments = extended_args
|
787
864
|
run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
|
788
865
|
end
|
789
866
|
else
|
790
867
|
yield(obj, args)
|
791
868
|
end
|
792
869
|
end
|
870
|
+
|
871
|
+
def apply_own_complexity_to(child_complexity, query, nodes)
|
872
|
+
case (own_complexity = complexity)
|
873
|
+
when Numeric
|
874
|
+
own_complexity + child_complexity
|
875
|
+
when Proc
|
876
|
+
arguments = query.arguments_for(nodes.first, self)
|
877
|
+
if arguments.is_a?(GraphQL::ExecutionError)
|
878
|
+
return child_complexity
|
879
|
+
elsif arguments.respond_to?(:keyword_arguments)
|
880
|
+
arguments = arguments.keyword_arguments
|
881
|
+
end
|
882
|
+
|
883
|
+
own_complexity.call(query.context, arguments, child_complexity)
|
884
|
+
else
|
885
|
+
raise ArgumentError, "Invalid complexity for #{self.path}: #{own_complexity.inspect}"
|
886
|
+
end
|
887
|
+
end
|
793
888
|
end
|
794
889
|
end
|
795
890
|
end
|