graphql 1.9.21 → 2.0.0
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 +44 -7
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/loader_generator.rb +1 -0
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +6 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +28 -12
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +63 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +8 -0
- data/lib/generators/graphql/templates/base_edge.erb +8 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +7 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +6 -2
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +3 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +7 -3
- data/lib/generators/graphql/templates/query_type.erb +3 -3
- data/lib/generators/graphql/templates/scalar.erb +5 -1
- data/lib/generators/graphql/templates/schema.erb +22 -27
- data/lib/generators/graphql/templates/union.erb +6 -2
- data/lib/generators/graphql/type_generator.rb +47 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/ast/field_usage.rb +29 -2
- data/lib/graphql/analysis/ast/query_complexity.rb +175 -68
- data/lib/graphql/analysis/ast/query_depth.rb +0 -1
- data/lib/graphql/analysis/ast/visitor.rb +17 -8
- data/lib/graphql/analysis/ast.rb +14 -14
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/inspect_result.rb +0 -1
- data/lib/graphql/backtrace/table.rb +37 -16
- data/lib/graphql/backtrace/traced_error.rb +0 -1
- data/lib/graphql/backtrace/tracer.rb +39 -9
- data/lib/graphql/backtrace.rb +20 -17
- data/lib/graphql/dataloader/null_dataloader.rb +22 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +155 -0
- data/lib/graphql/dataloader.rb +308 -0
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/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 +108 -14
- data/lib/graphql/execution/instrumentation.rb +1 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +88 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +105 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
- data/lib/graphql/execution/interpreter/resolve.rb +37 -25
- data/lib/graphql/execution/interpreter/runtime.rb +715 -387
- data/lib/graphql/execution/interpreter.rb +32 -31
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lazy.rb +5 -1
- data/lib/graphql/execution/lookahead.rb +32 -114
- data/lib/graphql/execution/multiplex.rb +60 -92
- data/lib/graphql/execution.rb +11 -3
- data/lib/graphql/filter.rb +1 -1
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/introspection/base_object.rb +2 -5
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +11 -5
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +5 -18
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +9 -5
- data/lib/graphql/introspection/input_value_type.rb +41 -11
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +10 -10
- data/lib/graphql/introspection/type_type.rb +27 -17
- data/lib/graphql/introspection.rb +99 -0
- data/lib/graphql/invalid_null_error.rb +18 -0
- data/lib/graphql/language/block_string.rb +20 -5
- data/lib/graphql/language/cache.rb +37 -0
- data/lib/graphql/language/definition_slice.rb +21 -10
- data/lib/graphql/language/document_from_schema_definition.rb +99 -63
- data/lib/graphql/language/lexer.rb +53 -27
- data/lib/graphql/language/lexer.rl +5 -3
- data/lib/graphql/language/nodes.rb +64 -93
- data/lib/graphql/language/parser.rb +929 -896
- data/lib/graphql/language/parser.y +125 -102
- data/lib/graphql/language/printer.rb +11 -2
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/language/visitor.rb +2 -2
- data/lib/graphql/language.rb +3 -1
- data/lib/graphql/name_validator.rb +2 -7
- data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
- data/lib/graphql/pagination/array_connection.rb +77 -0
- data/lib/graphql/pagination/connection.rb +226 -0
- data/lib/graphql/pagination/connections.rb +134 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +226 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/parse_error.rb +0 -1
- data/lib/graphql/query/context.rb +51 -190
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +23 -6
- data/lib/graphql/query/literal_input.rb +26 -11
- data/lib/graphql/query/null_context.rb +24 -8
- data/lib/graphql/query/validation_pipeline.rb +12 -38
- data/lib/graphql/query/variable_validation_error.rb +2 -2
- data/lib/graphql/query/variables.rb +26 -9
- data/lib/graphql/query.rb +62 -32
- data/lib/graphql/railtie.rb +6 -102
- data/lib/graphql/rake_task/validate.rb +3 -0
- data/lib/graphql/rake_task.rb +12 -9
- data/lib/graphql/relay/range_add.rb +23 -9
- 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 +240 -0
- data/lib/graphql/schema/argument.rb +262 -28
- 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 +319 -220
- data/lib/graphql/schema/built_in_types.rb +5 -5
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive/include.rb +2 -2
- data/lib/graphql/schema/directive/skip.rb +2 -2
- data/lib/graphql/schema/directive/transform.rb +14 -2
- data/lib/graphql/schema/directive.rb +117 -14
- data/lib/graphql/schema/enum.rb +115 -22
- data/lib/graphql/schema/enum_value.rb +16 -21
- data/lib/graphql/schema/field/connection_extension.rb +46 -20
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +376 -291
- 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 +147 -60
- data/lib/graphql/schema/interface.rb +28 -43
- data/lib/graphql/schema/introspection_system.rb +101 -38
- data/lib/graphql/schema/late_bound_type.rb +3 -2
- data/lib/graphql/schema/list.rb +46 -3
- data/lib/graphql/schema/loader.rb +144 -102
- data/lib/graphql/schema/member/base_dsl_methods.rb +33 -32
- data/lib/graphql/schema/member/build_type.rb +23 -14
- data/lib/graphql/schema/member/has_arguments.rb +212 -23
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
- data/lib/graphql/schema/member/has_directives.rb +98 -0
- data/lib/graphql/schema/member/has_fields.rb +99 -34
- data/lib/graphql/schema/member/has_interfaces.rb +88 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/has_validators.rb +31 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +11 -6
- data/lib/graphql/schema/mutation.rb +4 -9
- data/lib/graphql/schema/non_null.rb +34 -4
- data/lib/graphql/schema/object.rb +38 -65
- data/lib/graphql/schema/printer.rb +16 -35
- data/lib/graphql/schema/relay_classic_mutation.rb +57 -32
- data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
- data/lib/graphql/schema/resolver.rb +133 -79
- data/lib/graphql/schema/scalar.rb +40 -15
- data/lib/graphql/schema/subscription.rb +57 -21
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +19 -5
- data/lib/graphql/schema/union.rb +39 -14
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/format_validator.rb +48 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
- data/lib/graphql/schema/validator/length_validator.rb +59 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
- data/lib/graphql/schema/validator/required_validator.rb +82 -0
- data/lib/graphql/schema/validator.rb +171 -0
- data/lib/graphql/schema/warden.rb +182 -32
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +687 -891
- data/lib/graphql/static_validation/all_rules.rb +2 -0
- data/lib/graphql/static_validation/base_visitor.rb +21 -31
- data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +51 -26
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +45 -83
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +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/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +13 -3
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +31 -19
- data/lib/graphql/static_validation.rb +1 -2
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +123 -22
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
- data/lib/graphql/subscriptions/event.rb +85 -31
- data/lib/graphql/subscriptions/instrumentation.rb +0 -47
- data/lib/graphql/subscriptions/serialize.rb +53 -6
- data/lib/graphql/subscriptions.rb +111 -52
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +14 -1
- data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_tracing.rb +57 -29
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
- data/lib/graphql/tracing/scout_tracing.rb +19 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +15 -36
- data/lib/graphql/types/big_int.rb +5 -1
- data/lib/graphql/types/int.rb +10 -3
- data/lib/graphql/types/iso_8601_date.rb +16 -8
- data/lib/graphql/types/iso_8601_date_time.rb +32 -10
- data/lib/graphql/types/relay/base_connection.rb +6 -88
- data/lib/graphql/types/relay/base_edge.rb +2 -34
- data/lib/graphql/types/relay/connection_behaviors.rb +170 -0
- data/lib/graphql/types/relay/default_relay.rb +21 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
- data/lib/graphql/types/relay/has_node_field.rb +41 -0
- data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
- data/lib/graphql/types/relay/node.rb +2 -4
- data/lib/graphql/types/relay/node_behaviors.rb +19 -0
- data/lib/graphql/types/relay/page_info.rb +2 -14
- data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
- data/lib/graphql/types/relay.rb +11 -5
- data/lib/graphql/types/string.rb +8 -2
- data/lib/graphql/unauthorized_error.rb +2 -2
- data/lib/graphql/unresolved_type_error.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +41 -58
- data/readme.md +3 -6
- metadata +97 -231
- data/lib/graphql/analysis/analyze_query.rb +0 -91
- data/lib/graphql/analysis/field_usage.rb +0 -45
- data/lib/graphql/analysis/max_query_complexity.rb +0 -26
- data/lib/graphql/analysis/max_query_depth.rb +0 -26
- data/lib/graphql/analysis/query_complexity.rb +0 -88
- data/lib/graphql/analysis/query_depth.rb +0 -43
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -159
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backwards_compatibility.rb +0 -60
- data/lib/graphql/base_type.rb +0 -226
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -435
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -213
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -91
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -264
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -680
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -311
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -42
- data/lib/graphql/directive/deprecated_directive.rb +0 -13
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -104
- data/lib/graphql/enum_type.rb +0 -193
- data/lib/graphql/execution/execute.rb +0 -326
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -330
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -153
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -154
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -86
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/literal_validation_error.rb +0 -6
- data/lib/graphql/non_null_type.rb +0 -81
- data/lib/graphql/object_type.rb +0 -141
- data/lib/graphql/query/arguments.rb +0 -187
- data/lib/graphql/query/arguments_cache.rb +0 -25
- data/lib/graphql/query/executor.rb +0 -53
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -39
- data/lib/graphql/relay/array_connection.rb +0 -85
- data/lib/graphql/relay/base_connection.rb +0 -172
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -40
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -18
- data/lib/graphql/relay/edges_instrumentation.rb +0 -40
- data/lib/graphql/relay/global_id_resolve.rb +0 -18
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -190
- data/lib/graphql/relay/node.rb +0 -36
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -190
- data/lib/graphql/relay/type_extensions.rb +0 -30
- data/lib/graphql/scalar_type.rb +0 -133
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -15
- data/lib/graphql/schema/member/accepts_definition.rb +0 -152
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -26
- data/lib/graphql/schema/member/instrumentation.rb +0 -132
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -39
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -86
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -303
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/subscription_root.rb +0 -74
- data/lib/graphql/tracing/skylight_tracing.rb +0 -62
- data/lib/graphql/types/relay/base_field.rb +0 -22
- data/lib/graphql/types/relay/base_interface.rb +0 -29
- data/lib/graphql/types/relay/base_object.rb +0 -26
- data/lib/graphql/types/relay/node_field.rb +0 -43
- data/lib/graphql/types/relay/nodes_field.rb +0 -45
- data/lib/graphql/union_type.rb +0 -135
- data/lib/graphql/upgrader/member.rb +0 -936
- data/lib/graphql/upgrader/schema.rb +0 -37
data/lib/graphql/schema/field.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../object.rb
|
3
2
|
require "graphql/schema/field/connection_extension"
|
4
3
|
require "graphql/schema/field/scope_extension"
|
5
4
|
|
6
5
|
module GraphQL
|
7
6
|
class Schema
|
8
7
|
class Field
|
9
|
-
if !String.method_defined?(:-@)
|
10
|
-
using GraphQL::StringDedupBackport
|
11
|
-
end
|
12
|
-
|
13
|
-
include GraphQL::Schema::Member::CachedGraphQLDefinition
|
14
|
-
include GraphQL::Schema::Member::AcceptsDefinition
|
15
8
|
include GraphQL::Schema::Member::HasArguments
|
9
|
+
include GraphQL::Schema::Member::HasAstNode
|
16
10
|
include GraphQL::Schema::Member::HasPath
|
11
|
+
include GraphQL::Schema::Member::HasValidators
|
17
12
|
extend GraphQL::Schema::FindInheritedValue
|
13
|
+
include GraphQL::Schema::FindInheritedValue::EmptyObjects
|
14
|
+
include GraphQL::Schema::Member::HasDirectives
|
15
|
+
include GraphQL::Schema::Member::HasDeprecationReason
|
16
|
+
|
17
|
+
class FieldImplementationFailed < GraphQL::Error; end
|
18
18
|
|
19
19
|
# @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
|
20
20
|
attr_reader :name
|
@@ -22,9 +22,6 @@ module GraphQL
|
|
22
22
|
|
23
23
|
attr_writer :description
|
24
24
|
|
25
|
-
# @return [String, nil] If present, the field is marked as deprecated with this documentation
|
26
|
-
attr_accessor :deprecation_reason
|
27
|
-
|
28
25
|
# @return [Symbol] Method or hash key on the underlying object to look up
|
29
26
|
attr_reader :method_sym
|
30
27
|
|
@@ -34,10 +31,21 @@ module GraphQL
|
|
34
31
|
# @return [Symbol] The method on the type to look up
|
35
32
|
attr_reader :resolver_method
|
36
33
|
|
37
|
-
# @return [Class] The
|
38
|
-
|
34
|
+
# @return [Class] The thing this field was defined on (type, mutation, resolver)
|
35
|
+
attr_accessor :owner
|
39
36
|
|
40
|
-
# @return [
|
37
|
+
# @return [Class] The GraphQL type this field belongs to. (For fields defined on mutations, it's the payload type)
|
38
|
+
def owner_type
|
39
|
+
@owner_type ||= if owner.nil?
|
40
|
+
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?!"
|
41
|
+
elsif owner < GraphQL::Schema::Mutation
|
42
|
+
owner.payload_type
|
43
|
+
else
|
44
|
+
owner
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [Symbol] the original name of the field, passed in by the user
|
41
49
|
attr_reader :original_name
|
42
50
|
|
43
51
|
# @return [Class, nil] The {Schema::Resolver} this field was derived from, if there is one
|
@@ -45,13 +53,22 @@ module GraphQL
|
|
45
53
|
@resolver_class
|
46
54
|
end
|
47
55
|
|
56
|
+
# @return [Boolean] Is this field a predefined introspection field?
|
57
|
+
def introspection?
|
58
|
+
@introspection
|
59
|
+
end
|
60
|
+
|
61
|
+
def inspect
|
62
|
+
"#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
|
63
|
+
end
|
64
|
+
|
48
65
|
alias :mutation :resolver
|
49
66
|
|
50
67
|
# @return [Boolean] Apply tracing to this field? (Default: skip scalars, this is the override value)
|
51
68
|
attr_reader :trace
|
52
69
|
|
53
70
|
# @return [String, nil]
|
54
|
-
|
71
|
+
attr_accessor :subscription_scope
|
55
72
|
|
56
73
|
# Create a field instance from a list of arguments, keyword arguments, and a block.
|
57
74
|
#
|
@@ -65,16 +82,6 @@ module GraphQL
|
|
65
82
|
# @return [GraphQL::Schema:Field] an instance of `self
|
66
83
|
# @see {.initialize} for other options
|
67
84
|
def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
|
68
|
-
if kwargs[:field]
|
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
85
|
if (parent_config = resolver || mutation || subscription)
|
79
86
|
# Get the parent config, merge in local overrides
|
80
87
|
kwargs = parent_config.field_options.merge(kwargs)
|
@@ -87,9 +94,6 @@ module GraphQL
|
|
87
94
|
end
|
88
95
|
|
89
96
|
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
97
|
if desc
|
94
98
|
if kwargs[:description]
|
95
99
|
raise ArgumentError, "Provide description as a positional argument or `description:` keyword, but not both (#{desc.inspect}, #{kwargs[:description].inspect})"
|
@@ -103,6 +107,9 @@ module GraphQL
|
|
103
107
|
else
|
104
108
|
kwargs[:type] = type
|
105
109
|
end
|
110
|
+
if type.is_a?(Class) && type < GraphQL::Schema::Mutation
|
111
|
+
raise ArgumentError, "Use `field #{name.inspect}, mutation: Mutation, ...` to provide a mutation to this field instead"
|
112
|
+
end
|
106
113
|
end
|
107
114
|
new(**kwargs, &block)
|
108
115
|
end
|
@@ -152,6 +159,14 @@ module GraphQL
|
|
152
159
|
end
|
153
160
|
end
|
154
161
|
|
162
|
+
# @return Boolean
|
163
|
+
attr_reader :relay_node_field
|
164
|
+
|
165
|
+
# @return [Boolean] Should we warn if this field's name conflicts with a built-in method?
|
166
|
+
def method_conflict_warning?
|
167
|
+
@method_conflict_warning
|
168
|
+
end
|
169
|
+
|
155
170
|
# @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
|
156
171
|
# @param type [Class, GraphQL::BaseType, Array] The return type of this field
|
157
172
|
# @param owner [Class] The type that this field belongs to
|
@@ -160,9 +175,11 @@ module GraphQL
|
|
160
175
|
# @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
|
161
176
|
# @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
|
162
177
|
# @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`)
|
178
|
+
# @param dig [Array<String, Symbol>] The nested hash keys to lookup on the underlying hash to resolve this field using dig
|
163
179
|
# @param resolver_method [Symbol] The method on the type to call to resolve this field (defaults to `name`)
|
164
180
|
# @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
|
181
|
+
# @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
|
182
|
+
# @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
|
166
183
|
# @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
|
167
184
|
# @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
|
168
185
|
# @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
|
@@ -174,8 +191,13 @@ module GraphQL
|
|
174
191
|
# @param scope [Boolean] If true, the return type's `.scope_items` method will be called on the return value
|
175
192
|
# @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
|
176
193
|
# @param extensions [Array<Class, Hash<Class => Object>>] Named extensions to apply to this field (see also {#extension})
|
194
|
+
# @param directives [Hash{Class => Hash}] Directives to apply to this field
|
177
195
|
# @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
|
178
|
-
|
196
|
+
# @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
|
197
|
+
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
198
|
+
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
199
|
+
# @param validates [Array<Hash>] Configurations for validating this field
|
200
|
+
def initialize(type: nil, name: nil, owner: nil, null: true, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, &definition_block)
|
179
201
|
if name.nil?
|
180
202
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
181
203
|
end
|
@@ -183,16 +205,14 @@ module GraphQL
|
|
183
205
|
if type.nil?
|
184
206
|
raise ArgumentError, "missing second `type` argument or keyword `type:`"
|
185
207
|
end
|
186
|
-
if null.nil?
|
187
|
-
raise ArgumentError, "missing keyword argument null:"
|
188
|
-
end
|
189
208
|
end
|
190
209
|
if (field || function || resolve) && extras.any?
|
191
210
|
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
211
|
end
|
193
212
|
@original_name = name
|
194
|
-
|
195
|
-
@
|
213
|
+
name_s = -name.to_s
|
214
|
+
@underscored_name = -Member::BuildType.underscore(name_s)
|
215
|
+
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
196
216
|
@description = description
|
197
217
|
if field.is_a?(GraphQL::Schema::Field)
|
198
218
|
raise ArgumentError, "Instead of passing a field as `field:`, use `add_field(field)` to add an already-defined field."
|
@@ -201,10 +221,10 @@ module GraphQL
|
|
201
221
|
end
|
202
222
|
@function = function
|
203
223
|
@resolve = resolve
|
204
|
-
|
224
|
+
self.deprecation_reason = deprecation_reason
|
205
225
|
|
206
|
-
if method && hash_key
|
207
|
-
raise ArgumentError, "Provide `method:` _or_ `
|
226
|
+
if method && hash_key && dig
|
227
|
+
raise ArgumentError, "Provide `method:`, `hash_key:` _or_ `dig:`, not multiple. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}, dig: #{dig.inspect}`)"
|
208
228
|
end
|
209
229
|
|
210
230
|
if resolver_method
|
@@ -212,60 +232,79 @@ module GraphQL
|
|
212
232
|
raise ArgumentError, "Provide `method:` _or_ `resolver_method:`, not both. (called with: `method: #{method.inspect}, resolver_method: #{resolver_method.inspect}`)"
|
213
233
|
end
|
214
234
|
|
215
|
-
if hash_key
|
216
|
-
raise ArgumentError, "Provide `hash_key
|
235
|
+
if hash_key || dig
|
236
|
+
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
237
|
end
|
218
238
|
end
|
219
239
|
|
220
240
|
# TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
|
221
|
-
method_name = method || hash_key ||
|
222
|
-
|
241
|
+
method_name = method || hash_key || name_s
|
242
|
+
@dig_keys = dig
|
243
|
+
resolver_method ||= name_s.to_sym
|
223
244
|
|
224
|
-
@method_str = method_name.to_s
|
245
|
+
@method_str = -method_name.to_s
|
225
246
|
@method_sym = method_name.to_sym
|
226
247
|
@resolver_method = resolver_method
|
227
248
|
@complexity = complexity
|
228
249
|
@return_type_expr = type
|
229
250
|
@return_type_null = null
|
230
251
|
@connection = connection
|
231
|
-
@
|
252
|
+
@has_max_page_size = max_page_size != :not_given
|
253
|
+
@max_page_size = max_page_size == :not_given ? nil : max_page_size
|
232
254
|
@introspection = introspection
|
233
255
|
@extras = extras
|
256
|
+
@broadcastable = broadcastable
|
234
257
|
@resolver_class = resolver_class
|
235
258
|
@scope = scope
|
236
259
|
@trace = trace
|
237
260
|
@relay_node_field = relay_node_field
|
238
261
|
@relay_nodes_field = relay_nodes_field
|
262
|
+
@ast_node = ast_node
|
263
|
+
@method_conflict_warning = method_conflict_warning
|
239
264
|
|
240
|
-
# Override the default from HasArguments
|
241
|
-
@own_arguments = {}
|
242
265
|
arguments.each do |name, arg|
|
243
|
-
|
266
|
+
case arg
|
267
|
+
when Hash
|
244
268
|
argument(name: name, **arg)
|
269
|
+
when GraphQL::Schema::Argument
|
270
|
+
add_argument(arg)
|
271
|
+
when Array
|
272
|
+
arg.each { |a| add_argument(a) }
|
245
273
|
else
|
246
|
-
|
274
|
+
raise ArgumentError, "Unexpected argument config (#{arg.class}): #{arg.inspect}"
|
247
275
|
end
|
248
276
|
end
|
249
277
|
|
250
278
|
@owner = owner
|
251
279
|
@subscription_scope = subscription_scope
|
252
280
|
|
253
|
-
|
254
|
-
@
|
255
|
-
if extensions.any?
|
256
|
-
self.extensions(extensions)
|
257
|
-
end
|
281
|
+
@extensions = EMPTY_ARRAY
|
282
|
+
@call_after_define = false
|
258
283
|
# This should run before connection extension,
|
259
284
|
# but should it run after the definition block?
|
260
285
|
if scoped?
|
261
286
|
self.extension(ScopeExtension)
|
262
287
|
end
|
288
|
+
|
263
289
|
# The problem with putting this after the definition_block
|
264
290
|
# is that it would override arguments
|
265
|
-
if connection?
|
266
|
-
self.extension(
|
291
|
+
if connection? && connection_extension
|
292
|
+
self.extension(connection_extension)
|
293
|
+
end
|
294
|
+
|
295
|
+
# Do this last so we have as much context as possible when initializing them:
|
296
|
+
if extensions.any?
|
297
|
+
self.extensions(extensions)
|
267
298
|
end
|
268
299
|
|
300
|
+
if directives.any?
|
301
|
+
directives.each do |(dir_class, options)|
|
302
|
+
self.directive(dir_class, **options)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
self.validates(validates)
|
307
|
+
|
269
308
|
if definition_block
|
270
309
|
if definition_block.arity == 1
|
271
310
|
yield self
|
@@ -273,6 +312,16 @@ module GraphQL
|
|
273
312
|
instance_eval(&definition_block)
|
274
313
|
end
|
275
314
|
end
|
315
|
+
|
316
|
+
self.extensions.each(&:after_define_apply)
|
317
|
+
@call_after_define = true
|
318
|
+
end
|
319
|
+
|
320
|
+
# If true, subscription updates with this field can be shared between viewers
|
321
|
+
# @return [Boolean, nil]
|
322
|
+
# @see GraphQL::Subscriptions::BroadcastAnalyzer
|
323
|
+
def broadcastable?
|
324
|
+
@broadcastable
|
276
325
|
end
|
277
326
|
|
278
327
|
# @param text [String]
|
@@ -298,24 +347,20 @@ module GraphQL
|
|
298
347
|
# @example adding an extension with options
|
299
348
|
# extensions([MyExtensionClass, { AnotherExtensionClass => { filter: true } }])
|
300
349
|
#
|
301
|
-
# @param extensions [Array<Class, Hash<Class =>
|
350
|
+
# @param extensions [Array<Class, Hash<Class => Hash>>] Add extensions to this field. For hash elements, only the first key/value is used.
|
302
351
|
# @return [Array<GraphQL::Schema::FieldExtension>] extensions to apply to this field
|
303
352
|
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)
|
353
|
+
if new_extensions
|
354
|
+
new_extensions.each do |extension_config|
|
355
|
+
if extension_config.is_a?(Hash)
|
356
|
+
extension_class, options = *extension_config.to_a[0]
|
357
|
+
self.extension(extension_class, options)
|
313
358
|
else
|
314
|
-
|
315
|
-
@extensions << extension_class.new(field: self, options: nil)
|
359
|
+
self.extension(extension_config)
|
316
360
|
end
|
317
361
|
end
|
318
362
|
end
|
363
|
+
@extensions
|
319
364
|
end
|
320
365
|
|
321
366
|
# Add `extension` to this field, initialized with `options` if provided.
|
@@ -326,10 +371,19 @@ module GraphQL
|
|
326
371
|
# @example adding an extension with options
|
327
372
|
# extension(MyExtensionClass, filter: true)
|
328
373
|
#
|
329
|
-
# @param
|
330
|
-
# @param options [
|
331
|
-
|
332
|
-
|
374
|
+
# @param extension_class [Class] subclass of {Schema::FieldExtension}
|
375
|
+
# @param options [Hash] if provided, given as `options:` when initializing `extension`.
|
376
|
+
# @return [void]
|
377
|
+
def extension(extension_class, options = nil)
|
378
|
+
extension_inst = extension_class.new(field: self, options: options)
|
379
|
+
if @extensions.frozen?
|
380
|
+
@extensions = @extensions.dup
|
381
|
+
end
|
382
|
+
if @call_after_define
|
383
|
+
extension_inst.after_define_apply
|
384
|
+
end
|
385
|
+
@extensions << extension_inst
|
386
|
+
nil
|
333
387
|
end
|
334
388
|
|
335
389
|
# Read extras (as symbols) from this field,
|
@@ -342,12 +396,74 @@ module GraphQL
|
|
342
396
|
# Read the value
|
343
397
|
@extras
|
344
398
|
else
|
399
|
+
if @extras.frozen?
|
400
|
+
@extras = @extras.dup
|
401
|
+
end
|
345
402
|
# Append to the set of extras on this field
|
346
403
|
@extras.concat(new_extras)
|
347
404
|
end
|
348
405
|
end
|
349
406
|
|
350
|
-
def
|
407
|
+
def calculate_complexity(query:, nodes:, child_complexity:)
|
408
|
+
if respond_to?(:complexity_for)
|
409
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
410
|
+
complexity_for(child_complexity: child_complexity, query: query, lookahead: lookahead)
|
411
|
+
elsif connection?
|
412
|
+
arguments = query.arguments_for(nodes.first, self)
|
413
|
+
max_possible_page_size = nil
|
414
|
+
if arguments.respond_to?(:[]) # It might have been an error
|
415
|
+
if arguments[:first]
|
416
|
+
max_possible_page_size = arguments[:first]
|
417
|
+
end
|
418
|
+
|
419
|
+
if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
|
420
|
+
max_possible_page_size = arguments[:last]
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
if max_possible_page_size.nil?
|
425
|
+
max_possible_page_size = max_page_size || query.schema.default_max_page_size
|
426
|
+
end
|
427
|
+
|
428
|
+
if max_possible_page_size.nil?
|
429
|
+
raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `max_page_size` or `default_max_page_size`"
|
430
|
+
else
|
431
|
+
metadata_complexity = 0
|
432
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
433
|
+
|
434
|
+
if (page_info_lookahead = lookahead.selection(:page_info)).selected?
|
435
|
+
metadata_complexity += 1 # pageInfo
|
436
|
+
metadata_complexity += page_info_lookahead.selections.size # subfields
|
437
|
+
end
|
438
|
+
|
439
|
+
if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
|
440
|
+
metadata_complexity += 1
|
441
|
+
end
|
442
|
+
|
443
|
+
nodes_edges_complexity = 0
|
444
|
+
nodes_edges_complexity += 1 if lookahead.selects?(:edges)
|
445
|
+
nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
|
446
|
+
|
447
|
+
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
448
|
+
items_complexity = child_complexity - metadata_complexity - nodes_edges_complexity
|
449
|
+
# Add 1 for _this_ field
|
450
|
+
1 + (max_possible_page_size * items_complexity) + metadata_complexity + nodes_edges_complexity
|
451
|
+
end
|
452
|
+
else
|
453
|
+
defined_complexity = complexity
|
454
|
+
case defined_complexity
|
455
|
+
when Proc
|
456
|
+
arguments = query.arguments_for(nodes.first, self)
|
457
|
+
defined_complexity.call(query.context, arguments.keyword_arguments, child_complexity)
|
458
|
+
when Numeric
|
459
|
+
defined_complexity + child_complexity
|
460
|
+
else
|
461
|
+
raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
|
462
|
+
end
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
def complexity(new_complexity = nil)
|
351
467
|
case new_complexity
|
352
468
|
when Proc
|
353
469
|
if new_complexity.parameters.size != 3
|
@@ -360,87 +476,44 @@ module GraphQL
|
|
360
476
|
end
|
361
477
|
when Numeric
|
362
478
|
@complexity = new_complexity
|
479
|
+
when nil
|
480
|
+
@complexity
|
363
481
|
else
|
364
482
|
raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
|
365
483
|
end
|
366
484
|
end
|
367
485
|
|
368
|
-
# @return [
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
def to_graphql
|
373
|
-
field_defn = if @field
|
374
|
-
@field.dup
|
375
|
-
elsif @function
|
376
|
-
GraphQL::Function.build_field(@function)
|
377
|
-
else
|
378
|
-
GraphQL::Field.new
|
379
|
-
end
|
380
|
-
|
381
|
-
field_defn.name = @name
|
382
|
-
if @return_type_expr
|
383
|
-
field_defn.type = -> { type }
|
384
|
-
end
|
385
|
-
|
386
|
-
if @description
|
387
|
-
field_defn.description = @description
|
388
|
-
end
|
389
|
-
|
390
|
-
if @deprecation_reason
|
391
|
-
field_defn.deprecation_reason = @deprecation_reason
|
392
|
-
end
|
393
|
-
|
394
|
-
if @resolver_class
|
395
|
-
if @resolver_class < GraphQL::Schema::Mutation
|
396
|
-
field_defn.mutation = @resolver_class
|
397
|
-
end
|
398
|
-
field_defn.metadata[:resolver] = @resolver_class
|
399
|
-
end
|
400
|
-
|
401
|
-
if !@trace.nil?
|
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
|
486
|
+
# @return [Boolean] True if this field's {#max_page_size} should override the schema default.
|
487
|
+
def has_max_page_size?
|
488
|
+
@has_max_page_size
|
489
|
+
end
|
412
490
|
|
413
|
-
|
414
|
-
|
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
|
491
|
+
# @return [Integer, nil] Applied to connections if {#has_max_page_size?}
|
492
|
+
attr_reader :max_page_size
|
419
493
|
|
420
|
-
|
421
|
-
|
422
|
-
field_defn.arguments[arg_graphql.name] = arg_graphql
|
423
|
-
end
|
494
|
+
class MissingReturnTypeError < GraphQL::Error; end
|
495
|
+
attr_writer :type
|
424
496
|
|
425
|
-
|
426
|
-
@
|
427
|
-
@
|
428
|
-
elsif @function
|
429
|
-
@function
|
497
|
+
def type
|
498
|
+
@type ||= if @function
|
499
|
+
Member::BuildType.parse_type(@function.type, null: false)
|
430
500
|
elsif @field
|
431
|
-
@field.
|
501
|
+
Member::BuildType.parse_type(@field.type, null: false)
|
502
|
+
elsif @return_type_expr.nil?
|
503
|
+
# Not enough info to determine type
|
504
|
+
message = "Can't determine the return type for #{self.path}"
|
505
|
+
if @resolver_class
|
506
|
+
message += " (it has `resolver: #{@resolver_class}`, consider configuration a `type ...` for that class)"
|
507
|
+
end
|
508
|
+
raise MissingReturnTypeError, message
|
509
|
+
else
|
510
|
+
Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
432
511
|
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
|
512
|
+
rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
|
513
|
+
# Let this propagate up
|
514
|
+
raise err
|
515
|
+
rescue StandardError => err
|
516
|
+
raise MissingReturnTypeError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: (#{err.class}) #{err.message}", err.backtrace
|
444
517
|
end
|
445
518
|
|
446
519
|
def visible?(context)
|
@@ -459,48 +532,44 @@ module GraphQL
|
|
459
532
|
end
|
460
533
|
end
|
461
534
|
|
462
|
-
def authorized?(object, context)
|
535
|
+
def authorized?(object, args, context)
|
463
536
|
if @resolver_class
|
464
|
-
# The resolver will check itself during `resolve()`
|
537
|
+
# The resolver _instance_ will check itself during `resolve()`
|
465
538
|
@resolver_class.authorized?(object, context)
|
466
539
|
else
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
540
|
+
if (arg_values = context[:current_arguments])
|
541
|
+
# ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
|
542
|
+
using_arg_values = true
|
543
|
+
arg_values = arg_values.argument_values
|
544
|
+
else
|
545
|
+
arg_values = args
|
546
|
+
using_arg_values = false
|
472
547
|
end
|
473
|
-
|
474
|
-
|
475
|
-
|
548
|
+
# Faster than `.any?`
|
549
|
+
arguments(context).each_value do |arg|
|
550
|
+
arg_key = arg.keyword
|
551
|
+
if arg_values.key?(arg_key)
|
552
|
+
arg_value = arg_values[arg_key]
|
553
|
+
if using_arg_values
|
554
|
+
if arg_value.default_used?
|
555
|
+
# pass -- no auth required for default used
|
556
|
+
next
|
557
|
+
else
|
558
|
+
application_arg_value = arg_value.value
|
559
|
+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
|
560
|
+
application_arg_value.keyword_arguments
|
561
|
+
end
|
562
|
+
end
|
563
|
+
else
|
564
|
+
application_arg_value = arg_value
|
565
|
+
end
|
476
566
|
|
477
|
-
|
478
|
-
|
479
|
-
# Eventually, we might hook up field instances to execution in another way. TBD.
|
480
|
-
# @see #resolve for how the interpreter hooks up to it
|
481
|
-
def resolve_field(obj, args, ctx)
|
482
|
-
ctx.schema.after_lazy(obj) do |after_obj|
|
483
|
-
# First, apply auth ...
|
484
|
-
query_ctx = ctx.query.context
|
485
|
-
# Some legacy fields can have `nil` here, not exactly sure why.
|
486
|
-
# @see https://github.com/rmosolgo/graphql-ruby/issues/1990 before removing
|
487
|
-
inner_obj = after_obj && after_obj.object
|
488
|
-
if authorized?(inner_obj, query_ctx)
|
489
|
-
ruby_args = to_ruby_args(after_obj, args, ctx)
|
490
|
-
# Then if it passed, resolve the field
|
491
|
-
if @resolve_proc
|
492
|
-
# Might be nil, still want to call the func in that case
|
493
|
-
with_extensions(inner_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
|
494
|
-
# Pass the GraphQL args here for compatibility:
|
495
|
-
@resolve_proc.call(extended_obj, args, ctx)
|
567
|
+
if !arg.authorized?(object, application_arg_value, context)
|
568
|
+
return false
|
496
569
|
end
|
497
|
-
else
|
498
|
-
public_send_field(after_obj, ruby_args, ctx)
|
499
570
|
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
571
|
end
|
572
|
+
true
|
504
573
|
end
|
505
574
|
end
|
506
575
|
|
@@ -516,34 +585,15 @@ module GraphQL
|
|
516
585
|
begin
|
517
586
|
# Unwrap the GraphQL object to get the application object.
|
518
587
|
application_object = object.object
|
519
|
-
if self.authorized?(application_object, ctx)
|
520
|
-
# Apply field extensions
|
521
|
-
with_extensions(object, args, ctx) do |extended_obj, extended_args|
|
522
|
-
field_receiver = if @resolver_class
|
523
|
-
resolver_obj = if extended_obj.is_a?(GraphQL::Schema::Object)
|
524
|
-
extended_obj.object
|
525
|
-
else
|
526
|
-
extended_obj
|
527
|
-
end
|
528
|
-
@resolver_class.new(object: resolver_obj, context: ctx, field: self)
|
529
|
-
else
|
530
|
-
extended_obj
|
531
|
-
end
|
532
588
|
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
else
|
541
|
-
resolve_field_method(field_receiver, extended_args, ctx)
|
542
|
-
end
|
589
|
+
Schema::Validator.validate!(validators, application_object, ctx, args)
|
590
|
+
|
591
|
+
ctx.schema.after_lazy(self.authorized?(application_object, args, ctx)) do |is_authorized|
|
592
|
+
if is_authorized
|
593
|
+
public_send_field(object, args, ctx)
|
594
|
+
else
|
595
|
+
raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
|
543
596
|
end
|
544
|
-
else
|
545
|
-
err = GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
|
546
|
-
ctx.schema.unauthorized_field(err)
|
547
597
|
end
|
548
598
|
rescue GraphQL::UnauthorizedFieldError => err
|
549
599
|
err.field ||= self
|
@@ -555,46 +605,9 @@ module GraphQL
|
|
555
605
|
err
|
556
606
|
end
|
557
607
|
|
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
608
|
# @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
609
|
def fetch_extra(extra_name, ctx)
|
597
|
-
if extra_name != :path && respond_to?(extra_name)
|
610
|
+
if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
|
598
611
|
self.public_send(extra_name)
|
599
612
|
elsif ctx.respond_to?(extra_name)
|
600
613
|
ctx.public_send(extra_name)
|
@@ -605,56 +618,108 @@ module GraphQL
|
|
605
618
|
|
606
619
|
private
|
607
620
|
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
# Splat the GraphQL::Arguments to Ruby keyword arguments
|
619
|
-
ruby_kwargs = graphql_args.to_kwargs
|
620
|
-
# Apply any `prepare` methods. Not great code organization, can this go somewhere better?
|
621
|
-
arguments.each do |name, arg_defn|
|
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])
|
621
|
+
def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
|
622
|
+
with_extensions(unextended_obj, unextended_ruby_kwargs, query_ctx) do |obj, ruby_kwargs|
|
623
|
+
begin
|
624
|
+
method_receiver = nil
|
625
|
+
method_to_call = nil
|
626
|
+
if @resolver_class
|
627
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
628
|
+
obj = obj.object
|
629
|
+
end
|
630
|
+
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
625
631
|
end
|
626
|
-
end
|
627
632
|
|
628
|
-
|
629
|
-
|
630
|
-
|
633
|
+
# Find a way to resolve this field, checking:
|
634
|
+
#
|
635
|
+
# - A method on the type instance;
|
636
|
+
# - Hash keys, if the wrapped object is a hash;
|
637
|
+
# - A method on the wrapped object;
|
638
|
+
# - Or, raise not implemented.
|
639
|
+
#
|
640
|
+
if obj.respond_to?(@resolver_method)
|
641
|
+
method_to_call = @resolver_method
|
642
|
+
method_receiver = obj
|
643
|
+
# Call the method with kwargs, if there are any
|
644
|
+
if ruby_kwargs.any?
|
645
|
+
obj.public_send(@resolver_method, **ruby_kwargs)
|
646
|
+
else
|
647
|
+
obj.public_send(@resolver_method)
|
648
|
+
end
|
649
|
+
elsif obj.object.is_a?(Hash)
|
650
|
+
inner_object = obj.object
|
651
|
+
if @dig_keys
|
652
|
+
inner_object.dig(*@dig_keys)
|
653
|
+
elsif inner_object.key?(@method_sym)
|
654
|
+
inner_object[@method_sym]
|
655
|
+
else
|
656
|
+
inner_object[@method_str]
|
657
|
+
end
|
658
|
+
elsif obj.object.respond_to?(@method_sym)
|
659
|
+
method_to_call = @method_sym
|
660
|
+
method_receiver = obj.object
|
661
|
+
if ruby_kwargs.any?
|
662
|
+
obj.object.public_send(@method_sym, **ruby_kwargs)
|
663
|
+
else
|
664
|
+
obj.object.public_send(@method_sym)
|
665
|
+
end
|
666
|
+
else
|
667
|
+
raise <<-ERR
|
668
|
+
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
631
669
|
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
end
|
636
|
-
end
|
670
|
+
- `#{obj.class}##{@resolver_method}`, which did not exist
|
671
|
+
- `#{obj.object.class}##{@method_sym}`, which did not exist
|
672
|
+
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
|
637
673
|
|
638
|
-
|
639
|
-
|
640
|
-
with_extensions(obj, ruby_kwargs, query_ctx) do |extended_obj, extended_args|
|
641
|
-
if @resolver_class
|
642
|
-
if extended_obj.is_a?(GraphQL::Schema::Object)
|
643
|
-
extended_obj = extended_obj.object
|
674
|
+
To implement this field, define one of the methods above (and check for typos)
|
675
|
+
ERR
|
644
676
|
end
|
645
|
-
|
677
|
+
rescue ArgumentError
|
678
|
+
assert_satisfactory_implementation(method_receiver, method_to_call, ruby_kwargs)
|
679
|
+
# if the line above doesn't raise, re-raise
|
680
|
+
raise
|
646
681
|
end
|
682
|
+
end
|
683
|
+
end
|
647
684
|
|
648
|
-
|
649
|
-
|
650
|
-
|
685
|
+
def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
|
686
|
+
method_defn = receiver.method(method_name)
|
687
|
+
unsatisfied_ruby_kwargs = ruby_kwargs.dup
|
688
|
+
unsatisfied_method_params = []
|
689
|
+
encountered_keyrest = false
|
690
|
+
method_defn.parameters.each do |(param_type, param_name)|
|
691
|
+
case param_type
|
692
|
+
when :key
|
693
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
694
|
+
when :keyreq
|
695
|
+
if unsatisfied_ruby_kwargs.key?(param_name)
|
696
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
651
697
|
else
|
652
|
-
|
698
|
+
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
699
|
end
|
654
|
-
|
655
|
-
|
700
|
+
when :keyrest
|
701
|
+
encountered_keyrest = true
|
702
|
+
when :req
|
703
|
+
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."
|
704
|
+
when :opt, :rest
|
705
|
+
# This is fine, although it will never be present
|
656
706
|
end
|
657
707
|
end
|
708
|
+
|
709
|
+
if encountered_keyrest
|
710
|
+
unsatisfied_ruby_kwargs.clear
|
711
|
+
end
|
712
|
+
|
713
|
+
if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
|
714
|
+
raise FieldImplementationFailed.new, <<-ERR
|
715
|
+
Failed to call #{method_name} on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
|
716
|
+
|
717
|
+
#{ unsatisfied_ruby_kwargs
|
718
|
+
.map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
|
719
|
+
.concat(unsatisfied_method_params)
|
720
|
+
.join("\n") }
|
721
|
+
ERR
|
722
|
+
end
|
658
723
|
end
|
659
724
|
|
660
725
|
# Wrap execution with hooks.
|
@@ -664,32 +729,52 @@ module GraphQL
|
|
664
729
|
if @extensions.empty?
|
665
730
|
yield(obj, args)
|
666
731
|
else
|
667
|
-
#
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
732
|
+
# This is a hack to get the _last_ value for extended obj and args,
|
733
|
+
# in case one of the extensions doesn't `yield`.
|
734
|
+
# (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
|
735
|
+
extended = { args: args, obj: obj, memos: nil, added_extras: nil }
|
736
|
+
value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
|
737
|
+
if (added_extras = extended[:added_extras])
|
738
|
+
args = args.dup
|
739
|
+
added_extras.each { |e| args.delete(e) }
|
740
|
+
end
|
741
|
+
yield(obj, args)
|
674
742
|
end
|
675
743
|
|
744
|
+
extended_obj = extended[:obj]
|
745
|
+
extended_args = extended[:args]
|
746
|
+
memos = extended[:memos] || EMPTY_HASH
|
747
|
+
|
676
748
|
ctx.schema.after_lazy(value) do |resolved_value|
|
677
|
-
|
749
|
+
idx = 0
|
750
|
+
@extensions.each do |ext|
|
678
751
|
memo = memos[idx]
|
679
752
|
# TODO after_lazy?
|
680
|
-
resolved_value = ext.after_resolve(object:
|
753
|
+
resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
|
754
|
+
idx += 1
|
681
755
|
end
|
682
756
|
resolved_value
|
683
757
|
end
|
684
758
|
end
|
685
759
|
end
|
686
760
|
|
687
|
-
def run_extensions_before_resolve(
|
761
|
+
def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
|
688
762
|
extension = @extensions[idx]
|
689
763
|
if extension
|
690
764
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
691
|
-
|
692
|
-
|
765
|
+
if memo
|
766
|
+
memos = extended[:memos] ||= {}
|
767
|
+
memos[idx] = memo
|
768
|
+
end
|
769
|
+
|
770
|
+
if (extras = extension.added_extras)
|
771
|
+
ae = extended[:added_extras] ||= []
|
772
|
+
ae.concat(extras)
|
773
|
+
end
|
774
|
+
|
775
|
+
extended[:obj] = extended_obj
|
776
|
+
extended[:args] = extended_args
|
777
|
+
run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
|
693
778
|
end
|
694
779
|
else
|
695
780
|
yield(obj, args)
|