graphql 1.9.21 → 2.0.16
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 +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 +45 -8
- 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 +49 -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 +25 -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/ast/field_usage.rb +31 -2
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +175 -68
- data/lib/graphql/analysis/ast/query_depth.rb +0 -1
- data/lib/graphql/analysis/ast/visitor.rb +17 -8
- data/lib/graphql/analysis/ast.rb +14 -14
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/inspect_result.rb +0 -1
- data/lib/graphql/backtrace/table.rb +37 -16
- data/lib/graphql/backtrace/traced_error.rb +0 -1
- data/lib/graphql/backtrace/tracer.rb +39 -9
- data/lib/graphql/backtrace.rb +20 -17
- data/lib/graphql/dataloader/null_dataloader.rb +24 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +164 -0
- data/lib/graphql/dataloader.rb +311 -0
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/deprecation.rb +9 -0
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/execution/directive_checks.rb +2 -2
- data/lib/graphql/execution/errors.rb +77 -45
- 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 +44 -25
- data/lib/graphql/execution/interpreter/runtime.rb +755 -395
- data/lib/graphql/execution/interpreter.rb +201 -74
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lazy.rb +5 -9
- data/lib/graphql/execution/lookahead.rb +65 -136
- data/lib/graphql/execution/multiplex.rb +5 -152
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/filter.rb +1 -1
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +18 -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 +11 -5
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +5 -18
- 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 +10 -10
- data/lib/graphql/introspection/type_type.rb +34 -17
- data/lib/graphql/introspection.rb +100 -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 +104 -68
- data/lib/graphql/language/lexer.rb +83 -40
- data/lib/graphql/language/lexer.rl +31 -9
- data/lib/graphql/language/nodes.rb +64 -93
- data/lib/graphql/language/parser.rb +940 -896
- data/lib/graphql/language/parser.y +130 -103
- data/lib/graphql/language/printer.rb +48 -23
- 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/pagination/active_record_relation_connection.rb +85 -0
- data/lib/graphql/pagination/array_connection.rb +79 -0
- data/lib/graphql/pagination/connection.rb +253 -0
- data/lib/graphql/pagination/connections.rb +135 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +228 -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/context.rb +172 -198
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +33 -7
- data/lib/graphql/query/null_context.rb +21 -8
- data/lib/graphql/query/validation_pipeline.rb +16 -38
- data/lib/graphql/query/variable_validation_error.rb +3 -3
- data/lib/graphql/query/variables.rb +39 -12
- data/lib/graphql/query.rb +74 -38
- data/lib/graphql/railtie.rb +6 -102
- data/lib/graphql/rake_task/validate.rb +4 -1
- data/lib/graphql/rake_task.rb +41 -10
- data/lib/graphql/relay/range_add.rb +17 -10
- 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 +245 -0
- data/lib/graphql/schema/argument.rb +286 -31
- 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 +334 -220
- data/lib/graphql/schema/built_in_types.rb +5 -5
- 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/one_of.rb +12 -0
- data/lib/graphql/schema/directive/skip.rb +2 -2
- data/lib/graphql/schema/directive/transform.rb +14 -2
- data/lib/graphql/schema/directive.rb +117 -14
- data/lib/graphql/schema/enum.rb +113 -22
- data/lib/graphql/schema/enum_value.rb +16 -21
- data/lib/graphql/schema/field/connection_extension.rb +50 -20
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +491 -329
- 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 +182 -60
- data/lib/graphql/schema/interface.rb +28 -43
- data/lib/graphql/schema/introspection_system.rb +101 -38
- data/lib/graphql/schema/late_bound_type.rb +7 -2
- data/lib/graphql/schema/list.rb +61 -3
- data/lib/graphql/schema/loader.rb +144 -102
- data/lib/graphql/schema/member/base_dsl_methods.rb +33 -32
- data/lib/graphql/schema/member/build_type.rb +24 -15
- data/lib/graphql/schema/member/has_arguments.rb +261 -24
- 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 +113 -0
- data/lib/graphql/schema/member/has_fields.rb +99 -34
- data/lib/graphql/schema/member/has_interfaces.rb +88 -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/relay_shortcuts.rb +28 -2
- 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 -6
- data/lib/graphql/schema/mutation.rb +4 -9
- data/lib/graphql/schema/non_null.rb +34 -4
- data/lib/graphql/schema/object.rb +38 -60
- data/lib/graphql/schema/printer.rb +16 -35
- data/lib/graphql/schema/relay_classic_mutation.rb +90 -43
- data/lib/graphql/schema/resolver/has_payload_type.rb +46 -6
- data/lib/graphql/schema/resolver.rb +146 -93
- data/lib/graphql/schema/scalar.rb +40 -15
- data/lib/graphql/schema/subscription.rb +55 -26
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +22 -5
- data/lib/graphql/schema/union.rb +48 -14
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/format_validator.rb +48 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
- data/lib/graphql/schema/validator/length_validator.rb +59 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
- data/lib/graphql/schema/validator/required_validator.rb +82 -0
- data/lib/graphql/schema/validator.rb +171 -0
- data/lib/graphql/schema/warden.rb +187 -33
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +773 -892
- data/lib/graphql/static_validation/all_rules.rb +3 -0
- data/lib/graphql/static_validation/base_visitor.rb +21 -31
- 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 +55 -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 +12 -6
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -14
- 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/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 +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 +13 -7
- 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 +31 -19
- data/lib/graphql/static_validation.rb +1 -2
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +129 -22
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
- data/lib/graphql/subscriptions/event.rb +85 -31
- data/lib/graphql/subscriptions/instrumentation.rb +0 -47
- data/lib/graphql/subscriptions/serialize.rb +53 -6
- data/lib/graphql/subscriptions.rb +137 -57
- 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 +34 -2
- 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 +67 -38
- 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/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +15 -36
- 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 +20 -9
- data/lib/graphql/types/iso_8601_date_time.rb +36 -10
- data/lib/graphql/types/relay/base_connection.rb +18 -90
- data/lib/graphql/types/relay/base_edge.rb +2 -34
- data/lib/graphql/types/relay/connection_behaviors.rb +158 -0
- data/lib/graphql/types/relay/default_relay.rb +27 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +65 -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 +19 -0
- 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 -5
- data/lib/graphql/types/string.rb +8 -2
- data/lib/graphql/unauthorized_error.rb +2 -2
- data/lib/graphql/unresolved_type_error.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +41 -58
- data/readme.md +3 -6
- metadata +103 -237
- data/lib/graphql/analysis/analyze_query.rb +0 -91
- 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 -159
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backwards_compatibility.rb +0 -60
- data/lib/graphql/base_type.rb +0 -226
- 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 -435
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -213
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -91
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -264
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -680
- 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 -311
- 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 -42
- data/lib/graphql/directive/deprecated_directive.rb +0 -13
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -104
- data/lib/graphql/enum_type.rb +0 -193
- data/lib/graphql/execution/execute.rb +0 -326
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/instrumentation.rb +0 -92
- data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
- 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 -330
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -153
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -154
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -86
- 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/list_type.rb +0 -80
- data/lib/graphql/literal_validation_error.rb +0 -6
- data/lib/graphql/non_null_type.rb +0 -81
- data/lib/graphql/object_type.rb +0 -141
- data/lib/graphql/query/arguments.rb +0 -187
- data/lib/graphql/query/arguments_cache.rb +0 -25
- data/lib/graphql/query/executor.rb +0 -53
- data/lib/graphql/query/literal_input.rb +0 -116
- 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 -39
- data/lib/graphql/relay/array_connection.rb +0 -85
- data/lib/graphql/relay/base_connection.rb +0 -172
- 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 -40
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -18
- 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 -190
- data/lib/graphql/relay/node.rb +0 -36
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -190
- data/lib/graphql/relay/type_extensions.rb +0 -30
- data/lib/graphql/scalar_type.rb +0 -133
- 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 -15
- data/lib/graphql/schema/member/accepts_definition.rb +0 -152
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -26
- data/lib/graphql/schema/member/instrumentation.rb +0 -132
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -39
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -86
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -303
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/subscription_root.rb +0 -74
- data/lib/graphql/tracing/skylight_tracing.rb +0 -62
- 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/types/relay/node_field.rb +0 -43
- data/lib/graphql/types/relay/nodes_field.rb +0 -45
- data/lib/graphql/union_type.rb +0 -135
- data/lib/graphql/upgrader/member.rb +0 -936
- data/lib/graphql/upgrader/schema.rb +0 -37
data/lib/graphql/schema/field.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../object.rb
|
3
2
|
require "graphql/schema/field/connection_extension"
|
4
3
|
require "graphql/schema/field/scope_extension"
|
5
4
|
|
6
5
|
module GraphQL
|
7
6
|
class Schema
|
8
7
|
class Field
|
9
|
-
if !String.method_defined?(:-@)
|
10
|
-
using GraphQL::StringDedupBackport
|
11
|
-
end
|
12
|
-
|
13
|
-
include GraphQL::Schema::Member::CachedGraphQLDefinition
|
14
|
-
include GraphQL::Schema::Member::AcceptsDefinition
|
15
8
|
include GraphQL::Schema::Member::HasArguments
|
9
|
+
include GraphQL::Schema::Member::HasAstNode
|
16
10
|
include GraphQL::Schema::Member::HasPath
|
11
|
+
include GraphQL::Schema::Member::HasValidators
|
17
12
|
extend GraphQL::Schema::FindInheritedValue
|
13
|
+
include GraphQL::Schema::FindInheritedValue::EmptyObjects
|
14
|
+
include GraphQL::Schema::Member::HasDirectives
|
15
|
+
include GraphQL::Schema::Member::HasDeprecationReason
|
16
|
+
|
17
|
+
class FieldImplementationFailed < GraphQL::Error; end
|
18
18
|
|
19
19
|
# @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
|
20
20
|
attr_reader :name
|
@@ -22,22 +22,39 @@ module GraphQL
|
|
22
22
|
|
23
23
|
attr_writer :description
|
24
24
|
|
25
|
-
# @return [String, nil] If present, the field is marked as deprecated with this documentation
|
26
|
-
attr_accessor :deprecation_reason
|
27
|
-
|
28
25
|
# @return [Symbol] Method or hash key on the underlying object to look up
|
29
26
|
attr_reader :method_sym
|
30
27
|
|
31
28
|
# @return [String] Method or hash key on the underlying object to look up
|
32
29
|
attr_reader :method_str
|
33
30
|
|
31
|
+
attr_reader :hash_key
|
32
|
+
attr_reader :dig_keys
|
33
|
+
|
34
34
|
# @return [Symbol] The method on the type to look up
|
35
|
-
|
35
|
+
def resolver_method
|
36
|
+
if @resolver_class
|
37
|
+
@resolver_class.resolver_method
|
38
|
+
else
|
39
|
+
@resolver_method
|
40
|
+
end
|
41
|
+
end
|
36
42
|
|
37
|
-
# @return [Class] The
|
38
|
-
|
43
|
+
# @return [Class] The thing this field was defined on (type, mutation, resolver)
|
44
|
+
attr_accessor :owner
|
45
|
+
|
46
|
+
# @return [Class] The GraphQL type this field belongs to. (For fields defined on mutations, it's the payload type)
|
47
|
+
def owner_type
|
48
|
+
@owner_type ||= if owner.nil?
|
49
|
+
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?!"
|
50
|
+
elsif owner < GraphQL::Schema::Mutation
|
51
|
+
owner.payload_type
|
52
|
+
else
|
53
|
+
owner
|
54
|
+
end
|
55
|
+
end
|
39
56
|
|
40
|
-
# @return [
|
57
|
+
# @return [Symbol] the original name of the field, passed in by the user
|
41
58
|
attr_reader :original_name
|
42
59
|
|
43
60
|
# @return [Class, nil] The {Schema::Resolver} this field was derived from, if there is one
|
@@ -45,13 +62,25 @@ module GraphQL
|
|
45
62
|
@resolver_class
|
46
63
|
end
|
47
64
|
|
65
|
+
# @return [Boolean] Is this field a predefined introspection field?
|
66
|
+
def introspection?
|
67
|
+
@introspection
|
68
|
+
end
|
69
|
+
|
70
|
+
def inspect
|
71
|
+
"#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
|
72
|
+
end
|
73
|
+
|
48
74
|
alias :mutation :resolver
|
49
75
|
|
50
76
|
# @return [Boolean] Apply tracing to this field? (Default: skip scalars, this is the override value)
|
51
77
|
attr_reader :trace
|
52
78
|
|
53
79
|
# @return [String, nil]
|
54
|
-
|
80
|
+
def subscription_scope
|
81
|
+
@subscription_scope || (@resolver_class.respond_to?(:subscription_scope) ? @resolver_class.subscription_scope : nil)
|
82
|
+
end
|
83
|
+
attr_writer :subscription_scope
|
55
84
|
|
56
85
|
# Create a field instance from a list of arguments, keyword arguments, and a block.
|
57
86
|
#
|
@@ -65,21 +94,9 @@ module GraphQL
|
|
65
94
|
# @return [GraphQL::Schema:Field] an instance of `self
|
66
95
|
# @see {.initialize} for other options
|
67
96
|
def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
|
68
|
-
if
|
69
|
-
if kwargs[:field] == GraphQL::Relay::Node.field
|
70
|
-
warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
|
71
|
-
return GraphQL::Types::Relay::NodeField
|
72
|
-
elsif kwargs[:field] == GraphQL::Relay::Node.plural_field
|
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.")
|
74
|
-
return GraphQL::Types::Relay::NodesField
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
if (parent_config = resolver || mutation || subscription)
|
79
|
-
# Get the parent config, merge in local overrides
|
80
|
-
kwargs = parent_config.field_options.merge(kwargs)
|
97
|
+
if (resolver_class = resolver || mutation || subscription)
|
81
98
|
# Add a reference to that parent class
|
82
|
-
kwargs[:resolver_class] =
|
99
|
+
kwargs[:resolver_class] = resolver_class
|
83
100
|
end
|
84
101
|
|
85
102
|
if name
|
@@ -87,9 +104,6 @@ module GraphQL
|
|
87
104
|
end
|
88
105
|
|
89
106
|
if !type.nil?
|
90
|
-
if type.is_a?(GraphQL::Field)
|
91
|
-
raise ArgumentError, "A GraphQL::Field was passed as the second argument, use the `field:` keyword for this instead."
|
92
|
-
end
|
93
107
|
if desc
|
94
108
|
if kwargs[:description]
|
95
109
|
raise ArgumentError, "Provide description as a positional argument or `description:` keyword, but not both (#{desc.inspect}, #{kwargs[:description].inspect})"
|
@@ -97,12 +111,15 @@ module GraphQL
|
|
97
111
|
|
98
112
|
kwargs[:description] = desc
|
99
113
|
kwargs[:type] = type
|
100
|
-
elsif (
|
101
|
-
# The return type should be copied from
|
114
|
+
elsif (resolver || mutation) && type.is_a?(String)
|
115
|
+
# The return type should be copied from the resolver, and the second positional argument is the description
|
102
116
|
kwargs[:description] = type
|
103
117
|
else
|
104
118
|
kwargs[:type] = type
|
105
119
|
end
|
120
|
+
if type.is_a?(Class) && type < GraphQL::Schema::Mutation
|
121
|
+
raise ArgumentError, "Use `field #{name.inspect}, mutation: Mutation, ...` to provide a mutation to this field instead"
|
122
|
+
end
|
106
123
|
end
|
107
124
|
new(**kwargs, &block)
|
108
125
|
end
|
@@ -112,10 +129,10 @@ module GraphQL
|
|
112
129
|
def connection?
|
113
130
|
if @connection.nil?
|
114
131
|
# Provide default based on type name
|
115
|
-
return_type_name = if
|
116
|
-
Member::BuildType.to_type_name(contains_type.type)
|
117
|
-
elsif @return_type_expr
|
132
|
+
return_type_name = if @return_type_expr
|
118
133
|
Member::BuildType.to_type_name(@return_type_expr)
|
134
|
+
elsif @resolver_class && @resolver_class.type
|
135
|
+
Member::BuildType.to_type_name(@resolver_class.type)
|
119
136
|
else
|
120
137
|
# As a last ditch, try to force loading the return type:
|
121
138
|
type.unwrap.name
|
@@ -131,8 +148,18 @@ module GraphQL
|
|
131
148
|
if !@scope.nil?
|
132
149
|
# The default was overridden
|
133
150
|
@scope
|
151
|
+
elsif @return_type_expr
|
152
|
+
# Detect a list return type, but don't call `type` since that may eager-load an otherwise lazy-loaded type
|
153
|
+
@return_type_expr.is_a?(Array) ||
|
154
|
+
(@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) ||
|
155
|
+
connection?
|
156
|
+
elsif @resolver_class
|
157
|
+
resolver_type = @resolver_class.type_expr
|
158
|
+
resolver_type.is_a?(Array) ||
|
159
|
+
(resolver_type.is_a?(String) && resolver_type.include?("[")) ||
|
160
|
+
connection?
|
134
161
|
else
|
135
|
-
|
162
|
+
false
|
136
163
|
end
|
137
164
|
end
|
138
165
|
|
@@ -152,21 +179,31 @@ module GraphQL
|
|
152
179
|
end
|
153
180
|
end
|
154
181
|
|
182
|
+
# @return Boolean
|
183
|
+
attr_reader :relay_node_field
|
184
|
+
# @return Boolean
|
185
|
+
attr_reader :relay_nodes_field
|
186
|
+
|
187
|
+
# @return [Boolean] Should we warn if this field's name conflicts with a built-in method?
|
188
|
+
def method_conflict_warning?
|
189
|
+
@method_conflict_warning
|
190
|
+
end
|
191
|
+
|
155
192
|
# @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
|
156
193
|
# @param type [Class, GraphQL::BaseType, Array] The return type of this field
|
157
194
|
# @param owner [Class] The type that this field belongs to
|
158
|
-
# @param null [Boolean] `true` if this field may return `null`, `false` if it is never `null`
|
195
|
+
# @param null [Boolean] (defaults to `true`) `true` if this field may return `null`, `false` if it is never `null`
|
159
196
|
# @param description [String] Field description
|
160
197
|
# @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
|
161
198
|
# @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
|
162
199
|
# @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`)
|
200
|
+
# @param dig [Array<String, Symbol>] The nested hash keys to lookup on the underlying hash to resolve this field using dig
|
163
201
|
# @param resolver_method [Symbol] The method on the type to call to resolve this field (defaults to `name`)
|
164
202
|
# @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
|
203
|
+
# @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
|
204
|
+
# @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
|
205
|
+
# @param default_page_size [Integer, nil] For connections, the default number of items to return from this field, or `nil` to return unlimited results.
|
166
206
|
# @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
|
167
|
-
# @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
|
168
|
-
# @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
|
169
|
-
# @param function [GraphQL::Function] **deprecated** for compatibility with <1.8.0
|
170
207
|
# @param resolver_class [Class] (Private) A {Schema::Resolver} which this field was derived from. Use `resolver:` to create a field with a resolver.
|
171
208
|
# @param arguments [{String=>GraphQL::Schema::Argument, Hash}] Arguments for this field (may be added in the block, also)
|
172
209
|
# @param camelize [Boolean] If true, the field name will be camelized when building the schema
|
@@ -174,37 +211,33 @@ module GraphQL
|
|
174
211
|
# @param scope [Boolean] If true, the return type's `.scope_items` method will be called on the return value
|
175
212
|
# @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
|
176
213
|
# @param extensions [Array<Class, Hash<Class => Object>>] Named extensions to apply to this field (see also {#extension})
|
214
|
+
# @param directives [Hash{Class => Hash}] Directives to apply to this field
|
177
215
|
# @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
|
178
|
-
|
216
|
+
# @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
|
217
|
+
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
218
|
+
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
219
|
+
# @param validates [Array<Hash>] Configurations for validating this field
|
220
|
+
# @fallback_value [Object] A fallback value if the method is not defined
|
221
|
+
def initialize(type: nil, name: nil, owner: nil, null: nil, description: :not_given, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: :not_given, default_page_size: :not_given, 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: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: :not_given, &definition_block)
|
179
222
|
if name.nil?
|
180
223
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
181
224
|
end
|
182
|
-
if !(
|
225
|
+
if !(resolver_class)
|
183
226
|
if type.nil?
|
184
227
|
raise ArgumentError, "missing second `type` argument or keyword `type:`"
|
185
228
|
end
|
186
|
-
if null.nil?
|
187
|
-
raise ArgumentError, "missing keyword argument null:"
|
188
|
-
end
|
189
|
-
end
|
190
|
-
if (field || function || resolve) && extras.any?
|
191
|
-
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
|
-
@
|
196
|
-
@
|
197
|
-
if
|
198
|
-
|
199
|
-
else
|
200
|
-
@field = field
|
231
|
+
name_s = -name.to_s
|
232
|
+
@underscored_name = -Member::BuildType.underscore(name_s)
|
233
|
+
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
234
|
+
if description != :not_given
|
235
|
+
@description = description
|
201
236
|
end
|
202
|
-
|
203
|
-
@resolve = resolve
|
204
|
-
@deprecation_reason = deprecation_reason
|
237
|
+
self.deprecation_reason = deprecation_reason
|
205
238
|
|
206
|
-
if method && hash_key
|
207
|
-
raise ArgumentError, "Provide `method:` _or_ `
|
239
|
+
if method && hash_key && dig
|
240
|
+
raise ArgumentError, "Provide `method:`, `hash_key:` _or_ `dig:`, not multiple. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}, dig: #{dig.inspect}`)"
|
208
241
|
end
|
209
242
|
|
210
243
|
if resolver_method
|
@@ -212,58 +245,96 @@ module GraphQL
|
|
212
245
|
raise ArgumentError, "Provide `method:` _or_ `resolver_method:`, not both. (called with: `method: #{method.inspect}, resolver_method: #{resolver_method.inspect}`)"
|
213
246
|
end
|
214
247
|
|
215
|
-
if hash_key
|
216
|
-
raise ArgumentError, "Provide `hash_key
|
248
|
+
if hash_key || dig
|
249
|
+
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
250
|
end
|
218
251
|
end
|
219
252
|
|
220
|
-
|
221
|
-
|
222
|
-
|
253
|
+
method_name = method || hash_key || name_s
|
254
|
+
@dig_keys = dig
|
255
|
+
if hash_key
|
256
|
+
@hash_key = hash_key
|
257
|
+
@hash_key_str = hash_key.to_s
|
258
|
+
end
|
223
259
|
|
224
|
-
@method_str = method_name.to_s
|
260
|
+
@method_str = -method_name.to_s
|
225
261
|
@method_sym = method_name.to_sym
|
226
|
-
@resolver_method = resolver_method
|
262
|
+
@resolver_method = (resolver_method || name_s).to_sym
|
227
263
|
@complexity = complexity
|
228
264
|
@return_type_expr = type
|
229
|
-
@return_type_null = null
|
265
|
+
@return_type_null = if !null.nil?
|
266
|
+
null
|
267
|
+
elsif resolver_class
|
268
|
+
nil
|
269
|
+
else
|
270
|
+
true
|
271
|
+
end
|
230
272
|
@connection = connection
|
231
|
-
@
|
273
|
+
@has_max_page_size = max_page_size != :not_given
|
274
|
+
@max_page_size = max_page_size == :not_given ? nil : max_page_size
|
275
|
+
@has_default_page_size = default_page_size != :not_given
|
276
|
+
@default_page_size = default_page_size == :not_given ? nil : default_page_size
|
232
277
|
@introspection = introspection
|
233
278
|
@extras = extras
|
279
|
+
if !broadcastable.nil?
|
280
|
+
@broadcastable = broadcastable
|
281
|
+
end
|
234
282
|
@resolver_class = resolver_class
|
235
283
|
@scope = scope
|
236
284
|
@trace = trace
|
237
285
|
@relay_node_field = relay_node_field
|
238
286
|
@relay_nodes_field = relay_nodes_field
|
287
|
+
@ast_node = ast_node
|
288
|
+
@method_conflict_warning = method_conflict_warning
|
289
|
+
@fallback_value = fallback_value
|
239
290
|
|
240
|
-
# Override the default from HasArguments
|
241
|
-
@own_arguments = {}
|
242
291
|
arguments.each do |name, arg|
|
243
|
-
|
292
|
+
case arg
|
293
|
+
when Hash
|
244
294
|
argument(name: name, **arg)
|
295
|
+
when GraphQL::Schema::Argument
|
296
|
+
add_argument(arg)
|
297
|
+
when Array
|
298
|
+
arg.each { |a| add_argument(a) }
|
245
299
|
else
|
246
|
-
|
300
|
+
raise ArgumentError, "Unexpected argument config (#{arg.class}): #{arg.inspect}"
|
247
301
|
end
|
248
302
|
end
|
249
303
|
|
250
304
|
@owner = owner
|
251
305
|
@subscription_scope = subscription_scope
|
252
306
|
|
253
|
-
|
254
|
-
@
|
255
|
-
if extensions.any?
|
256
|
-
self.extensions(extensions)
|
257
|
-
end
|
307
|
+
@extensions = EMPTY_ARRAY
|
308
|
+
@call_after_define = false
|
258
309
|
# This should run before connection extension,
|
259
310
|
# but should it run after the definition block?
|
260
311
|
if scoped?
|
261
312
|
self.extension(ScopeExtension)
|
262
313
|
end
|
314
|
+
|
263
315
|
# The problem with putting this after the definition_block
|
264
316
|
# is that it would override arguments
|
265
|
-
if connection?
|
266
|
-
self.extension(
|
317
|
+
if connection? && connection_extension
|
318
|
+
self.extension(connection_extension)
|
319
|
+
end
|
320
|
+
|
321
|
+
# Do this last so we have as much context as possible when initializing them:
|
322
|
+
if extensions.any?
|
323
|
+
self.extensions(extensions)
|
324
|
+
end
|
325
|
+
|
326
|
+
if resolver_class && resolver_class.extensions.any?
|
327
|
+
self.extensions(resolver_class.extensions)
|
328
|
+
end
|
329
|
+
|
330
|
+
if directives.any?
|
331
|
+
directives.each do |(dir_class, options)|
|
332
|
+
self.directive(dir_class, **options)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
if !validates.empty?
|
337
|
+
self.validates(validates)
|
267
338
|
end
|
268
339
|
|
269
340
|
if definition_block
|
@@ -273,6 +344,22 @@ module GraphQL
|
|
273
344
|
instance_eval(&definition_block)
|
274
345
|
end
|
275
346
|
end
|
347
|
+
|
348
|
+
self.extensions.each(&:after_define_apply)
|
349
|
+
@call_after_define = true
|
350
|
+
end
|
351
|
+
|
352
|
+
# If true, subscription updates with this field can be shared between viewers
|
353
|
+
# @return [Boolean, nil]
|
354
|
+
# @see GraphQL::Subscriptions::BroadcastAnalyzer
|
355
|
+
def broadcastable?
|
356
|
+
if defined?(@broadcastable)
|
357
|
+
@broadcastable
|
358
|
+
elsif @resolver_class
|
359
|
+
@resolver_class.broadcastable?
|
360
|
+
else
|
361
|
+
nil
|
362
|
+
end
|
276
363
|
end
|
277
364
|
|
278
365
|
# @param text [String]
|
@@ -280,8 +367,12 @@ module GraphQL
|
|
280
367
|
def description(text = nil)
|
281
368
|
if text
|
282
369
|
@description = text
|
283
|
-
|
370
|
+
elsif defined?(@description)
|
284
371
|
@description
|
372
|
+
elsif @resolver_class
|
373
|
+
@description || @resolver_class.description
|
374
|
+
else
|
375
|
+
nil
|
285
376
|
end
|
286
377
|
end
|
287
378
|
|
@@ -298,24 +389,20 @@ module GraphQL
|
|
298
389
|
# @example adding an extension with options
|
299
390
|
# extensions([MyExtensionClass, { AnotherExtensionClass => { filter: true } }])
|
300
391
|
#
|
301
|
-
# @param extensions [Array<Class, Hash<Class =>
|
392
|
+
# @param extensions [Array<Class, Hash<Class => Hash>>] Add extensions to this field. For hash elements, only the first key/value is used.
|
302
393
|
# @return [Array<GraphQL::Schema::FieldExtension>] extensions to apply to this field
|
303
394
|
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)
|
395
|
+
if new_extensions
|
396
|
+
new_extensions.each do |extension_config|
|
397
|
+
if extension_config.is_a?(Hash)
|
398
|
+
extension_class, options = *extension_config.to_a[0]
|
399
|
+
self.extension(extension_class, options)
|
313
400
|
else
|
314
|
-
|
315
|
-
@extensions << extension_class.new(field: self, options: nil)
|
401
|
+
self.extension(extension_config)
|
316
402
|
end
|
317
403
|
end
|
318
404
|
end
|
405
|
+
@extensions
|
319
406
|
end
|
320
407
|
|
321
408
|
# Add `extension` to this field, initialized with `options` if provided.
|
@@ -326,10 +413,19 @@ module GraphQL
|
|
326
413
|
# @example adding an extension with options
|
327
414
|
# extension(MyExtensionClass, filter: true)
|
328
415
|
#
|
329
|
-
# @param
|
330
|
-
# @param options [
|
331
|
-
|
332
|
-
|
416
|
+
# @param extension_class [Class] subclass of {Schema::FieldExtension}
|
417
|
+
# @param options [Hash] if provided, given as `options:` when initializing `extension`.
|
418
|
+
# @return [void]
|
419
|
+
def extension(extension_class, options = nil)
|
420
|
+
extension_inst = extension_class.new(field: self, options: options)
|
421
|
+
if @extensions.frozen?
|
422
|
+
@extensions = @extensions.dup
|
423
|
+
end
|
424
|
+
if @call_after_define
|
425
|
+
extension_inst.after_define_apply
|
426
|
+
end
|
427
|
+
@extensions << extension_inst
|
428
|
+
nil
|
333
429
|
end
|
334
430
|
|
335
431
|
# Read extras (as symbols) from this field,
|
@@ -340,14 +436,87 @@ module GraphQL
|
|
340
436
|
def extras(new_extras = nil)
|
341
437
|
if new_extras.nil?
|
342
438
|
# Read the value
|
343
|
-
@extras
|
439
|
+
field_extras = @extras
|
440
|
+
if @resolver_class && @resolver_class.extras.any?
|
441
|
+
field_extras + @resolver_class.extras
|
442
|
+
else
|
443
|
+
field_extras
|
444
|
+
end
|
344
445
|
else
|
446
|
+
if @extras.frozen?
|
447
|
+
@extras = @extras.dup
|
448
|
+
end
|
345
449
|
# Append to the set of extras on this field
|
346
450
|
@extras.concat(new_extras)
|
347
451
|
end
|
348
452
|
end
|
349
453
|
|
350
|
-
def
|
454
|
+
def calculate_complexity(query:, nodes:, child_complexity:)
|
455
|
+
if respond_to?(:complexity_for)
|
456
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
457
|
+
complexity_for(child_complexity: child_complexity, query: query, lookahead: lookahead)
|
458
|
+
elsif connection?
|
459
|
+
arguments = query.arguments_for(nodes.first, self)
|
460
|
+
max_possible_page_size = nil
|
461
|
+
if arguments.respond_to?(:[]) # It might have been an error
|
462
|
+
if arguments[:first]
|
463
|
+
max_possible_page_size = arguments[:first]
|
464
|
+
end
|
465
|
+
|
466
|
+
if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
|
467
|
+
max_possible_page_size = arguments[:last]
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
if max_possible_page_size.nil?
|
472
|
+
max_possible_page_size = default_page_size || query.schema.default_page_size || max_page_size || query.schema.default_max_page_size
|
473
|
+
end
|
474
|
+
|
475
|
+
if max_possible_page_size.nil?
|
476
|
+
raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `default_page_size`, `max_page_size` or `default_max_page_size`"
|
477
|
+
else
|
478
|
+
metadata_complexity = 0
|
479
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
480
|
+
|
481
|
+
if (page_info_lookahead = lookahead.selection(:page_info)).selected?
|
482
|
+
metadata_complexity += 1 # pageInfo
|
483
|
+
metadata_complexity += page_info_lookahead.selections.size # subfields
|
484
|
+
end
|
485
|
+
|
486
|
+
if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
|
487
|
+
metadata_complexity += 1
|
488
|
+
end
|
489
|
+
|
490
|
+
nodes_edges_complexity = 0
|
491
|
+
nodes_edges_complexity += 1 if lookahead.selects?(:edges)
|
492
|
+
nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
|
493
|
+
|
494
|
+
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
495
|
+
items_complexity = child_complexity - metadata_complexity - nodes_edges_complexity
|
496
|
+
# Add 1 for _this_ field
|
497
|
+
1 + (max_possible_page_size * items_complexity) + metadata_complexity + nodes_edges_complexity
|
498
|
+
end
|
499
|
+
else
|
500
|
+
defined_complexity = complexity
|
501
|
+
case defined_complexity
|
502
|
+
when Proc
|
503
|
+
arguments = query.arguments_for(nodes.first, self)
|
504
|
+
if arguments.is_a?(GraphQL::ExecutionError)
|
505
|
+
return child_complexity
|
506
|
+
elsif arguments.respond_to?(:keyword_arguments)
|
507
|
+
arguments = arguments.keyword_arguments
|
508
|
+
end
|
509
|
+
|
510
|
+
defined_complexity.call(query.context, arguments, child_complexity)
|
511
|
+
when Numeric
|
512
|
+
defined_complexity + child_complexity
|
513
|
+
else
|
514
|
+
raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
def complexity(new_complexity = nil)
|
351
520
|
case new_complexity
|
352
521
|
when Proc
|
353
522
|
if new_complexity.parameters.size != 3
|
@@ -360,87 +529,56 @@ module GraphQL
|
|
360
529
|
end
|
361
530
|
when Numeric
|
362
531
|
@complexity = new_complexity
|
532
|
+
when nil
|
533
|
+
if @resolver_class
|
534
|
+
@complexity || @resolver_class.complexity || 1
|
535
|
+
else
|
536
|
+
@complexity || 1
|
537
|
+
end
|
363
538
|
else
|
364
539
|
raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
|
365
540
|
end
|
366
541
|
end
|
367
542
|
|
368
|
-
# @return [
|
369
|
-
|
543
|
+
# @return [Boolean] True if this field's {#max_page_size} should override the schema default.
|
544
|
+
def has_max_page_size?
|
545
|
+
@has_max_page_size || (@resolver_class && @resolver_class.has_max_page_size?)
|
546
|
+
end
|
370
547
|
|
371
|
-
# @return [
|
372
|
-
def
|
373
|
-
|
374
|
-
|
375
|
-
elsif @function
|
376
|
-
GraphQL::Function.build_field(@function)
|
377
|
-
else
|
378
|
-
GraphQL::Field.new
|
379
|
-
end
|
548
|
+
# @return [Integer, nil] Applied to connections if {#has_max_page_size?}
|
549
|
+
def max_page_size
|
550
|
+
@max_page_size || (@resolver_class && @resolver_class.max_page_size)
|
551
|
+
end
|
380
552
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
553
|
+
# @return [Boolean] True if this field's {#default_page_size} should override the schema default.
|
554
|
+
def has_default_page_size?
|
555
|
+
@has_default_page_size || (@resolver_class && @resolver_class.has_default_page_size?)
|
556
|
+
end
|
385
557
|
|
386
|
-
|
387
|
-
|
388
|
-
|
558
|
+
# @return [Integer, nil] Applied to connections if {#has_default_page_size?}
|
559
|
+
def default_page_size
|
560
|
+
@default_page_size || (@resolver_class && @resolver_class.default_page_size)
|
561
|
+
end
|
389
562
|
|
390
|
-
|
391
|
-
|
392
|
-
end
|
563
|
+
class MissingReturnTypeError < GraphQL::Error; end
|
564
|
+
attr_writer :type
|
393
565
|
|
566
|
+
def type
|
394
567
|
if @resolver_class
|
395
|
-
|
396
|
-
|
568
|
+
return_type = @return_type_expr || @resolver_class.type_expr
|
569
|
+
if return_type.nil?
|
570
|
+
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)"
|
397
571
|
end
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
field_defn.trace = @trace
|
403
|
-
end
|
404
|
-
|
405
|
-
if @relay_node_field
|
406
|
-
field_defn.relay_node_field = @relay_node_field
|
407
|
-
end
|
408
|
-
|
409
|
-
if @relay_nodes_field
|
410
|
-
field_defn.relay_nodes_field = @relay_nodes_field
|
411
|
-
end
|
412
|
-
|
413
|
-
field_defn.resolve = self.method(:resolve_field)
|
414
|
-
field_defn.connection = connection?
|
415
|
-
field_defn.connection_max_page_size = max_page_size
|
416
|
-
field_defn.introspection = @introspection
|
417
|
-
field_defn.complexity = @complexity
|
418
|
-
field_defn.subscription_scope = @subscription_scope
|
419
|
-
|
420
|
-
arguments.each do |name, defn|
|
421
|
-
arg_graphql = defn.to_graphql
|
422
|
-
field_defn.arguments[arg_graphql.name] = arg_graphql
|
423
|
-
end
|
424
|
-
|
425
|
-
# Support a passed-in proc, one way or another
|
426
|
-
@resolve_proc = if @resolve
|
427
|
-
@resolve
|
428
|
-
elsif @function
|
429
|
-
@function
|
430
|
-
elsif @field
|
431
|
-
@field.resolve_proc
|
572
|
+
nullable = @return_type_null.nil? ? @resolver_class.null : @return_type_null
|
573
|
+
Member::BuildType.parse_type(return_type, null: nullable)
|
574
|
+
else
|
575
|
+
@type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
432
576
|
end
|
433
|
-
|
434
|
-
#
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
end
|
439
|
-
|
440
|
-
def type
|
441
|
-
@type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
442
|
-
rescue
|
443
|
-
raise ArgumentError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: #{$!.message}", $!.backtrace
|
577
|
+
rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
|
578
|
+
# Let this propagate up
|
579
|
+
raise err
|
580
|
+
rescue StandardError => err
|
581
|
+
raise MissingReturnTypeError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: (#{err.class}) #{err.message}", err.backtrace
|
444
582
|
end
|
445
583
|
|
446
584
|
def visible?(context)
|
@@ -459,48 +597,44 @@ module GraphQL
|
|
459
597
|
end
|
460
598
|
end
|
461
599
|
|
462
|
-
def authorized?(object, context)
|
600
|
+
def authorized?(object, args, context)
|
463
601
|
if @resolver_class
|
464
|
-
# The resolver will check itself during `resolve()`
|
602
|
+
# The resolver _instance_ will check itself during `resolve()`
|
465
603
|
@resolver_class.authorized?(object, context)
|
466
604
|
else
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
605
|
+
if (arg_values = context[:current_arguments])
|
606
|
+
# ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
|
607
|
+
using_arg_values = true
|
608
|
+
arg_values = arg_values.argument_values
|
609
|
+
else
|
610
|
+
arg_values = args
|
611
|
+
using_arg_values = false
|
472
612
|
end
|
473
|
-
|
474
|
-
|
475
|
-
|
613
|
+
# Faster than `.any?`
|
614
|
+
arguments(context).each_value do |arg|
|
615
|
+
arg_key = arg.keyword
|
616
|
+
if arg_values.key?(arg_key)
|
617
|
+
arg_value = arg_values[arg_key]
|
618
|
+
if using_arg_values
|
619
|
+
if arg_value.default_used?
|
620
|
+
# pass -- no auth required for default used
|
621
|
+
next
|
622
|
+
else
|
623
|
+
application_arg_value = arg_value.value
|
624
|
+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
|
625
|
+
application_arg_value.keyword_arguments
|
626
|
+
end
|
627
|
+
end
|
628
|
+
else
|
629
|
+
application_arg_value = arg_value
|
630
|
+
end
|
476
631
|
|
477
|
-
|
478
|
-
|
479
|
-
# Eventually, we might hook up field instances to execution in another way. TBD.
|
480
|
-
# @see #resolve for how the interpreter hooks up to it
|
481
|
-
def resolve_field(obj, args, ctx)
|
482
|
-
ctx.schema.after_lazy(obj) do |after_obj|
|
483
|
-
# First, apply auth ...
|
484
|
-
query_ctx = ctx.query.context
|
485
|
-
# Some legacy fields can have `nil` here, not exactly sure why.
|
486
|
-
# @see https://github.com/rmosolgo/graphql-ruby/issues/1990 before removing
|
487
|
-
inner_obj = after_obj && after_obj.object
|
488
|
-
if authorized?(inner_obj, query_ctx)
|
489
|
-
ruby_args = to_ruby_args(after_obj, args, ctx)
|
490
|
-
# Then if it passed, resolve the field
|
491
|
-
if @resolve_proc
|
492
|
-
# Might be nil, still want to call the func in that case
|
493
|
-
with_extensions(inner_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
|
494
|
-
# Pass the GraphQL args here for compatibility:
|
495
|
-
@resolve_proc.call(extended_obj, args, ctx)
|
632
|
+
if !arg.authorized?(object, application_arg_value, context)
|
633
|
+
return false
|
496
634
|
end
|
497
|
-
else
|
498
|
-
public_send_field(after_obj, ruby_args, ctx)
|
499
635
|
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
636
|
end
|
637
|
+
true
|
504
638
|
end
|
505
639
|
end
|
506
640
|
|
@@ -509,92 +643,112 @@ module GraphQL
|
|
509
643
|
# @param object [GraphQL::Schema::Object] An instance of some type class, wrapping an application object
|
510
644
|
# @param args [Hash] A symbol-keyed hash of Ruby keyword arguments. (Empty if no args)
|
511
645
|
# @param ctx [GraphQL::Query::Context]
|
512
|
-
def resolve(object, args,
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
646
|
+
def resolve(object, args, query_ctx)
|
647
|
+
# Unwrap the GraphQL object to get the application object.
|
648
|
+
application_object = object.object
|
649
|
+
method_receiver = nil
|
650
|
+
method_to_call = nil
|
651
|
+
method_args = nil
|
652
|
+
|
653
|
+
Schema::Validator.validate!(validators, application_object, query_ctx, args)
|
654
|
+
|
655
|
+
query_ctx.schema.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
|
656
|
+
if is_authorized
|
657
|
+
with_extensions(object, args, query_ctx) do |obj, ruby_kwargs|
|
658
|
+
method_args = ruby_kwargs
|
659
|
+
if @resolver_class
|
660
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
661
|
+
obj = obj.object
|
527
662
|
end
|
528
|
-
@resolver_class.new(object:
|
529
|
-
else
|
530
|
-
extended_obj
|
663
|
+
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
531
664
|
end
|
532
665
|
|
533
|
-
|
666
|
+
inner_object = obj.object
|
667
|
+
|
668
|
+
if defined?(@hash_key)
|
669
|
+
hash_value = if inner_object.is_a?(Hash)
|
670
|
+
inner_object.key?(@hash_key) ? inner_object[@hash_key] : inner_object[@hash_key_str]
|
671
|
+
elsif inner_object.respond_to?(:[])
|
672
|
+
inner_object[@hash_key]
|
673
|
+
else
|
674
|
+
nil
|
675
|
+
end
|
676
|
+
if hash_value == false
|
677
|
+
hash_value
|
678
|
+
else
|
679
|
+
hash_value || (@fallback_value != :not_given ? @fallback_value : nil)
|
680
|
+
end
|
681
|
+
elsif obj.respond_to?(resolver_method)
|
682
|
+
method_to_call = resolver_method
|
683
|
+
method_receiver = obj
|
534
684
|
# Call the method with kwargs, if there are any
|
535
|
-
if
|
536
|
-
|
685
|
+
if ruby_kwargs.any?
|
686
|
+
obj.public_send(resolver_method, **ruby_kwargs)
|
687
|
+
else
|
688
|
+
obj.public_send(resolver_method)
|
689
|
+
end
|
690
|
+
elsif inner_object.is_a?(Hash)
|
691
|
+
if @dig_keys
|
692
|
+
inner_object.dig(*@dig_keys)
|
693
|
+
elsif inner_object.key?(@method_sym)
|
694
|
+
inner_object[@method_sym]
|
695
|
+
elsif inner_object.key?(@method_str)
|
696
|
+
inner_object[@method_str]
|
697
|
+
elsif @fallback_value != :not_given
|
698
|
+
@fallback_value
|
537
699
|
else
|
538
|
-
|
700
|
+
nil
|
539
701
|
end
|
702
|
+
elsif inner_object.respond_to?(@method_sym)
|
703
|
+
method_to_call = @method_sym
|
704
|
+
method_receiver = obj.object
|
705
|
+
if ruby_kwargs.any?
|
706
|
+
inner_object.public_send(@method_sym, **ruby_kwargs)
|
707
|
+
else
|
708
|
+
inner_object.public_send(@method_sym)
|
709
|
+
end
|
710
|
+
elsif @fallback_value != :not_given
|
711
|
+
@fallback_value
|
540
712
|
else
|
541
|
-
|
713
|
+
raise <<-ERR
|
714
|
+
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
715
|
+
|
716
|
+
- `#{obj.class}##{resolver_method}`, which did not exist
|
717
|
+
- `#{inner_object.class}##{@method_sym}`, which did not exist
|
718
|
+
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{inner_object}`, but it wasn't a Hash
|
719
|
+
|
720
|
+
To implement this field, define one of the methods above (and check for typos), or supply a `fallback_value`.
|
721
|
+
ERR
|
542
722
|
end
|
543
723
|
end
|
544
724
|
else
|
545
|
-
|
546
|
-
ctx.schema.unauthorized_field(err)
|
725
|
+
raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: query_ctx, field: self)
|
547
726
|
end
|
548
|
-
rescue GraphQL::UnauthorizedFieldError => err
|
549
|
-
err.field ||= self
|
550
|
-
ctx.schema.unauthorized_field(err)
|
551
|
-
rescue GraphQL::UnauthorizedError => err
|
552
|
-
ctx.schema.unauthorized_object(err)
|
553
727
|
end
|
554
|
-
rescue GraphQL::
|
555
|
-
err
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
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
|
728
|
+
rescue GraphQL::UnauthorizedFieldError => err
|
729
|
+
err.field ||= self
|
730
|
+
begin
|
731
|
+
query_ctx.schema.unauthorized_field(err)
|
732
|
+
rescue GraphQL::ExecutionError => err
|
733
|
+
err
|
734
|
+
end
|
735
|
+
rescue GraphQL::UnauthorizedError => err
|
736
|
+
begin
|
737
|
+
query_ctx.schema.unauthorized_object(err)
|
738
|
+
rescue GraphQL::ExecutionError => err
|
739
|
+
err
|
740
|
+
end
|
741
|
+
rescue ArgumentError
|
742
|
+
if method_receiver && method_to_call
|
743
|
+
assert_satisfactory_implementation(method_receiver, method_to_call, method_args)
|
592
744
|
end
|
745
|
+
# if the line above doesn't raise, re-raise
|
746
|
+
raise
|
593
747
|
end
|
594
748
|
|
595
|
-
# @param ctx [GraphQL::Query::Context
|
749
|
+
# @param ctx [GraphQL::Query::Context]
|
596
750
|
def fetch_extra(extra_name, ctx)
|
597
|
-
if extra_name != :path && respond_to?(extra_name)
|
751
|
+
if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
|
598
752
|
self.public_send(extra_name)
|
599
753
|
elsif ctx.respond_to?(extra_name)
|
600
754
|
ctx.public_send(extra_name)
|
@@ -605,55 +759,43 @@ module GraphQL
|
|
605
759
|
|
606
760
|
private
|
607
761
|
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
ruby_kwargs_key = arg_defn.keyword
|
623
|
-
if ruby_kwargs.key?(ruby_kwargs_key) && arg_defn.prepare
|
624
|
-
ruby_kwargs[ruby_kwargs_key] = arg_defn.prepare_value(obj, ruby_kwargs[ruby_kwargs_key])
|
762
|
+
def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
|
763
|
+
method_defn = receiver.method(method_name)
|
764
|
+
unsatisfied_ruby_kwargs = ruby_kwargs.dup
|
765
|
+
unsatisfied_method_params = []
|
766
|
+
encountered_keyrest = false
|
767
|
+
method_defn.parameters.each do |(param_type, param_name)|
|
768
|
+
case param_type
|
769
|
+
when :key
|
770
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
771
|
+
when :keyreq
|
772
|
+
if unsatisfied_ruby_kwargs.key?(param_name)
|
773
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
774
|
+
else
|
775
|
+
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."
|
625
776
|
end
|
777
|
+
when :keyrest
|
778
|
+
encountered_keyrest = true
|
779
|
+
when :req
|
780
|
+
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."
|
781
|
+
when :opt, :rest
|
782
|
+
# This is fine, although it will never be present
|
626
783
|
end
|
784
|
+
end
|
627
785
|
|
628
|
-
|
629
|
-
|
630
|
-
end
|
631
|
-
|
632
|
-
ruby_kwargs
|
633
|
-
else
|
634
|
-
NO_ARGS
|
786
|
+
if encountered_keyrest
|
787
|
+
unsatisfied_ruby_kwargs.clear
|
635
788
|
end
|
636
|
-
end
|
637
789
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
if @resolver_class
|
642
|
-
if extended_obj.is_a?(GraphQL::Schema::Object)
|
643
|
-
extended_obj = extended_obj.object
|
644
|
-
end
|
645
|
-
extended_obj = @resolver_class.new(object: extended_obj, context: query_ctx, field: self)
|
646
|
-
end
|
790
|
+
if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
|
791
|
+
raise FieldImplementationFailed.new, <<-ERR
|
792
|
+
Failed to call `#{method_name.inspect}` on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
|
647
793
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
end
|
654
|
-
else
|
655
|
-
resolve_field_method(extended_obj, extended_args, query_ctx)
|
656
|
-
end
|
794
|
+
#{ unsatisfied_ruby_kwargs
|
795
|
+
.map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
|
796
|
+
.concat(unsatisfied_method_params)
|
797
|
+
.join("\n") }
|
798
|
+
ERR
|
657
799
|
end
|
658
800
|
end
|
659
801
|
|
@@ -664,32 +806,52 @@ module GraphQL
|
|
664
806
|
if @extensions.empty?
|
665
807
|
yield(obj, args)
|
666
808
|
else
|
667
|
-
#
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
809
|
+
# This is a hack to get the _last_ value for extended obj and args,
|
810
|
+
# in case one of the extensions doesn't `yield`.
|
811
|
+
# (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
|
812
|
+
extended = { args: args, obj: obj, memos: nil, added_extras: nil }
|
813
|
+
value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
|
814
|
+
if (added_extras = extended[:added_extras])
|
815
|
+
args = args.dup
|
816
|
+
added_extras.each { |e| args.delete(e) }
|
817
|
+
end
|
818
|
+
yield(obj, args)
|
674
819
|
end
|
675
820
|
|
821
|
+
extended_obj = extended[:obj]
|
822
|
+
extended_args = extended[:args]
|
823
|
+
memos = extended[:memos] || EMPTY_HASH
|
824
|
+
|
676
825
|
ctx.schema.after_lazy(value) do |resolved_value|
|
677
|
-
|
826
|
+
idx = 0
|
827
|
+
@extensions.each do |ext|
|
678
828
|
memo = memos[idx]
|
679
829
|
# TODO after_lazy?
|
680
|
-
resolved_value = ext.after_resolve(object:
|
830
|
+
resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
|
831
|
+
idx += 1
|
681
832
|
end
|
682
833
|
resolved_value
|
683
834
|
end
|
684
835
|
end
|
685
836
|
end
|
686
837
|
|
687
|
-
def run_extensions_before_resolve(
|
838
|
+
def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
|
688
839
|
extension = @extensions[idx]
|
689
840
|
if extension
|
690
841
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
691
|
-
|
692
|
-
|
842
|
+
if memo
|
843
|
+
memos = extended[:memos] ||= {}
|
844
|
+
memos[idx] = memo
|
845
|
+
end
|
846
|
+
|
847
|
+
if (extras = extension.added_extras)
|
848
|
+
ae = extended[:added_extras] ||= []
|
849
|
+
ae.concat(extras)
|
850
|
+
end
|
851
|
+
|
852
|
+
extended[:obj] = extended_obj
|
853
|
+
extended[:args] = extended_args
|
854
|
+
run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
|
693
855
|
end
|
694
856
|
else
|
695
857
|
yield(obj, args)
|