graphql 0.16.0 → 2.0.15
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 +5 -5
- data/.yardopts +5 -0
- data/lib/generators/graphql/core.rb +69 -0
- data/lib/generators/graphql/enum_generator.rb +27 -0
- 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/install/templates/base_mutation.erb +10 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +12 -0
- data/lib/generators/graphql/install_generator.rb +197 -0
- data/lib/generators/graphql/interface_generator.rb +27 -0
- data/lib/generators/graphql/loader_generator.rb +21 -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 +30 -0
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +50 -0
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +49 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/scalar_generator.rb +22 -0
- data/lib/generators/graphql/templates/base_argument.erb +6 -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 +6 -0
- data/lib/generators/graphql/templates/base_field.erb +7 -0
- data/lib/generators/graphql/templates/base_input_object.erb +7 -0
- data/lib/generators/graphql/templates/base_interface.erb +9 -0
- data/lib/generators/graphql/templates/base_object.erb +7 -0
- data/lib/generators/graphql/templates/base_scalar.erb +6 -0
- data/lib/generators/graphql/templates/base_union.erb +6 -0
- data/lib/generators/graphql/templates/enum.erb +11 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +52 -0
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +10 -0
- data/lib/generators/graphql/templates/loader.erb +19 -0
- data/lib/generators/graphql/templates/mutation.erb +16 -0
- 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 +10 -0
- data/lib/generators/graphql/templates/query_type.erb +15 -0
- data/lib/generators/graphql/templates/scalar.erb +17 -0
- data/lib/generators/graphql/templates/schema.erb +30 -0
- data/lib/generators/graphql/templates/union.erb +9 -0
- data/lib/generators/graphql/type_generator.rb +135 -0
- data/lib/generators/graphql/union_generator.rb +33 -0
- data/lib/graphql/analysis/ast/analyzer.rb +84 -0
- data/lib/graphql/analysis/ast/field_usage.rb +57 -0
- data/lib/graphql/analysis/ast/max_query_complexity.rb +22 -0
- data/lib/graphql/analysis/ast/max_query_depth.rb +22 -0
- data/lib/graphql/analysis/ast/query_complexity.rb +230 -0
- data/lib/graphql/analysis/ast/query_depth.rb +55 -0
- data/lib/graphql/analysis/ast/visitor.rb +269 -0
- data/lib/graphql/analysis/ast.rb +81 -0
- data/lib/graphql/analysis.rb +2 -5
- data/lib/graphql/analysis_error.rb +1 -0
- data/lib/graphql/backtrace/inspect_result.rb +50 -0
- data/lib/graphql/backtrace/table.rb +141 -0
- data/lib/graphql/backtrace/traced_error.rb +54 -0
- data/lib/graphql/backtrace/tracer.rb +80 -0
- data/lib/graphql/backtrace.rb +58 -0
- data/lib/graphql/coercion_error.rb +13 -0
- data/lib/graphql/dataloader/null_dataloader.rb +24 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +164 -0
- data/lib/graphql/dataloader.rb +311 -0
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/deprecation.rb +9 -0
- data/lib/graphql/dig.rb +19 -0
- data/lib/graphql/execution/directive_checks.rb +37 -0
- data/lib/graphql/execution/errors.rb +93 -0
- 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/execution_errors.rb +29 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
- data/lib/graphql/execution/interpreter/resolve.rb +77 -0
- data/lib/graphql/execution/interpreter/runtime.rb +994 -0
- data/lib/graphql/execution/interpreter.rb +226 -0
- data/lib/graphql/execution/lazy/lazy_method_map.rb +98 -0
- data/lib/graphql/execution/lazy.rb +75 -0
- data/lib/graphql/execution/lookahead.rb +311 -0
- data/lib/graphql/execution/multiplex.rb +45 -0
- data/lib/graphql/execution.rb +18 -0
- data/lib/graphql/execution_error.rb +34 -1
- data/lib/graphql/filter.rb +53 -0
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +36 -0
- data/lib/graphql/introspection/base_object.rb +13 -0
- data/lib/graphql/introspection/directive_location_enum.rb +12 -5
- data/lib/graphql/introspection/directive_type.rb +30 -10
- data/lib/graphql/introspection/dynamic_fields.rb +12 -0
- data/lib/graphql/introspection/entry_points.rb +22 -0
- data/lib/graphql/introspection/enum_value_type.rb +21 -8
- data/lib/graphql/introspection/field_type.rb +26 -10
- data/lib/graphql/introspection/input_value_type.rb +64 -14
- data/lib/graphql/introspection/introspection_query.rb +7 -76
- data/lib/graphql/introspection/schema_type.rb +42 -17
- data/lib/graphql/introspection/type_kind_enum.rb +11 -5
- data/lib/graphql/introspection/type_type.rb +104 -16
- data/lib/graphql/introspection.rb +104 -13
- data/lib/graphql/invalid_name_error.rb +11 -0
- data/lib/graphql/invalid_null_error.rb +36 -8
- data/lib/graphql/language/block_string.rb +99 -0
- data/lib/graphql/language/cache.rb +37 -0
- data/lib/graphql/language/definition_slice.rb +41 -0
- data/lib/graphql/language/document_from_schema_definition.rb +335 -0
- data/lib/graphql/language/generation.rb +16 -86
- data/lib/graphql/language/lexer.rb +1436 -705
- data/lib/graphql/language/lexer.rl +172 -64
- data/lib/graphql/language/nodes.rb +617 -105
- data/lib/graphql/language/parser.rb +1524 -430
- data/lib/graphql/language/parser.y +348 -73
- data/lib/graphql/language/printer.rb +386 -0
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/token.rb +16 -3
- data/lib/graphql/language/visitor.rb +169 -25
- data/lib/graphql/language.rb +30 -0
- data/lib/graphql/load_application_object_failed_error.rb +22 -0
- data/lib/graphql/name_validator.rb +11 -0
- data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
- data/lib/graphql/pagination/array_connection.rb +79 -0
- data/lib/graphql/pagination/connection.rb +253 -0
- data/lib/graphql/pagination/connections.rb +135 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +228 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/parse_error.rb +24 -0
- data/lib/graphql/query/context.rb +266 -12
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +34 -7
- data/lib/graphql/query/null_context.rb +52 -0
- data/lib/graphql/query/result.rb +63 -0
- data/lib/graphql/query/validation_pipeline.rb +114 -0
- data/lib/graphql/query/variable_validation_error.rb +27 -3
- data/lib/graphql/query/variables.rb +75 -24
- data/lib/graphql/query.rb +359 -92
- data/lib/graphql/railtie.rb +13 -0
- data/lib/graphql/rake_task/validate.rb +63 -0
- data/lib/graphql/rake_task.rb +146 -0
- data/lib/graphql/relay/range_add.rb +52 -0
- data/lib/graphql/relay.rb +3 -0
- 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/runtime_type_error.rb +5 -0
- data/lib/graphql/schema/addition.rb +245 -0
- data/lib/graphql/schema/argument.rb +395 -0
- data/lib/graphql/schema/base_64_bp.rb +26 -0
- data/lib/graphql/schema/base_64_encoder.rb +21 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +47 -0
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +78 -0
- data/lib/graphql/schema/build_from_definition.rb +492 -0
- data/lib/graphql/schema/built_in_types.rb +12 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/feature.rb +66 -0
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive/include.rb +25 -0
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/skip.rb +25 -0
- data/lib/graphql/schema/directive/transform.rb +60 -0
- data/lib/graphql/schema/directive.rb +212 -0
- data/lib/graphql/schema/enum.rb +176 -0
- data/lib/graphql/schema/enum_value.rb +77 -0
- data/lib/graphql/schema/field/connection_extension.rb +80 -0
- data/lib/graphql/schema/field/scope_extension.rb +22 -0
- data/lib/graphql/schema/field.rb +862 -0
- data/lib/graphql/schema/field_extension.rb +156 -0
- data/lib/graphql/schema/find_inherited_value.rb +36 -0
- data/lib/graphql/schema/finder.rb +155 -0
- data/lib/graphql/schema/input_object.rb +258 -0
- data/lib/graphql/schema/interface.rb +113 -0
- data/lib/graphql/schema/introspection_system.rb +164 -0
- data/lib/graphql/schema/invalid_type_error.rb +1 -0
- data/lib/graphql/schema/late_bound_type.rb +37 -0
- data/lib/graphql/schema/list.rb +86 -0
- data/lib/graphql/schema/loader.rb +228 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +124 -0
- data/lib/graphql/schema/member/build_type.rb +178 -0
- data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
- data/lib/graphql/schema/member/has_arguments.rb +376 -0
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
- data/lib/graphql/schema/member/has_directives.rb +113 -0
- data/lib/graphql/schema/member/has_fields.rb +163 -0
- data/lib/graphql/schema/member/has_interfaces.rb +88 -0
- data/lib/graphql/schema/member/has_path.rb +25 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/has_validators.rb +31 -0
- data/lib/graphql/schema/member/relay_shortcuts.rb +73 -0
- data/lib/graphql/schema/member/scoped.rb +21 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +38 -0
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +39 -0
- data/lib/graphql/schema/mutation.rb +85 -0
- data/lib/graphql/schema/non_null.rb +67 -0
- data/lib/graphql/schema/null_mask.rb +11 -0
- data/lib/graphql/schema/object.rb +117 -0
- data/lib/graphql/schema/printer.rb +72 -128
- data/lib/graphql/schema/relay_classic_mutation.rb +179 -0
- data/lib/graphql/schema/resolver/has_payload_type.rb +106 -0
- data/lib/graphql/schema/resolver.rb +402 -0
- data/lib/graphql/schema/scalar.rb +68 -0
- data/lib/graphql/schema/subscription.rb +148 -0
- data/lib/graphql/schema/timeout.rb +123 -0
- data/lib/graphql/schema/type_expression.rb +29 -5
- data/lib/graphql/schema/type_membership.rb +51 -0
- data/lib/graphql/schema/union.rb +81 -0
- data/lib/graphql/schema/unique_within_type.rb +34 -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 +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 +413 -0
- data/lib/graphql/schema/wrapper.rb +24 -0
- data/lib/graphql/schema.rb +1179 -104
- data/lib/graphql/static_validation/all_rules.rb +14 -0
- data/lib/graphql/static_validation/base_visitor.rb +200 -0
- data/lib/graphql/static_validation/definition_dependencies.rb +198 -0
- data/lib/graphql/static_validation/error.rb +46 -0
- data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
- data/lib/graphql/static_validation/literal_validator.rb +113 -22
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +59 -11
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +48 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +31 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +62 -8
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +37 -0
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +20 -13
- data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +32 -26
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +21 -23
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +55 -18
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +390 -70
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +53 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +54 -37
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +26 -16
- data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +13 -19
- data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_named.rb +16 -0
- data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +25 -20
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +22 -33
- data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
- 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/mutation_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +41 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +36 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -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 +22 -21
- data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +59 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +56 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +36 -18
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +24 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +103 -39
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +22 -14
- data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +92 -70
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
- data/lib/graphql/static_validation/type_stack.rb +85 -24
- data/lib/graphql/static_validation/validation_context.rb +25 -46
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +46 -15
- data/lib/graphql/static_validation.rb +6 -3
- data/lib/graphql/string_encoding_error.rb +20 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +247 -0
- 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 +144 -0
- data/lib/graphql/subscriptions/instrumentation.rb +28 -0
- data/lib/graphql/subscriptions/serialize.rb +158 -0
- data/lib/graphql/subscriptions.rb +306 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +21 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +51 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +100 -0
- data/lib/graphql/tracing/instrumentation_tracing.rb +83 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +51 -0
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_tracing.rb +122 -0
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +32 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +67 -0
- data/lib/graphql/tracing/scout_tracing.rb +54 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +94 -0
- data/lib/graphql/type_kinds.rb +50 -22
- data/lib/graphql/types/big_int.rb +23 -0
- data/lib/graphql/types/boolean.rb +18 -0
- data/lib/graphql/types/float.rb +19 -0
- data/lib/graphql/types/id.rb +24 -0
- data/lib/graphql/types/int.rb +36 -0
- data/lib/graphql/types/iso_8601_date.rb +45 -0
- data/lib/graphql/types/iso_8601_date_time.rb +76 -0
- data/lib/graphql/types/json.rb +25 -0
- data/lib/graphql/types/relay/base_connection.rb +49 -0
- data/lib/graphql/types/relay/base_edge.rb +29 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +154 -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 +15 -0
- data/lib/graphql/types/relay/node_behaviors.rb +19 -0
- data/lib/graphql/types/relay/page_info.rb +11 -0
- data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
- data/lib/graphql/types/relay.rb +39 -0
- data/lib/graphql/types/string.rb +29 -0
- data/lib/graphql/types.rb +11 -0
- data/lib/graphql/unauthorized_error.rb +29 -0
- data/lib/graphql/unauthorized_field_error.rb +23 -0
- data/lib/graphql/unresolved_type_error.rb +35 -0
- data/lib/graphql/version.rb +2 -1
- data/lib/graphql.rb +86 -41
- data/readme.md +15 -101
- metadata +394 -279
- data/lib/graphql/analysis/analyze_query.rb +0 -73
- data/lib/graphql/analysis/max_query_complexity.rb +0 -25
- data/lib/graphql/analysis/max_query_depth.rb +0 -25
- data/lib/graphql/analysis/query_complexity.rb +0 -122
- data/lib/graphql/analysis/query_depth.rb +0 -54
- data/lib/graphql/argument.rb +0 -25
- data/lib/graphql/base_type.rb +0 -115
- data/lib/graphql/boolean_type.rb +0 -9
- data/lib/graphql/define/assign_argument.rb +0 -20
- data/lib/graphql/define/assign_enum_value.rb +0 -16
- data/lib/graphql/define/assign_object_field.rb +0 -21
- data/lib/graphql/define/assignment_dictionary.rb +0 -26
- data/lib/graphql/define/defined_object_proxy.rb +0 -32
- data/lib/graphql/define/instance_definable.rb +0 -79
- data/lib/graphql/define/non_null_with_bang.rb +0 -15
- data/lib/graphql/define/type_definer.rb +0 -30
- data/lib/graphql/define.rb +0 -8
- data/lib/graphql/directive/include_directive.rb +0 -10
- data/lib/graphql/directive/skip_directive.rb +0 -11
- data/lib/graphql/directive.rb +0 -49
- data/lib/graphql/enum_type.rb +0 -95
- data/lib/graphql/field.rb +0 -131
- data/lib/graphql/float_type.rb +0 -5
- data/lib/graphql/id_type.rb +0 -12
- data/lib/graphql/input_object_type.rb +0 -71
- data/lib/graphql/int_type.rb +0 -5
- data/lib/graphql/interface_type.rb +0 -38
- data/lib/graphql/internal_representation/node.rb +0 -81
- data/lib/graphql/internal_representation/rewrite.rb +0 -177
- data/lib/graphql/internal_representation.rb +0 -2
- data/lib/graphql/introspection/arguments_field.rb +0 -5
- data/lib/graphql/introspection/enum_values_field.rb +0 -13
- data/lib/graphql/introspection/fields_field.rb +0 -13
- data/lib/graphql/introspection/input_fields_field.rb +0 -12
- data/lib/graphql/introspection/interfaces_field.rb +0 -5
- data/lib/graphql/introspection/of_type_field.rb +0 -6
- data/lib/graphql/introspection/possible_types_field.rb +0 -11
- data/lib/graphql/introspection/schema_field.rb +0 -15
- data/lib/graphql/introspection/type_by_name_field.rb +0 -16
- data/lib/graphql/introspection/typename_field.rb +0 -15
- data/lib/graphql/list_type.rb +0 -46
- data/lib/graphql/non_null_type.rb +0 -43
- data/lib/graphql/object_type.rb +0 -93
- data/lib/graphql/query/arguments.rb +0 -76
- data/lib/graphql/query/directive_resolution.rb +0 -16
- data/lib/graphql/query/executor.rb +0 -45
- data/lib/graphql/query/literal_input.rb +0 -90
- data/lib/graphql/query/serial_execution/execution_context.rb +0 -31
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -82
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -27
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -42
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -107
- data/lib/graphql/query/serial_execution.rb +0 -41
- data/lib/graphql/query/type_resolver.rb +0 -25
- data/lib/graphql/scalar_type.rb +0 -53
- data/lib/graphql/schema/catchall_middleware.rb +0 -34
- data/lib/graphql/schema/middleware_chain.rb +0 -28
- data/lib/graphql/schema/possible_types.rb +0 -34
- data/lib/graphql/schema/reduce_types.rb +0 -68
- data/lib/graphql/schema/rescue_middleware.rb +0 -53
- data/lib/graphql/schema/timeout_middleware.rb +0 -67
- data/lib/graphql/schema/type_map.rb +0 -30
- data/lib/graphql/schema/validation.rb +0 -164
- data/lib/graphql/static_validation/arguments_validator.rb +0 -48
- data/lib/graphql/static_validation/message.rb +0 -36
- data/lib/graphql/string_type.rb +0 -5
- data/lib/graphql/union_type.rb +0 -38
- data/spec/graphql/analysis/analyze_query_spec.rb +0 -50
- data/spec/graphql/analysis/max_query_complexity_spec.rb +0 -62
- data/spec/graphql/analysis/max_query_depth_spec.rb +0 -100
- data/spec/graphql/analysis/query_complexity_spec.rb +0 -235
- data/spec/graphql/analysis/query_depth_spec.rb +0 -80
- data/spec/graphql/argument_spec.rb +0 -20
- data/spec/graphql/base_type_spec.rb +0 -24
- data/spec/graphql/boolean_type_spec.rb +0 -20
- data/spec/graphql/define/instance_definable_spec.rb +0 -55
- data/spec/graphql/directive_spec.rb +0 -77
- data/spec/graphql/enum_type_spec.rb +0 -31
- data/spec/graphql/execution_error_spec.rb +0 -61
- data/spec/graphql/field_spec.rb +0 -92
- data/spec/graphql/float_type_spec.rb +0 -15
- data/spec/graphql/id_type_spec.rb +0 -32
- data/spec/graphql/input_object_type_spec.rb +0 -162
- data/spec/graphql/int_type_spec.rb +0 -15
- data/spec/graphql/interface_type_spec.rb +0 -56
- data/spec/graphql/internal_representation/rewrite_spec.rb +0 -120
- data/spec/graphql/introspection/directive_type_spec.rb +0 -50
- data/spec/graphql/introspection/input_value_type_spec.rb +0 -42
- data/spec/graphql/introspection/introspection_query_spec.rb +0 -10
- data/spec/graphql/introspection/schema_type_spec.rb +0 -45
- data/spec/graphql/introspection/type_type_spec.rb +0 -122
- data/spec/graphql/language/generation_spec.rb +0 -42
- data/spec/graphql/language/parser_spec.rb +0 -442
- data/spec/graphql/language/visitor_spec.rb +0 -49
- data/spec/graphql/list_type_spec.rb +0 -32
- data/spec/graphql/non_null_type_spec.rb +0 -31
- data/spec/graphql/object_type_spec.rb +0 -42
- data/spec/graphql/query/arguments_spec.rb +0 -25
- data/spec/graphql/query/context_spec.rb +0 -83
- data/spec/graphql/query/executor_spec.rb +0 -273
- data/spec/graphql/query/serial_execution/execution_context_spec.rb +0 -53
- data/spec/graphql/query/serial_execution/value_resolution_spec.rb +0 -66
- data/spec/graphql/query/type_resolver_spec.rb +0 -8
- data/spec/graphql/query/variables_spec.rb +0 -28
- data/spec/graphql/query_spec.rb +0 -363
- data/spec/graphql/scalar_type_spec.rb +0 -61
- data/spec/graphql/schema/catchall_middleware_spec.rb +0 -32
- data/spec/graphql/schema/middleware_chain_spec.rb +0 -42
- data/spec/graphql/schema/printer_spec.rb +0 -190
- data/spec/graphql/schema/reduce_types_spec.rb +0 -102
- data/spec/graphql/schema/rescue_middleware_spec.rb +0 -33
- data/spec/graphql/schema/timeout_middleware_spec.rb +0 -180
- data/spec/graphql/schema/type_expression_spec.rb +0 -38
- data/spec/graphql/schema/validation_spec.rb +0 -219
- data/spec/graphql/schema_spec.rb +0 -23
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +0 -63
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +0 -48
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +0 -34
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +0 -39
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +0 -60
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +0 -31
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +0 -48
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +0 -47
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +0 -39
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +0 -44
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +0 -49
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +0 -25
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +0 -42
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +0 -44
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +0 -63
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +0 -37
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +0 -53
- data/spec/graphql/static_validation/type_stack_spec.rb +0 -37
- data/spec/graphql/static_validation/validator_spec.rb +0 -69
- data/spec/graphql/string_type_spec.rb +0 -15
- data/spec/graphql/union_type_spec.rb +0 -31
- data/spec/spec_helper.rb +0 -18
- data/spec/support/dairy_app.rb +0 -309
- data/spec/support/dairy_data.rb +0 -23
- data/spec/support/minimum_input_object.rb +0 -16
- data/spec/support/star_wars_data.rb +0 -71
- data/spec/support/star_wars_schema.rb +0 -76
@@ -0,0 +1,862 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "graphql/schema/field/connection_extension"
|
3
|
+
require "graphql/schema/field/scope_extension"
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
class Schema
|
7
|
+
class Field
|
8
|
+
include GraphQL::Schema::Member::HasArguments
|
9
|
+
include GraphQL::Schema::Member::HasAstNode
|
10
|
+
include GraphQL::Schema::Member::HasPath
|
11
|
+
include GraphQL::Schema::Member::HasValidators
|
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
|
+
|
19
|
+
# @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
|
20
|
+
attr_reader :name
|
21
|
+
alias :graphql_name :name
|
22
|
+
|
23
|
+
attr_writer :description
|
24
|
+
|
25
|
+
# @return [Symbol] Method or hash key on the underlying object to look up
|
26
|
+
attr_reader :method_sym
|
27
|
+
|
28
|
+
# @return [String] Method or hash key on the underlying object to look up
|
29
|
+
attr_reader :method_str
|
30
|
+
|
31
|
+
attr_reader :hash_key
|
32
|
+
attr_reader :dig_keys
|
33
|
+
|
34
|
+
# @return [Symbol] The method on the type to look up
|
35
|
+
def resolver_method
|
36
|
+
if @resolver_class
|
37
|
+
@resolver_class.resolver_method
|
38
|
+
else
|
39
|
+
@resolver_method
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Class] The thing this field was defined on (type, mutation, resolver)
|
44
|
+
attr_accessor :owner
|
45
|
+
|
46
|
+
# @return [Class] The GraphQL type this field belongs to. (For fields defined on mutations, it's the payload type)
|
47
|
+
def owner_type
|
48
|
+
@owner_type ||= if owner.nil?
|
49
|
+
raise GraphQL::InvariantError, "Field #{original_name.inspect} (graphql name: #{graphql_name.inspect}) has no owner, but all fields should have an owner. How did this happen?!"
|
50
|
+
elsif owner < GraphQL::Schema::Mutation
|
51
|
+
owner.payload_type
|
52
|
+
else
|
53
|
+
owner
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Symbol] the original name of the field, passed in by the user
|
58
|
+
attr_reader :original_name
|
59
|
+
|
60
|
+
# @return [Class, nil] The {Schema::Resolver} this field was derived from, if there is one
|
61
|
+
def resolver
|
62
|
+
@resolver_class
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Boolean] Is this field a predefined introspection field?
|
66
|
+
def introspection?
|
67
|
+
@introspection
|
68
|
+
end
|
69
|
+
|
70
|
+
def inspect
|
71
|
+
"#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
|
72
|
+
end
|
73
|
+
|
74
|
+
alias :mutation :resolver
|
75
|
+
|
76
|
+
# @return [Boolean] Apply tracing to this field? (Default: skip scalars, this is the override value)
|
77
|
+
attr_reader :trace
|
78
|
+
|
79
|
+
# @return [String, nil]
|
80
|
+
def subscription_scope
|
81
|
+
@subscription_scope || (@resolver_class.respond_to?(:subscription_scope) ? @resolver_class.subscription_scope : nil)
|
82
|
+
end
|
83
|
+
attr_writer :subscription_scope
|
84
|
+
|
85
|
+
# Create a field instance from a list of arguments, keyword arguments, and a block.
|
86
|
+
#
|
87
|
+
# This method implements prioritization between the `resolver` or `mutation` defaults
|
88
|
+
# and the local overrides via other keywords.
|
89
|
+
#
|
90
|
+
# It also normalizes positional arguments into keywords for {Schema::Field#initialize}.
|
91
|
+
# @param resolver [Class] A {GraphQL::Schema::Resolver} class to use for field configuration
|
92
|
+
# @param mutation [Class] A {GraphQL::Schema::Mutation} class to use for field configuration
|
93
|
+
# @param subscription [Class] A {GraphQL::Schema::Subscription} class to use for field configuration
|
94
|
+
# @return [GraphQL::Schema:Field] an instance of `self
|
95
|
+
# @see {.initialize} for other options
|
96
|
+
def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
|
97
|
+
if (resolver_class = resolver || mutation || subscription)
|
98
|
+
# Add a reference to that parent class
|
99
|
+
kwargs[:resolver_class] = resolver_class
|
100
|
+
end
|
101
|
+
|
102
|
+
if name
|
103
|
+
kwargs[:name] = name
|
104
|
+
end
|
105
|
+
|
106
|
+
if !type.nil?
|
107
|
+
if desc
|
108
|
+
if kwargs[:description]
|
109
|
+
raise ArgumentError, "Provide description as a positional argument or `description:` keyword, but not both (#{desc.inspect}, #{kwargs[:description].inspect})"
|
110
|
+
end
|
111
|
+
|
112
|
+
kwargs[:description] = desc
|
113
|
+
kwargs[:type] = type
|
114
|
+
elsif (resolver || mutation) && type.is_a?(String)
|
115
|
+
# The return type should be copied from the resolver, and the second positional argument is the description
|
116
|
+
kwargs[:description] = type
|
117
|
+
else
|
118
|
+
kwargs[:type] = type
|
119
|
+
end
|
120
|
+
if type.is_a?(Class) && type < GraphQL::Schema::Mutation
|
121
|
+
raise ArgumentError, "Use `field #{name.inspect}, mutation: Mutation, ...` to provide a mutation to this field instead"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
new(**kwargs, &block)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Can be set with `connection: true|false` or inferred from a type name ending in `*Connection`
|
128
|
+
# @return [Boolean] if true, this field will be wrapped with Relay connection behavior
|
129
|
+
def connection?
|
130
|
+
if @connection.nil?
|
131
|
+
# Provide default based on type name
|
132
|
+
return_type_name = if @return_type_expr
|
133
|
+
Member::BuildType.to_type_name(@return_type_expr)
|
134
|
+
elsif @resolver_class && @resolver_class.type
|
135
|
+
Member::BuildType.to_type_name(@resolver_class.type)
|
136
|
+
else
|
137
|
+
# As a last ditch, try to force loading the return type:
|
138
|
+
type.unwrap.name
|
139
|
+
end
|
140
|
+
@connection = return_type_name.end_with?("Connection")
|
141
|
+
else
|
142
|
+
@connection
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# @return [Boolean] if true, the return type's `.scope_items` method will be applied to this field's return value
|
147
|
+
def scoped?
|
148
|
+
if !@scope.nil?
|
149
|
+
# The default was overridden
|
150
|
+
@scope
|
151
|
+
elsif @return_type_expr
|
152
|
+
# Detect a list return type, but don't call `type` since that may eager-load an otherwise lazy-loaded type
|
153
|
+
@return_type_expr.is_a?(Array) ||
|
154
|
+
(@return_type_expr.is_a?(String) && @return_type_expr.include?("[")) ||
|
155
|
+
connection?
|
156
|
+
elsif @resolver_class
|
157
|
+
resolver_type = @resolver_class.type_expr
|
158
|
+
resolver_type.is_a?(Array) ||
|
159
|
+
(resolver_type.is_a?(String) && resolver_type.include?("[")) ||
|
160
|
+
connection?
|
161
|
+
else
|
162
|
+
false
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# This extension is applied to fields when {#connection?} is true.
|
167
|
+
#
|
168
|
+
# You can override it in your base field definition.
|
169
|
+
# @return [Class] A {FieldExtension} subclass for implementing pagination behavior.
|
170
|
+
# @example Configuring a custom extension
|
171
|
+
# class Types::BaseField < GraphQL::Schema::Field
|
172
|
+
# connection_extension(MyCustomExtension)
|
173
|
+
# end
|
174
|
+
def self.connection_extension(new_extension_class = nil)
|
175
|
+
if new_extension_class
|
176
|
+
@connection_extension = new_extension_class
|
177
|
+
else
|
178
|
+
@connection_extension ||= find_inherited_value(:connection_extension, ConnectionExtension)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# @return Boolean
|
183
|
+
attr_reader :relay_node_field
|
184
|
+
# @return Boolean
|
185
|
+
attr_reader :relay_nodes_field
|
186
|
+
|
187
|
+
# @return [Boolean] Should we warn if this field's name conflicts with a built-in method?
|
188
|
+
def method_conflict_warning?
|
189
|
+
@method_conflict_warning
|
190
|
+
end
|
191
|
+
|
192
|
+
# @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
|
193
|
+
# @param type [Class, GraphQL::BaseType, Array] The return type of this field
|
194
|
+
# @param owner [Class] The type that this field belongs to
|
195
|
+
# @param null [Boolean] (defaults to `true`) `true` if this field may return `null`, `false` if it is never `null`
|
196
|
+
# @param description [String] Field description
|
197
|
+
# @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
|
198
|
+
# @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
|
199
|
+
# @param hash_key [String, Symbol] The hash key to lookup on the underlying object (if its a Hash) to resolve this field (defaults to `name` or `name.to_s`)
|
200
|
+
# @param dig [Array<String, Symbol>] The nested hash keys to lookup on the underlying hash to resolve this field using dig
|
201
|
+
# @param resolver_method [Symbol] The method on the type to call to resolve this field (defaults to `name`)
|
202
|
+
# @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
|
203
|
+
# @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
|
204
|
+
# @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
|
205
|
+
# @param default_page_size [Integer, nil] For connections, the default number of items to return from this field, or `nil` to return unlimited results.
|
206
|
+
# @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
|
207
|
+
# @param resolver_class [Class] (Private) A {Schema::Resolver} which this field was derived from. Use `resolver:` to create a field with a resolver.
|
208
|
+
# @param arguments [{String=>GraphQL::Schema::Argument, Hash}] Arguments for this field (may be added in the block, also)
|
209
|
+
# @param camelize [Boolean] If true, the field name will be camelized when building the schema
|
210
|
+
# @param complexity [Numeric] When provided, set the complexity for this field
|
211
|
+
# @param scope [Boolean] If true, the return type's `.scope_items` method will be called on the return value
|
212
|
+
# @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
|
213
|
+
# @param extensions [Array<Class, Hash<Class => Object>>] Named extensions to apply to this field (see also {#extension})
|
214
|
+
# @param directives [Hash{Class => Hash}] Directives to apply to this field
|
215
|
+
# @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
|
216
|
+
# @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
|
217
|
+
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
218
|
+
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
219
|
+
# @param validates [Array<Hash>] Configurations for validating this field
|
220
|
+
# @fallback_value [Object] A fallback value if the method is not defined
|
221
|
+
def initialize(type: nil, name: nil, owner: nil, null: nil, description: :not_given, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: :not_given, default_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: :not_given, &definition_block)
|
222
|
+
if name.nil?
|
223
|
+
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
224
|
+
end
|
225
|
+
if !(resolver_class)
|
226
|
+
if type.nil?
|
227
|
+
raise ArgumentError, "missing second `type` argument or keyword `type:`"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
@original_name = name
|
231
|
+
name_s = -name.to_s
|
232
|
+
@underscored_name = -Member::BuildType.underscore(name_s)
|
233
|
+
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
234
|
+
if description != :not_given
|
235
|
+
@description = description
|
236
|
+
end
|
237
|
+
self.deprecation_reason = deprecation_reason
|
238
|
+
|
239
|
+
if method && hash_key && dig
|
240
|
+
raise ArgumentError, "Provide `method:`, `hash_key:` _or_ `dig:`, not multiple. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}, dig: #{dig.inspect}`)"
|
241
|
+
end
|
242
|
+
|
243
|
+
if resolver_method
|
244
|
+
if method
|
245
|
+
raise ArgumentError, "Provide `method:` _or_ `resolver_method:`, not both. (called with: `method: #{method.inspect}, resolver_method: #{resolver_method.inspect}`)"
|
246
|
+
end
|
247
|
+
|
248
|
+
if hash_key || dig
|
249
|
+
raise ArgumentError, "Provide `hash_key:`, `dig:`, _or_ `resolver_method:`, not multiple. (called with: `hash_key: #{hash_key.inspect}, dig: #{dig.inspect}, resolver_method: #{resolver_method.inspect}`)"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
method_name = method || hash_key || name_s
|
254
|
+
@dig_keys = dig
|
255
|
+
if hash_key
|
256
|
+
@hash_key = hash_key
|
257
|
+
@hash_key_str = hash_key.to_s
|
258
|
+
end
|
259
|
+
|
260
|
+
@method_str = -method_name.to_s
|
261
|
+
@method_sym = method_name.to_sym
|
262
|
+
@resolver_method = (resolver_method || name_s).to_sym
|
263
|
+
@complexity = complexity
|
264
|
+
@return_type_expr = type
|
265
|
+
@return_type_null = if !null.nil?
|
266
|
+
null
|
267
|
+
elsif resolver_class
|
268
|
+
nil
|
269
|
+
else
|
270
|
+
true
|
271
|
+
end
|
272
|
+
@connection = connection
|
273
|
+
@has_max_page_size = max_page_size != :not_given
|
274
|
+
@max_page_size = max_page_size == :not_given ? nil : max_page_size
|
275
|
+
@has_default_page_size = default_page_size != :not_given
|
276
|
+
@default_page_size = default_page_size == :not_given ? nil : default_page_size
|
277
|
+
@introspection = introspection
|
278
|
+
@extras = extras
|
279
|
+
if !broadcastable.nil?
|
280
|
+
@broadcastable = broadcastable
|
281
|
+
end
|
282
|
+
@resolver_class = resolver_class
|
283
|
+
@scope = scope
|
284
|
+
@trace = trace
|
285
|
+
@relay_node_field = relay_node_field
|
286
|
+
@relay_nodes_field = relay_nodes_field
|
287
|
+
@ast_node = ast_node
|
288
|
+
@method_conflict_warning = method_conflict_warning
|
289
|
+
@fallback_value = fallback_value
|
290
|
+
|
291
|
+
arguments.each do |name, arg|
|
292
|
+
case arg
|
293
|
+
when Hash
|
294
|
+
argument(name: name, **arg)
|
295
|
+
when GraphQL::Schema::Argument
|
296
|
+
add_argument(arg)
|
297
|
+
when Array
|
298
|
+
arg.each { |a| add_argument(a) }
|
299
|
+
else
|
300
|
+
raise ArgumentError, "Unexpected argument config (#{arg.class}): #{arg.inspect}"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
@owner = owner
|
305
|
+
@subscription_scope = subscription_scope
|
306
|
+
|
307
|
+
@extensions = EMPTY_ARRAY
|
308
|
+
@call_after_define = false
|
309
|
+
# This should run before connection extension,
|
310
|
+
# but should it run after the definition block?
|
311
|
+
if scoped?
|
312
|
+
self.extension(ScopeExtension)
|
313
|
+
end
|
314
|
+
|
315
|
+
# The problem with putting this after the definition_block
|
316
|
+
# is that it would override arguments
|
317
|
+
if connection? && connection_extension
|
318
|
+
self.extension(connection_extension)
|
319
|
+
end
|
320
|
+
|
321
|
+
# Do this last so we have as much context as possible when initializing them:
|
322
|
+
if extensions.any?
|
323
|
+
self.extensions(extensions)
|
324
|
+
end
|
325
|
+
|
326
|
+
if resolver_class && resolver_class.extensions.any?
|
327
|
+
self.extensions(resolver_class.extensions)
|
328
|
+
end
|
329
|
+
|
330
|
+
if directives.any?
|
331
|
+
directives.each do |(dir_class, options)|
|
332
|
+
self.directive(dir_class, **options)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
if !validates.empty?
|
337
|
+
self.validates(validates)
|
338
|
+
end
|
339
|
+
|
340
|
+
if definition_block
|
341
|
+
if definition_block.arity == 1
|
342
|
+
yield self
|
343
|
+
else
|
344
|
+
instance_eval(&definition_block)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
self.extensions.each(&:after_define_apply)
|
349
|
+
@call_after_define = true
|
350
|
+
end
|
351
|
+
|
352
|
+
# If true, subscription updates with this field can be shared between viewers
|
353
|
+
# @return [Boolean, nil]
|
354
|
+
# @see GraphQL::Subscriptions::BroadcastAnalyzer
|
355
|
+
def broadcastable?
|
356
|
+
if defined?(@broadcastable)
|
357
|
+
@broadcastable
|
358
|
+
elsif @resolver_class
|
359
|
+
@resolver_class.broadcastable?
|
360
|
+
else
|
361
|
+
nil
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
# @param text [String]
|
366
|
+
# @return [String]
|
367
|
+
def description(text = nil)
|
368
|
+
if text
|
369
|
+
@description = text
|
370
|
+
elsif defined?(@description)
|
371
|
+
@description
|
372
|
+
elsif @resolver_class
|
373
|
+
@description || @resolver_class.description
|
374
|
+
else
|
375
|
+
nil
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
# Read extension instances from this field,
|
380
|
+
# or add new classes/options to be initialized on this field.
|
381
|
+
# Extensions are executed in the order they are added.
|
382
|
+
#
|
383
|
+
# @example adding an extension
|
384
|
+
# extensions([MyExtensionClass])
|
385
|
+
#
|
386
|
+
# @example adding multiple extensions
|
387
|
+
# extensions([MyExtensionClass, AnotherExtensionClass])
|
388
|
+
#
|
389
|
+
# @example adding an extension with options
|
390
|
+
# extensions([MyExtensionClass, { AnotherExtensionClass => { filter: true } }])
|
391
|
+
#
|
392
|
+
# @param extensions [Array<Class, Hash<Class => Hash>>] Add extensions to this field. For hash elements, only the first key/value is used.
|
393
|
+
# @return [Array<GraphQL::Schema::FieldExtension>] extensions to apply to this field
|
394
|
+
def extensions(new_extensions = nil)
|
395
|
+
if new_extensions
|
396
|
+
new_extensions.each do |extension_config|
|
397
|
+
if extension_config.is_a?(Hash)
|
398
|
+
extension_class, options = *extension_config.to_a[0]
|
399
|
+
self.extension(extension_class, options)
|
400
|
+
else
|
401
|
+
self.extension(extension_config)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
@extensions
|
406
|
+
end
|
407
|
+
|
408
|
+
# Add `extension` to this field, initialized with `options` if provided.
|
409
|
+
#
|
410
|
+
# @example adding an extension
|
411
|
+
# extension(MyExtensionClass)
|
412
|
+
#
|
413
|
+
# @example adding an extension with options
|
414
|
+
# extension(MyExtensionClass, filter: true)
|
415
|
+
#
|
416
|
+
# @param extension_class [Class] subclass of {Schema::FieldExtension}
|
417
|
+
# @param options [Hash] if provided, given as `options:` when initializing `extension`.
|
418
|
+
# @return [void]
|
419
|
+
def extension(extension_class, options = nil)
|
420
|
+
extension_inst = extension_class.new(field: self, options: options)
|
421
|
+
if @extensions.frozen?
|
422
|
+
@extensions = @extensions.dup
|
423
|
+
end
|
424
|
+
if @call_after_define
|
425
|
+
extension_inst.after_define_apply
|
426
|
+
end
|
427
|
+
@extensions << extension_inst
|
428
|
+
nil
|
429
|
+
end
|
430
|
+
|
431
|
+
# Read extras (as symbols) from this field,
|
432
|
+
# or add new extras to be opted into by this field's resolver.
|
433
|
+
#
|
434
|
+
# @param new_extras [Array<Symbol>] Add extras to this field
|
435
|
+
# @return [Array<Symbol>]
|
436
|
+
def extras(new_extras = nil)
|
437
|
+
if new_extras.nil?
|
438
|
+
# Read the value
|
439
|
+
field_extras = @extras
|
440
|
+
if @resolver_class && @resolver_class.extras.any?
|
441
|
+
field_extras + @resolver_class.extras
|
442
|
+
else
|
443
|
+
field_extras
|
444
|
+
end
|
445
|
+
else
|
446
|
+
if @extras.frozen?
|
447
|
+
@extras = @extras.dup
|
448
|
+
end
|
449
|
+
# Append to the set of extras on this field
|
450
|
+
@extras.concat(new_extras)
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
def calculate_complexity(query:, nodes:, child_complexity:)
|
455
|
+
if respond_to?(:complexity_for)
|
456
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
457
|
+
complexity_for(child_complexity: child_complexity, query: query, lookahead: lookahead)
|
458
|
+
elsif connection?
|
459
|
+
arguments = query.arguments_for(nodes.first, self)
|
460
|
+
max_possible_page_size = nil
|
461
|
+
if arguments.respond_to?(:[]) # It might have been an error
|
462
|
+
if arguments[:first]
|
463
|
+
max_possible_page_size = arguments[:first]
|
464
|
+
end
|
465
|
+
|
466
|
+
if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
|
467
|
+
max_possible_page_size = arguments[:last]
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
if max_possible_page_size.nil?
|
472
|
+
max_possible_page_size = default_page_size || query.schema.default_page_size || max_page_size || query.schema.default_max_page_size
|
473
|
+
end
|
474
|
+
|
475
|
+
if max_possible_page_size.nil?
|
476
|
+
raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `default_page_size`, `max_page_size` or `default_max_page_size`"
|
477
|
+
else
|
478
|
+
metadata_complexity = 0
|
479
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
480
|
+
|
481
|
+
if (page_info_lookahead = lookahead.selection(:page_info)).selected?
|
482
|
+
metadata_complexity += 1 # pageInfo
|
483
|
+
metadata_complexity += page_info_lookahead.selections.size # subfields
|
484
|
+
end
|
485
|
+
|
486
|
+
if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
|
487
|
+
metadata_complexity += 1
|
488
|
+
end
|
489
|
+
|
490
|
+
nodes_edges_complexity = 0
|
491
|
+
nodes_edges_complexity += 1 if lookahead.selects?(:edges)
|
492
|
+
nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
|
493
|
+
|
494
|
+
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
495
|
+
items_complexity = child_complexity - metadata_complexity - nodes_edges_complexity
|
496
|
+
# Add 1 for _this_ field
|
497
|
+
1 + (max_possible_page_size * items_complexity) + metadata_complexity + nodes_edges_complexity
|
498
|
+
end
|
499
|
+
else
|
500
|
+
defined_complexity = complexity
|
501
|
+
case defined_complexity
|
502
|
+
when Proc
|
503
|
+
arguments = query.arguments_for(nodes.first, self)
|
504
|
+
if arguments.is_a?(GraphQL::ExecutionError)
|
505
|
+
return child_complexity
|
506
|
+
elsif arguments.respond_to?(:keyword_arguments)
|
507
|
+
arguments = arguments.keyword_arguments
|
508
|
+
end
|
509
|
+
|
510
|
+
defined_complexity.call(query.context, arguments, child_complexity)
|
511
|
+
when Numeric
|
512
|
+
defined_complexity + child_complexity
|
513
|
+
else
|
514
|
+
raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
def complexity(new_complexity = nil)
|
520
|
+
case new_complexity
|
521
|
+
when Proc
|
522
|
+
if new_complexity.parameters.size != 3
|
523
|
+
fail(
|
524
|
+
"A complexity proc should always accept 3 parameters: ctx, args, child_complexity. "\
|
525
|
+
"E.g.: complexity ->(ctx, args, child_complexity) { child_complexity * args[:limit] }"
|
526
|
+
)
|
527
|
+
else
|
528
|
+
@complexity = new_complexity
|
529
|
+
end
|
530
|
+
when Numeric
|
531
|
+
@complexity = new_complexity
|
532
|
+
when nil
|
533
|
+
if @resolver_class
|
534
|
+
@complexity || @resolver_class.complexity || 1
|
535
|
+
else
|
536
|
+
@complexity || 1
|
537
|
+
end
|
538
|
+
else
|
539
|
+
raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
# @return [Boolean] True if this field's {#max_page_size} should override the schema default.
|
544
|
+
def has_max_page_size?
|
545
|
+
@has_max_page_size || (@resolver_class && @resolver_class.has_max_page_size?)
|
546
|
+
end
|
547
|
+
|
548
|
+
# @return [Integer, nil] Applied to connections if {#has_max_page_size?}
|
549
|
+
def max_page_size
|
550
|
+
@max_page_size || (@resolver_class && @resolver_class.max_page_size)
|
551
|
+
end
|
552
|
+
|
553
|
+
# @return [Boolean] True if this field's {#default_page_size} should override the schema default.
|
554
|
+
def has_default_page_size?
|
555
|
+
@has_default_page_size || (@resolver_class && @resolver_class.has_default_page_size?)
|
556
|
+
end
|
557
|
+
|
558
|
+
# @return [Integer, nil] Applied to connections if {#has_default_page_size?}
|
559
|
+
def default_page_size
|
560
|
+
@default_page_size || (@resolver_class && @resolver_class.default_page_size)
|
561
|
+
end
|
562
|
+
|
563
|
+
class MissingReturnTypeError < GraphQL::Error; end
|
564
|
+
attr_writer :type
|
565
|
+
|
566
|
+
def type
|
567
|
+
if @resolver_class
|
568
|
+
return_type = @return_type_expr || @resolver_class.type_expr
|
569
|
+
if return_type.nil?
|
570
|
+
raise MissingReturnTypeError, "Can't determine the return type for #{self.path} (it has `resolver: #{@resolver_class}`, perhaps that class is missing a `type ...` declaration, or perhaps its type causes a cyclical loading issue)"
|
571
|
+
end
|
572
|
+
nullable = @return_type_null.nil? ? @resolver_class.null : @return_type_null
|
573
|
+
Member::BuildType.parse_type(return_type, null: nullable)
|
574
|
+
else
|
575
|
+
@type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
576
|
+
end
|
577
|
+
rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
|
578
|
+
# Let this propagate up
|
579
|
+
raise err
|
580
|
+
rescue StandardError => err
|
581
|
+
raise MissingReturnTypeError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: (#{err.class}) #{err.message}", err.backtrace
|
582
|
+
end
|
583
|
+
|
584
|
+
def visible?(context)
|
585
|
+
if @resolver_class
|
586
|
+
@resolver_class.visible?(context)
|
587
|
+
else
|
588
|
+
true
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
def accessible?(context)
|
593
|
+
if @resolver_class
|
594
|
+
@resolver_class.accessible?(context)
|
595
|
+
else
|
596
|
+
true
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
def authorized?(object, args, context)
|
601
|
+
if @resolver_class
|
602
|
+
# The resolver _instance_ will check itself during `resolve()`
|
603
|
+
@resolver_class.authorized?(object, context)
|
604
|
+
else
|
605
|
+
if (arg_values = context[:current_arguments])
|
606
|
+
# ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
|
607
|
+
using_arg_values = true
|
608
|
+
arg_values = arg_values.argument_values
|
609
|
+
else
|
610
|
+
arg_values = args
|
611
|
+
using_arg_values = false
|
612
|
+
end
|
613
|
+
# Faster than `.any?`
|
614
|
+
arguments(context).each_value do |arg|
|
615
|
+
arg_key = arg.keyword
|
616
|
+
if arg_values.key?(arg_key)
|
617
|
+
arg_value = arg_values[arg_key]
|
618
|
+
if using_arg_values
|
619
|
+
if arg_value.default_used?
|
620
|
+
# pass -- no auth required for default used
|
621
|
+
next
|
622
|
+
else
|
623
|
+
application_arg_value = arg_value.value
|
624
|
+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
|
625
|
+
application_arg_value.keyword_arguments
|
626
|
+
end
|
627
|
+
end
|
628
|
+
else
|
629
|
+
application_arg_value = arg_value
|
630
|
+
end
|
631
|
+
|
632
|
+
if !arg.authorized?(object, application_arg_value, context)
|
633
|
+
return false
|
634
|
+
end
|
635
|
+
end
|
636
|
+
end
|
637
|
+
true
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
# This method is called by the interpreter for each field.
|
642
|
+
# You can extend it in your base field classes.
|
643
|
+
# @param object [GraphQL::Schema::Object] An instance of some type class, wrapping an application object
|
644
|
+
# @param args [Hash] A symbol-keyed hash of Ruby keyword arguments. (Empty if no args)
|
645
|
+
# @param ctx [GraphQL::Query::Context]
|
646
|
+
def resolve(object, args, query_ctx)
|
647
|
+
# Unwrap the GraphQL object to get the application object.
|
648
|
+
application_object = object.object
|
649
|
+
method_receiver = nil
|
650
|
+
method_to_call = nil
|
651
|
+
method_args = nil
|
652
|
+
|
653
|
+
Schema::Validator.validate!(validators, application_object, query_ctx, args)
|
654
|
+
|
655
|
+
query_ctx.schema.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
|
656
|
+
if is_authorized
|
657
|
+
with_extensions(object, args, query_ctx) do |obj, ruby_kwargs|
|
658
|
+
method_args = ruby_kwargs
|
659
|
+
if @resolver_class
|
660
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
661
|
+
obj = obj.object
|
662
|
+
end
|
663
|
+
obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
|
664
|
+
end
|
665
|
+
|
666
|
+
inner_object = obj.object
|
667
|
+
|
668
|
+
if defined?(@hash_key)
|
669
|
+
hash_value = if inner_object.is_a?(Hash)
|
670
|
+
inner_object.key?(@hash_key) ? inner_object[@hash_key] : inner_object[@hash_key_str]
|
671
|
+
elsif inner_object.respond_to?(:[])
|
672
|
+
inner_object[@hash_key]
|
673
|
+
else
|
674
|
+
nil
|
675
|
+
end
|
676
|
+
if hash_value == false
|
677
|
+
hash_value
|
678
|
+
else
|
679
|
+
hash_value || (@fallback_value != :not_given ? @fallback_value : nil)
|
680
|
+
end
|
681
|
+
elsif obj.respond_to?(resolver_method)
|
682
|
+
method_to_call = resolver_method
|
683
|
+
method_receiver = obj
|
684
|
+
# Call the method with kwargs, if there are any
|
685
|
+
if ruby_kwargs.any?
|
686
|
+
obj.public_send(resolver_method, **ruby_kwargs)
|
687
|
+
else
|
688
|
+
obj.public_send(resolver_method)
|
689
|
+
end
|
690
|
+
elsif inner_object.is_a?(Hash)
|
691
|
+
if @dig_keys
|
692
|
+
inner_object.dig(*@dig_keys)
|
693
|
+
elsif inner_object.key?(@method_sym)
|
694
|
+
inner_object[@method_sym]
|
695
|
+
elsif inner_object.key?(@method_str)
|
696
|
+
inner_object[@method_str]
|
697
|
+
elsif @fallback_value != :not_given
|
698
|
+
@fallback_value
|
699
|
+
else
|
700
|
+
nil
|
701
|
+
end
|
702
|
+
elsif inner_object.respond_to?(@method_sym)
|
703
|
+
method_to_call = @method_sym
|
704
|
+
method_receiver = obj.object
|
705
|
+
if ruby_kwargs.any?
|
706
|
+
inner_object.public_send(@method_sym, **ruby_kwargs)
|
707
|
+
else
|
708
|
+
inner_object.public_send(@method_sym)
|
709
|
+
end
|
710
|
+
elsif @fallback_value != :not_given
|
711
|
+
@fallback_value
|
712
|
+
else
|
713
|
+
raise <<-ERR
|
714
|
+
Failed to implement #{@owner.graphql_name}.#{@name}, tried:
|
715
|
+
|
716
|
+
- `#{obj.class}##{resolver_method}`, which did not exist
|
717
|
+
- `#{inner_object.class}##{@method_sym}`, which did not exist
|
718
|
+
- Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{inner_object}`, but it wasn't a Hash
|
719
|
+
|
720
|
+
To implement this field, define one of the methods above (and check for typos), or supply a `fallback_value`.
|
721
|
+
ERR
|
722
|
+
end
|
723
|
+
end
|
724
|
+
else
|
725
|
+
raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: query_ctx, field: self)
|
726
|
+
end
|
727
|
+
end
|
728
|
+
rescue GraphQL::UnauthorizedFieldError => err
|
729
|
+
err.field ||= self
|
730
|
+
begin
|
731
|
+
query_ctx.schema.unauthorized_field(err)
|
732
|
+
rescue GraphQL::ExecutionError => err
|
733
|
+
err
|
734
|
+
end
|
735
|
+
rescue GraphQL::UnauthorizedError => err
|
736
|
+
begin
|
737
|
+
query_ctx.schema.unauthorized_object(err)
|
738
|
+
rescue GraphQL::ExecutionError => err
|
739
|
+
err
|
740
|
+
end
|
741
|
+
rescue ArgumentError
|
742
|
+
if method_receiver && method_to_call
|
743
|
+
assert_satisfactory_implementation(method_receiver, method_to_call, method_args)
|
744
|
+
end
|
745
|
+
# if the line above doesn't raise, re-raise
|
746
|
+
raise
|
747
|
+
end
|
748
|
+
|
749
|
+
# @param ctx [GraphQL::Query::Context]
|
750
|
+
def fetch_extra(extra_name, ctx)
|
751
|
+
if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
|
752
|
+
self.public_send(extra_name)
|
753
|
+
elsif ctx.respond_to?(extra_name)
|
754
|
+
ctx.public_send(extra_name)
|
755
|
+
else
|
756
|
+
raise GraphQL::RequiredImplementationMissingError, "Unknown field extra for #{self.path}: #{extra_name.inspect}"
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
private
|
761
|
+
|
762
|
+
def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
|
763
|
+
method_defn = receiver.method(method_name)
|
764
|
+
unsatisfied_ruby_kwargs = ruby_kwargs.dup
|
765
|
+
unsatisfied_method_params = []
|
766
|
+
encountered_keyrest = false
|
767
|
+
method_defn.parameters.each do |(param_type, param_name)|
|
768
|
+
case param_type
|
769
|
+
when :key
|
770
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
771
|
+
when :keyreq
|
772
|
+
if unsatisfied_ruby_kwargs.key?(param_name)
|
773
|
+
unsatisfied_ruby_kwargs.delete(param_name)
|
774
|
+
else
|
775
|
+
unsatisfied_method_params << "- `#{param_name}:` is required by Ruby, but not by GraphQL. Consider `#{param_name}: nil` instead, or making this argument required in GraphQL."
|
776
|
+
end
|
777
|
+
when :keyrest
|
778
|
+
encountered_keyrest = true
|
779
|
+
when :req
|
780
|
+
unsatisfied_method_params << "- `#{param_name}` is required by Ruby, but GraphQL doesn't pass positional arguments. If it's meant to be a GraphQL argument, use `#{param_name}:` instead. Otherwise, remove it."
|
781
|
+
when :opt, :rest
|
782
|
+
# This is fine, although it will never be present
|
783
|
+
end
|
784
|
+
end
|
785
|
+
|
786
|
+
if encountered_keyrest
|
787
|
+
unsatisfied_ruby_kwargs.clear
|
788
|
+
end
|
789
|
+
|
790
|
+
if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
|
791
|
+
raise FieldImplementationFailed.new, <<-ERR
|
792
|
+
Failed to call `#{method_name.inspect}` on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
|
793
|
+
|
794
|
+
#{ unsatisfied_ruby_kwargs
|
795
|
+
.map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
|
796
|
+
.concat(unsatisfied_method_params)
|
797
|
+
.join("\n") }
|
798
|
+
ERR
|
799
|
+
end
|
800
|
+
end
|
801
|
+
|
802
|
+
# Wrap execution with hooks.
|
803
|
+
# Written iteratively to avoid big stack traces.
|
804
|
+
# @return [Object] Whatever the
|
805
|
+
def with_extensions(obj, args, ctx)
|
806
|
+
if @extensions.empty?
|
807
|
+
yield(obj, args)
|
808
|
+
else
|
809
|
+
# This is a hack to get the _last_ value for extended obj and args,
|
810
|
+
# in case one of the extensions doesn't `yield`.
|
811
|
+
# (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
|
812
|
+
extended = { args: args, obj: obj, memos: nil, added_extras: nil }
|
813
|
+
value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
|
814
|
+
if (added_extras = extended[:added_extras])
|
815
|
+
args = args.dup
|
816
|
+
added_extras.each { |e| args.delete(e) }
|
817
|
+
end
|
818
|
+
yield(obj, args)
|
819
|
+
end
|
820
|
+
|
821
|
+
extended_obj = extended[:obj]
|
822
|
+
extended_args = extended[:args]
|
823
|
+
memos = extended[:memos] || EMPTY_HASH
|
824
|
+
|
825
|
+
ctx.schema.after_lazy(value) do |resolved_value|
|
826
|
+
idx = 0
|
827
|
+
@extensions.each do |ext|
|
828
|
+
memo = memos[idx]
|
829
|
+
# TODO after_lazy?
|
830
|
+
resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
|
831
|
+
idx += 1
|
832
|
+
end
|
833
|
+
resolved_value
|
834
|
+
end
|
835
|
+
end
|
836
|
+
end
|
837
|
+
|
838
|
+
def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
|
839
|
+
extension = @extensions[idx]
|
840
|
+
if extension
|
841
|
+
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
842
|
+
if memo
|
843
|
+
memos = extended[:memos] ||= {}
|
844
|
+
memos[idx] = memo
|
845
|
+
end
|
846
|
+
|
847
|
+
if (extras = extension.added_extras)
|
848
|
+
ae = extended[:added_extras] ||= []
|
849
|
+
ae.concat(extras)
|
850
|
+
end
|
851
|
+
|
852
|
+
extended[:obj] = extended_obj
|
853
|
+
extended[:args] = extended_args
|
854
|
+
run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
|
855
|
+
end
|
856
|
+
else
|
857
|
+
yield(obj, args)
|
858
|
+
end
|
859
|
+
end
|
860
|
+
end
|
861
|
+
end
|
862
|
+
end
|