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.rb
CHANGED
@@ -1,24 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "logger"
|
2
3
|
require "graphql/schema/addition"
|
4
|
+
require "graphql/schema/always_visible"
|
3
5
|
require "graphql/schema/base_64_encoder"
|
4
|
-
require "graphql/schema/catchall_middleware"
|
5
|
-
require "graphql/schema/default_parse_error"
|
6
|
-
require "graphql/schema/default_type_error"
|
7
6
|
require "graphql/schema/find_inherited_value"
|
8
7
|
require "graphql/schema/finder"
|
9
|
-
require "graphql/schema/invalid_type_error"
|
10
8
|
require "graphql/schema/introspection_system"
|
11
9
|
require "graphql/schema/late_bound_type"
|
12
|
-
require "graphql/schema/middleware_chain"
|
13
10
|
require "graphql/schema/null_mask"
|
14
|
-
require "graphql/schema/possible_types"
|
15
|
-
require "graphql/schema/rescue_middleware"
|
16
11
|
require "graphql/schema/timeout"
|
17
|
-
require "graphql/schema/timeout_middleware"
|
18
|
-
require "graphql/schema/traversal"
|
19
12
|
require "graphql/schema/type_expression"
|
20
13
|
require "graphql/schema/unique_within_type"
|
21
|
-
require "graphql/schema/validation"
|
22
14
|
require "graphql/schema/warden"
|
23
15
|
require "graphql/schema/build_from_definition"
|
24
16
|
|
@@ -40,16 +32,20 @@ require "graphql/schema/union"
|
|
40
32
|
require "graphql/schema/directive"
|
41
33
|
require "graphql/schema/directive/deprecated"
|
42
34
|
require "graphql/schema/directive/include"
|
35
|
+
require "graphql/schema/directive/one_of"
|
43
36
|
require "graphql/schema/directive/skip"
|
44
37
|
require "graphql/schema/directive/feature"
|
45
38
|
require "graphql/schema/directive/flagged"
|
46
39
|
require "graphql/schema/directive/transform"
|
40
|
+
require "graphql/schema/directive/specified_by"
|
47
41
|
require "graphql/schema/type_membership"
|
48
42
|
|
49
43
|
require "graphql/schema/resolver"
|
50
44
|
require "graphql/schema/mutation"
|
45
|
+
require "graphql/schema/has_single_input_argument"
|
51
46
|
require "graphql/schema/relay_classic_mutation"
|
52
47
|
require "graphql/schema/subscription"
|
48
|
+
require "graphql/schema/visibility"
|
53
49
|
|
54
50
|
module GraphQL
|
55
51
|
# A GraphQL schema which may be queried with {GraphQL::Query}.
|
@@ -67,10 +63,6 @@ module GraphQL
|
|
67
63
|
# Schemas can restrict large incoming queries with `max_depth` and `max_complexity` configurations.
|
68
64
|
# (These configurations can be overridden by specific calls to {Schema#execute})
|
69
65
|
#
|
70
|
-
# Schemas can specify how queries should be executed against them.
|
71
|
-
# `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
|
72
|
-
# each apply to corresponding root types.
|
73
|
-
# #
|
74
66
|
# @example defining a schema
|
75
67
|
# class MySchema < GraphQL::Schema
|
76
68
|
# query QueryType
|
@@ -79,16 +71,19 @@ module GraphQL
|
|
79
71
|
# end
|
80
72
|
#
|
81
73
|
class Schema
|
82
|
-
extend Forwardable
|
83
|
-
extend GraphQL::Schema::Member::AcceptsDefinition
|
84
74
|
extend GraphQL::Schema::Member::HasAstNode
|
85
|
-
include GraphQL::Define::InstanceDefinable
|
86
|
-
extend GraphQL::Define::InstanceDefinable::DeprecatedDefine
|
87
75
|
extend GraphQL::Schema::FindInheritedValue
|
76
|
+
extend Autoload
|
88
77
|
|
89
|
-
|
90
|
-
|
91
|
-
|
78
|
+
autoload :BUILT_IN_TYPES, "graphql/schema/built_in_types"
|
79
|
+
|
80
|
+
class DuplicateNamesError < GraphQL::Error
|
81
|
+
attr_reader :duplicated_name
|
82
|
+
def initialize(duplicated_name:, duplicated_definition_1:, duplicated_definition_2:)
|
83
|
+
@duplicated_name = duplicated_name
|
84
|
+
super(
|
85
|
+
"Found two visible definitions for `#{duplicated_name}`: #{duplicated_definition_1}, #{duplicated_definition_2}"
|
86
|
+
)
|
92
87
|
end
|
93
88
|
end
|
94
89
|
|
@@ -100,760 +95,165 @@ module GraphQL
|
|
100
95
|
end
|
101
96
|
end
|
102
97
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
#
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
98
|
+
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
99
|
+
class InvalidDocumentError < Error; end;
|
100
|
+
|
101
|
+
class << self
|
102
|
+
# Create schema with the result of an introspection query.
|
103
|
+
# @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
|
104
|
+
# @return [Class<GraphQL::Schema>] the schema described by `input`
|
105
|
+
def from_introspection(introspection_result)
|
106
|
+
GraphQL::Schema::Loader.load(introspection_result)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Create schema from an IDL schema or file containing an IDL definition.
|
110
|
+
# @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
|
111
|
+
# @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
|
112
|
+
# @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
|
113
|
+
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
114
|
+
# @return [Class] the schema described by `document`
|
115
|
+
def from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
|
116
|
+
# If the file ends in `.graphql` or `.graphqls`, treat it like a filepath
|
117
|
+
if definition_or_path.end_with?(".graphql") || definition_or_path.end_with?(".graphqls")
|
118
|
+
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
119
|
+
self,
|
120
|
+
definition_or_path,
|
121
|
+
default_resolve: default_resolve,
|
122
|
+
parser: parser,
|
123
|
+
using: using,
|
124
|
+
)
|
115
125
|
else
|
116
|
-
|
126
|
+
GraphQL::Schema::BuildFromDefinition.from_definition(
|
127
|
+
self,
|
128
|
+
definition_or_path,
|
129
|
+
default_resolve: default_resolve,
|
130
|
+
parser: parser,
|
131
|
+
using: using,
|
132
|
+
)
|
117
133
|
end
|
118
134
|
end
|
119
135
|
|
120
|
-
|
121
|
-
|
122
|
-
# @return [Object] A GraphQL-ready (non-lazy) object
|
123
|
-
# @api private
|
124
|
-
def sync_lazy(value)
|
125
|
-
lazy_method = lazy_method_name(value)
|
126
|
-
if lazy_method
|
127
|
-
synced_value = value.public_send(lazy_method)
|
128
|
-
sync_lazy(synced_value)
|
129
|
-
else
|
130
|
-
value
|
131
|
-
end
|
136
|
+
def deprecated_graphql_definition
|
137
|
+
graphql_definition(silence_deprecation_warning: true)
|
132
138
|
end
|
133
139
|
|
134
|
-
# @return [
|
135
|
-
def
|
136
|
-
|
140
|
+
# @return [GraphQL::Subscriptions]
|
141
|
+
def subscriptions(inherited: true)
|
142
|
+
defined?(@subscriptions) ? @subscriptions : (inherited ? find_inherited_value(:subscriptions, nil) : nil)
|
137
143
|
end
|
138
144
|
|
139
|
-
|
140
|
-
|
141
|
-
!!lazy_method_name(obj)
|
145
|
+
def subscriptions=(new_implementation)
|
146
|
+
@subscriptions = new_implementation
|
142
147
|
end
|
143
148
|
|
144
|
-
#
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
end
|
149
|
+
# @param new_mode [Symbol] If configured, this will be used when `context: { trace_mode: ... }` isn't set.
|
150
|
+
def default_trace_mode(new_mode = nil)
|
151
|
+
if new_mode
|
152
|
+
@default_trace_mode = new_mode
|
153
|
+
elsif defined?(@default_trace_mode)
|
154
|
+
@default_trace_mode
|
155
|
+
elsif superclass.respond_to?(:default_trace_mode)
|
156
|
+
superclass.default_trace_mode
|
153
157
|
else
|
154
|
-
|
158
|
+
:default
|
155
159
|
end
|
156
160
|
end
|
157
|
-
end
|
158
|
-
|
159
|
-
include LazyHandlingMethods
|
160
|
-
extend LazyHandlingMethods
|
161
|
-
|
162
|
-
accepts_definitions \
|
163
|
-
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
164
|
-
:validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
|
165
|
-
:orphan_types, :resolve_type, :type_error, :parse_error,
|
166
|
-
:error_bubbling,
|
167
|
-
:raise_definition_error,
|
168
|
-
:object_from_id, :id_from_object,
|
169
|
-
:default_mask,
|
170
|
-
:cursor_encoder,
|
171
|
-
# If these are given as classes, normalize them. Accept `nil` when building from string.
|
172
|
-
query: ->(schema, t) { schema.query = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
173
|
-
mutation: ->(schema, t) { schema.mutation = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
174
|
-
subscription: ->(schema, t) { schema.subscription = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
175
|
-
disable_introspection_entry_points: ->(schema) { schema.disable_introspection_entry_points = true },
|
176
|
-
disable_schema_introspection_entry_point: ->(schema) { schema.disable_schema_introspection_entry_point = true },
|
177
|
-
disable_type_introspection_entry_point: ->(schema) { schema.disable_type_introspection_entry_point = true },
|
178
|
-
directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.graphql_name] = d; m } },
|
179
|
-
directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
|
180
|
-
instrument: ->(schema, type, instrumenter, after_built_ins: false) {
|
181
|
-
if type == :field && after_built_ins
|
182
|
-
type = :field_after_built_ins
|
183
|
-
end
|
184
|
-
schema.instrumenters[type] << instrumenter
|
185
|
-
},
|
186
|
-
query_analyzer: ->(schema, analyzer) {
|
187
|
-
if analyzer == GraphQL::Authorization::Analyzer
|
188
|
-
GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
|
189
|
-
end
|
190
|
-
schema.query_analyzers << analyzer
|
191
|
-
},
|
192
|
-
multiplex_analyzer: ->(schema, analyzer) { schema.multiplex_analyzers << analyzer },
|
193
|
-
middleware: ->(schema, middleware) { schema.middleware << middleware },
|
194
|
-
lazy_resolve: ->(schema, lazy_class, lazy_value_method) { schema.lazy_methods.set(lazy_class, lazy_value_method) },
|
195
|
-
rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block) },
|
196
|
-
tracer: ->(schema, tracer) { schema.tracers.push(tracer) }
|
197
|
-
|
198
|
-
ensure_defined :introspection_system
|
199
|
-
|
200
|
-
attr_accessor \
|
201
|
-
:query, :mutation, :subscription,
|
202
|
-
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
203
|
-
:validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
|
204
|
-
:orphan_types, :directives,
|
205
|
-
:query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
|
206
|
-
:cursor_encoder,
|
207
|
-
:ast_node,
|
208
|
-
:raise_definition_error,
|
209
|
-
:introspection_namespace,
|
210
|
-
:analysis_engine
|
211
|
-
|
212
|
-
# [Boolean] True if this object bubbles validation errors up from a field into its parent InputObject, if there is one.
|
213
|
-
attr_accessor :error_bubbling
|
214
|
-
|
215
|
-
# Single, long-lived instance of the provided subscriptions class, if there is one.
|
216
|
-
# @return [GraphQL::Subscriptions]
|
217
|
-
attr_accessor :subscriptions
|
218
|
-
|
219
|
-
# @return [MiddlewareChain] MiddlewareChain which is applied to fields during execution
|
220
|
-
attr_accessor :middleware
|
221
|
-
|
222
|
-
# @return [<#call(member, ctx)>] A callable for filtering members of the schema
|
223
|
-
# @see {Query.new} for query-specific filters with `except:`
|
224
|
-
attr_accessor :default_mask
|
225
|
-
|
226
|
-
# @see {GraphQL::Query::Context} The parent class of these classes
|
227
|
-
# @return [Class] Instantiated for each query
|
228
|
-
attr_accessor :context_class
|
229
|
-
|
230
|
-
# [Boolean] True if this object disables the introspection entry point fields
|
231
|
-
attr_accessor :disable_introspection_entry_points
|
232
|
-
|
233
|
-
def disable_introspection_entry_points?
|
234
|
-
!!@disable_introspection_entry_points
|
235
|
-
end
|
236
|
-
|
237
|
-
# [Boolean] True if this object disables the __schema introspection entry point field
|
238
|
-
attr_accessor :disable_schema_introspection_entry_point
|
239
|
-
|
240
|
-
def disable_schema_introspection_entry_point?
|
241
|
-
!!@disable_schema_introspection_entry_point
|
242
|
-
end
|
243
|
-
|
244
|
-
# [Boolean] True if this object disables the __type introspection entry point field
|
245
|
-
attr_accessor :disable_type_introspection_entry_point
|
246
|
-
|
247
|
-
def disable_type_introspection_entry_point?
|
248
|
-
!!@disable_type_introspection_entry_point
|
249
|
-
end
|
250
|
-
|
251
|
-
class << self
|
252
|
-
attr_writer :default_execution_strategy
|
253
|
-
end
|
254
|
-
|
255
|
-
def default_filter
|
256
|
-
GraphQL::Filter.new(except: default_mask)
|
257
|
-
end
|
258
|
-
|
259
|
-
# @return [Array<#trace(key, data)>] Tracers applied to every query
|
260
|
-
# @see {Query#tracers} for query-specific tracers
|
261
|
-
attr_reader :tracers
|
262
|
-
|
263
|
-
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"].freeze
|
264
|
-
|
265
|
-
attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
|
266
|
-
|
267
|
-
def initialize
|
268
|
-
@tracers = []
|
269
|
-
@definition_error = nil
|
270
|
-
@orphan_types = []
|
271
|
-
@directives = {}
|
272
|
-
self.class.default_directives.each do |name, dir|
|
273
|
-
@directives[name] = dir.graphql_definition
|
274
|
-
end
|
275
|
-
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
276
|
-
@middleware = MiddlewareChain.new(final_step: GraphQL::Execution::Execute::FieldResolveStep)
|
277
|
-
@query_analyzers = []
|
278
|
-
@multiplex_analyzers = []
|
279
|
-
@resolve_type_proc = nil
|
280
|
-
@object_from_id_proc = nil
|
281
|
-
@id_from_object_proc = nil
|
282
|
-
@type_error_proc = DefaultTypeError
|
283
|
-
@parse_error_proc = DefaultParseError
|
284
|
-
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
285
|
-
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
286
|
-
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
287
|
-
@cursor_encoder = Base64Encoder
|
288
|
-
# For schema instances, default to legacy runtime modules
|
289
|
-
@analysis_engine = GraphQL::Analysis
|
290
|
-
@query_execution_strategy = GraphQL::Execution::Execute
|
291
|
-
@mutation_execution_strategy = GraphQL::Execution::Execute
|
292
|
-
@subscription_execution_strategy = GraphQL::Execution::Execute
|
293
|
-
@default_mask = GraphQL::Schema::NullMask
|
294
|
-
@rebuilding_artifacts = false
|
295
|
-
@context_class = GraphQL::Query::Context
|
296
|
-
@introspection_namespace = nil
|
297
|
-
@introspection_system = nil
|
298
|
-
@interpreter = false
|
299
|
-
@error_bubbling = false
|
300
|
-
@disable_introspection_entry_points = false
|
301
|
-
@disable_schema_introspection_entry_point = false
|
302
|
-
@disable_type_introspection_entry_point = false
|
303
|
-
end
|
304
|
-
|
305
|
-
# @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
|
306
|
-
def interpreter?
|
307
|
-
query_execution_strategy == GraphQL::Execution::Interpreter &&
|
308
|
-
mutation_execution_strategy == GraphQL::Execution::Interpreter &&
|
309
|
-
subscription_execution_strategy == GraphQL::Execution::Interpreter
|
310
|
-
end
|
311
|
-
|
312
|
-
def inspect
|
313
|
-
"#<#{self.class.name} ...>"
|
314
|
-
end
|
315
|
-
|
316
|
-
def initialize_copy(other)
|
317
|
-
super
|
318
|
-
@orphan_types = other.orphan_types.dup
|
319
|
-
@directives = other.directives.dup
|
320
|
-
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
321
|
-
@middleware = other.middleware.dup
|
322
|
-
@query_analyzers = other.query_analyzers.dup
|
323
|
-
@multiplex_analyzers = other.multiplex_analyzers.dup
|
324
|
-
@tracers = other.tracers.dup
|
325
|
-
@possible_types = GraphQL::Schema::PossibleTypes.new(self)
|
326
|
-
|
327
|
-
@lazy_methods = other.lazy_methods.dup
|
328
|
-
|
329
|
-
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
330
|
-
other.instrumenters.each do |key, insts|
|
331
|
-
@instrumenters[key].concat(insts)
|
332
|
-
end
|
333
|
-
|
334
|
-
if other.rescues?
|
335
|
-
@rescue_middleware = other.rescue_middleware
|
336
|
-
end
|
337
|
-
|
338
|
-
# This will be rebuilt when it's requested
|
339
|
-
# or during a later `define` call
|
340
|
-
@types = nil
|
341
|
-
@introspection_system = nil
|
342
|
-
end
|
343
|
-
|
344
|
-
def rescue_from(*args, &block)
|
345
|
-
rescue_middleware.rescue_from(*args, &block)
|
346
|
-
end
|
347
|
-
|
348
|
-
def remove_handler(*args, &block)
|
349
|
-
rescue_middleware.remove_handler(*args, &block)
|
350
|
-
end
|
351
|
-
|
352
|
-
def using_ast_analysis?
|
353
|
-
@analysis_engine == GraphQL::Analysis::AST
|
354
|
-
end
|
355
|
-
|
356
|
-
# For forwards-compatibility with Schema classes
|
357
|
-
alias :graphql_definition :itself
|
358
|
-
|
359
|
-
def deprecated_define(**kwargs, &block)
|
360
|
-
super
|
361
|
-
ensure_defined
|
362
|
-
# Assert that all necessary configs are present:
|
363
|
-
validation_error = Validation.validate(self)
|
364
|
-
validation_error && raise(GraphQL::RequiredImplementationMissingError, validation_error)
|
365
|
-
rebuild_artifacts
|
366
|
-
|
367
|
-
@definition_error = nil
|
368
|
-
nil
|
369
|
-
rescue StandardError => err
|
370
|
-
if @raise_definition_error || err.is_a?(CyclicalDefinitionError) || err.is_a?(GraphQL::RequiredImplementationMissingError)
|
371
|
-
raise
|
372
|
-
else
|
373
|
-
# Raise this error _later_ to avoid messing with Rails constant loading
|
374
|
-
@definition_error = err
|
375
|
-
end
|
376
|
-
nil
|
377
|
-
end
|
378
|
-
|
379
|
-
# Attach `instrumenter` to this schema for instrumenting events of `instrumentation_type`.
|
380
|
-
# @param instrumentation_type [Symbol]
|
381
|
-
# @param instrumenter
|
382
|
-
# @return [void]
|
383
|
-
def instrument(instrumentation_type, instrumenter)
|
384
|
-
@instrumenters[instrumentation_type] << instrumenter
|
385
|
-
if instrumentation_type == :field
|
386
|
-
rebuild_artifacts
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
# @return [Array<GraphQL::BaseType>] The root types of this schema
|
391
|
-
def root_types
|
392
|
-
@root_types ||= begin
|
393
|
-
rebuild_artifacts
|
394
|
-
@root_types
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
399
|
-
# @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
|
400
|
-
def types
|
401
|
-
@types ||= begin
|
402
|
-
rebuild_artifacts
|
403
|
-
@types
|
404
|
-
end
|
405
|
-
end
|
406
161
|
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
# @param type_name [String]
|
421
|
-
# @return [Hash]
|
422
|
-
def references_to(type_name = nil)
|
423
|
-
rebuild_artifacts unless defined?(@type_reference_map)
|
424
|
-
if type_name
|
425
|
-
@type_reference_map.fetch(type_name, [])
|
426
|
-
else
|
427
|
-
@type_reference_map
|
428
|
-
end
|
429
|
-
end
|
430
|
-
|
431
|
-
# Returns a list of Union types in which a type is a member
|
432
|
-
# @param type [GraphQL::ObjectType]
|
433
|
-
# @return [Array<GraphQL::UnionType>] list of union types of which the type is a member
|
434
|
-
def union_memberships(type)
|
435
|
-
rebuild_artifacts unless defined?(@union_memberships)
|
436
|
-
@union_memberships.fetch(type.name, [])
|
437
|
-
end
|
438
|
-
|
439
|
-
# Execute a query on itself. Raises an error if the schema definition is invalid.
|
440
|
-
# @see {Query#initialize} for arguments.
|
441
|
-
# @return [Hash] query result, ready to be serialized as JSON
|
442
|
-
def execute(query_str = nil, **kwargs)
|
443
|
-
if query_str
|
444
|
-
kwargs[:query] = query_str
|
445
|
-
end
|
446
|
-
# Some of the query context _should_ be passed to the multiplex, too
|
447
|
-
multiplex_context = if (ctx = kwargs[:context])
|
448
|
-
{
|
449
|
-
backtrace: ctx[:backtrace],
|
450
|
-
tracers: ctx[:tracers],
|
451
|
-
}
|
452
|
-
else
|
453
|
-
{}
|
162
|
+
def trace_class(new_class = nil)
|
163
|
+
if new_class
|
164
|
+
# If any modules were already added for `:default`,
|
165
|
+
# re-apply them here
|
166
|
+
mods = trace_modules_for(:default)
|
167
|
+
mods.each { |mod| new_class.include(mod) }
|
168
|
+
new_class.include(DefaultTraceClass)
|
169
|
+
trace_mode(:default, new_class)
|
170
|
+
backtrace_class = Class.new(new_class)
|
171
|
+
backtrace_class.include(GraphQL::Backtrace::Trace)
|
172
|
+
trace_mode(:default_backtrace, backtrace_class)
|
173
|
+
end
|
174
|
+
trace_class_for(:default, build: true)
|
454
175
|
end
|
455
|
-
# Since we're running one query, don't run a multiplex-level complexity analyzer
|
456
|
-
all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
|
457
|
-
all_results[0]
|
458
|
-
end
|
459
176
|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
# render json: {
|
469
|
-
# result_1: results[0],
|
470
|
-
# result_2: results[1],
|
471
|
-
# }
|
472
|
-
#
|
473
|
-
# @see {Query#initialize} for query keyword arguments
|
474
|
-
# @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
|
475
|
-
# @param queries [Array<Hash>] Keyword arguments for each query
|
476
|
-
# @param context [Hash] Multiplex-level context
|
477
|
-
# @return [Array<Hash>] One result for each query in the input
|
478
|
-
def multiplex(queries, **kwargs)
|
479
|
-
with_definition_error_check {
|
480
|
-
GraphQL::Execution::Multiplex.run_all(self, queries, **kwargs)
|
481
|
-
}
|
482
|
-
end
|
483
|
-
|
484
|
-
# Search for a schema member using a string path
|
485
|
-
# @example Finding a Field
|
486
|
-
# Schema.find("Ensemble.musicians")
|
487
|
-
#
|
488
|
-
# @see {GraphQL::Schema::Finder} for more examples
|
489
|
-
# @param path [String] A dot-separated path to the member
|
490
|
-
# @raise [Schema::Finder::MemberNotFoundError] if path could not be found
|
491
|
-
# @return [GraphQL::BaseType, GraphQL::Field, GraphQL::Argument, GraphQL::Directive] A GraphQL Schema Member
|
492
|
-
def find(path)
|
493
|
-
rebuild_artifacts unless defined?(@finder)
|
494
|
-
@find_cache[path] ||= @finder.find(path)
|
495
|
-
end
|
496
|
-
|
497
|
-
# Resolve field named `field_name` for type `parent_type`.
|
498
|
-
# Handles dynamic fields `__typename`, `__type` and `__schema`, too
|
499
|
-
# @param parent_type [String, GraphQL::BaseType]
|
500
|
-
# @param field_name [String]
|
501
|
-
# @return [GraphQL::Field, nil] The field named `field_name` on `parent_type`
|
502
|
-
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
503
|
-
def get_field(parent_type, field_name)
|
504
|
-
with_definition_error_check do
|
505
|
-
parent_type_name = case parent_type
|
506
|
-
when GraphQL::BaseType, Class, Module
|
507
|
-
parent_type.graphql_name
|
508
|
-
when String
|
509
|
-
parent_type
|
510
|
-
else
|
511
|
-
raise "Unexpected parent_type: #{parent_type}"
|
512
|
-
end
|
513
|
-
|
514
|
-
defined_field = @instrumented_field_map[parent_type_name][field_name]
|
515
|
-
if defined_field
|
516
|
-
defined_field
|
517
|
-
elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
|
518
|
-
entry_point_field
|
519
|
-
elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
|
520
|
-
dynamic_field
|
177
|
+
# @return [Class] Return the trace class to use for this mode, looking one up on the superclass if this Schema doesn't have one defined.
|
178
|
+
def trace_class_for(mode, build: false)
|
179
|
+
if (trace_class = own_trace_modes[mode])
|
180
|
+
trace_class
|
181
|
+
elsif superclass.respond_to?(:trace_class_for) && (trace_class = superclass.trace_class_for(mode, build: false))
|
182
|
+
trace_class
|
183
|
+
elsif build
|
184
|
+
own_trace_modes[mode] = build_trace_mode(mode)
|
521
185
|
else
|
522
186
|
nil
|
523
187
|
end
|
524
188
|
end
|
525
|
-
end
|
526
|
-
|
527
|
-
# Fields for this type, after instrumentation is applied
|
528
|
-
# @return [Hash<String, GraphQL::Field>]
|
529
|
-
def get_fields(type)
|
530
|
-
@instrumented_field_map[type.graphql_name]
|
531
|
-
end
|
532
|
-
|
533
|
-
def type_from_ast(ast_node, context:)
|
534
|
-
GraphQL::Schema::TypeExpression.build_type(self, ast_node)
|
535
|
-
end
|
536
|
-
|
537
|
-
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
538
|
-
# @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
|
539
|
-
# @param context [GraphQL::Query::Context] The context for the current query
|
540
|
-
# @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
|
541
|
-
def possible_types(type_defn, context = GraphQL::Query::NullContext)
|
542
|
-
if context == GraphQL::Query::NullContext
|
543
|
-
@possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
|
544
|
-
@possible_types.possible_types(type_defn, context)
|
545
|
-
else
|
546
|
-
# Use the incoming context to cache this instance --
|
547
|
-
# if it were cached on the schema, we'd have a memory leak
|
548
|
-
# https://github.com/rmosolgo/graphql-ruby/issues/2878
|
549
|
-
ns = context.namespace(:possible_types)
|
550
|
-
per_query_possible_types = ns[:possible_types] ||= GraphQL::Schema::PossibleTypes.new(self)
|
551
|
-
per_query_possible_types.possible_types(type_defn, context)
|
552
|
-
end
|
553
|
-
end
|
554
|
-
|
555
|
-
# @see [GraphQL::Schema::Warden] Resticted access to root types
|
556
|
-
# @return [GraphQL::ObjectType, nil]
|
557
|
-
def root_type_for_operation(operation)
|
558
|
-
case operation
|
559
|
-
when "query"
|
560
|
-
query
|
561
|
-
when "mutation"
|
562
|
-
mutation
|
563
|
-
when "subscription"
|
564
|
-
subscription
|
565
|
-
else
|
566
|
-
raise ArgumentError, "unknown operation type: #{operation}"
|
567
|
-
end
|
568
|
-
end
|
569
|
-
|
570
|
-
def execution_strategy_for_operation(operation)
|
571
|
-
case operation
|
572
|
-
when "query"
|
573
|
-
query_execution_strategy
|
574
|
-
when "mutation"
|
575
|
-
mutation_execution_strategy
|
576
|
-
when "subscription"
|
577
|
-
subscription_execution_strategy
|
578
|
-
else
|
579
|
-
raise ArgumentError, "unknown operation type: #{operation}"
|
580
|
-
end
|
581
|
-
end
|
582
|
-
|
583
|
-
# Determine the GraphQL type for a given object.
|
584
|
-
# This is required for unions and interfaces (including Relay's `Node` interface)
|
585
|
-
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
586
|
-
# @param type [GraphQL::UnionType, GraphQL:InterfaceType] the abstract type which is being resolved
|
587
|
-
# @param object [Any] An application object which GraphQL is currently resolving on
|
588
|
-
# @param ctx [GraphQL::Query::Context] The context for the current query
|
589
|
-
# @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
|
590
|
-
def resolve_type(type, object, ctx = :__undefined__)
|
591
|
-
check_resolved_type(type, object, ctx) do |ok_type, ok_object, ok_ctx|
|
592
|
-
if @resolve_type_proc.nil?
|
593
|
-
raise(GraphQL::RequiredImplementationMissingError, "Can't determine GraphQL type for: #{ok_object.inspect}, define `resolve_type (type, obj, ctx) -> { ... }` inside `Schema.define`.")
|
594
|
-
end
|
595
|
-
@resolve_type_proc.call(ok_type, ok_object, ok_ctx)
|
596
|
-
end
|
597
|
-
end
|
598
|
-
|
599
|
-
# This is a compatibility hack so that instance-level and class-level
|
600
|
-
# methods can get correctness checks without calling one another
|
601
|
-
# @api private
|
602
|
-
def check_resolved_type(type, object, ctx = :__undefined__)
|
603
|
-
if ctx == :__undefined__
|
604
|
-
# Old method signature
|
605
|
-
ctx = object
|
606
|
-
object = type
|
607
|
-
type = nil
|
608
|
-
end
|
609
|
-
|
610
|
-
if object.is_a?(GraphQL::Schema::Object)
|
611
|
-
object = object.object
|
612
|
-
end
|
613
189
|
|
614
|
-
|
615
|
-
|
190
|
+
# Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
|
191
|
+
# {default_trace_mode} is used when no `trace_mode: ...` is requested.
|
192
|
+
#
|
193
|
+
# When a `trace_class` is added this way, it will _not_ receive other modules added with `trace_with(...)`
|
194
|
+
# unless `trace_mode` is explicitly given. (This class will not receive any default trace modules.)
|
195
|
+
#
|
196
|
+
# Subclasses of the schema will use `trace_class` as a base class for this mode and those
|
197
|
+
# subclass also will _not_ receive default tracing modules.
|
198
|
+
#
|
199
|
+
# @param mode_name [Symbol]
|
200
|
+
# @param trace_class [Class] subclass of GraphQL::Tracing::Trace
|
201
|
+
# @return void
|
202
|
+
def trace_mode(mode_name, trace_class)
|
203
|
+
own_trace_modes[mode_name] = trace_class
|
204
|
+
nil
|
616
205
|
end
|
617
206
|
|
618
|
-
|
619
|
-
|
620
|
-
type_result = if type_proc
|
621
|
-
type_proc.call(object, ctx)
|
622
|
-
else
|
623
|
-
yield(type, object, ctx)
|
207
|
+
def own_trace_modes
|
208
|
+
@own_trace_modes ||= {}
|
624
209
|
end
|
625
210
|
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
211
|
+
def build_trace_mode(mode)
|
212
|
+
case mode
|
213
|
+
when :default
|
214
|
+
# Use the superclass's default mode if it has one, or else start an inheritance chain at the built-in base class.
|
215
|
+
base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode, build: true)) || GraphQL::Tracing::Trace
|
216
|
+
const_set(:DefaultTrace, Class.new(base_class) do
|
217
|
+
include DefaultTraceClass
|
218
|
+
end)
|
219
|
+
when :default_backtrace
|
220
|
+
schema_base_class = trace_class_for(:default, build: true)
|
221
|
+
const_set(:DefaultTraceBacktrace, Class.new(schema_base_class) do
|
222
|
+
include(GraphQL::Backtrace::Trace)
|
223
|
+
end)
|
224
|
+
else
|
225
|
+
# First, see if the superclass has a custom-defined class for this.
|
226
|
+
# Then, if it doesn't, use this class's default trace
|
227
|
+
base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || trace_class_for(:default, build: true)
|
228
|
+
# Prepare the default trace class if it hasn't been initialized yet
|
229
|
+
base_class ||= (own_trace_modes[:default] = build_trace_mode(:default))
|
230
|
+
mods = trace_modules_for(mode)
|
231
|
+
if base_class < DefaultTraceClass
|
232
|
+
mods = trace_modules_for(:default) + mods
|
632
233
|
end
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
234
|
+
# Copy the existing default options into this mode's options
|
235
|
+
default_options = trace_options_for(:default)
|
236
|
+
add_trace_options_for(mode, default_options)
|
237
|
+
|
238
|
+
Class.new(base_class) do
|
239
|
+
!mods.empty? && include(*mods)
|
638
240
|
end
|
639
241
|
end
|
640
242
|
end
|
641
|
-
end
|
642
|
-
|
643
|
-
def resolve_type=(new_resolve_type_proc)
|
644
|
-
callable = GraphQL::BackwardsCompatibility.wrap_arity(new_resolve_type_proc, from: 2, to: 3, last: true, name: "Schema#resolve_type(type, obj, ctx)")
|
645
|
-
@resolve_type_proc = callable
|
646
|
-
end
|
647
|
-
|
648
|
-
# Fetch an application object by its unique id
|
649
|
-
# @param id [String] A unique identifier, provided previously by this GraphQL schema
|
650
|
-
# @param ctx [GraphQL::Query::Context] The context for the current query
|
651
|
-
# @return [Any] The application object identified by `id`
|
652
|
-
def object_from_id(id, ctx)
|
653
|
-
if @object_from_id_proc.nil?
|
654
|
-
raise(GraphQL::RequiredImplementationMissingError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
|
655
|
-
else
|
656
|
-
@object_from_id_proc.call(id, ctx)
|
657
|
-
end
|
658
|
-
end
|
659
|
-
|
660
|
-
# @param new_proc [#call] A new callable for fetching objects by ID
|
661
|
-
def object_from_id=(new_proc)
|
662
|
-
@object_from_id_proc = new_proc
|
663
|
-
end
|
664
|
-
|
665
|
-
# When we encounter a type error during query execution, we call this hook.
|
666
|
-
#
|
667
|
-
# You can use this hook to write a log entry,
|
668
|
-
# add a {GraphQL::ExecutionError} to the response (with `ctx.add_error`)
|
669
|
-
# or raise an exception and halt query execution.
|
670
|
-
#
|
671
|
-
# @example A `nil` is encountered by a non-null field
|
672
|
-
# type_error ->(err, query_ctx) {
|
673
|
-
# err.is_a?(GraphQL::InvalidNullError) # => true
|
674
|
-
# }
|
675
|
-
#
|
676
|
-
# @example An object doesn't resolve to one of a {UnionType}'s members
|
677
|
-
# type_error ->(err, query_ctx) {
|
678
|
-
# err.is_a?(GraphQL::UnresolvedTypeError) # => true
|
679
|
-
# }
|
680
|
-
#
|
681
|
-
# @see {DefaultTypeError} is the default behavior.
|
682
|
-
# @param err [GraphQL::TypeError] The error encountered during execution
|
683
|
-
# @param ctx [GraphQL::Query::Context] The context for the field where the error occurred
|
684
|
-
# @return void
|
685
|
-
def type_error(err, ctx)
|
686
|
-
@type_error_proc.call(err, ctx)
|
687
|
-
end
|
688
|
-
|
689
|
-
# @param new_proc [#call] A new callable for handling type errors during execution
|
690
|
-
def type_error=(new_proc)
|
691
|
-
@type_error_proc = new_proc
|
692
|
-
end
|
693
|
-
|
694
|
-
# Can't delegate to `class`
|
695
|
-
alias :_schema_class :class
|
696
|
-
def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
|
697
|
-
def_delegators :_schema_class, :directive
|
698
|
-
def_delegators :_schema_class, :error_handler
|
699
|
-
def_delegators :_schema_class, :validate
|
700
|
-
|
701
|
-
|
702
|
-
# Given this schema member, find the class-based definition object
|
703
|
-
# whose `method_name` should be treated as an application hook
|
704
|
-
# @see {.visible?}
|
705
|
-
# @see {.accessible?}
|
706
|
-
def call_on_type_class(member, method_name, context, default:)
|
707
|
-
member = if member.respond_to?(:type_class)
|
708
|
-
member.type_class
|
709
|
-
else
|
710
|
-
member
|
711
|
-
end
|
712
|
-
|
713
|
-
if member.respond_to?(:relay_node_type) && (t = member.relay_node_type)
|
714
|
-
member = t
|
715
|
-
end
|
716
243
|
|
717
|
-
|
718
|
-
|
719
|
-
else
|
720
|
-
default
|
244
|
+
def own_trace_modules
|
245
|
+
@own_trace_modules ||= Hash.new { |h, k| h[k] = [] }
|
721
246
|
end
|
722
|
-
end
|
723
247
|
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
# A function to call when {#execute} receives an invalid query string
|
733
|
-
#
|
734
|
-
# @see {DefaultParseError} is the default behavior.
|
735
|
-
# @param err [GraphQL::ParseError] The error encountered during parsing
|
736
|
-
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
737
|
-
# @return void
|
738
|
-
def parse_error(err, ctx)
|
739
|
-
@parse_error_proc.call(err, ctx)
|
740
|
-
end
|
741
|
-
|
742
|
-
# @param new_proc [#call] A new callable for handling parse errors during execution
|
743
|
-
def parse_error=(new_proc)
|
744
|
-
@parse_error_proc = new_proc
|
745
|
-
end
|
746
|
-
|
747
|
-
# Get a unique identifier from this object
|
748
|
-
# @param object [Any] An application object
|
749
|
-
# @param type [GraphQL::BaseType] The current type definition
|
750
|
-
# @param ctx [GraphQL::Query::Context] the context for the current query
|
751
|
-
# @return [String] a unique identifier for `object` which clients can use to refetch it
|
752
|
-
def id_from_object(object, type, ctx)
|
753
|
-
if @id_from_object_proc.nil?
|
754
|
-
raise(GraphQL::RequiredImplementationMissingError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
|
755
|
-
else
|
756
|
-
@id_from_object_proc.call(object, type, ctx)
|
757
|
-
end
|
758
|
-
end
|
759
|
-
|
760
|
-
# @param new_proc [#call] A new callable for generating unique IDs
|
761
|
-
def id_from_object=(new_proc)
|
762
|
-
@id_from_object_proc = new_proc
|
763
|
-
end
|
764
|
-
|
765
|
-
# Create schema with the result of an introspection query.
|
766
|
-
# @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
|
767
|
-
# @return [GraphQL::Schema] the schema described by `input`
|
768
|
-
def self.from_introspection(introspection_result)
|
769
|
-
GraphQL::Schema::Loader.load(introspection_result)
|
770
|
-
end
|
771
|
-
|
772
|
-
# Create schema from an IDL schema or file containing an IDL definition.
|
773
|
-
# @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
|
774
|
-
# @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
|
775
|
-
# @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
|
776
|
-
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
777
|
-
# @return [Class] the schema described by `document`
|
778
|
-
def self.from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
|
779
|
-
# If the file ends in `.graphql`, treat it like a filepath
|
780
|
-
if definition_or_path.end_with?(".graphql")
|
781
|
-
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
782
|
-
definition_or_path,
|
783
|
-
default_resolve: default_resolve,
|
784
|
-
parser: parser,
|
785
|
-
using: using,
|
786
|
-
)
|
787
|
-
else
|
788
|
-
GraphQL::Schema::BuildFromDefinition.from_definition(
|
789
|
-
definition_or_path,
|
790
|
-
default_resolve: default_resolve,
|
791
|
-
parser: parser,
|
792
|
-
using: using,
|
793
|
-
)
|
248
|
+
# @return [Array<Module>] Modules added for tracing in `trace_mode`, including inherited ones
|
249
|
+
def trace_modules_for(trace_mode)
|
250
|
+
modules = own_trace_modules[trace_mode]
|
251
|
+
if superclass.respond_to?(:trace_modules_for)
|
252
|
+
modules += superclass.trace_modules_for(trace_mode)
|
253
|
+
end
|
254
|
+
modules
|
794
255
|
end
|
795
|
-
end
|
796
256
|
|
797
|
-
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
798
|
-
class InvalidDocumentError < Error; end;
|
799
|
-
|
800
|
-
# Return the GraphQL IDL for the schema
|
801
|
-
# @param context [Hash]
|
802
|
-
# @param only [<#call(member, ctx)>]
|
803
|
-
# @param except [<#call(member, ctx)>]
|
804
|
-
# @return [String]
|
805
|
-
def to_definition(only: nil, except: nil, context: {})
|
806
|
-
GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
|
807
|
-
end
|
808
|
-
|
809
|
-
# Return the GraphQL::Language::Document IDL AST for the schema
|
810
|
-
# @param context [Hash]
|
811
|
-
# @param only [<#call(member, ctx)>]
|
812
|
-
# @param except [<#call(member, ctx)>]
|
813
|
-
# @return [GraphQL::Language::Document]
|
814
|
-
def to_document(only: nil, except: nil, context: {})
|
815
|
-
GraphQL::Language::DocumentFromSchemaDefinition.new(self, only: only, except: except, context: context).document
|
816
|
-
end
|
817
|
-
|
818
|
-
# Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
|
819
|
-
# @param context [Hash]
|
820
|
-
# @param only [<#call(member, ctx)>]
|
821
|
-
# @param except [<#call(member, ctx)>]
|
822
|
-
# @return [Hash] GraphQL result
|
823
|
-
def as_json(only: nil, except: nil, context: {})
|
824
|
-
execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
|
825
|
-
end
|
826
|
-
|
827
|
-
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
828
|
-
# @see {#as_json}
|
829
|
-
# @return [String]
|
830
|
-
def to_json(*args)
|
831
|
-
JSON.pretty_generate(as_json(*args))
|
832
|
-
end
|
833
|
-
|
834
|
-
def new_connections?
|
835
|
-
!!connections
|
836
|
-
end
|
837
|
-
|
838
|
-
attr_accessor :connections
|
839
|
-
|
840
|
-
class << self
|
841
|
-
extend Forwardable
|
842
|
-
# For compatibility, these methods all:
|
843
|
-
# - Cause the Schema instance to be created, if it hasn't been created yet
|
844
|
-
# - Delegate to that instance
|
845
|
-
# Eventually, the methods will be moved into this class, removing the need for the singleton.
|
846
|
-
def_delegators :graphql_definition,
|
847
|
-
# Execution
|
848
|
-
:execution_strategy_for_operation,
|
849
|
-
# Configuration
|
850
|
-
:metadata, :redefine,
|
851
|
-
:id_from_object_proc, :object_from_id_proc,
|
852
|
-
:id_from_object=, :object_from_id=,
|
853
|
-
:remove_handler
|
854
|
-
|
855
|
-
# @return [GraphQL::Subscriptions]
|
856
|
-
attr_accessor :subscriptions
|
857
257
|
|
858
258
|
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
859
259
|
# @see {#as_json}
|
@@ -866,18 +266,29 @@ module GraphQL
|
|
866
266
|
# @param context [Hash]
|
867
267
|
# @param only [<#call(member, ctx)>]
|
868
268
|
# @param except [<#call(member, ctx)>]
|
269
|
+
# @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
|
270
|
+
# @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
|
271
|
+
# @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
|
272
|
+
# @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
|
273
|
+
# @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
|
869
274
|
# @return [Hash] GraphQL result
|
870
|
-
def as_json(
|
871
|
-
|
275
|
+
def as_json(context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
|
276
|
+
introspection_query = Introspection.query(
|
277
|
+
include_deprecated_args: include_deprecated_args,
|
278
|
+
include_schema_description: include_schema_description,
|
279
|
+
include_is_repeatable: include_is_repeatable,
|
280
|
+
include_is_one_of: include_is_one_of,
|
281
|
+
include_specified_by_url: include_specified_by_url,
|
282
|
+
)
|
283
|
+
|
284
|
+
execute(introspection_query, context: context).to_h
|
872
285
|
end
|
873
286
|
|
874
287
|
# Return the GraphQL IDL for the schema
|
875
288
|
# @param context [Hash]
|
876
|
-
# @param only [<#call(member, ctx)>]
|
877
|
-
# @param except [<#call(member, ctx)>]
|
878
289
|
# @return [String]
|
879
|
-
def to_definition(
|
880
|
-
GraphQL::Schema::Printer.print_schema(self,
|
290
|
+
def to_definition(context: {})
|
291
|
+
GraphQL::Schema::Printer.print_schema(self, context: context)
|
881
292
|
end
|
882
293
|
|
883
294
|
# Return the GraphQL::Language::Document IDL AST for the schema
|
@@ -886,6 +297,17 @@ module GraphQL
|
|
886
297
|
GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
|
887
298
|
end
|
888
299
|
|
300
|
+
# @return [String, nil]
|
301
|
+
def description(new_description = nil)
|
302
|
+
if new_description
|
303
|
+
@description = new_description
|
304
|
+
elsif defined?(@description)
|
305
|
+
@description
|
306
|
+
else
|
307
|
+
find_inherited_value(:description, nil)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
889
311
|
def find(path)
|
890
312
|
if !@finder
|
891
313
|
@find_cache = {}
|
@@ -894,28 +316,15 @@ module GraphQL
|
|
894
316
|
@find_cache[path] ||= @finder.find(path)
|
895
317
|
end
|
896
318
|
|
897
|
-
def graphql_definition
|
898
|
-
@graphql_definition ||= to_graphql
|
899
|
-
end
|
900
|
-
|
901
|
-
def default_filter
|
902
|
-
GraphQL::Filter.new(except: default_mask)
|
903
|
-
end
|
904
|
-
|
905
|
-
def default_mask(new_mask = nil)
|
906
|
-
if new_mask
|
907
|
-
@own_default_mask = new_mask
|
908
|
-
else
|
909
|
-
@own_default_mask || find_inherited_value(:default_mask, Schema::NullMask)
|
910
|
-
end
|
911
|
-
end
|
912
|
-
|
913
319
|
def static_validator
|
914
320
|
GraphQL::StaticValidation::Validator.new(schema: self)
|
915
321
|
end
|
916
322
|
|
323
|
+
# Add `plugin` to this schema
|
324
|
+
# @param plugin [#use] A Schema plugin
|
325
|
+
# @return void
|
917
326
|
def use(plugin, **kwargs)
|
918
|
-
if kwargs.
|
327
|
+
if !kwargs.empty?
|
919
328
|
plugin.use(self, **kwargs)
|
920
329
|
else
|
921
330
|
plugin.use(self)
|
@@ -927,84 +336,83 @@ module GraphQL
|
|
927
336
|
find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
|
928
337
|
end
|
929
338
|
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
schema_defn.max_complexity = max_complexity
|
938
|
-
schema_defn.error_bubbling = error_bubbling
|
939
|
-
schema_defn.max_depth = max_depth
|
940
|
-
schema_defn.default_max_page_size = default_max_page_size
|
941
|
-
schema_defn.orphan_types = orphan_types.map(&:graphql_definition)
|
942
|
-
schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
|
943
|
-
schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
|
944
|
-
schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
|
945
|
-
|
946
|
-
prepped_dirs = {}
|
947
|
-
directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
|
948
|
-
schema_defn.directives = prepped_dirs
|
949
|
-
schema_defn.introspection_namespace = introspection
|
950
|
-
schema_defn.resolve_type = method(:resolve_type)
|
951
|
-
schema_defn.object_from_id = method(:object_from_id)
|
952
|
-
schema_defn.id_from_object = method(:id_from_object)
|
953
|
-
schema_defn.type_error = method(:type_error)
|
954
|
-
schema_defn.context_class = context_class
|
955
|
-
schema_defn.cursor_encoder = cursor_encoder
|
956
|
-
schema_defn.tracers.concat(tracers)
|
957
|
-
schema_defn.query_analyzers.concat(query_analyzers)
|
958
|
-
schema_defn.analysis_engine = analysis_engine
|
959
|
-
|
960
|
-
schema_defn.middleware.concat(all_middleware)
|
961
|
-
schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
|
962
|
-
schema_defn.query_execution_strategy = query_execution_strategy
|
963
|
-
schema_defn.mutation_execution_strategy = mutation_execution_strategy
|
964
|
-
schema_defn.subscription_execution_strategy = subscription_execution_strategy
|
965
|
-
schema_defn.default_mask = default_mask
|
966
|
-
instrumenters.each do |step, insts|
|
967
|
-
insts.each do |inst|
|
968
|
-
schema_defn.instrumenters[step] << inst
|
969
|
-
end
|
970
|
-
end
|
971
|
-
|
972
|
-
lazy_methods.each do |lazy_class, value_method|
|
973
|
-
schema_defn.lazy_methods.set(lazy_class, value_method)
|
339
|
+
# Build a map of `{ name => type }` and return it
|
340
|
+
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
341
|
+
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
342
|
+
def types(context = GraphQL::Query::NullContext.instance)
|
343
|
+
if use_visibility_profile?
|
344
|
+
types = Visibility::Profile.from_context(context, self)
|
345
|
+
return types.all_types_h
|
974
346
|
end
|
975
|
-
|
976
|
-
|
977
|
-
|
347
|
+
all_types = non_introspection_types.merge(introspection_system.types)
|
348
|
+
visible_types = {}
|
349
|
+
all_types.each do |k, v|
|
350
|
+
visible_types[k] =if v.is_a?(Array)
|
351
|
+
visible_t = nil
|
352
|
+
v.each do |t|
|
353
|
+
if t.visible?(context)
|
354
|
+
if visible_t.nil?
|
355
|
+
visible_t = t
|
356
|
+
else
|
357
|
+
raise DuplicateNamesError.new(
|
358
|
+
duplicated_name: k, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
359
|
+
)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
visible_t
|
364
|
+
else
|
365
|
+
v
|
366
|
+
end
|
978
367
|
end
|
368
|
+
visible_types
|
369
|
+
end
|
979
370
|
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
371
|
+
# @param type_name [String]
|
372
|
+
# @param context [GraphQL::Query::Context] Used for filtering definitions at query-time
|
373
|
+
# @param use_visibility_profile Private, for migration to {Schema::Visibility}
|
374
|
+
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
375
|
+
def get_type(type_name, context = GraphQL::Query::NullContext.instance, use_visibility_profile = use_visibility_profile?)
|
376
|
+
if use_visibility_profile
|
377
|
+
return Visibility::Profile.from_context(context, self).type(type_name)
|
984
378
|
end
|
985
|
-
|
986
|
-
|
987
|
-
|
379
|
+
local_entry = own_types[type_name]
|
380
|
+
type_defn = case local_entry
|
381
|
+
when nil
|
382
|
+
nil
|
383
|
+
when Array
|
384
|
+
if context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Visibility::Profile)
|
385
|
+
local_entry
|
386
|
+
else
|
387
|
+
visible_t = nil
|
388
|
+
warden = Warden.from_context(context)
|
389
|
+
local_entry.each do |t|
|
390
|
+
if warden.visible_type?(t, context)
|
391
|
+
if visible_t.nil?
|
392
|
+
visible_t = t
|
393
|
+
else
|
394
|
+
raise DuplicateNamesError.new(
|
395
|
+
duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
396
|
+
)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
visible_t
|
401
|
+
end
|
402
|
+
when Module
|
403
|
+
local_entry
|
404
|
+
else
|
405
|
+
raise "Invariant: unexpected own_types[#{type_name.inspect}]: #{local_entry.inspect}"
|
988
406
|
end
|
989
407
|
|
990
|
-
|
991
|
-
|
992
|
-
|
408
|
+
type_defn ||
|
409
|
+
introspection_system.types[type_name] || # todo context-specific introspection?
|
410
|
+
(superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context, use_visibility_profile) : nil)
|
993
411
|
end
|
994
412
|
|
995
|
-
#
|
996
|
-
|
997
|
-
|
998
|
-
def types
|
999
|
-
non_introspection_types.merge(introspection_system.types)
|
1000
|
-
end
|
1001
|
-
|
1002
|
-
# @param type_name [String]
|
1003
|
-
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
1004
|
-
def get_type(type_name)
|
1005
|
-
own_types[type_name] ||
|
1006
|
-
introspection_system.types[type_name] ||
|
1007
|
-
find_inherited_value(:types, EMPTY_HASH)[type_name]
|
413
|
+
# @return [Boolean] Does this schema have _any_ definition for a type named `type_name`, regardless of visibility?
|
414
|
+
def has_defined_type?(type_name)
|
415
|
+
own_types.key?(type_name) || introspection_system.types.key?(type_name) || (superclass.respond_to?(:has_defined_type?) ? superclass.has_defined_type?(type_name) : false)
|
1008
416
|
end
|
1009
417
|
|
1010
418
|
# @api private
|
@@ -1026,55 +434,127 @@ module GraphQL
|
|
1026
434
|
end
|
1027
435
|
end
|
1028
436
|
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
437
|
+
# Get or set the root `query { ... }` object for this schema.
|
438
|
+
#
|
439
|
+
# @example Using `Types::Query` as the entry-point
|
440
|
+
# query { Types::Query }
|
441
|
+
#
|
442
|
+
# @param new_query_object [Class<GraphQL::Schema::Object>] The root type to use for queries
|
443
|
+
# @param lazy_load_block If a block is given, then it will be called when GraphQL-Ruby needs the root query type.
|
444
|
+
# @return [Class<GraphQL::Schema::Object>, nil] The configured query root type, if there is one.
|
445
|
+
def query(new_query_object = nil, &lazy_load_block)
|
446
|
+
if new_query_object || block_given?
|
1035
447
|
if @query_object
|
1036
|
-
|
448
|
+
dup_defn = new_query_object || yield
|
449
|
+
raise GraphQL::Error, "Second definition of `query(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@query_object.inspect}"
|
450
|
+
elsif use_visibility_profile?
|
451
|
+
if block_given?
|
452
|
+
if visibility.preload?
|
453
|
+
@query_object = lazy_load_block.call
|
454
|
+
self.visibility.query_configured(@query_object)
|
455
|
+
else
|
456
|
+
@query_object = lazy_load_block
|
457
|
+
end
|
458
|
+
else
|
459
|
+
@query_object = new_query_object
|
460
|
+
self.visibility.query_configured(@query_object)
|
461
|
+
end
|
1037
462
|
else
|
1038
|
-
@query_object = new_query_object
|
1039
|
-
add_type_and_traverse(
|
1040
|
-
nil
|
463
|
+
@query_object = new_query_object || lazy_load_block.call
|
464
|
+
add_type_and_traverse(@query_object, root: true)
|
1041
465
|
end
|
466
|
+
nil
|
467
|
+
elsif @query_object.is_a?(Proc)
|
468
|
+
@query_object = @query_object.call
|
469
|
+
self.visibility&.query_configured(@query_object)
|
470
|
+
@query_object
|
1042
471
|
else
|
1043
472
|
@query_object || find_inherited_value(:query)
|
1044
473
|
end
|
1045
474
|
end
|
1046
475
|
|
1047
|
-
|
1048
|
-
|
476
|
+
# Get or set the root `mutation { ... }` object for this schema.
|
477
|
+
#
|
478
|
+
# @example Using `Types::Mutation` as the entry-point
|
479
|
+
# mutation { Types::Mutation }
|
480
|
+
#
|
481
|
+
# @param new_mutation_object [Class<GraphQL::Schema::Object>] The root type to use for mutations
|
482
|
+
# @param lazy_load_block If a block is given, then it will be called when GraphQL-Ruby needs the root mutation type.
|
483
|
+
# @return [Class<GraphQL::Schema::Object>, nil] The configured mutation root type, if there is one.
|
484
|
+
def mutation(new_mutation_object = nil, &lazy_load_block)
|
485
|
+
if new_mutation_object || block_given?
|
1049
486
|
if @mutation_object
|
1050
|
-
|
487
|
+
dup_defn = new_mutation_object || yield
|
488
|
+
raise GraphQL::Error, "Second definition of `mutation(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@mutation_object.inspect}"
|
489
|
+
elsif use_visibility_profile?
|
490
|
+
if block_given?
|
491
|
+
if visibility.preload?
|
492
|
+
@mutation_object = lazy_load_block.call
|
493
|
+
self.visibility.mutation_configured(@mutation_object)
|
494
|
+
else
|
495
|
+
@mutation_object = lazy_load_block
|
496
|
+
end
|
497
|
+
else
|
498
|
+
@mutation_object = new_mutation_object
|
499
|
+
self.visibility.mutation_configured(@mutation_object)
|
500
|
+
end
|
1051
501
|
else
|
1052
|
-
@mutation_object = new_mutation_object
|
1053
|
-
add_type_and_traverse(
|
1054
|
-
nil
|
502
|
+
@mutation_object = new_mutation_object || lazy_load_block.call
|
503
|
+
add_type_and_traverse(@mutation_object, root: true)
|
1055
504
|
end
|
505
|
+
nil
|
506
|
+
elsif @mutation_object.is_a?(Proc)
|
507
|
+
@mutation_object = @mutation_object.call
|
508
|
+
self.visibility&.mutation_configured(@mutation_object)
|
509
|
+
@mutation_object
|
1056
510
|
else
|
1057
511
|
@mutation_object || find_inherited_value(:mutation)
|
1058
512
|
end
|
1059
513
|
end
|
1060
514
|
|
1061
|
-
|
1062
|
-
|
515
|
+
# Get or set the root `subscription { ... }` object for this schema.
|
516
|
+
#
|
517
|
+
# @example Using `Types::Subscription` as the entry-point
|
518
|
+
# subscription { Types::Subscription }
|
519
|
+
#
|
520
|
+
# @param new_subscription_object [Class<GraphQL::Schema::Object>] The root type to use for subscriptions
|
521
|
+
# @param lazy_load_block If a block is given, then it will be called when GraphQL-Ruby needs the root subscription type.
|
522
|
+
# @return [Class<GraphQL::Schema::Object>, nil] The configured subscription root type, if there is one.
|
523
|
+
def subscription(new_subscription_object = nil, &lazy_load_block)
|
524
|
+
if new_subscription_object || block_given?
|
1063
525
|
if @subscription_object
|
1064
|
-
|
526
|
+
dup_defn = new_subscription_object || yield
|
527
|
+
raise GraphQL::Error, "Second definition of `subscription(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
|
528
|
+
elsif use_visibility_profile?
|
529
|
+
if block_given?
|
530
|
+
if visibility.preload?
|
531
|
+
@subscription_object = lazy_load_block.call
|
532
|
+
visibility.subscription_configured(@subscription_object)
|
533
|
+
else
|
534
|
+
@subscription_object = lazy_load_block
|
535
|
+
end
|
536
|
+
else
|
537
|
+
@subscription_object = new_subscription_object
|
538
|
+
self.visibility.subscription_configured(@subscription_object)
|
539
|
+
end
|
540
|
+
add_subscription_extension_if_necessary
|
1065
541
|
else
|
1066
|
-
@subscription_object = new_subscription_object
|
542
|
+
@subscription_object = new_subscription_object || lazy_load_block.call
|
1067
543
|
add_subscription_extension_if_necessary
|
1068
|
-
add_type_and_traverse(
|
1069
|
-
nil
|
544
|
+
add_type_and_traverse(@subscription_object, root: true)
|
1070
545
|
end
|
546
|
+
nil
|
547
|
+
elsif @subscription_object.is_a?(Proc)
|
548
|
+
@subscription_object = @subscription_object.call
|
549
|
+
add_subscription_extension_if_necessary
|
550
|
+
self.visibility.subscription_configured(@subscription_object)
|
551
|
+
@subscription_object
|
1071
552
|
else
|
1072
553
|
@subscription_object || find_inherited_value(:subscription)
|
1073
554
|
end
|
1074
555
|
end
|
1075
556
|
|
1076
|
-
# @
|
1077
|
-
# @return [GraphQL::ObjectType, nil]
|
557
|
+
# @api private
|
1078
558
|
def root_type_for_operation(operation)
|
1079
559
|
case operation
|
1080
560
|
when "query"
|
@@ -1084,38 +564,90 @@ module GraphQL
|
|
1084
564
|
when "subscription"
|
1085
565
|
subscription
|
1086
566
|
else
|
1087
|
-
raise ArgumentError, "unknown operation type: #{operation}"
|
567
|
+
raise ArgumentError, "unknown operation type: #{operation}"
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
# @return [Array<Class>] The root types (query, mutation, subscription) defined for this schema
|
572
|
+
def root_types
|
573
|
+
if use_visibility_profile?
|
574
|
+
[query, mutation, subscription].compact
|
575
|
+
else
|
576
|
+
@root_types
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
# @api private
|
581
|
+
def warden_class
|
582
|
+
if defined?(@warden_class)
|
583
|
+
@warden_class
|
584
|
+
elsif superclass.respond_to?(:warden_class)
|
585
|
+
superclass.warden_class
|
586
|
+
else
|
587
|
+
GraphQL::Schema::Warden
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
# @api private
|
592
|
+
attr_writer :warden_class
|
593
|
+
|
594
|
+
# @api private
|
595
|
+
def visibility_profile_class
|
596
|
+
if defined?(@visibility_profile_class)
|
597
|
+
@visibility_profile_class
|
598
|
+
elsif superclass.respond_to?(:visibility_profile_class)
|
599
|
+
superclass.visibility_profile_class
|
600
|
+
else
|
601
|
+
GraphQL::Schema::Visibility::Profile
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
# @api private
|
606
|
+
attr_writer :visibility_profile_class, :use_visibility_profile
|
607
|
+
# @api private
|
608
|
+
attr_accessor :visibility
|
609
|
+
# @api private
|
610
|
+
def use_visibility_profile?
|
611
|
+
if defined?(@use_visibility_profile)
|
612
|
+
@use_visibility_profile
|
613
|
+
elsif superclass.respond_to?(:use_visibility_profile?)
|
614
|
+
superclass.use_visibility_profile?
|
615
|
+
else
|
616
|
+
false
|
1088
617
|
end
|
1089
618
|
end
|
1090
619
|
|
1091
|
-
def root_types
|
1092
|
-
@root_types
|
1093
|
-
end
|
1094
|
-
|
1095
620
|
# @param type [Module] The type definition whose possible types you want to see
|
621
|
+
# @param context [GraphQL::Query::Context] used for filtering visible possible types at runtime
|
622
|
+
# @param use_visibility_profile Private, for migration to {Schema::Visibility}
|
1096
623
|
# @return [Hash<String, Module>] All possible types, if no `type` is given.
|
1097
624
|
# @return [Array<Module>] Possible types for `type`, if it's given.
|
1098
|
-
def possible_types(type = nil, context = GraphQL::Query::NullContext)
|
625
|
+
def possible_types(type = nil, context = GraphQL::Query::NullContext.instance, use_visibility_profile = use_visibility_profile?)
|
626
|
+
if use_visibility_profile
|
627
|
+
if type
|
628
|
+
return Visibility::Profile.from_context(context, self).possible_types(type)
|
629
|
+
else
|
630
|
+
raise "Schema.possible_types is not implemented for `use_visibility_profile?`"
|
631
|
+
end
|
632
|
+
end
|
1099
633
|
if type
|
1100
634
|
# TODO duck-typing `.possible_types` would probably be nicer here
|
1101
635
|
if type.kind.union?
|
1102
636
|
type.possible_types(context: context)
|
1103
637
|
else
|
1104
|
-
stored_possible_types = own_possible_types[type
|
638
|
+
stored_possible_types = own_possible_types[type]
|
1105
639
|
visible_possible_types = if stored_possible_types && type.kind.interface?
|
1106
640
|
stored_possible_types.select do |possible_type|
|
1107
|
-
|
1108
|
-
# When we don't need to support legacy `.define` types, use `.include?(type)` instead.
|
1109
|
-
possible_type.interfaces(context).any? { |interface| interface.graphql_name == type.graphql_name }
|
641
|
+
possible_type.interfaces(context).include?(type)
|
1110
642
|
end
|
1111
643
|
else
|
1112
644
|
stored_possible_types
|
1113
645
|
end
|
1114
646
|
visible_possible_types ||
|
1115
|
-
introspection_system.possible_types[type
|
647
|
+
introspection_system.possible_types[type] ||
|
1116
648
|
(
|
1117
649
|
superclass.respond_to?(:possible_types) ?
|
1118
|
-
superclass.possible_types(type, context) :
|
650
|
+
superclass.possible_types(type, context, use_visibility_profile) :
|
1119
651
|
EMPTY_ARRAY
|
1120
652
|
)
|
1121
653
|
end
|
@@ -1150,50 +682,43 @@ module GraphQL
|
|
1150
682
|
attr_writer :dataloader_class
|
1151
683
|
|
1152
684
|
def references_to(to_type = nil, from: nil)
|
1153
|
-
@own_references_to ||= Hash.new { |h, k| h[k] = [] }
|
1154
685
|
if to_type
|
1155
|
-
if !to_type.is_a?(String)
|
1156
|
-
to_type = to_type.graphql_name
|
1157
|
-
end
|
1158
|
-
|
1159
686
|
if from
|
1160
|
-
|
687
|
+
refs = own_references_to[to_type] ||= []
|
688
|
+
refs << from
|
1161
689
|
else
|
1162
|
-
|
1163
|
-
inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
|
1164
|
-
own_refs + inherited_refs
|
690
|
+
get_references_to(to_type) || EMPTY_ARRAY
|
1165
691
|
end
|
1166
692
|
else
|
1167
693
|
# `@own_references_to` can be quite large for big schemas,
|
1168
694
|
# and generally speaking, we won't inherit any values.
|
1169
695
|
# So optimize the most common case -- don't create a duplicate Hash.
|
1170
696
|
inherited_value = find_inherited_value(:references_to, EMPTY_HASH)
|
1171
|
-
if inherited_value.
|
1172
|
-
inherited_value.merge(
|
697
|
+
if !inherited_value.empty?
|
698
|
+
inherited_value.merge(own_references_to)
|
1173
699
|
else
|
1174
|
-
|
700
|
+
own_references_to
|
1175
701
|
end
|
1176
702
|
end
|
1177
703
|
end
|
1178
704
|
|
1179
|
-
def type_from_ast(ast_node, context:
|
1180
|
-
|
1181
|
-
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
705
|
+
def type_from_ast(ast_node, context: self.query_class.new(self, "{ __typename }").context)
|
706
|
+
GraphQL::Schema::TypeExpression.build_type(context.query.types, ast_node)
|
1182
707
|
end
|
1183
708
|
|
1184
|
-
def get_field(type_or_name, field_name)
|
709
|
+
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext.instance)
|
1185
710
|
parent_type = case type_or_name
|
1186
711
|
when LateBoundType
|
1187
|
-
get_type(type_or_name.name)
|
712
|
+
get_type(type_or_name.name, context)
|
1188
713
|
when String
|
1189
|
-
get_type(type_or_name)
|
714
|
+
get_type(type_or_name, context)
|
1190
715
|
when Module
|
1191
716
|
type_or_name
|
1192
717
|
else
|
1193
|
-
raise
|
718
|
+
raise GraphQL::InvariantError, "Unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
|
1194
719
|
end
|
1195
720
|
|
1196
|
-
if parent_type.kind.fields? && (field = parent_type.get_field(field_name))
|
721
|
+
if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
|
1197
722
|
field
|
1198
723
|
elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
|
1199
724
|
entry_point_field
|
@@ -1204,24 +729,31 @@ module GraphQL
|
|
1204
729
|
end
|
1205
730
|
end
|
1206
731
|
|
1207
|
-
def get_fields(type)
|
1208
|
-
type.fields
|
732
|
+
def get_fields(type, context = GraphQL::Query::NullContext.instance)
|
733
|
+
type.fields(context)
|
1209
734
|
end
|
1210
735
|
|
736
|
+
# Pass a custom introspection module here to use it for this schema.
|
737
|
+
# @param new_introspection_namespace [Module] If given, use this module for custom introspection on the schema
|
738
|
+
# @return [Module, nil] The configured namespace, if there is one
|
1211
739
|
def introspection(new_introspection_namespace = nil)
|
1212
740
|
if new_introspection_namespace
|
1213
741
|
@introspection = new_introspection_namespace
|
1214
742
|
# reset this cached value:
|
1215
743
|
@introspection_system = nil
|
744
|
+
introspection_system
|
745
|
+
@introspection
|
1216
746
|
else
|
1217
747
|
@introspection || find_inherited_value(:introspection)
|
1218
748
|
end
|
1219
749
|
end
|
1220
750
|
|
751
|
+
# @return [Schema::IntrospectionSystem] Based on {introspection}
|
1221
752
|
def introspection_system
|
1222
753
|
if !@introspection_system
|
1223
754
|
@introspection_system = Schema::IntrospectionSystem.new(self)
|
1224
755
|
@introspection_system.resolve_late_bindings
|
756
|
+
self.visibility&.introspection_system_configured(@introspection_system)
|
1225
757
|
end
|
1226
758
|
@introspection_system
|
1227
759
|
end
|
@@ -1241,27 +773,58 @@ module GraphQL
|
|
1241
773
|
end
|
1242
774
|
end
|
1243
775
|
|
1244
|
-
|
776
|
+
# A limit on the number of tokens to accept on incoming query strings.
|
777
|
+
# Use this to prevent parsing maliciously-large query strings.
|
778
|
+
# @return [nil, Integer]
|
779
|
+
def max_query_string_tokens(new_max_tokens = NOT_CONFIGURED)
|
780
|
+
if NOT_CONFIGURED.equal?(new_max_tokens)
|
781
|
+
defined?(@max_query_string_tokens) ? @max_query_string_tokens : find_inherited_value(:max_query_string_tokens)
|
782
|
+
else
|
783
|
+
@max_query_string_tokens = new_max_tokens
|
784
|
+
end
|
785
|
+
end
|
786
|
+
|
787
|
+
def default_page_size(new_default_page_size = nil)
|
788
|
+
if new_default_page_size
|
789
|
+
@default_page_size = new_default_page_size
|
790
|
+
else
|
791
|
+
@default_page_size || find_inherited_value(:default_page_size)
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
795
|
+
def query_execution_strategy(new_query_execution_strategy = nil, deprecation_warning: true)
|
796
|
+
if deprecation_warning
|
797
|
+
warn "GraphQL::Schema.query_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
|
798
|
+
warn " #{caller(1, 1).first}"
|
799
|
+
end
|
1245
800
|
if new_query_execution_strategy
|
1246
801
|
@query_execution_strategy = new_query_execution_strategy
|
1247
802
|
else
|
1248
|
-
@query_execution_strategy ||
|
803
|
+
@query_execution_strategy || (superclass.respond_to?(:query_execution_strategy) ? superclass.query_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
|
1249
804
|
end
|
1250
805
|
end
|
1251
806
|
|
1252
|
-
def mutation_execution_strategy(new_mutation_execution_strategy = nil)
|
807
|
+
def mutation_execution_strategy(new_mutation_execution_strategy = nil, deprecation_warning: true)
|
808
|
+
if deprecation_warning
|
809
|
+
warn "GraphQL::Schema.mutation_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
|
810
|
+
warn " #{caller(1, 1).first}"
|
811
|
+
end
|
1253
812
|
if new_mutation_execution_strategy
|
1254
813
|
@mutation_execution_strategy = new_mutation_execution_strategy
|
1255
814
|
else
|
1256
|
-
@mutation_execution_strategy ||
|
815
|
+
@mutation_execution_strategy || (superclass.respond_to?(:mutation_execution_strategy) ? superclass.mutation_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
|
1257
816
|
end
|
1258
817
|
end
|
1259
818
|
|
1260
|
-
def subscription_execution_strategy(new_subscription_execution_strategy = nil)
|
819
|
+
def subscription_execution_strategy(new_subscription_execution_strategy = nil, deprecation_warning: true)
|
820
|
+
if deprecation_warning
|
821
|
+
warn "GraphQL::Schema.subscription_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
|
822
|
+
warn " #{caller(1, 1).first}"
|
823
|
+
end
|
1261
824
|
if new_subscription_execution_strategy
|
1262
825
|
@subscription_execution_strategy = new_subscription_execution_strategy
|
1263
826
|
else
|
1264
|
-
@subscription_execution_strategy ||
|
827
|
+
@subscription_execution_strategy || (superclass.respond_to?(:subscription_execution_strategy) ? superclass.subscription_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
|
1265
828
|
end
|
1266
829
|
end
|
1267
830
|
|
@@ -1286,19 +849,39 @@ module GraphQL
|
|
1286
849
|
else
|
1287
850
|
string_or_document
|
1288
851
|
end
|
1289
|
-
query =
|
852
|
+
query = query_class.new(self, document: doc, context: context)
|
1290
853
|
validator_opts = { schema: self }
|
1291
854
|
rules && (validator_opts[:rules] = rules)
|
1292
855
|
validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
|
1293
|
-
res = validator.validate(query, timeout: validate_timeout)
|
856
|
+
res = validator.validate(query, timeout: validate_timeout, max_errors: validate_max_errors)
|
1294
857
|
res[:errors]
|
1295
858
|
end
|
1296
859
|
|
860
|
+
# @param new_query_class [Class<GraphQL::Query>] A subclass to use when executing queries
|
861
|
+
def query_class(new_query_class = NOT_CONFIGURED)
|
862
|
+
if NOT_CONFIGURED.equal?(new_query_class)
|
863
|
+
@query_class || (superclass.respond_to?(:query_class) ? superclass.query_class : GraphQL::Query)
|
864
|
+
else
|
865
|
+
@query_class = new_query_class
|
866
|
+
end
|
867
|
+
end
|
868
|
+
|
869
|
+
attr_writer :validate_max_errors
|
870
|
+
|
871
|
+
def validate_max_errors(new_validate_max_errors = NOT_CONFIGURED)
|
872
|
+
if NOT_CONFIGURED.equal?(new_validate_max_errors)
|
873
|
+
defined?(@validate_max_errors) ? @validate_max_errors : find_inherited_value(:validate_max_errors)
|
874
|
+
else
|
875
|
+
@validate_max_errors = new_validate_max_errors
|
876
|
+
end
|
877
|
+
end
|
878
|
+
|
1297
879
|
attr_writer :max_complexity
|
1298
880
|
|
1299
|
-
def max_complexity(max_complexity = nil)
|
881
|
+
def max_complexity(max_complexity = nil, count_introspection_fields: true)
|
1300
882
|
if max_complexity
|
1301
883
|
@max_complexity = max_complexity
|
884
|
+
@max_complexity_count_introspection_fields = count_introspection_fields
|
1302
885
|
elsif defined?(@max_complexity)
|
1303
886
|
@max_complexity
|
1304
887
|
else
|
@@ -1306,26 +889,23 @@ module GraphQL
|
|
1306
889
|
end
|
1307
890
|
end
|
1308
891
|
|
892
|
+
def max_complexity_count_introspection_fields
|
893
|
+
if defined?(@max_complexity_count_introspection_fields)
|
894
|
+
@max_complexity_count_introspection_fields
|
895
|
+
else
|
896
|
+
find_inherited_value(:max_complexity_count_introspection_fields, true)
|
897
|
+
end
|
898
|
+
end
|
899
|
+
|
1309
900
|
attr_writer :analysis_engine
|
1310
901
|
|
1311
902
|
def analysis_engine
|
1312
903
|
@analysis_engine || find_inherited_value(:analysis_engine, self.default_analysis_engine)
|
1313
904
|
end
|
1314
905
|
|
1315
|
-
def using_ast_analysis?
|
1316
|
-
analysis_engine == GraphQL::Analysis::AST
|
1317
|
-
end
|
1318
|
-
|
1319
|
-
def interpreter?
|
1320
|
-
query_execution_strategy == GraphQL::Execution::Interpreter &&
|
1321
|
-
mutation_execution_strategy == GraphQL::Execution::Interpreter &&
|
1322
|
-
subscription_execution_strategy == GraphQL::Execution::Interpreter
|
1323
|
-
end
|
1324
|
-
|
1325
|
-
attr_writer :interpreter
|
1326
|
-
|
1327
906
|
def error_bubbling(new_error_bubbling = nil)
|
1328
907
|
if !new_error_bubbling.nil?
|
908
|
+
warn("error_bubbling(#{new_error_bubbling.inspect}) is deprecated; the default value of `false` will be the only option in GraphQL-Ruby 3.0")
|
1329
909
|
@error_bubbling = new_error_bubbling
|
1330
910
|
else
|
1331
911
|
@error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
|
@@ -1336,9 +916,10 @@ module GraphQL
|
|
1336
916
|
|
1337
917
|
attr_writer :max_depth
|
1338
918
|
|
1339
|
-
def max_depth(new_max_depth = nil)
|
919
|
+
def max_depth(new_max_depth = nil, count_introspection_fields: true)
|
1340
920
|
if new_max_depth
|
1341
921
|
@max_depth = new_max_depth
|
922
|
+
@count_introspection_fields = count_introspection_fields
|
1342
923
|
elsif defined?(@max_depth)
|
1343
924
|
@max_depth
|
1344
925
|
else
|
@@ -1346,6 +927,14 @@ module GraphQL
|
|
1346
927
|
end
|
1347
928
|
end
|
1348
929
|
|
930
|
+
def count_introspection_fields
|
931
|
+
if defined?(@count_introspection_fields)
|
932
|
+
@count_introspection_fields
|
933
|
+
else
|
934
|
+
find_inherited_value(:count_introspection_fields, true)
|
935
|
+
end
|
936
|
+
end
|
937
|
+
|
1349
938
|
def disable_introspection_entry_points
|
1350
939
|
@disable_introspection_entry_points = true
|
1351
940
|
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
@@ -1388,15 +977,62 @@ module GraphQL
|
|
1388
977
|
end
|
1389
978
|
end
|
1390
979
|
|
980
|
+
# @param new_extra_types [Module] Type definitions to include in printing and introspection, even though they aren't referenced in the schema
|
981
|
+
# @return [Array<Module>] Type definitions added to this schema
|
982
|
+
def extra_types(*new_extra_types)
|
983
|
+
if !new_extra_types.empty?
|
984
|
+
new_extra_types = new_extra_types.flatten
|
985
|
+
@own_extra_types ||= []
|
986
|
+
@own_extra_types.concat(new_extra_types)
|
987
|
+
end
|
988
|
+
inherited_et = find_inherited_value(:extra_types, nil)
|
989
|
+
if inherited_et
|
990
|
+
if @own_extra_types
|
991
|
+
inherited_et + @own_extra_types
|
992
|
+
else
|
993
|
+
inherited_et
|
994
|
+
end
|
995
|
+
else
|
996
|
+
@own_extra_types || EMPTY_ARRAY
|
997
|
+
end
|
998
|
+
end
|
999
|
+
|
1000
|
+
# Tell the schema about these types so that they can be registered as implementations of interfaces in the schema.
|
1001
|
+
#
|
1002
|
+
# This method must be used when an object type is connected to the schema as an interface implementor but
|
1003
|
+
# not as a return type of a field. In that case, if the object type isn't registered here, GraphQL-Ruby won't be able to find it.
|
1004
|
+
#
|
1005
|
+
# @param new_orphan_types [Array<Class<GraphQL::Schema::Object>>] Object types to register as implementations of interfaces in the schema.
|
1006
|
+
# @return [Array<Class<GraphQL::Schema::Object>>] All previously-registered orphan types for this schema
|
1391
1007
|
def orphan_types(*new_orphan_types)
|
1392
|
-
if new_orphan_types.
|
1008
|
+
if !new_orphan_types.empty?
|
1393
1009
|
new_orphan_types = new_orphan_types.flatten
|
1394
|
-
|
1395
|
-
|
1010
|
+
non_object_types = new_orphan_types.reject { |ot| ot.is_a?(Class) && ot < GraphQL::Schema::Object }
|
1011
|
+
if !non_object_types.empty?
|
1012
|
+
raise ArgumentError, <<~ERR
|
1013
|
+
Only object type classes should be added as `orphan_types(...)`.
|
1014
|
+
|
1015
|
+
- Remove these no-op types from `orphan_types`: #{non_object_types.map { |t| "#{t.inspect} (#{t.kind.name})"}.join(", ")}
|
1016
|
+
- See https://graphql-ruby.org/type_definitions/interfaces.html#orphan-types
|
1017
|
+
|
1018
|
+
To add other types to your schema, you might want `extra_types`: https://graphql-ruby.org/schema/definition.html#extra-types
|
1019
|
+
ERR
|
1020
|
+
end
|
1021
|
+
add_type_and_traverse(new_orphan_types, root: false) unless use_visibility_profile?
|
1396
1022
|
own_orphan_types.concat(new_orphan_types.flatten)
|
1023
|
+
self.visibility&.orphan_types_configured(new_orphan_types)
|
1397
1024
|
end
|
1398
1025
|
|
1399
|
-
find_inherited_value(:orphan_types,
|
1026
|
+
inherited_ot = find_inherited_value(:orphan_types, nil)
|
1027
|
+
if inherited_ot
|
1028
|
+
if !own_orphan_types.empty?
|
1029
|
+
inherited_ot + own_orphan_types
|
1030
|
+
else
|
1031
|
+
inherited_ot
|
1032
|
+
end
|
1033
|
+
else
|
1034
|
+
own_orphan_types
|
1035
|
+
end
|
1400
1036
|
end
|
1401
1037
|
|
1402
1038
|
def default_execution_strategy
|
@@ -1415,6 +1051,29 @@ module GraphQL
|
|
1415
1051
|
end
|
1416
1052
|
end
|
1417
1053
|
|
1054
|
+
|
1055
|
+
# @param new_default_logger [#log] Something to use for logging messages
|
1056
|
+
def default_logger(new_default_logger = NOT_CONFIGURED)
|
1057
|
+
if NOT_CONFIGURED.equal?(new_default_logger)
|
1058
|
+
if defined?(@default_logger)
|
1059
|
+
@default_logger
|
1060
|
+
elsif superclass.respond_to?(:default_logger)
|
1061
|
+
superclass.default_logger
|
1062
|
+
elsif defined?(Rails) && Rails.respond_to?(:logger) && (rails_logger = Rails.logger)
|
1063
|
+
rails_logger
|
1064
|
+
else
|
1065
|
+
def_logger = Logger.new($stdout)
|
1066
|
+
def_logger.info! # It doesn't output debug info by default
|
1067
|
+
def_logger
|
1068
|
+
end
|
1069
|
+
elsif new_default_logger == nil
|
1070
|
+
@default_logger = Logger.new(IO::NULL)
|
1071
|
+
else
|
1072
|
+
@default_logger = new_default_logger
|
1073
|
+
end
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
# @param new_context_class [Class<GraphQL::Query::Context>] A subclass to use when executing queries
|
1418
1077
|
def context_class(new_context_class = nil)
|
1419
1078
|
if new_context_class
|
1420
1079
|
@context_class = new_context_class
|
@@ -1423,28 +1082,79 @@ module GraphQL
|
|
1423
1082
|
end
|
1424
1083
|
end
|
1425
1084
|
|
1085
|
+
# Register a handler for errors raised during execution. The handlers can return a new value or raise a new error.
|
1086
|
+
#
|
1087
|
+
# @example Handling "not found" with a client-facing error
|
1088
|
+
# rescue_from(ActiveRecord::NotFound) { raise GraphQL::ExecutionError, "An object could not be found" }
|
1089
|
+
#
|
1090
|
+
# @param err_classes [Array<StandardError>] Classes which should be rescued by `handler_block`
|
1091
|
+
# @param handler_block The code to run when one of those errors is raised during execution
|
1092
|
+
# @yieldparam error [StandardError] An instance of one of the configured `err_classes`
|
1093
|
+
# @yieldparam object [Object] The current application object in the query when the error was raised
|
1094
|
+
# @yieldparam arguments [GraphQL::Query::Arguments] The current field arguments when the error was raised
|
1095
|
+
# @yieldparam context [GraphQL::Query::Context] The context for the currently-running operation
|
1096
|
+
# @yieldreturn [Object] Some object to use in the place where this error was raised
|
1097
|
+
# @raise [GraphQL::ExecutionError] In the handler, raise to add a client-facing error to the response
|
1098
|
+
# @raise [StandardError] In the handler, raise to crash the query with a developer-facing error
|
1426
1099
|
def rescue_from(*err_classes, &handler_block)
|
1427
1100
|
err_classes.each do |err_class|
|
1428
|
-
|
1101
|
+
Execution::Errors.register_rescue_from(err_class, error_handlers[:subclass_handlers], handler_block)
|
1102
|
+
end
|
1103
|
+
end
|
1104
|
+
|
1105
|
+
NEW_HANDLER_HASH = ->(h, k) {
|
1106
|
+
h[k] = {
|
1107
|
+
class: k,
|
1108
|
+
handler: nil,
|
1109
|
+
subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
|
1110
|
+
}
|
1111
|
+
}
|
1112
|
+
|
1113
|
+
def error_handlers
|
1114
|
+
@error_handlers ||= {
|
1115
|
+
class: nil,
|
1116
|
+
handler: nil,
|
1117
|
+
subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
|
1118
|
+
}
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
# @api private
|
1122
|
+
def handle_or_reraise(context, err)
|
1123
|
+
handler = Execution::Errors.find_handler_for(self, err.class)
|
1124
|
+
if handler
|
1125
|
+
obj = context[:current_object]
|
1126
|
+
args = context[:current_arguments]
|
1127
|
+
args = args && args.respond_to?(:keyword_arguments) ? args.keyword_arguments : nil
|
1128
|
+
field = context[:current_field]
|
1129
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
1130
|
+
obj = obj.object
|
1131
|
+
end
|
1132
|
+
handler[:handler].call(err, obj, args, context, field)
|
1133
|
+
else
|
1134
|
+
raise err
|
1429
1135
|
end
|
1430
1136
|
end
|
1431
1137
|
|
1432
1138
|
# rubocop:disable Lint/DuplicateMethods
|
1433
1139
|
module ResolveTypeWithType
|
1434
1140
|
def resolve_type(type, obj, ctx)
|
1435
|
-
|
1141
|
+
maybe_lazy_resolve_type_result = if type.is_a?(Module) && type.respond_to?(:resolve_type)
|
1436
1142
|
type.resolve_type(obj, ctx)
|
1437
1143
|
else
|
1438
1144
|
super
|
1439
1145
|
end
|
1440
1146
|
|
1441
|
-
after_lazy(
|
1442
|
-
if
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1147
|
+
after_lazy(maybe_lazy_resolve_type_result) do |resolve_type_result|
|
1148
|
+
if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
|
1149
|
+
resolved_type = resolve_type_result[0]
|
1150
|
+
resolved_value = resolve_type_result[1]
|
1151
|
+
else
|
1152
|
+
resolved_type = resolve_type_result
|
1153
|
+
resolved_value = obj
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind))
|
1157
|
+
[resolved_type, resolved_value]
|
1448
1158
|
else
|
1449
1159
|
raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
|
1450
1160
|
end
|
@@ -1452,51 +1162,96 @@ module GraphQL
|
|
1452
1162
|
end
|
1453
1163
|
end
|
1454
1164
|
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1165
|
+
# GraphQL-Ruby calls this method during execution when it needs the application to determine the type to use for an object.
|
1166
|
+
#
|
1167
|
+
# Usually, this object was returned from a field whose return type is an {GraphQL::Schema::Interface} or a {GraphQL::Schema::Union}.
|
1168
|
+
# But this method is called in other cases, too -- for example, when {GraphQL::Schema::Argument.loads} cases an object to be directly loaded from the database.
|
1169
|
+
#
|
1170
|
+
# @example Returning a GraphQL type based on the object's class name
|
1171
|
+
# class MySchema < GraphQL::Schema
|
1172
|
+
# def resolve_type(_abs_type, object, _context)
|
1173
|
+
# graphql_type_name = "Types::#{object.class.name}Type"
|
1174
|
+
# graphql_type_name.constantize # If this raises a NameError, then come implement special cases in this method
|
1175
|
+
# end
|
1176
|
+
# end
|
1177
|
+
# @param abstract_type [Class, Module, nil] The Interface or Union type which is being resolved, if there is one
|
1178
|
+
# @param application_object [Object] The object returned from a field whose type must be determined
|
1179
|
+
# @param context [GraphQL::Query::Context] The query context for the currently-executing query
|
1180
|
+
# @return [Class<GraphQL::Schema::Object] The Object type definition to use for `obj`
|
1181
|
+
def resolve_type(abstract_type, application_object, context)
|
1182
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(abstract_type, application_object, context) must be implemented to use Union types, Interface types, or `loads:` (tried to resolve: #{abstract_type.name})"
|
1461
1183
|
end
|
1462
1184
|
# rubocop:enable Lint/DuplicateMethods
|
1463
1185
|
|
1464
1186
|
def inherited(child_class)
|
1465
1187
|
if self == GraphQL::Schema
|
1466
1188
|
child_class.directives(default_directives.values)
|
1189
|
+
child_class.extend(SubclassGetReferencesTo)
|
1190
|
+
end
|
1191
|
+
# Make sure the child class has these built out, so that
|
1192
|
+
# subclasses can be modified by later calls to `trace_with`
|
1193
|
+
own_trace_modes.each do |name, _class|
|
1194
|
+
child_class.own_trace_modes[name] = child_class.build_trace_mode(name)
|
1467
1195
|
end
|
1468
1196
|
child_class.singleton_class.prepend(ResolveTypeWithType)
|
1469
|
-
super
|
1470
|
-
end
|
1471
1197
|
|
1472
|
-
|
1473
|
-
|
1198
|
+
if use_visibility_profile?
|
1199
|
+
vis = self.visibility
|
1200
|
+
child_class.visibility = vis.dup_for(child_class)
|
1201
|
+
end
|
1202
|
+
super
|
1474
1203
|
end
|
1475
1204
|
|
1476
|
-
|
1477
|
-
|
1205
|
+
# Fetch an object based on an incoming ID and the current context. This method should return an object
|
1206
|
+
# from your application, or return `nil` if there is no object or the object shouldn't be available to this operation.
|
1207
|
+
#
|
1208
|
+
# @example Fetching an object with Rails's GlobalID
|
1209
|
+
# def self.object_from_id(object_id, _context)
|
1210
|
+
# GlobalID.find(global_id)
|
1211
|
+
# # TODO: use `context[:current_user]` to determine if this object is authorized.
|
1212
|
+
# end
|
1213
|
+
# @param object_id [String] The ID to fetch an object for. This may be client-provided (as in `node(id: ...)` or `loads:`) or previously stored by the schema (eg, by the `ObjectCache`)
|
1214
|
+
# @param context [GraphQL::Query::Context] The context for the currently-executing operation
|
1215
|
+
# @return [Object, nil] The application which `object_id` references, or `nil` if there is no object or the current operation shouldn't have access to the object
|
1216
|
+
# @see id_from_object which produces these IDs
|
1217
|
+
def object_from_id(object_id, context)
|
1218
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(object_id, context) must be implemented to load by ID (tried to load from id `#{object_id}`)"
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
# Return a stable ID string for `object` so that it can be refetched later, using {.object_from_id}.
|
1222
|
+
#
|
1223
|
+
# {GlobalID}(https://github.com/rails/globalid) and {SQIDs}(https://sqids.org/ruby) can both be used to create IDs.
|
1224
|
+
#
|
1225
|
+
# @example Using Rails's GlobalID to generate IDs
|
1226
|
+
# def self.id_from_object(application_object, graphql_type, context)
|
1227
|
+
# application_object.to_gid_param
|
1228
|
+
# end
|
1229
|
+
#
|
1230
|
+
# @param application_object [Object] Some object encountered by GraphQL-Ruby while running a query
|
1231
|
+
# @param graphql_type [Class, Module] The type that GraphQL-Ruby is using for `application_object` during this query
|
1232
|
+
# @param context [GraphQL::Query::Context] The context for the operation that is currently running
|
1233
|
+
# @return [String] A stable identifier which can be passed to {.object_from_id} later to re-fetch `application_object`
|
1234
|
+
def id_from_object(application_object, graphql_type, context)
|
1235
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.id_from_object(application_object, graphql_type, context) must be implemented to create global ids (tried to create an id for `#{application_object.inspect}`)"
|
1478
1236
|
end
|
1479
1237
|
|
1480
1238
|
def visible?(member, ctx)
|
1481
|
-
member.
|
1239
|
+
member.visible?(ctx)
|
1482
1240
|
end
|
1483
1241
|
|
1484
|
-
def
|
1485
|
-
|
1242
|
+
def schema_directive(dir_class, **options)
|
1243
|
+
@own_schema_directives ||= []
|
1244
|
+
Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
|
1486
1245
|
end
|
1487
1246
|
|
1488
|
-
|
1489
|
-
|
1490
|
-
#
|
1491
|
-
# By default, an error is added to the response. Override this hook to
|
1492
|
-
# track metrics or return a different error to the client.
|
1493
|
-
#
|
1494
|
-
# @param error [InaccessibleFieldsError] The analysis error for this check
|
1495
|
-
# @return [AnalysisError, nil] Return an error to skip the query
|
1496
|
-
def inaccessible_fields(error)
|
1497
|
-
error
|
1247
|
+
def schema_directives
|
1248
|
+
Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
|
1498
1249
|
end
|
1499
1250
|
|
1251
|
+
# Called when a type is needed by name at runtime
|
1252
|
+
def load_type(type_name, ctx)
|
1253
|
+
get_type(type_name, ctx)
|
1254
|
+
end
|
1500
1255
|
# This hook is called when an object fails an `authorized?` check.
|
1501
1256
|
# You might report to your bug tracker here, so you can correct
|
1502
1257
|
# the field resolvers not to return unauthorized objects.
|
@@ -1532,58 +1287,75 @@ module GraphQL
|
|
1532
1287
|
unauthorized_object(unauthorized_error)
|
1533
1288
|
end
|
1534
1289
|
|
1535
|
-
|
1536
|
-
|
1290
|
+
# Called at runtime when GraphQL-Ruby encounters a mismatch between the application behavior
|
1291
|
+
# and the GraphQL type system.
|
1292
|
+
#
|
1293
|
+
# The default implementation of this method is to follow the GraphQL specification,
|
1294
|
+
# but you can override this to report errors to your bug tracker or customize error handling.
|
1295
|
+
# @param type_error [GraphQL::Error] several specific error classes are passed here, see the default implementation for details
|
1296
|
+
# @param context [GraphQL::Query::Context] the context for the currently-running operation
|
1297
|
+
# @return [void]
|
1298
|
+
# @raise [GraphQL::ExecutionError] to return this error to the client
|
1299
|
+
# @raise [GraphQL::Error] to crash the query and raise a developer-facing error
|
1300
|
+
def type_error(type_error, ctx)
|
1301
|
+
case type_error
|
1302
|
+
when GraphQL::InvalidNullError
|
1303
|
+
ctx.errors << type_error
|
1304
|
+
when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
|
1305
|
+
raise type_error
|
1306
|
+
when GraphQL::IntegerDecodingError
|
1307
|
+
nil
|
1308
|
+
end
|
1537
1309
|
end
|
1538
1310
|
|
1539
1311
|
# A function to call when {#execute} receives an invalid query string
|
1540
1312
|
#
|
1541
1313
|
# The default is to add the error to `context.errors`
|
1542
|
-
# @param
|
1314
|
+
# @param parse_err [GraphQL::ParseError] The error encountered during parsing
|
1543
1315
|
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
1544
1316
|
# @return void
|
1545
1317
|
def parse_error(parse_err, ctx)
|
1546
1318
|
ctx.errors.push(parse_err)
|
1547
1319
|
end
|
1548
1320
|
|
1549
|
-
# @return [GraphQL::Execution::Errors]
|
1550
|
-
def error_handler
|
1551
|
-
@error_handler ||= GraphQL::Execution::Errors.new(self)
|
1552
|
-
end
|
1553
|
-
|
1554
1321
|
def lazy_resolve(lazy_class, value_method)
|
1555
1322
|
lazy_methods.set(lazy_class, value_method)
|
1556
1323
|
end
|
1557
1324
|
|
1558
1325
|
def instrument(instrument_step, instrumenter, options = {})
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
step = if instrument_step == :field && options[:after_built_ins]
|
1564
|
-
:field_after_built_ins
|
1565
|
-
else
|
1566
|
-
instrument_step
|
1567
|
-
end
|
1326
|
+
warn <<~WARN
|
1327
|
+
Schema.instrument is deprecated, use `trace_with` instead: https://graphql-ruby.org/queries/tracing.html"
|
1328
|
+
(From `#{self}.instrument(#{instrument_step}, #{instrumenter})` at #{caller(1, 1).first})
|
1568
1329
|
|
1569
|
-
|
1330
|
+
WARN
|
1331
|
+
trace_with(Tracing::LegacyHooksTrace)
|
1332
|
+
own_instrumenters[instrument_step] << instrumenter
|
1570
1333
|
end
|
1571
1334
|
|
1572
1335
|
# Add several directives at once
|
1573
1336
|
# @param new_directives [Class]
|
1574
1337
|
def directives(*new_directives)
|
1575
|
-
if new_directives.
|
1338
|
+
if !new_directives.empty?
|
1576
1339
|
new_directives.flatten.each { |d| directive(d) }
|
1577
1340
|
end
|
1578
1341
|
|
1579
|
-
find_inherited_value(:directives, default_directives)
|
1342
|
+
inherited_dirs = find_inherited_value(:directives, default_directives)
|
1343
|
+
if !own_directives.empty?
|
1344
|
+
inherited_dirs.merge(own_directives)
|
1345
|
+
else
|
1346
|
+
inherited_dirs
|
1347
|
+
end
|
1580
1348
|
end
|
1581
1349
|
|
1582
1350
|
# Attach a single directive to this schema
|
1583
1351
|
# @param new_directive [Class]
|
1584
1352
|
# @return void
|
1585
1353
|
def directive(new_directive)
|
1586
|
-
|
1354
|
+
if use_visibility_profile?
|
1355
|
+
own_directives[new_directive.graphql_name] = new_directive
|
1356
|
+
else
|
1357
|
+
add_type_and_traverse(new_directive, root: false)
|
1358
|
+
end
|
1587
1359
|
end
|
1588
1360
|
|
1589
1361
|
def default_directives
|
@@ -1591,10 +1363,21 @@ module GraphQL
|
|
1591
1363
|
"include" => GraphQL::Schema::Directive::Include,
|
1592
1364
|
"skip" => GraphQL::Schema::Directive::Skip,
|
1593
1365
|
"deprecated" => GraphQL::Schema::Directive::Deprecated,
|
1366
|
+
"oneOf" => GraphQL::Schema::Directive::OneOf,
|
1367
|
+
"specifiedBy" => GraphQL::Schema::Directive::SpecifiedBy,
|
1594
1368
|
}.freeze
|
1595
1369
|
end
|
1596
1370
|
|
1597
|
-
def tracer(new_tracer)
|
1371
|
+
def tracer(new_tracer, silence_deprecation_warning: false)
|
1372
|
+
if !silence_deprecation_warning
|
1373
|
+
warn("`Schema.tracer(#{new_tracer.inspect})` is deprecated; use module-based `trace_with` instead. See: https://graphql-ruby.org/queries/tracing.html")
|
1374
|
+
warn " #{caller(1, 1).first}"
|
1375
|
+
end
|
1376
|
+
default_trace = trace_class_for(:default, build: true)
|
1377
|
+
if default_trace.nil? || !(default_trace < GraphQL::Tracing::CallLegacyTracers)
|
1378
|
+
trace_with(GraphQL::Tracing::CallLegacyTracers)
|
1379
|
+
end
|
1380
|
+
|
1598
1381
|
own_tracers << new_tracer
|
1599
1382
|
end
|
1600
1383
|
|
@@ -1602,27 +1385,103 @@ module GraphQL
|
|
1602
1385
|
find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
|
1603
1386
|
end
|
1604
1387
|
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1388
|
+
# Mix `trace_mod` into this schema's `Trace` class so that its methods
|
1389
|
+
# will be called at runtime.
|
1390
|
+
#
|
1391
|
+
# @param trace_mod [Module] A module that implements tracing methods
|
1392
|
+
# @param mode [Symbol] Trace module will only be used for this trade mode
|
1393
|
+
# @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
|
1394
|
+
# @return [void]
|
1395
|
+
# @see GraphQL::Tracing::Trace for available tracing methods
|
1396
|
+
def trace_with(trace_mod, mode: :default, **options)
|
1397
|
+
if mode.is_a?(Array)
|
1398
|
+
mode.each { |m| trace_with(trace_mod, mode: m, **options) }
|
1399
|
+
else
|
1400
|
+
tc = own_trace_modes[mode] ||= build_trace_mode(mode)
|
1401
|
+
tc.include(trace_mod)
|
1402
|
+
own_trace_modules[mode] << trace_mod
|
1403
|
+
add_trace_options_for(mode, options)
|
1404
|
+
if mode == :default
|
1405
|
+
# This module is being added as a default tracer. If any other mode classes
|
1406
|
+
# have already been created, but get their default behavior from a superclass,
|
1407
|
+
# Then mix this into this schema's subclass.
|
1408
|
+
# (But don't mix it into mode classes that aren't default-based.)
|
1409
|
+
own_trace_modes.each do |other_mode_name, other_mode_class|
|
1410
|
+
if other_mode_class < DefaultTraceClass
|
1411
|
+
# Don't add it back to the inheritance tree if it's already there
|
1412
|
+
if !(other_mode_class < trace_mod)
|
1413
|
+
other_mode_class.include(trace_mod)
|
1414
|
+
end
|
1415
|
+
# Add any options so they'll be available
|
1416
|
+
add_trace_options_for(other_mode_name, options)
|
1417
|
+
end
|
1418
|
+
end
|
1419
|
+
end
|
1608
1420
|
end
|
1609
|
-
|
1421
|
+
nil
|
1610
1422
|
end
|
1611
1423
|
|
1612
|
-
|
1613
|
-
|
1424
|
+
# The options hash for this trace mode
|
1425
|
+
# @return [Hash]
|
1426
|
+
def trace_options_for(mode)
|
1427
|
+
@trace_options_for_mode ||= {}
|
1428
|
+
@trace_options_for_mode[mode] ||= begin
|
1429
|
+
# It may be time to create an options hash for a mode that wasn't registered yet.
|
1430
|
+
# Mix in the default options in that case.
|
1431
|
+
default_options = mode == :default ? EMPTY_HASH : trace_options_for(:default)
|
1432
|
+
# Make sure this returns a new object so that other hashes aren't modified later
|
1433
|
+
if superclass.respond_to?(:trace_options_for)
|
1434
|
+
superclass.trace_options_for(mode).merge(default_options)
|
1435
|
+
else
|
1436
|
+
default_options.dup
|
1437
|
+
end
|
1438
|
+
end
|
1614
1439
|
end
|
1615
1440
|
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1441
|
+
# Create a trace instance which will include the trace modules specified for the optional mode.
|
1442
|
+
#
|
1443
|
+
# If no `mode:` is given, then {default_trace_mode} will be used.
|
1444
|
+
#
|
1445
|
+
# @param mode [Symbol] Trace modules for this trade mode will be included
|
1446
|
+
# @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
|
1447
|
+
# @return [Tracing::Trace]
|
1448
|
+
def new_trace(mode: nil, **options)
|
1449
|
+
target = options[:query] || options[:multiplex]
|
1450
|
+
mode ||= target && target.context[:trace_mode]
|
1451
|
+
|
1452
|
+
trace_mode = if mode
|
1453
|
+
mode
|
1454
|
+
elsif target && target.context[:backtrace]
|
1455
|
+
if default_trace_mode != :default
|
1456
|
+
raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
|
1457
|
+
else
|
1458
|
+
own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
|
1459
|
+
options_trace_mode = :default
|
1460
|
+
:default_backtrace
|
1461
|
+
end
|
1620
1462
|
else
|
1621
|
-
|
1622
|
-
MiddlewareChain.new(steps: all_middleware, final_step: GraphQL::Execution::Execute::FieldResolveStep)
|
1463
|
+
default_trace_mode
|
1623
1464
|
end
|
1465
|
+
|
1466
|
+
options_trace_mode ||= trace_mode
|
1467
|
+
base_trace_options = trace_options_for(options_trace_mode)
|
1468
|
+
trace_options = base_trace_options.merge(options)
|
1469
|
+
trace_class_for_mode = trace_class_for(trace_mode, build: true)
|
1470
|
+
trace_class_for_mode.new(**trace_options)
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
# @param new_analyzer [Class<GraphQL::Analysis::Analyzer>] An analyzer to run on queries to this schema
|
1474
|
+
# @see GraphQL::Analysis the analysis system
|
1475
|
+
def query_analyzer(new_analyzer)
|
1476
|
+
own_query_analyzers << new_analyzer
|
1477
|
+
end
|
1478
|
+
|
1479
|
+
def query_analyzers
|
1480
|
+
find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
|
1624
1481
|
end
|
1625
1482
|
|
1483
|
+
# @param new_analyzer [Class<GraphQL::Analysis::Analyzer>] An analyzer to run on multiplexes to this schema
|
1484
|
+
# @see GraphQL::Analysis the analysis system
|
1626
1485
|
def multiplex_analyzer(new_analyzer)
|
1627
1486
|
own_multiplex_analyzers << new_analyzer
|
1628
1487
|
end
|
@@ -1631,9 +1490,17 @@ module GraphQL
|
|
1631
1490
|
find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
|
1632
1491
|
end
|
1633
1492
|
|
1493
|
+
def sanitized_printer(new_sanitized_printer = nil)
|
1494
|
+
if new_sanitized_printer
|
1495
|
+
@own_sanitized_printer = new_sanitized_printer
|
1496
|
+
else
|
1497
|
+
@own_sanitized_printer || GraphQL::Language::SanitizedPrinter
|
1498
|
+
end
|
1499
|
+
end
|
1500
|
+
|
1634
1501
|
# Execute a query on itself.
|
1635
1502
|
# @see {Query#initialize} for arguments.
|
1636
|
-
# @return [
|
1503
|
+
# @return [GraphQL::Query::Result] query result, ready to be serialized as JSON
|
1637
1504
|
def execute(query_str = nil, **kwargs)
|
1638
1505
|
if query_str
|
1639
1506
|
kwargs[:query] = query_str
|
@@ -1643,6 +1510,9 @@ module GraphQL
|
|
1643
1510
|
{
|
1644
1511
|
backtrace: ctx[:backtrace],
|
1645
1512
|
tracers: ctx[:tracers],
|
1513
|
+
trace: ctx[:trace],
|
1514
|
+
dataloader: ctx[:dataloader],
|
1515
|
+
trace_mode: ctx[:trace_mode],
|
1646
1516
|
}
|
1647
1517
|
else
|
1648
1518
|
{}
|
@@ -1667,17 +1537,12 @@ module GraphQL
|
|
1667
1537
|
# }
|
1668
1538
|
#
|
1669
1539
|
# @see {Query#initialize} for query keyword arguments
|
1670
|
-
# @see {Execution::Multiplex#
|
1540
|
+
# @see {Execution::Multiplex#run_all} for multiplex keyword arguments
|
1671
1541
|
# @param queries [Array<Hash>] Keyword arguments for each query
|
1672
1542
|
# @param context [Hash] Multiplex-level context
|
1673
|
-
# @return [Array<
|
1543
|
+
# @return [Array<GraphQL::Query::Result>] One result for each query in the input
|
1674
1544
|
def multiplex(queries, **kwargs)
|
1675
|
-
|
1676
|
-
self
|
1677
|
-
else
|
1678
|
-
graphql_definition
|
1679
|
-
end
|
1680
|
-
GraphQL::Execution::Multiplex.run_all(schema, queries, **kwargs)
|
1545
|
+
GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
|
1681
1546
|
end
|
1682
1547
|
|
1683
1548
|
def instrumenters
|
@@ -1689,24 +1554,111 @@ module GraphQL
|
|
1689
1554
|
|
1690
1555
|
# @api private
|
1691
1556
|
def add_subscription_extension_if_necessary
|
1692
|
-
|
1557
|
+
# TODO: when there's a proper API for extending root types, migrat this to use it.
|
1558
|
+
if !defined?(@subscription_extension_added) && @subscription_object.is_a?(Class) && self.subscriptions
|
1693
1559
|
@subscription_extension_added = true
|
1694
|
-
|
1695
|
-
|
1696
|
-
else
|
1697
|
-
subscription.fields.each do |name, field|
|
1560
|
+
subscription.all_field_definitions.each do |field|
|
1561
|
+
if !field.extensions.any? { |ext| ext.is_a?(Subscriptions::DefaultSubscriptionResolveExtension) }
|
1698
1562
|
field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
|
1699
1563
|
end
|
1700
1564
|
end
|
1701
1565
|
end
|
1702
1566
|
end
|
1703
1567
|
|
1568
|
+
# Called when execution encounters a `SystemStackError`. By default, it adds a client-facing error to the response.
|
1569
|
+
# You could modify this method to report this error to your bug tracker.
|
1570
|
+
# @param query [GraphQL::Query]
|
1571
|
+
# @param err [SystemStackError]
|
1572
|
+
# @return [void]
|
1704
1573
|
def query_stack_error(query, err)
|
1705
1574
|
query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
|
1706
1575
|
end
|
1707
1576
|
|
1577
|
+
# Call the given block at the right time, either:
|
1578
|
+
# - Right away, if `value` is not registered with `lazy_resolve`
|
1579
|
+
# - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
|
1580
|
+
# @api private
|
1581
|
+
def after_lazy(value, &block)
|
1582
|
+
if lazy?(value)
|
1583
|
+
GraphQL::Execution::Lazy.new do
|
1584
|
+
result = sync_lazy(value)
|
1585
|
+
# The returned result might also be lazy, so check it, too
|
1586
|
+
after_lazy(result, &block)
|
1587
|
+
end
|
1588
|
+
else
|
1589
|
+
yield(value) if block_given?
|
1590
|
+
end
|
1591
|
+
end
|
1592
|
+
|
1593
|
+
# Override this method to handle lazy objects in a custom way.
|
1594
|
+
# @param value [Object] an instance of a class registered with {.lazy_resolve}
|
1595
|
+
# @return [Object] A GraphQL-ready (non-lazy) object
|
1596
|
+
# @api private
|
1597
|
+
def sync_lazy(value)
|
1598
|
+
lazy_method = lazy_method_name(value)
|
1599
|
+
if lazy_method
|
1600
|
+
synced_value = value.public_send(lazy_method)
|
1601
|
+
sync_lazy(synced_value)
|
1602
|
+
else
|
1603
|
+
value
|
1604
|
+
end
|
1605
|
+
end
|
1606
|
+
|
1607
|
+
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
|
1608
|
+
def lazy_method_name(obj)
|
1609
|
+
lazy_methods.get(obj)
|
1610
|
+
end
|
1611
|
+
|
1612
|
+
# @return [Boolean] True if this object should be lazily resolved
|
1613
|
+
def lazy?(obj)
|
1614
|
+
!!lazy_method_name(obj)
|
1615
|
+
end
|
1616
|
+
|
1617
|
+
# Return a lazy if any of `maybe_lazies` are lazy,
|
1618
|
+
# otherwise, call the block eagerly and return the result.
|
1619
|
+
# @param maybe_lazies [Array]
|
1620
|
+
# @api private
|
1621
|
+
def after_any_lazies(maybe_lazies)
|
1622
|
+
if maybe_lazies.any? { |l| lazy?(l) }
|
1623
|
+
GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
|
1624
|
+
yield result
|
1625
|
+
end
|
1626
|
+
else
|
1627
|
+
yield maybe_lazies
|
1628
|
+
end
|
1629
|
+
end
|
1630
|
+
|
1631
|
+
# Returns `DidYouMean` if it's defined.
|
1632
|
+
# Override this to return `nil` if you don't want to use `DidYouMean`
|
1633
|
+
def did_you_mean(new_dym = NOT_CONFIGURED)
|
1634
|
+
if NOT_CONFIGURED.equal?(new_dym)
|
1635
|
+
if defined?(@did_you_mean)
|
1636
|
+
@did_you_mean
|
1637
|
+
else
|
1638
|
+
find_inherited_value(:did_you_mean, defined?(DidYouMean) ? DidYouMean : nil)
|
1639
|
+
end
|
1640
|
+
else
|
1641
|
+
@did_you_mean = new_dym
|
1642
|
+
end
|
1643
|
+
end
|
1644
|
+
|
1708
1645
|
private
|
1709
1646
|
|
1647
|
+
def add_trace_options_for(mode, new_options)
|
1648
|
+
if mode == :default
|
1649
|
+
own_trace_modes.each do |mode_name, t_class|
|
1650
|
+
if t_class <= DefaultTraceClass
|
1651
|
+
t_opts = trace_options_for(mode_name)
|
1652
|
+
t_opts.merge!(new_options)
|
1653
|
+
end
|
1654
|
+
end
|
1655
|
+
else
|
1656
|
+
t_opts = trace_options_for(mode)
|
1657
|
+
t_opts.merge!(new_options)
|
1658
|
+
end
|
1659
|
+
nil
|
1660
|
+
end
|
1661
|
+
|
1710
1662
|
# @param t [Module, Array<Module>]
|
1711
1663
|
# @return [void]
|
1712
1664
|
def add_type_and_traverse(t, root:)
|
@@ -1716,12 +1668,42 @@ module GraphQL
|
|
1716
1668
|
end
|
1717
1669
|
new_types = Array(t)
|
1718
1670
|
addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
|
1719
|
-
|
1671
|
+
addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
|
1672
|
+
if (prev_entry = own_types[name])
|
1673
|
+
prev_entries = case prev_entry
|
1674
|
+
when Array
|
1675
|
+
prev_entry
|
1676
|
+
when Module
|
1677
|
+
own_types[name] = [prev_entry]
|
1678
|
+
else
|
1679
|
+
raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
|
1680
|
+
end
|
1681
|
+
|
1682
|
+
case types_entry
|
1683
|
+
when Array
|
1684
|
+
prev_entries.concat(types_entry)
|
1685
|
+
prev_entries.uniq! # in case any are being re-visited
|
1686
|
+
when Module
|
1687
|
+
if !prev_entries.include?(types_entry)
|
1688
|
+
prev_entries << types_entry
|
1689
|
+
end
|
1690
|
+
else
|
1691
|
+
raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
|
1692
|
+
end
|
1693
|
+
else
|
1694
|
+
if types_entry.is_a?(Array)
|
1695
|
+
types_entry.uniq!
|
1696
|
+
end
|
1697
|
+
own_types[name] = types_entry
|
1698
|
+
end
|
1699
|
+
end
|
1700
|
+
|
1720
1701
|
own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
|
1721
1702
|
own_union_memberships.merge!(addition.union_memberships)
|
1722
1703
|
|
1723
1704
|
addition.references.each { |thing, pointers|
|
1724
|
-
|
1705
|
+
prev_refs = own_references_to[thing] || []
|
1706
|
+
own_references_to[thing] = prev_refs | pointers.to_a
|
1725
1707
|
}
|
1726
1708
|
|
1727
1709
|
addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
|
@@ -1739,7 +1721,7 @@ module GraphQL
|
|
1739
1721
|
else
|
1740
1722
|
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
1741
1723
|
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
1742
|
-
@lazy_methods.set(GraphQL::Dataloader::Request, :
|
1724
|
+
@lazy_methods.set(GraphQL::Dataloader::Request, :load_with_deprecation_warning)
|
1743
1725
|
end
|
1744
1726
|
end
|
1745
1727
|
@lazy_methods
|
@@ -1749,6 +1731,10 @@ module GraphQL
|
|
1749
1731
|
@own_types ||= {}
|
1750
1732
|
end
|
1751
1733
|
|
1734
|
+
def own_references_to
|
1735
|
+
@own_references_to ||= {}.compare_by_identity
|
1736
|
+
end
|
1737
|
+
|
1752
1738
|
def non_introspection_types
|
1753
1739
|
find_inherited_value(:non_introspection_types, EMPTY_HASH).merge(own_types)
|
1754
1740
|
end
|
@@ -1762,7 +1748,7 @@ module GraphQL
|
|
1762
1748
|
end
|
1763
1749
|
|
1764
1750
|
def own_possible_types
|
1765
|
-
@own_possible_types ||= {}
|
1751
|
+
@own_possible_types ||= {}.compare_by_identity
|
1766
1752
|
end
|
1767
1753
|
|
1768
1754
|
def own_union_memberships
|
@@ -1785,68 +1771,40 @@ module GraphQL
|
|
1785
1771
|
@defined_query_analyzers ||= []
|
1786
1772
|
end
|
1787
1773
|
|
1788
|
-
def all_middleware
|
1789
|
-
find_inherited_value(:all_middleware, EMPTY_ARRAY) + own_middleware
|
1790
|
-
end
|
1791
|
-
|
1792
|
-
def own_middleware
|
1793
|
-
@own_middleware ||= []
|
1794
|
-
end
|
1795
|
-
|
1796
1774
|
def own_multiplex_analyzers
|
1797
1775
|
@own_multiplex_analyzers ||= []
|
1798
1776
|
end
|
1799
|
-
end
|
1800
|
-
|
1801
|
-
def dataloader_class
|
1802
|
-
self.class.dataloader_class
|
1803
|
-
end
|
1804
|
-
|
1805
|
-
# Install these here so that subclasses will also install it.
|
1806
|
-
use(GraphQL::Pagination::Connections)
|
1807
|
-
|
1808
|
-
protected
|
1809
|
-
|
1810
|
-
def rescues?
|
1811
|
-
!!@rescue_middleware
|
1812
|
-
end
|
1813
1777
|
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
1778
|
+
# This is overridden in subclasses to check the inheritance chain
|
1779
|
+
def get_references_to(type_defn)
|
1780
|
+
own_references_to[type_defn]
|
1781
|
+
end
|
1818
1782
|
end
|
1819
1783
|
|
1820
|
-
|
1821
|
-
|
1822
|
-
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1834
|
-
@find_cache = {}
|
1835
|
-
@finder = Finder.new(self)
|
1836
|
-
end
|
1837
|
-
ensure
|
1838
|
-
@rebuilding_artifacts = false
|
1784
|
+
module SubclassGetReferencesTo
|
1785
|
+
def get_references_to(type_defn)
|
1786
|
+
own_refs = own_references_to[type_defn]
|
1787
|
+
inherited_refs = superclass.references_to(type_defn)
|
1788
|
+
if inherited_refs&.any?
|
1789
|
+
if own_refs&.any?
|
1790
|
+
own_refs + inherited_refs
|
1791
|
+
else
|
1792
|
+
inherited_refs
|
1793
|
+
end
|
1794
|
+
else
|
1795
|
+
own_refs
|
1796
|
+
end
|
1797
|
+
end
|
1839
1798
|
end
|
1840
1799
|
|
1841
|
-
|
1842
|
-
|
1800
|
+
# Install these here so that subclasses will also install it.
|
1801
|
+
self.connections = GraphQL::Pagination::Connections.new(schema: self)
|
1843
1802
|
|
1844
|
-
|
1845
|
-
|
1846
|
-
raise @definition_error
|
1847
|
-
else
|
1848
|
-
yield
|
1849
|
-
end
|
1803
|
+
# @api private
|
1804
|
+
module DefaultTraceClass
|
1850
1805
|
end
|
1851
1806
|
end
|
1852
1807
|
end
|
1808
|
+
|
1809
|
+
require "graphql/schema/loader"
|
1810
|
+
require "graphql/schema/printer"
|