graphql 1.9.17 → 2.0.20
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 +54 -38
- data/lib/graphql/analysis/ast.rb +16 -16
- 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 +62 -24
- data/lib/graphql/execution/interpreter/runtime.rb +773 -399
- data/lib/graphql/execution/interpreter.rb +206 -74
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lazy.rb +11 -21
- data/lib/graphql/execution/lookahead.rb +65 -136
- data/lib/graphql/execution/multiplex.rb +6 -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 +12 -6
- 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 +12 -12
- 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 +113 -71
- data/lib/graphql/language/lexer.rb +216 -1462
- data/lib/graphql/language/nodes.rb +128 -131
- data/lib/graphql/language/parser.rb +957 -912
- data/lib/graphql/language/parser.y +148 -120
- 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 +192 -84
- data/lib/graphql/language.rb +3 -1
- data/lib/graphql/name_validator.rb +2 -7
- data/lib/graphql/pagination/active_record_relation_connection.rb +77 -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 +204 -203
- 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 +88 -40
- 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 +284 -33
- 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 +336 -205
- 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 +134 -15
- data/lib/graphql/schema/enum.rb +137 -39
- data/lib/graphql/schema/enum_value.rb +20 -23
- 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 +503 -331
- 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 +24 -49
- data/lib/graphql/schema/introspection_system.rb +103 -37
- data/lib/graphql/schema/late_bound_type.rb +9 -2
- data/lib/graphql/schema/list.rb +61 -3
- data/lib/graphql/schema/loader.rb +144 -96
- data/lib/graphql/schema/member/base_dsl_methods.rb +41 -37
- data/lib/graphql/schema/member/build_type.rb +24 -15
- data/lib/graphql/schema/member/has_arguments.rb +310 -26
- data/lib/graphql/schema/member/has_ast_node.rb +32 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +24 -0
- data/lib/graphql/schema/member/has_directives.rb +120 -0
- data/lib/graphql/schema/member/has_fields.rb +112 -34
- data/lib/graphql/schema/member/has_interfaces.rb +129 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/has_validators.rb +57 -0
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/type_system_helpers.rb +20 -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 +36 -60
- data/lib/graphql/schema/printer.rb +16 -35
- data/lib/graphql/schema/relay_classic_mutation.rb +91 -44
- data/lib/graphql/schema/resolver/has_payload_type.rb +51 -11
- data/lib/graphql/schema/resolver.rb +147 -94
- data/lib/graphql/schema/scalar.rb +40 -15
- data/lib/graphql/schema/subscription.rb +60 -31
- data/lib/graphql/schema/timeout.rb +45 -35
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +23 -6
- data/lib/graphql/schema/union.rb +49 -15
- 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 +211 -35
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +833 -889
- 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 +69 -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 +32 -20
- 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 +84 -35
- 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_trace.rb +16 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
- data/lib/graphql/tracing/appoptics_trace.rb +231 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_trace.rb +71 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
- data/lib/graphql/tracing/data_dog_trace.rb +148 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +34 -2
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
- data/lib/graphql/tracing/notifications_trace.rb +41 -0
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_trace.rb +107 -0
- data/lib/graphql/tracing/platform_tracing.rb +76 -35
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +11 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/scout_tracing.rb +19 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +143 -67
- data/lib/graphql/type_kinds.rb +6 -3
- 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 +176 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +75 -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 +25 -0
- data/lib/graphql/types/relay/page_info.rb +2 -14
- data/lib/graphql/types/relay/page_info_behaviors.rb +30 -0
- data/lib/graphql/types/relay.rb +10 -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 +60 -66
- data/readme.md +3 -6
- metadata +124 -236
- 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 -50
- data/lib/graphql/define/instance_definable.rb +0 -300
- 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/language/lexer.rl +0 -258
- 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 -66
- 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 -128
- 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,21 @@
|
|
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::HasArguments::FieldConfigured
|
10
|
+
include GraphQL::Schema::Member::HasAstNode
|
16
11
|
include GraphQL::Schema::Member::HasPath
|
12
|
+
include GraphQL::Schema::Member::HasValidators
|
17
13
|
extend GraphQL::Schema::FindInheritedValue
|
14
|
+
include GraphQL::Schema::FindInheritedValue::EmptyObjects
|
15
|
+
include GraphQL::Schema::Member::HasDirectives
|
16
|
+
include GraphQL::Schema::Member::HasDeprecationReason
|
17
|
+
|
18
|
+
class FieldImplementationFailed < GraphQL::Error; end
|
18
19
|
|
19
20
|
# @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
|
20
21
|
attr_reader :name
|
@@ -22,22 +23,39 @@ module GraphQL
|
|
22
23
|
|
23
24
|
attr_writer :description
|
24
25
|
|
25
|
-
# @return [String, nil] If present, the field is marked as deprecated with this documentation
|
26
|
-
attr_accessor :deprecation_reason
|
27
|
-
|
28
26
|
# @return [Symbol] Method or hash key on the underlying object to look up
|
29
27
|
attr_reader :method_sym
|
30
28
|
|
31
29
|
# @return [String] Method or hash key on the underlying object to look up
|
32
30
|
attr_reader :method_str
|
33
31
|
|
32
|
+
attr_reader :hash_key
|
33
|
+
attr_reader :dig_keys
|
34
|
+
|
34
35
|
# @return [Symbol] The method on the type to look up
|
35
|
-
|
36
|
+
def resolver_method
|
37
|
+
if @resolver_class
|
38
|
+
@resolver_class.resolver_method
|
39
|
+
else
|
40
|
+
@resolver_method
|
41
|
+
end
|
42
|
+
end
|
36
43
|
|
37
|
-
# @return [Class] The
|
38
|
-
|
44
|
+
# @return [Class] The thing this field was defined on (type, mutation, resolver)
|
45
|
+
attr_accessor :owner
|
46
|
+
|
47
|
+
# @return [Class] The GraphQL type this field belongs to. (For fields defined on mutations, it's the payload type)
|
48
|
+
def owner_type
|
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
|
52
|
+
owner.payload_type
|
53
|
+
else
|
54
|
+
owner
|
55
|
+
end
|
56
|
+
end
|
39
57
|
|
40
|
-
# @return [
|
58
|
+
# @return [Symbol] the original name of the field, passed in by the user
|
41
59
|
attr_reader :original_name
|
42
60
|
|
43
61
|
# @return [Class, nil] The {Schema::Resolver} this field was derived from, if there is one
|
@@ -45,13 +63,25 @@ module GraphQL
|
|
45
63
|
@resolver_class
|
46
64
|
end
|
47
65
|
|
66
|
+
# @return [Boolean] Is this field a predefined introspection field?
|
67
|
+
def introspection?
|
68
|
+
@introspection
|
69
|
+
end
|
70
|
+
|
71
|
+
def inspect
|
72
|
+
"#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
|
73
|
+
end
|
74
|
+
|
48
75
|
alias :mutation :resolver
|
49
76
|
|
50
77
|
# @return [Boolean] Apply tracing to this field? (Default: skip scalars, this is the override value)
|
51
78
|
attr_reader :trace
|
52
79
|
|
53
80
|
# @return [String, nil]
|
54
|
-
|
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
|
55
85
|
|
56
86
|
# Create a field instance from a list of arguments, keyword arguments, and a block.
|
57
87
|
#
|
@@ -65,21 +95,9 @@ module GraphQL
|
|
65
95
|
# @return [GraphQL::Schema:Field] an instance of `self
|
66
96
|
# @see {.initialize} for other options
|
67
97
|
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)
|
98
|
+
if (resolver_class = resolver || mutation || subscription)
|
81
99
|
# Add a reference to that parent class
|
82
|
-
kwargs[:resolver_class] =
|
100
|
+
kwargs[:resolver_class] = resolver_class
|
83
101
|
end
|
84
102
|
|
85
103
|
if name
|
@@ -87,9 +105,6 @@ module GraphQL
|
|
87
105
|
end
|
88
106
|
|
89
107
|
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
108
|
if desc
|
94
109
|
if kwargs[:description]
|
95
110
|
raise ArgumentError, "Provide description as a positional argument or `description:` keyword, but not both (#{desc.inspect}, #{kwargs[:description].inspect})"
|
@@ -97,12 +112,15 @@ module GraphQL
|
|
97
112
|
|
98
113
|
kwargs[:description] = desc
|
99
114
|
kwargs[:type] = type
|
100
|
-
elsif (
|
101
|
-
# 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
|
102
117
|
kwargs[:description] = type
|
103
118
|
else
|
104
119
|
kwargs[:type] = type
|
105
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
|
106
124
|
end
|
107
125
|
new(**kwargs, &block)
|
108
126
|
end
|
@@ -112,10 +130,10 @@ module GraphQL
|
|
112
130
|
def connection?
|
113
131
|
if @connection.nil?
|
114
132
|
# 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
|
133
|
+
return_type_name = if @return_type_expr
|
118
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)
|
119
137
|
else
|
120
138
|
# As a last ditch, try to force loading the return type:
|
121
139
|
type.unwrap.name
|
@@ -131,8 +149,18 @@ module GraphQL
|
|
131
149
|
if !@scope.nil?
|
132
150
|
# The default was overridden
|
133
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?
|
134
162
|
else
|
135
|
-
|
163
|
+
false
|
136
164
|
end
|
137
165
|
end
|
138
166
|
|
@@ -152,21 +180,31 @@ module GraphQL
|
|
152
180
|
end
|
153
181
|
end
|
154
182
|
|
183
|
+
# @return Boolean
|
184
|
+
attr_reader :relay_node_field
|
185
|
+
# @return Boolean
|
186
|
+
attr_reader :relay_nodes_field
|
187
|
+
|
188
|
+
# @return [Boolean] Should we warn if this field's name conflicts with a built-in method?
|
189
|
+
def method_conflict_warning?
|
190
|
+
@method_conflict_warning
|
191
|
+
end
|
192
|
+
|
155
193
|
# @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
|
156
194
|
# @param type [Class, GraphQL::BaseType, Array] The return type of this field
|
157
195
|
# @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`
|
196
|
+
# @param null [Boolean] (defaults to `true`) `true` if this field may return `null`, `false` if it is never `null`
|
159
197
|
# @param description [String] Field description
|
160
198
|
# @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
|
161
199
|
# @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
|
162
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
|
163
202
|
# @param resolver_method [Symbol] The method on the type to call to resolve this field (defaults to `name`)
|
164
203
|
# @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
|
204
|
+
# @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
|
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.
|
166
207
|
# @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
208
|
# @param resolver_class [Class] (Private) A {Schema::Resolver} which this field was derived from. Use `resolver:` to create a field with a resolver.
|
171
209
|
# @param arguments [{String=>GraphQL::Schema::Argument, Hash}] Arguments for this field (may be added in the block, also)
|
172
210
|
# @param camelize [Boolean] If true, the field name will be camelized when building the schema
|
@@ -174,37 +212,35 @@ module GraphQL
|
|
174
212
|
# @param scope [Boolean] If true, the return type's `.scope_items` method will be called on the return value
|
175
213
|
# @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
|
176
214
|
# @param extensions [Array<Class, Hash<Class => Object>>] Named extensions to apply to this field (see also {#extension})
|
215
|
+
# @param directives [Hash{Class => Hash}] Directives to apply to this field
|
177
216
|
# @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
|
178
|
-
|
217
|
+
# @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
|
218
|
+
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
219
|
+
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
220
|
+
# @param validates [Array<Hash>] Configurations for validating this field
|
221
|
+
# @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_given, &definition_block)
|
179
223
|
if name.nil?
|
180
224
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
181
225
|
end
|
182
|
-
if !(
|
226
|
+
if !(resolver_class)
|
183
227
|
if type.nil?
|
184
228
|
raise ArgumentError, "missing second `type` argument or keyword `type:`"
|
185
229
|
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
230
|
end
|
193
231
|
@original_name = name
|
194
|
-
|
195
|
-
|
232
|
+
name_s = -name.to_s
|
233
|
+
|
234
|
+
@underscored_name = -Member::BuildType.underscore(name_s)
|
235
|
+
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
236
|
+
|
196
237
|
@description = description
|
197
|
-
if
|
198
|
-
|
199
|
-
|
200
|
-
@field = field
|
201
|
-
end
|
202
|
-
@function = function
|
203
|
-
@resolve = resolve
|
204
|
-
@deprecation_reason = deprecation_reason
|
238
|
+
@type = @owner_type = @own_validators = @own_directives = @own_arguments = nil # these will be prepared later if necessary
|
239
|
+
|
240
|
+
self.deprecation_reason = deprecation_reason
|
205
241
|
|
206
|
-
if method && hash_key
|
207
|
-
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}`)"
|
208
244
|
end
|
209
245
|
|
210
246
|
if resolver_method
|
@@ -212,58 +248,95 @@ module GraphQL
|
|
212
248
|
raise ArgumentError, "Provide `method:` _or_ `resolver_method:`, not both. (called with: `method: #{method.inspect}, resolver_method: #{resolver_method.inspect}`)"
|
213
249
|
end
|
214
250
|
|
215
|
-
if hash_key
|
216
|
-
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}`)"
|
217
253
|
end
|
218
254
|
end
|
219
255
|
|
220
|
-
|
221
|
-
|
222
|
-
|
256
|
+
method_name = method || hash_key || name_s
|
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
|
223
265
|
|
224
|
-
@method_str = method_name.to_s
|
266
|
+
@method_str = -method_name.to_s
|
225
267
|
@method_sym = method_name.to_sym
|
226
|
-
@resolver_method = resolver_method
|
268
|
+
@resolver_method = (resolver_method || name_s).to_sym
|
227
269
|
@complexity = complexity
|
228
270
|
@return_type_expr = type
|
229
|
-
@return_type_null = null
|
271
|
+
@return_type_null = if !null.nil?
|
272
|
+
null
|
273
|
+
elsif resolver_class
|
274
|
+
nil
|
275
|
+
else
|
276
|
+
true
|
277
|
+
end
|
230
278
|
@connection = connection
|
231
279
|
@max_page_size = max_page_size
|
280
|
+
@default_page_size = default_page_size
|
232
281
|
@introspection = introspection
|
233
282
|
@extras = extras
|
283
|
+
@broadcastable = broadcastable
|
234
284
|
@resolver_class = resolver_class
|
235
285
|
@scope = scope
|
236
286
|
@trace = trace
|
237
287
|
@relay_node_field = relay_node_field
|
238
288
|
@relay_nodes_field = relay_nodes_field
|
289
|
+
@ast_node = ast_node
|
290
|
+
@method_conflict_warning = method_conflict_warning
|
291
|
+
@fallback_value = fallback_value
|
239
292
|
|
240
|
-
# Override the default from HasArguments
|
241
|
-
@own_arguments = {}
|
242
293
|
arguments.each do |name, arg|
|
243
|
-
|
294
|
+
case arg
|
295
|
+
when Hash
|
244
296
|
argument(name: name, **arg)
|
297
|
+
when GraphQL::Schema::Argument
|
298
|
+
add_argument(arg)
|
299
|
+
when Array
|
300
|
+
arg.each { |a| add_argument(a) }
|
245
301
|
else
|
246
|
-
|
302
|
+
raise ArgumentError, "Unexpected argument config (#{arg.class}): #{arg.inspect}"
|
247
303
|
end
|
248
304
|
end
|
249
305
|
|
250
306
|
@owner = owner
|
251
307
|
@subscription_scope = subscription_scope
|
252
308
|
|
253
|
-
|
254
|
-
@
|
255
|
-
if extensions.any?
|
256
|
-
self.extensions(extensions)
|
257
|
-
end
|
309
|
+
@extensions = EMPTY_ARRAY
|
310
|
+
@call_after_define = false
|
258
311
|
# This should run before connection extension,
|
259
312
|
# but should it run after the definition block?
|
260
313
|
if scoped?
|
261
314
|
self.extension(ScopeExtension)
|
262
315
|
end
|
316
|
+
|
263
317
|
# The problem with putting this after the definition_block
|
264
318
|
# is that it would override arguments
|
265
|
-
if connection?
|
266
|
-
self.extension(
|
319
|
+
if connection? && connection_extension
|
320
|
+
self.extension(connection_extension)
|
321
|
+
end
|
322
|
+
|
323
|
+
# Do this last so we have as much context as possible when initializing them:
|
324
|
+
if extensions.any?
|
325
|
+
self.extensions(extensions)
|
326
|
+
end
|
327
|
+
|
328
|
+
if resolver_class && resolver_class.extensions.any?
|
329
|
+
self.extensions(resolver_class.extensions)
|
330
|
+
end
|
331
|
+
|
332
|
+
if directives.any?
|
333
|
+
directives.each do |(dir_class, options)|
|
334
|
+
self.directive(dir_class, **options)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
if !validates.empty?
|
339
|
+
self.validates(validates)
|
267
340
|
end
|
268
341
|
|
269
342
|
if definition_block
|
@@ -273,6 +346,22 @@ module GraphQL
|
|
273
346
|
instance_eval(&definition_block)
|
274
347
|
end
|
275
348
|
end
|
349
|
+
|
350
|
+
self.extensions.each(&:after_define_apply)
|
351
|
+
@call_after_define = true
|
352
|
+
end
|
353
|
+
|
354
|
+
# If true, subscription updates with this field can be shared between viewers
|
355
|
+
# @return [Boolean, nil]
|
356
|
+
# @see GraphQL::Subscriptions::BroadcastAnalyzer
|
357
|
+
def broadcastable?
|
358
|
+
if !NOT_CONFIGURED.equal?(@broadcastable)
|
359
|
+
@broadcastable
|
360
|
+
elsif @resolver_class
|
361
|
+
@resolver_class.broadcastable?
|
362
|
+
else
|
363
|
+
nil
|
364
|
+
end
|
276
365
|
end
|
277
366
|
|
278
367
|
# @param text [String]
|
@@ -280,8 +369,12 @@ module GraphQL
|
|
280
369
|
def description(text = nil)
|
281
370
|
if text
|
282
371
|
@description = text
|
283
|
-
|
372
|
+
elsif !NOT_CONFIGURED.equal?(@description)
|
284
373
|
@description
|
374
|
+
elsif @resolver_class
|
375
|
+
@resolver_class.description
|
376
|
+
else
|
377
|
+
nil
|
285
378
|
end
|
286
379
|
end
|
287
380
|
|
@@ -298,24 +391,20 @@ module GraphQL
|
|
298
391
|
# @example adding an extension with options
|
299
392
|
# extensions([MyExtensionClass, { AnotherExtensionClass => { filter: true } }])
|
300
393
|
#
|
301
|
-
# @param extensions [Array<Class, Hash<Class =>
|
394
|
+
# @param extensions [Array<Class, Hash<Class => Hash>>] Add extensions to this field. For hash elements, only the first key/value is used.
|
302
395
|
# @return [Array<GraphQL::Schema::FieldExtension>] extensions to apply to this field
|
303
396
|
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)
|
397
|
+
if new_extensions
|
398
|
+
new_extensions.each do |extension_config|
|
399
|
+
if extension_config.is_a?(Hash)
|
400
|
+
extension_class, options = *extension_config.to_a[0]
|
401
|
+
self.extension(extension_class, options)
|
313
402
|
else
|
314
|
-
|
315
|
-
@extensions << extension_class.new(field: self, options: nil)
|
403
|
+
self.extension(extension_config)
|
316
404
|
end
|
317
405
|
end
|
318
406
|
end
|
407
|
+
@extensions
|
319
408
|
end
|
320
409
|
|
321
410
|
# Add `extension` to this field, initialized with `options` if provided.
|
@@ -326,10 +415,19 @@ module GraphQL
|
|
326
415
|
# @example adding an extension with options
|
327
416
|
# extension(MyExtensionClass, filter: true)
|
328
417
|
#
|
329
|
-
# @param
|
330
|
-
# @param options [
|
331
|
-
|
332
|
-
|
418
|
+
# @param extension_class [Class] subclass of {Schema::FieldExtension}
|
419
|
+
# @param options [Hash] if provided, given as `options:` when initializing `extension`.
|
420
|
+
# @return [void]
|
421
|
+
def extension(extension_class, options = nil)
|
422
|
+
extension_inst = extension_class.new(field: self, options: options)
|
423
|
+
if @extensions.frozen?
|
424
|
+
@extensions = @extensions.dup
|
425
|
+
end
|
426
|
+
if @call_after_define
|
427
|
+
extension_inst.after_define_apply
|
428
|
+
end
|
429
|
+
@extensions << extension_inst
|
430
|
+
nil
|
333
431
|
end
|
334
432
|
|
335
433
|
# Read extras (as symbols) from this field,
|
@@ -340,14 +438,87 @@ module GraphQL
|
|
340
438
|
def extras(new_extras = nil)
|
341
439
|
if new_extras.nil?
|
342
440
|
# Read the value
|
343
|
-
@extras
|
441
|
+
field_extras = @extras
|
442
|
+
if @resolver_class && @resolver_class.extras.any?
|
443
|
+
field_extras + @resolver_class.extras
|
444
|
+
else
|
445
|
+
field_extras
|
446
|
+
end
|
344
447
|
else
|
448
|
+
if @extras.frozen?
|
449
|
+
@extras = @extras.dup
|
450
|
+
end
|
345
451
|
# Append to the set of extras on this field
|
346
452
|
@extras.concat(new_extras)
|
347
453
|
end
|
348
454
|
end
|
349
455
|
|
350
|
-
def
|
456
|
+
def calculate_complexity(query:, nodes:, child_complexity:)
|
457
|
+
if respond_to?(:complexity_for)
|
458
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
459
|
+
complexity_for(child_complexity: child_complexity, query: query, lookahead: lookahead)
|
460
|
+
elsif connection?
|
461
|
+
arguments = query.arguments_for(nodes.first, self)
|
462
|
+
max_possible_page_size = nil
|
463
|
+
if arguments.respond_to?(:[]) # It might have been an error
|
464
|
+
if arguments[:first]
|
465
|
+
max_possible_page_size = arguments[:first]
|
466
|
+
end
|
467
|
+
|
468
|
+
if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
|
469
|
+
max_possible_page_size = arguments[:last]
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
if max_possible_page_size.nil?
|
474
|
+
max_possible_page_size = default_page_size || query.schema.default_page_size || max_page_size || query.schema.default_max_page_size
|
475
|
+
end
|
476
|
+
|
477
|
+
if max_possible_page_size.nil?
|
478
|
+
raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `default_page_size`, `max_page_size` or `default_max_page_size`"
|
479
|
+
else
|
480
|
+
metadata_complexity = 0
|
481
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
482
|
+
|
483
|
+
if (page_info_lookahead = lookahead.selection(:page_info)).selected?
|
484
|
+
metadata_complexity += 1 # pageInfo
|
485
|
+
metadata_complexity += page_info_lookahead.selections.size # subfields
|
486
|
+
end
|
487
|
+
|
488
|
+
if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
|
489
|
+
metadata_complexity += 1
|
490
|
+
end
|
491
|
+
|
492
|
+
nodes_edges_complexity = 0
|
493
|
+
nodes_edges_complexity += 1 if lookahead.selects?(:edges)
|
494
|
+
nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
|
495
|
+
|
496
|
+
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
497
|
+
items_complexity = child_complexity - metadata_complexity - nodes_edges_complexity
|
498
|
+
# Add 1 for _this_ field
|
499
|
+
1 + (max_possible_page_size * items_complexity) + metadata_complexity + nodes_edges_complexity
|
500
|
+
end
|
501
|
+
else
|
502
|
+
defined_complexity = complexity
|
503
|
+
case defined_complexity
|
504
|
+
when Proc
|
505
|
+
arguments = query.arguments_for(nodes.first, self)
|
506
|
+
if arguments.is_a?(GraphQL::ExecutionError)
|
507
|
+
return child_complexity
|
508
|
+
elsif arguments.respond_to?(:keyword_arguments)
|
509
|
+
arguments = arguments.keyword_arguments
|
510
|
+
end
|
511
|
+
|
512
|
+
defined_complexity.call(query.context, arguments, child_complexity)
|
513
|
+
when Numeric
|
514
|
+
defined_complexity + child_complexity
|
515
|
+
else
|
516
|
+
raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
def complexity(new_complexity = nil)
|
351
522
|
case new_complexity
|
352
523
|
when Proc
|
353
524
|
if new_complexity.parameters.size != 3
|
@@ -360,87 +531,68 @@ module GraphQL
|
|
360
531
|
end
|
361
532
|
when Numeric
|
362
533
|
@complexity = new_complexity
|
534
|
+
when nil
|
535
|
+
if @resolver_class
|
536
|
+
@complexity || @resolver_class.complexity || 1
|
537
|
+
else
|
538
|
+
@complexity || 1
|
539
|
+
end
|
363
540
|
else
|
364
541
|
raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
|
365
542
|
end
|
366
543
|
end
|
367
544
|
|
368
|
-
# @return [
|
369
|
-
|
545
|
+
# @return [Boolean] True if this field's {#max_page_size} should override the schema default.
|
546
|
+
def has_max_page_size?
|
547
|
+
!NOT_CONFIGURED.equal?(@max_page_size) || (@resolver_class && @resolver_class.has_max_page_size?)
|
548
|
+
end
|
370
549
|
|
371
|
-
# @return [
|
372
|
-
def
|
373
|
-
|
374
|
-
@
|
375
|
-
elsif @
|
376
|
-
|
550
|
+
# @return [Integer, nil] Applied to connections if {#has_max_page_size?}
|
551
|
+
def max_page_size
|
552
|
+
if !NOT_CONFIGURED.equal?(@max_page_size)
|
553
|
+
@max_page_size
|
554
|
+
elsif @resolver_class && @resolver_class.has_max_page_size?
|
555
|
+
@resolver_class.max_page_size
|
377
556
|
else
|
378
|
-
|
557
|
+
nil
|
379
558
|
end
|
559
|
+
end
|
380
560
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
561
|
+
# @return [Boolean] True if this field's {#default_page_size} should override the schema default.
|
562
|
+
def has_default_page_size?
|
563
|
+
!NOT_CONFIGURED.equal?(@default_page_size) || (@resolver_class && @resolver_class.has_default_page_size?)
|
564
|
+
end
|
385
565
|
|
386
|
-
|
387
|
-
|
566
|
+
# @return [Integer, nil] Applied to connections if {#has_default_page_size?}
|
567
|
+
def default_page_size
|
568
|
+
if !NOT_CONFIGURED.equal?(@default_page_size)
|
569
|
+
@default_page_size
|
570
|
+
elsif @resolver_class && @resolver_class.has_default_page_size?
|
571
|
+
@resolver_class.default_page_size
|
572
|
+
else
|
573
|
+
nil
|
388
574
|
end
|
575
|
+
end
|
389
576
|
|
390
|
-
|
391
|
-
|
392
|
-
end
|
577
|
+
class MissingReturnTypeError < GraphQL::Error; end
|
578
|
+
attr_writer :type
|
393
579
|
|
580
|
+
def type
|
394
581
|
if @resolver_class
|
395
|
-
|
396
|
-
|
582
|
+
return_type = @return_type_expr || @resolver_class.type_expr
|
583
|
+
if return_type.nil?
|
584
|
+
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
585
|
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
|
586
|
+
nullable = @return_type_null.nil? ? @resolver_class.null : @return_type_null
|
587
|
+
Member::BuildType.parse_type(return_type, null: nullable)
|
588
|
+
else
|
589
|
+
@type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
432
590
|
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
|
591
|
+
rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
|
592
|
+
# Let this propagate up
|
593
|
+
raise err
|
594
|
+
rescue StandardError => err
|
595
|
+
raise MissingReturnTypeError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: (#{err.class}) #{err.message}", err.backtrace
|
444
596
|
end
|
445
597
|
|
446
598
|
def visible?(context)
|
@@ -451,56 +603,46 @@ module GraphQL
|
|
451
603
|
end
|
452
604
|
end
|
453
605
|
|
454
|
-
def
|
455
|
-
if @resolver_class
|
456
|
-
@resolver_class.accessible?(context)
|
457
|
-
else
|
458
|
-
true
|
459
|
-
end
|
460
|
-
end
|
461
|
-
|
462
|
-
def authorized?(object, context)
|
606
|
+
def authorized?(object, args, context)
|
463
607
|
if @resolver_class
|
464
|
-
# The resolver will check itself during `resolve()`
|
608
|
+
# The resolver _instance_ will check itself during `resolve()`
|
465
609
|
@resolver_class.authorized?(object, context)
|
466
610
|
else
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
611
|
+
if (arg_values = context[:current_arguments])
|
612
|
+
# ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
|
613
|
+
using_arg_values = true
|
614
|
+
arg_values = arg_values.argument_values
|
615
|
+
else
|
616
|
+
arg_values = args
|
617
|
+
using_arg_values = false
|
472
618
|
end
|
473
|
-
|
474
|
-
|
475
|
-
|
619
|
+
if args.size > 0
|
620
|
+
args = context.warden.arguments(self)
|
621
|
+
args.each do |arg|
|
622
|
+
arg_key = arg.keyword
|
623
|
+
if arg_values.key?(arg_key)
|
624
|
+
arg_value = arg_values[arg_key]
|
625
|
+
if using_arg_values
|
626
|
+
if arg_value.default_used?
|
627
|
+
# pass -- no auth required for default used
|
628
|
+
next
|
629
|
+
else
|
630
|
+
application_arg_value = arg_value.value
|
631
|
+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
|
632
|
+
application_arg_value.keyword_arguments
|
633
|
+
end
|
634
|
+
end
|
635
|
+
else
|
636
|
+
application_arg_value = arg_value
|
637
|
+
end
|
476
638
|
|
477
|
-
|
478
|
-
|
479
|
-
|
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)
|
639
|
+
if !arg.authorized?(object, application_arg_value, context)
|
640
|
+
return false
|
641
|
+
end
|
496
642
|
end
|
497
|
-
else
|
498
|
-
public_send_field(after_obj, ruby_args, ctx)
|
499
643
|
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
644
|
end
|
645
|
+
true
|
504
646
|
end
|
505
647
|
end
|
506
648
|
|
@@ -509,92 +651,114 @@ module GraphQL
|
|
509
651
|
# @param object [GraphQL::Schema::Object] An instance of some type class, wrapping an application object
|
510
652
|
# @param args [Hash] A symbol-keyed hash of Ruby keyword arguments. (Empty if no args)
|
511
653
|
# @param ctx [GraphQL::Query::Context]
|
512
|
-
def resolve(object, args,
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
654
|
+
def resolve(object, args, query_ctx)
|
655
|
+
# Unwrap the GraphQL object to get the application object.
|
656
|
+
application_object = object.object
|
657
|
+
method_receiver = nil
|
658
|
+
method_to_call = nil
|
659
|
+
method_args = nil
|
660
|
+
|
661
|
+
Schema::Validator.validate!(validators, application_object, query_ctx, args)
|
662
|
+
|
663
|
+
query_ctx.schema.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
|
664
|
+
if is_authorized
|
665
|
+
with_extensions(object, args, query_ctx) do |obj, ruby_kwargs|
|
666
|
+
method_args = ruby_kwargs
|
667
|
+
if @resolver_class
|
668
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
669
|
+
obj = obj.object
|
527
670
|
end
|
528
|
-
@resolver_class.new(object:
|
529
|
-
else
|
530
|
-
extended_obj
|
671
|
+
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
531
672
|
end
|
532
673
|
|
533
|
-
|
674
|
+
inner_object = obj.object
|
675
|
+
|
676
|
+
if !NOT_CONFIGURED.equal?(@hash_key)
|
677
|
+
hash_value = if inner_object.is_a?(Hash)
|
678
|
+
inner_object.key?(@hash_key) ? inner_object[@hash_key] : inner_object[@hash_key_str]
|
679
|
+
elsif inner_object.respond_to?(:[])
|
680
|
+
inner_object[@hash_key]
|
681
|
+
else
|
682
|
+
nil
|
683
|
+
end
|
684
|
+
if hash_value == false
|
685
|
+
hash_value
|
686
|
+
else
|
687
|
+
hash_value || (@fallback_value != :not_given ? @fallback_value : nil)
|
688
|
+
end
|
689
|
+
elsif obj.respond_to?(resolver_method)
|
690
|
+
method_to_call = resolver_method
|
691
|
+
method_receiver = obj
|
534
692
|
# Call the method with kwargs, if there are any
|
535
|
-
if
|
536
|
-
|
693
|
+
if ruby_kwargs.any?
|
694
|
+
obj.public_send(resolver_method, **ruby_kwargs)
|
695
|
+
else
|
696
|
+
obj.public_send(resolver_method)
|
697
|
+
end
|
698
|
+
elsif inner_object.is_a?(Hash)
|
699
|
+
if @dig_keys
|
700
|
+
inner_object.dig(*@dig_keys)
|
701
|
+
elsif inner_object.key?(@method_sym)
|
702
|
+
inner_object[@method_sym]
|
703
|
+
elsif inner_object.key?(@method_str)
|
704
|
+
inner_object[@method_str]
|
705
|
+
elsif @fallback_value != :not_given
|
706
|
+
@fallback_value
|
707
|
+
else
|
708
|
+
nil
|
709
|
+
end
|
710
|
+
elsif inner_object.respond_to?(@method_sym)
|
711
|
+
method_to_call = @method_sym
|
712
|
+
method_receiver = obj.object
|
713
|
+
if ruby_kwargs.any?
|
714
|
+
inner_object.public_send(@method_sym, **ruby_kwargs)
|
537
715
|
else
|
538
|
-
|
716
|
+
inner_object.public_send(@method_sym)
|
539
717
|
end
|
718
|
+
elsif @fallback_value != :not_given
|
719
|
+
@fallback_value
|
540
720
|
else
|
541
|
-
|
721
|
+
raise <<-ERR
|
722
|
+
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
723
|
+
|
724
|
+
- `#{obj.class}##{resolver_method}`, which did not exist
|
725
|
+
- `#{inner_object.class}##{@method_sym}`, which did not exist
|
726
|
+
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{inner_object}`, but it wasn't a Hash
|
727
|
+
|
728
|
+
To implement this field, define one of the methods above (and check for typos), or supply a `fallback_value`.
|
729
|
+
ERR
|
542
730
|
end
|
543
731
|
end
|
544
732
|
else
|
545
|
-
|
546
|
-
ctx.schema.unauthorized_field(err)
|
733
|
+
raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: query_ctx, field: self)
|
547
734
|
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
735
|
end
|
736
|
+
rescue GraphQL::UnauthorizedFieldError => err
|
737
|
+
err.field ||= self
|
738
|
+
begin
|
739
|
+
query_ctx.schema.unauthorized_field(err)
|
740
|
+
rescue GraphQL::ExecutionError => err
|
741
|
+
err
|
742
|
+
end
|
743
|
+
rescue GraphQL::UnauthorizedError => err
|
744
|
+
begin
|
745
|
+
query_ctx.schema.unauthorized_object(err)
|
746
|
+
rescue GraphQL::ExecutionError => err
|
747
|
+
err
|
748
|
+
end
|
749
|
+
rescue ArgumentError
|
750
|
+
if method_receiver && method_to_call
|
751
|
+
assert_satisfactory_implementation(method_receiver, method_to_call, method_args)
|
752
|
+
end
|
753
|
+
# if the line above doesn't raise, re-raise
|
754
|
+
raise
|
554
755
|
rescue GraphQL::ExecutionError => err
|
555
756
|
err
|
556
757
|
end
|
557
758
|
|
558
|
-
# Find a way to resolve this field, checking:
|
559
|
-
#
|
560
|
-
# - Hash keys, if the wrapped object is a hash;
|
561
|
-
# - A method on the wrapped object;
|
562
|
-
# - Or, raise not implemented.
|
563
|
-
#
|
564
|
-
# This can be overridden by defining a method on the object type.
|
565
|
-
# @param obj [GraphQL::Schema::Object]
|
566
|
-
# @param ruby_kwargs [Hash<Symbol => Object>]
|
567
759
|
# @param ctx [GraphQL::Query::Context]
|
568
|
-
def resolve_field_method(obj, ruby_kwargs, ctx)
|
569
|
-
if obj.object.is_a?(Hash)
|
570
|
-
inner_object = obj.object
|
571
|
-
if inner_object.key?(@method_sym)
|
572
|
-
inner_object[@method_sym]
|
573
|
-
else
|
574
|
-
inner_object[@method_str]
|
575
|
-
end
|
576
|
-
elsif obj.object.respond_to?(@method_sym)
|
577
|
-
if ruby_kwargs.any?
|
578
|
-
obj.object.public_send(@method_sym, **ruby_kwargs)
|
579
|
-
else
|
580
|
-
obj.object.public_send(@method_sym)
|
581
|
-
end
|
582
|
-
else
|
583
|
-
raise <<-ERR
|
584
|
-
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
585
|
-
|
586
|
-
- `#{obj.class}##{@resolver_method}`, which did not exist
|
587
|
-
- `#{obj.object.class}##{@method_sym}`, which did not exist
|
588
|
-
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
|
589
|
-
|
590
|
-
To implement this field, define one of the methods above (and check for typos)
|
591
|
-
ERR
|
592
|
-
end
|
593
|
-
end
|
594
|
-
|
595
|
-
# @param ctx [GraphQL::Query::Context::FieldResolutionContext]
|
596
760
|
def fetch_extra(extra_name, ctx)
|
597
|
-
if extra_name != :path && respond_to?(extra_name)
|
761
|
+
if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
|
598
762
|
self.public_send(extra_name)
|
599
763
|
elsif ctx.respond_to?(extra_name)
|
600
764
|
ctx.public_send(extra_name)
|
@@ -605,55 +769,43 @@ module GraphQL
|
|
605
769
|
|
606
770
|
private
|
607
771
|
|
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])
|
772
|
+
def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
|
773
|
+
method_defn = receiver.method(method_name)
|
774
|
+
unsatisfied_ruby_kwargs = ruby_kwargs.dup
|
775
|
+
unsatisfied_method_params = []
|
776
|
+
encountered_keyrest = false
|
777
|
+
method_defn.parameters.each do |(param_type, param_name)|
|
778
|
+
case param_type
|
779
|
+
when :key
|
780
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
781
|
+
when :keyreq
|
782
|
+
if unsatisfied_ruby_kwargs.key?(param_name)
|
783
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
784
|
+
else
|
785
|
+
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
786
|
end
|
787
|
+
when :keyrest
|
788
|
+
encountered_keyrest = true
|
789
|
+
when :req
|
790
|
+
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."
|
791
|
+
when :opt, :rest
|
792
|
+
# This is fine, although it will never be present
|
626
793
|
end
|
794
|
+
end
|
627
795
|
|
628
|
-
|
629
|
-
|
630
|
-
end
|
631
|
-
|
632
|
-
ruby_kwargs
|
633
|
-
else
|
634
|
-
NO_ARGS
|
796
|
+
if encountered_keyrest
|
797
|
+
unsatisfied_ruby_kwargs.clear
|
635
798
|
end
|
636
|
-
end
|
637
799
|
|
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
|
800
|
+
if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
|
801
|
+
raise FieldImplementationFailed.new, <<-ERR
|
802
|
+
Failed to call `#{method_name.inspect}` on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
|
647
803
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
end
|
654
|
-
else
|
655
|
-
resolve_field_method(extended_obj, extended_args, query_ctx)
|
656
|
-
end
|
804
|
+
#{ unsatisfied_ruby_kwargs
|
805
|
+
.map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
|
806
|
+
.concat(unsatisfied_method_params)
|
807
|
+
.join("\n") }
|
808
|
+
ERR
|
657
809
|
end
|
658
810
|
end
|
659
811
|
|
@@ -664,32 +816,52 @@ module GraphQL
|
|
664
816
|
if @extensions.empty?
|
665
817
|
yield(obj, args)
|
666
818
|
else
|
667
|
-
#
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
819
|
+
# This is a hack to get the _last_ value for extended obj and args,
|
820
|
+
# in case one of the extensions doesn't `yield`.
|
821
|
+
# (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
|
822
|
+
extended = { args: args, obj: obj, memos: nil, added_extras: nil }
|
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
|
828
|
+
yield(obj, args)
|
674
829
|
end
|
675
830
|
|
831
|
+
extended_obj = extended[:obj]
|
832
|
+
extended_args = extended[:args]
|
833
|
+
memos = extended[:memos] || EMPTY_HASH
|
834
|
+
|
676
835
|
ctx.schema.after_lazy(value) do |resolved_value|
|
677
|
-
|
836
|
+
idx = 0
|
837
|
+
@extensions.each do |ext|
|
678
838
|
memo = memos[idx]
|
679
839
|
# TODO after_lazy?
|
680
|
-
resolved_value = ext.after_resolve(object:
|
840
|
+
resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
|
841
|
+
idx += 1
|
681
842
|
end
|
682
843
|
resolved_value
|
683
844
|
end
|
684
845
|
end
|
685
846
|
end
|
686
847
|
|
687
|
-
def run_extensions_before_resolve(
|
848
|
+
def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
|
688
849
|
extension = @extensions[idx]
|
689
850
|
if extension
|
690
851
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
691
|
-
|
692
|
-
|
852
|
+
if memo
|
853
|
+
memos = extended[:memos] ||= {}
|
854
|
+
memos[idx] = memo
|
855
|
+
end
|
856
|
+
|
857
|
+
if (extras = extension.added_extras)
|
858
|
+
ae = extended[:added_extras] ||= []
|
859
|
+
ae.concat(extras)
|
860
|
+
end
|
861
|
+
|
862
|
+
extended[:obj] = extended_obj
|
863
|
+
extended[:args] = extended_args
|
864
|
+
run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
|
693
865
|
end
|
694
866
|
else
|
695
867
|
yield(obj, args)
|