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