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