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