graphql 1.9.17 → 2.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +21 -10
- data/lib/generators/graphql/enum_generator.rb +4 -10
- data/lib/generators/graphql/field_extractor.rb +31 -0
- data/lib/generators/graphql/input_generator.rb +50 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
- data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
- data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +45 -8
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/loader_generator.rb +1 -0
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +6 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +28 -12
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +49 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +8 -0
- data/lib/generators/graphql/templates/base_edge.erb +8 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +7 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +6 -2
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +3 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +7 -3
- data/lib/generators/graphql/templates/query_type.erb +3 -3
- data/lib/generators/graphql/templates/scalar.erb +5 -1
- data/lib/generators/graphql/templates/schema.erb +25 -27
- data/lib/generators/graphql/templates/union.erb +6 -2
- data/lib/generators/graphql/type_generator.rb +47 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/ast/field_usage.rb +31 -2
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +175 -68
- data/lib/graphql/analysis/ast/query_depth.rb +0 -1
- data/lib/graphql/analysis/ast/visitor.rb +54 -38
- data/lib/graphql/analysis/ast.rb +16 -16
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/inspect_result.rb +0 -1
- data/lib/graphql/backtrace/table.rb +37 -16
- data/lib/graphql/backtrace/traced_error.rb +0 -1
- data/lib/graphql/backtrace/tracer.rb +39 -9
- data/lib/graphql/backtrace.rb +20 -17
- data/lib/graphql/dataloader/null_dataloader.rb +24 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +164 -0
- data/lib/graphql/dataloader.rb +311 -0
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/deprecation.rb +9 -0
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/execution/directive_checks.rb +2 -2
- data/lib/graphql/execution/errors.rb +77 -45
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +88 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +105 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
- data/lib/graphql/execution/interpreter/resolve.rb +62 -24
- data/lib/graphql/execution/interpreter/runtime.rb +773 -399
- data/lib/graphql/execution/interpreter.rb +206 -74
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lazy.rb +11 -21
- data/lib/graphql/execution/lookahead.rb +65 -136
- data/lib/graphql/execution/multiplex.rb +6 -152
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/filter.rb +1 -1
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/introspection/base_object.rb +2 -5
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +12 -6
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +5 -18
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +9 -5
- data/lib/graphql/introspection/input_value_type.rb +41 -11
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +12 -12
- data/lib/graphql/introspection/type_type.rb +34 -17
- data/lib/graphql/introspection.rb +100 -0
- data/lib/graphql/invalid_null_error.rb +18 -0
- data/lib/graphql/language/block_string.rb +20 -5
- data/lib/graphql/language/cache.rb +37 -0
- data/lib/graphql/language/definition_slice.rb +21 -10
- data/lib/graphql/language/document_from_schema_definition.rb +113 -71
- data/lib/graphql/language/lexer.rb +216 -1462
- data/lib/graphql/language/nodes.rb +128 -131
- data/lib/graphql/language/parser.rb +957 -912
- data/lib/graphql/language/parser.y +148 -120
- data/lib/graphql/language/printer.rb +48 -23
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/language/visitor.rb +192 -84
- data/lib/graphql/language.rb +3 -1
- data/lib/graphql/name_validator.rb +2 -7
- data/lib/graphql/pagination/active_record_relation_connection.rb +77 -0
- data/lib/graphql/pagination/array_connection.rb +79 -0
- data/lib/graphql/pagination/connection.rb +253 -0
- data/lib/graphql/pagination/connections.rb +135 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +228 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/parse_error.rb +0 -1
- data/lib/graphql/query/context.rb +204 -203
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +33 -7
- data/lib/graphql/query/null_context.rb +21 -8
- data/lib/graphql/query/validation_pipeline.rb +16 -38
- data/lib/graphql/query/variable_validation_error.rb +3 -3
- data/lib/graphql/query/variables.rb +39 -12
- data/lib/graphql/query.rb +88 -40
- data/lib/graphql/railtie.rb +6 -102
- data/lib/graphql/rake_task/validate.rb +4 -1
- data/lib/graphql/rake_task.rb +41 -10
- data/lib/graphql/relay/range_add.rb +17 -10
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/schema/addition.rb +245 -0
- data/lib/graphql/schema/argument.rb +284 -33
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
- data/lib/graphql/schema/build_from_definition.rb +336 -205
- data/lib/graphql/schema/built_in_types.rb +5 -5
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive/include.rb +2 -2
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/skip.rb +2 -2
- data/lib/graphql/schema/directive/transform.rb +14 -2
- data/lib/graphql/schema/directive.rb +134 -15
- data/lib/graphql/schema/enum.rb +137 -39
- data/lib/graphql/schema/enum_value.rb +20 -23
- data/lib/graphql/schema/field/connection_extension.rb +50 -20
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +503 -331
- data/lib/graphql/schema/field_extension.rb +89 -2
- data/lib/graphql/schema/find_inherited_value.rb +17 -1
- data/lib/graphql/schema/finder.rb +16 -14
- data/lib/graphql/schema/input_object.rb +182 -60
- data/lib/graphql/schema/interface.rb +24 -49
- data/lib/graphql/schema/introspection_system.rb +103 -37
- data/lib/graphql/schema/late_bound_type.rb +9 -2
- data/lib/graphql/schema/list.rb +61 -3
- data/lib/graphql/schema/loader.rb +144 -96
- data/lib/graphql/schema/member/base_dsl_methods.rb +41 -37
- data/lib/graphql/schema/member/build_type.rb +24 -15
- data/lib/graphql/schema/member/has_arguments.rb +310 -26
- data/lib/graphql/schema/member/has_ast_node.rb +32 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +24 -0
- data/lib/graphql/schema/member/has_directives.rb +120 -0
- data/lib/graphql/schema/member/has_fields.rb +112 -34
- data/lib/graphql/schema/member/has_interfaces.rb +129 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/has_validators.rb +57 -0
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/type_system_helpers.rb +20 -3
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +11 -6
- data/lib/graphql/schema/mutation.rb +4 -9
- data/lib/graphql/schema/non_null.rb +34 -4
- data/lib/graphql/schema/object.rb +36 -60
- data/lib/graphql/schema/printer.rb +16 -35
- data/lib/graphql/schema/relay_classic_mutation.rb +91 -44
- data/lib/graphql/schema/resolver/has_payload_type.rb +51 -11
- data/lib/graphql/schema/resolver.rb +147 -94
- data/lib/graphql/schema/scalar.rb +40 -15
- data/lib/graphql/schema/subscription.rb +60 -31
- data/lib/graphql/schema/timeout.rb +45 -35
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +23 -6
- data/lib/graphql/schema/union.rb +49 -15
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/format_validator.rb +48 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
- data/lib/graphql/schema/validator/length_validator.rb +59 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
- data/lib/graphql/schema/validator/required_validator.rb +82 -0
- data/lib/graphql/schema/validator.rb +171 -0
- data/lib/graphql/schema/warden.rb +211 -35
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +833 -889
- data/lib/graphql/static_validation/all_rules.rb +3 -0
- data/lib/graphql/static_validation/base_visitor.rb +21 -31
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +69 -26
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +45 -83
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +12 -6
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -14
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +94 -51
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +13 -3
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +32 -20
- data/lib/graphql/static_validation.rb +1 -2
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +129 -22
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
- data/lib/graphql/subscriptions/event.rb +84 -35
- data/lib/graphql/subscriptions/instrumentation.rb +0 -47
- data/lib/graphql/subscriptions/serialize.rb +53 -6
- data/lib/graphql/subscriptions.rb +137 -57
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
- data/lib/graphql/tracing/appoptics_trace.rb +231 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_trace.rb +71 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
- data/lib/graphql/tracing/data_dog_trace.rb +148 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +34 -2
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
- data/lib/graphql/tracing/notifications_trace.rb +41 -0
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_trace.rb +107 -0
- data/lib/graphql/tracing/platform_tracing.rb +76 -35
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +11 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/scout_tracing.rb +19 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +143 -67
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/big_int.rb +5 -1
- data/lib/graphql/types/int.rb +10 -3
- data/lib/graphql/types/iso_8601_date.rb +20 -9
- data/lib/graphql/types/iso_8601_date_time.rb +36 -10
- data/lib/graphql/types/relay/base_connection.rb +18 -90
- data/lib/graphql/types/relay/base_edge.rb +2 -34
- data/lib/graphql/types/relay/connection_behaviors.rb +176 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +75 -0
- data/lib/graphql/types/relay/has_node_field.rb +41 -0
- data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
- data/lib/graphql/types/relay/node.rb +2 -4
- data/lib/graphql/types/relay/node_behaviors.rb +25 -0
- data/lib/graphql/types/relay/page_info.rb +2 -14
- data/lib/graphql/types/relay/page_info_behaviors.rb +30 -0
- data/lib/graphql/types/relay.rb +10 -5
- data/lib/graphql/types/string.rb +8 -2
- data/lib/graphql/unauthorized_error.rb +2 -2
- data/lib/graphql/unresolved_type_error.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +60 -66
- data/readme.md +3 -6
- metadata +124 -236
- data/lib/graphql/analysis/analyze_query.rb +0 -91
- data/lib/graphql/analysis/field_usage.rb +0 -45
- data/lib/graphql/analysis/max_query_complexity.rb +0 -26
- data/lib/graphql/analysis/max_query_depth.rb +0 -26
- data/lib/graphql/analysis/query_complexity.rb +0 -88
- data/lib/graphql/analysis/query_depth.rb +0 -43
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -159
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backwards_compatibility.rb +0 -60
- data/lib/graphql/base_type.rb +0 -226
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -435
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -213
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -91
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -264
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -680
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -50
- data/lib/graphql/define/instance_definable.rb +0 -300
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -42
- data/lib/graphql/directive/deprecated_directive.rb +0 -13
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -104
- data/lib/graphql/enum_type.rb +0 -193
- data/lib/graphql/execution/execute.rb +0 -326
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/instrumentation.rb +0 -92
- data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
- 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 -330
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -153
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -154
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -86
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -258
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/literal_validation_error.rb +0 -6
- data/lib/graphql/non_null_type.rb +0 -81
- data/lib/graphql/object_type.rb +0 -141
- data/lib/graphql/query/arguments.rb +0 -187
- data/lib/graphql/query/arguments_cache.rb +0 -25
- data/lib/graphql/query/executor.rb +0 -53
- data/lib/graphql/query/literal_input.rb +0 -116
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -39
- data/lib/graphql/relay/array_connection.rb +0 -85
- data/lib/graphql/relay/base_connection.rb +0 -172
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -40
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -18
- data/lib/graphql/relay/edges_instrumentation.rb +0 -40
- data/lib/graphql/relay/global_id_resolve.rb +0 -18
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -190
- data/lib/graphql/relay/node.rb +0 -36
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -190
- data/lib/graphql/relay/type_extensions.rb +0 -30
- data/lib/graphql/scalar_type.rb +0 -133
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -15
- data/lib/graphql/schema/member/accepts_definition.rb +0 -152
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -26
- data/lib/graphql/schema/member/instrumentation.rb +0 -132
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -39
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -86
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -303
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/subscription_root.rb +0 -66
- data/lib/graphql/tracing/skylight_tracing.rb +0 -62
- data/lib/graphql/types/relay/base_field.rb +0 -22
- data/lib/graphql/types/relay/base_interface.rb +0 -29
- data/lib/graphql/types/relay/base_object.rb +0 -26
- data/lib/graphql/types/relay/node_field.rb +0 -43
- data/lib/graphql/types/relay/nodes_field.rb +0 -45
- data/lib/graphql/union_type.rb +0 -128
- data/lib/graphql/upgrader/member.rb +0 -936
- data/lib/graphql/upgrader/schema.rb +0 -37
data/lib/graphql/schema.rb
CHANGED
@@ -1,26 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "graphql/schema/addition"
|
2
3
|
require "graphql/schema/base_64_encoder"
|
3
|
-
require "graphql/schema/catchall_middleware"
|
4
|
-
require "graphql/schema/default_parse_error"
|
5
|
-
require "graphql/schema/default_type_error"
|
6
4
|
require "graphql/schema/find_inherited_value"
|
7
5
|
require "graphql/schema/finder"
|
8
6
|
require "graphql/schema/invalid_type_error"
|
9
7
|
require "graphql/schema/introspection_system"
|
10
8
|
require "graphql/schema/late_bound_type"
|
11
|
-
require "graphql/schema/middleware_chain"
|
12
9
|
require "graphql/schema/null_mask"
|
13
|
-
require "graphql/schema/possible_types"
|
14
|
-
require "graphql/schema/rescue_middleware"
|
15
10
|
require "graphql/schema/timeout"
|
16
|
-
require "graphql/schema/timeout_middleware"
|
17
|
-
require "graphql/schema/traversal"
|
18
11
|
require "graphql/schema/type_expression"
|
19
12
|
require "graphql/schema/unique_within_type"
|
20
|
-
require "graphql/schema/validation"
|
21
13
|
require "graphql/schema/warden"
|
22
14
|
require "graphql/schema/build_from_definition"
|
23
15
|
|
16
|
+
require "graphql/schema/validator"
|
24
17
|
require "graphql/schema/member"
|
25
18
|
require "graphql/schema/wrapper"
|
26
19
|
require "graphql/schema/list"
|
@@ -36,9 +29,12 @@ require "graphql/schema/scalar"
|
|
36
29
|
require "graphql/schema/object"
|
37
30
|
require "graphql/schema/union"
|
38
31
|
require "graphql/schema/directive"
|
32
|
+
require "graphql/schema/directive/deprecated"
|
39
33
|
require "graphql/schema/directive/include"
|
34
|
+
require "graphql/schema/directive/one_of"
|
40
35
|
require "graphql/schema/directive/skip"
|
41
36
|
require "graphql/schema/directive/feature"
|
37
|
+
require "graphql/schema/directive/flagged"
|
42
38
|
require "graphql/schema/directive/transform"
|
43
39
|
require "graphql/schema/type_membership"
|
44
40
|
|
@@ -55,7 +51,6 @@ module GraphQL
|
|
55
51
|
# - types for exposing your application
|
56
52
|
# - query analyzers for assessing incoming queries (including max depth & max complexity restrictions)
|
57
53
|
# - execution strategies for running incoming queries
|
58
|
-
# - middleware for interacting with execution
|
59
54
|
#
|
60
55
|
# Schemas start with root types, {Schema#query}, {Schema#mutation} and {Schema#subscription}.
|
61
56
|
# The schema will traverse the tree of fields & types, using those as starting points.
|
@@ -68,784 +63,470 @@ module GraphQL
|
|
68
63
|
# `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
|
69
64
|
# each apply to corresponding root types.
|
70
65
|
#
|
71
|
-
# A schema accepts a `Relay::GlobalNodeIdentification` instance for use with Relay IDs.
|
72
|
-
#
|
73
66
|
# @example defining a schema
|
74
|
-
# MySchema
|
67
|
+
# class MySchema < GraphQL::Schema
|
75
68
|
# query QueryType
|
76
|
-
# middleware PermissionMiddleware
|
77
|
-
# rescue_from(ActiveRecord::RecordNotFound) { "Not found" }
|
78
69
|
# # If types are only connected by way of interfaces, they must be added here
|
79
70
|
# orphan_types ImageType, AudioType
|
80
71
|
# end
|
81
72
|
#
|
82
73
|
class Schema
|
83
|
-
extend
|
84
|
-
extend GraphQL::Schema::Member::AcceptsDefinition
|
85
|
-
include GraphQL::Define::InstanceDefinable
|
74
|
+
extend GraphQL::Schema::Member::HasAstNode
|
86
75
|
extend GraphQL::Schema::FindInheritedValue
|
87
76
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
:default_mask,
|
96
|
-
:cursor_encoder,
|
97
|
-
# If these are given as classes, normalize them. Accept `nil` when building from string.
|
98
|
-
query: ->(schema, t) { schema.query = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
99
|
-
mutation: ->(schema, t) { schema.mutation = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
100
|
-
subscription: ->(schema, t) { schema.subscription = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
101
|
-
disable_introspection_entry_points: ->(schema) { schema.disable_introspection_entry_points = true },
|
102
|
-
directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.name] = d; m } },
|
103
|
-
directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
|
104
|
-
instrument: ->(schema, type, instrumenter, after_built_ins: false) {
|
105
|
-
if type == :field && after_built_ins
|
106
|
-
type = :field_after_built_ins
|
107
|
-
end
|
108
|
-
schema.instrumenters[type] << instrumenter
|
109
|
-
},
|
110
|
-
query_analyzer: ->(schema, analyzer) {
|
111
|
-
if analyzer == GraphQL::Authorization::Analyzer
|
112
|
-
warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
|
113
|
-
end
|
114
|
-
schema.query_analyzers << analyzer
|
115
|
-
},
|
116
|
-
multiplex_analyzer: ->(schema, analyzer) { schema.multiplex_analyzers << analyzer },
|
117
|
-
middleware: ->(schema, middleware) { schema.middleware << middleware },
|
118
|
-
lazy_resolve: ->(schema, lazy_class, lazy_value_method) { schema.lazy_methods.set(lazy_class, lazy_value_method) },
|
119
|
-
rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block) },
|
120
|
-
tracer: ->(schema, tracer) { schema.tracers.push(tracer) }
|
121
|
-
|
122
|
-
ensure_defined :introspection_system
|
123
|
-
|
124
|
-
attr_accessor \
|
125
|
-
:query, :mutation, :subscription,
|
126
|
-
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
127
|
-
:max_depth, :max_complexity, :default_max_page_size,
|
128
|
-
:orphan_types, :directives,
|
129
|
-
:query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
|
130
|
-
:cursor_encoder,
|
131
|
-
:ast_node,
|
132
|
-
:raise_definition_error,
|
133
|
-
:introspection_namespace,
|
134
|
-
:analysis_engine
|
135
|
-
|
136
|
-
# [Boolean] True if this object bubbles validation errors up from a field into its parent InputObject, if there is one.
|
137
|
-
attr_accessor :error_bubbling
|
138
|
-
|
139
|
-
# Single, long-lived instance of the provided subscriptions class, if there is one.
|
140
|
-
# @return [GraphQL::Subscriptions]
|
141
|
-
attr_accessor :subscriptions
|
142
|
-
|
143
|
-
# @return [MiddlewareChain] MiddlewareChain which is applied to fields during execution
|
144
|
-
attr_accessor :middleware
|
145
|
-
|
146
|
-
# @return [<#call(member, ctx)>] A callable for filtering members of the schema
|
147
|
-
# @see {Query.new} for query-specific filters with `except:`
|
148
|
-
attr_accessor :default_mask
|
149
|
-
|
150
|
-
# @see {GraphQL::Query::Context} The parent class of these classes
|
151
|
-
# @return [Class] Instantiated for each query
|
152
|
-
attr_accessor :context_class
|
153
|
-
|
154
|
-
# [Boolean] True if this object disables the introspection entry point fields
|
155
|
-
attr_accessor :disable_introspection_entry_points
|
156
|
-
|
157
|
-
class << self
|
158
|
-
attr_writer :default_execution_strategy
|
159
|
-
end
|
160
|
-
|
161
|
-
def default_filter
|
162
|
-
GraphQL::Filter.new(except: default_mask)
|
163
|
-
end
|
164
|
-
|
165
|
-
# @return [Array<#trace(key, data)>] Tracers applied to every query
|
166
|
-
# @see {Query#tracers} for query-specific tracers
|
167
|
-
attr_reader :tracers
|
168
|
-
|
169
|
-
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"].freeze
|
170
|
-
EMPTY_ARRAY = [].freeze
|
171
|
-
EMPTY_HASH = {}.freeze
|
172
|
-
|
173
|
-
attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
|
174
|
-
|
175
|
-
def initialize
|
176
|
-
@tracers = []
|
177
|
-
@definition_error = nil
|
178
|
-
@orphan_types = []
|
179
|
-
@directives = self.class.default_directives
|
180
|
-
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
181
|
-
@middleware = MiddlewareChain.new(final_step: GraphQL::Execution::Execute::FieldResolveStep)
|
182
|
-
@query_analyzers = []
|
183
|
-
@multiplex_analyzers = []
|
184
|
-
@resolve_type_proc = nil
|
185
|
-
@object_from_id_proc = nil
|
186
|
-
@id_from_object_proc = nil
|
187
|
-
@type_error_proc = DefaultTypeError
|
188
|
-
@parse_error_proc = DefaultParseError
|
189
|
-
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
190
|
-
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
191
|
-
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
192
|
-
@cursor_encoder = Base64Encoder
|
193
|
-
# Default to the built-in execution strategy:
|
194
|
-
@analysis_engine = GraphQL::Analysis
|
195
|
-
@query_execution_strategy = self.class.default_execution_strategy
|
196
|
-
@mutation_execution_strategy = self.class.default_execution_strategy
|
197
|
-
@subscription_execution_strategy = self.class.default_execution_strategy
|
198
|
-
@default_mask = GraphQL::Schema::NullMask
|
199
|
-
@rebuilding_artifacts = false
|
200
|
-
@context_class = GraphQL::Query::Context
|
201
|
-
@introspection_namespace = nil
|
202
|
-
@introspection_system = nil
|
203
|
-
@interpreter = false
|
204
|
-
@error_bubbling = false
|
205
|
-
@disable_introspection_entry_points = false
|
206
|
-
end
|
207
|
-
|
208
|
-
# @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
|
209
|
-
def interpreter?
|
210
|
-
@interpreter
|
211
|
-
end
|
212
|
-
|
213
|
-
# @api private
|
214
|
-
attr_writer :interpreter
|
215
|
-
|
216
|
-
def inspect
|
217
|
-
"#<#{self.class.name} ...>"
|
218
|
-
end
|
219
|
-
|
220
|
-
def initialize_copy(other)
|
221
|
-
super
|
222
|
-
@orphan_types = other.orphan_types.dup
|
223
|
-
@directives = other.directives.dup
|
224
|
-
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
225
|
-
@middleware = other.middleware.dup
|
226
|
-
@query_analyzers = other.query_analyzers.dup
|
227
|
-
@multiplex_analyzers = other.multiplex_analyzers.dup
|
228
|
-
@tracers = other.tracers.dup
|
229
|
-
@possible_types = GraphQL::Schema::PossibleTypes.new(self)
|
230
|
-
|
231
|
-
@lazy_methods = other.lazy_methods.dup
|
232
|
-
|
233
|
-
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
234
|
-
other.instrumenters.each do |key, insts|
|
235
|
-
@instrumenters[key].concat(insts)
|
77
|
+
class DuplicateNamesError < GraphQL::Error
|
78
|
+
attr_reader :duplicated_name
|
79
|
+
def initialize(duplicated_name:, duplicated_definition_1:, duplicated_definition_2:)
|
80
|
+
@duplicated_name = duplicated_name
|
81
|
+
super(
|
82
|
+
"Found two visible definitions for `#{duplicated_name}`: #{duplicated_definition_1}, #{duplicated_definition_2}"
|
83
|
+
)
|
236
84
|
end
|
237
|
-
|
238
|
-
if other.rescues?
|
239
|
-
@rescue_middleware = other.rescue_middleware
|
240
|
-
end
|
241
|
-
|
242
|
-
# This will be rebuilt when it's requested
|
243
|
-
# or during a later `define` call
|
244
|
-
@types = nil
|
245
|
-
@introspection_system = nil
|
246
|
-
end
|
247
|
-
|
248
|
-
def rescue_from(*args, &block)
|
249
|
-
rescue_middleware.rescue_from(*args, &block)
|
250
|
-
end
|
251
|
-
|
252
|
-
def remove_handler(*args, &block)
|
253
|
-
rescue_middleware.remove_handler(*args, &block)
|
254
|
-
end
|
255
|
-
|
256
|
-
def using_ast_analysis?
|
257
|
-
@analysis_engine == GraphQL::Analysis::AST
|
258
|
-
end
|
259
|
-
|
260
|
-
# For forwards-compatibility with Schema classes
|
261
|
-
alias :graphql_definition :itself
|
262
|
-
|
263
|
-
# Validate a query string according to this schema.
|
264
|
-
# @param string_or_document [String, GraphQL::Language::Nodes::Document]
|
265
|
-
# @return [Array<GraphQL::StaticValidation::Error >]
|
266
|
-
def validate(string_or_document, rules: nil, context: nil)
|
267
|
-
doc = if string_or_document.is_a?(String)
|
268
|
-
GraphQL.parse(string_or_document)
|
269
|
-
else
|
270
|
-
string_or_document
|
271
|
-
end
|
272
|
-
query = GraphQL::Query.new(self, document: doc, context: context)
|
273
|
-
validator_opts = { schema: self }
|
274
|
-
rules && (validator_opts[:rules] = rules)
|
275
|
-
validator = GraphQL::StaticValidation::Validator.new(validator_opts)
|
276
|
-
res = validator.validate(query)
|
277
|
-
res[:errors]
|
278
|
-
end
|
279
|
-
|
280
|
-
def define(**kwargs, &block)
|
281
|
-
super
|
282
|
-
ensure_defined
|
283
|
-
# Assert that all necessary configs are present:
|
284
|
-
validation_error = Validation.validate(self)
|
285
|
-
validation_error && raise(GraphQL::RequiredImplementationMissingError, validation_error)
|
286
|
-
rebuild_artifacts
|
287
|
-
|
288
|
-
@definition_error = nil
|
289
|
-
nil
|
290
|
-
rescue StandardError => err
|
291
|
-
if @raise_definition_error || err.is_a?(CyclicalDefinitionError) || err.is_a?(GraphQL::RequiredImplementationMissingError)
|
292
|
-
raise
|
293
|
-
else
|
294
|
-
# Raise this error _later_ to avoid messing with Rails constant loading
|
295
|
-
@definition_error = err
|
296
|
-
end
|
297
|
-
nil
|
298
85
|
end
|
299
86
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
@instrumenters[instrumentation_type] << instrumenter
|
306
|
-
if instrumentation_type == :field
|
307
|
-
rebuild_artifacts
|
87
|
+
class UnresolvedLateBoundTypeError < GraphQL::Error
|
88
|
+
attr_reader :type
|
89
|
+
def initialize(type:)
|
90
|
+
@type = type
|
91
|
+
super("Late bound type was never found: #{type.inspect}")
|
308
92
|
end
|
309
93
|
end
|
310
94
|
|
311
|
-
#
|
312
|
-
|
313
|
-
@root_types ||= begin
|
314
|
-
rebuild_artifacts
|
315
|
-
@root_types
|
316
|
-
end
|
317
|
-
end
|
95
|
+
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
96
|
+
class InvalidDocumentError < Error; end;
|
318
97
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
@
|
323
|
-
|
324
|
-
|
98
|
+
class << self
|
99
|
+
# Create schema with the result of an introspection query.
|
100
|
+
# @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
|
101
|
+
# @return [Class<GraphQL::Schema>] the schema described by `input`
|
102
|
+
def from_introspection(introspection_result)
|
103
|
+
GraphQL::Schema::Loader.load(introspection_result)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Create schema from an IDL schema or file containing an IDL definition.
|
107
|
+
# @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
|
108
|
+
# @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
|
109
|
+
# @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
|
110
|
+
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
111
|
+
# @return [Class] the schema described by `document`
|
112
|
+
def from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
|
113
|
+
# If the file ends in `.graphql` or `.graphqls`, treat it like a filepath
|
114
|
+
if definition_or_path.end_with?(".graphql") || definition_or_path.end_with?(".graphqls")
|
115
|
+
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
116
|
+
self,
|
117
|
+
definition_or_path,
|
118
|
+
default_resolve: default_resolve,
|
119
|
+
parser: parser,
|
120
|
+
using: using,
|
121
|
+
)
|
122
|
+
else
|
123
|
+
GraphQL::Schema::BuildFromDefinition.from_definition(
|
124
|
+
self,
|
125
|
+
definition_or_path,
|
126
|
+
default_resolve: default_resolve,
|
127
|
+
parser: parser,
|
128
|
+
using: using,
|
129
|
+
)
|
130
|
+
end
|
325
131
|
end
|
326
|
-
end
|
327
132
|
|
328
|
-
|
329
|
-
|
330
|
-
@introspection_system ||= begin
|
331
|
-
rebuild_artifacts
|
332
|
-
@introspection_system
|
133
|
+
def deprecated_graphql_definition
|
134
|
+
graphql_definition(silence_deprecation_warning: true)
|
333
135
|
end
|
334
|
-
end
|
335
136
|
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
def references_to(type_name)
|
340
|
-
rebuild_artifacts unless defined?(@type_reference_map)
|
341
|
-
@type_reference_map.fetch(type_name, [])
|
342
|
-
end
|
343
|
-
|
344
|
-
# Returns a list of Union types in which a type is a member
|
345
|
-
# @param type [GraphQL::ObjectType]
|
346
|
-
# @return [Array<GraphQL::UnionType>] list of union types of which the type is a member
|
347
|
-
def union_memberships(type)
|
348
|
-
rebuild_artifacts unless defined?(@union_memberships)
|
349
|
-
@union_memberships.fetch(type.name, [])
|
350
|
-
end
|
351
|
-
|
352
|
-
# Execute a query on itself. Raises an error if the schema definition is invalid.
|
353
|
-
# @see {Query#initialize} for arguments.
|
354
|
-
# @return [Hash] query result, ready to be serialized as JSON
|
355
|
-
def execute(query_str = nil, **kwargs)
|
356
|
-
if query_str
|
357
|
-
kwargs[:query] = query_str
|
358
|
-
end
|
359
|
-
# Some of the query context _should_ be passed to the multiplex, too
|
360
|
-
multiplex_context = if (ctx = kwargs[:context])
|
361
|
-
{
|
362
|
-
backtrace: ctx[:backtrace],
|
363
|
-
tracers: ctx[:tracers],
|
364
|
-
}
|
365
|
-
else
|
366
|
-
{}
|
137
|
+
# @return [GraphQL::Subscriptions]
|
138
|
+
def subscriptions(inherited: true)
|
139
|
+
defined?(@subscriptions) ? @subscriptions : (inherited ? find_inherited_value(:subscriptions, nil) : nil)
|
367
140
|
end
|
368
|
-
# Since we're running one query, don't run a multiplex-level complexity analyzer
|
369
|
-
all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
|
370
|
-
all_results[0]
|
371
|
-
end
|
372
141
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
# queries = [
|
377
|
-
# { query: params[:query_1], variables: params[:variables_1], context: context },
|
378
|
-
# { query: params[:query_2], variables: params[:variables_2], context: context },
|
379
|
-
# ]
|
380
|
-
# results = MySchema.multiplex(queries)
|
381
|
-
# render json: {
|
382
|
-
# result_1: results[0],
|
383
|
-
# result_2: results[1],
|
384
|
-
# }
|
385
|
-
#
|
386
|
-
# @see {Query#initialize} for query keyword arguments
|
387
|
-
# @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
|
388
|
-
# @param queries [Array<Hash>] Keyword arguments for each query
|
389
|
-
# @param context [Hash] Multiplex-level context
|
390
|
-
# @return [Array<Hash>] One result for each query in the input
|
391
|
-
def multiplex(queries, **kwargs)
|
392
|
-
with_definition_error_check {
|
393
|
-
GraphQL::Execution::Multiplex.run_all(self, queries, **kwargs)
|
394
|
-
}
|
395
|
-
end
|
396
|
-
|
397
|
-
# Search for a schema member using a string path
|
398
|
-
# @example Finding a Field
|
399
|
-
# Schema.find("Ensemble.musicians")
|
400
|
-
#
|
401
|
-
# @see {GraphQL::Schema::Finder} for more examples
|
402
|
-
# @param path [String] A dot-separated path to the member
|
403
|
-
# @raise [Schema::Finder::MemberNotFoundError] if path could not be found
|
404
|
-
# @return [GraphQL::BaseType, GraphQL::Field, GraphQL::Argument, GraphQL::Directive] A GraphQL Schema Member
|
405
|
-
def find(path)
|
406
|
-
rebuild_artifacts unless defined?(@finder)
|
407
|
-
@find_cache[path] ||= @finder.find(path)
|
408
|
-
end
|
142
|
+
def subscriptions=(new_implementation)
|
143
|
+
@subscriptions = new_implementation
|
144
|
+
end
|
409
145
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
parent_type.name
|
421
|
-
when String
|
422
|
-
parent_type
|
423
|
-
else
|
424
|
-
raise "Unexpected parent_type: #{parent_type}"
|
146
|
+
def trace_class(new_class = nil)
|
147
|
+
if new_class
|
148
|
+
@trace_class = new_class
|
149
|
+
elsif !defined?(@trace_class)
|
150
|
+
parent_trace_class = if superclass.respond_to?(:trace_class)
|
151
|
+
superclass.trace_class
|
152
|
+
else
|
153
|
+
GraphQL::Tracing::Trace
|
154
|
+
end
|
155
|
+
@trace_class = Class.new(parent_trace_class)
|
425
156
|
end
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
157
|
+
@trace_class
|
158
|
+
end
|
159
|
+
|
160
|
+
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
161
|
+
# @see {#as_json}
|
162
|
+
# @return [String]
|
163
|
+
def to_json(**args)
|
164
|
+
JSON.pretty_generate(as_json(**args))
|
165
|
+
end
|
166
|
+
|
167
|
+
# Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
|
168
|
+
# @param context [Hash]
|
169
|
+
# @param only [<#call(member, ctx)>]
|
170
|
+
# @param except [<#call(member, ctx)>]
|
171
|
+
# @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
|
172
|
+
# @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
|
173
|
+
# @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
|
174
|
+
# @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
|
175
|
+
# @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
|
176
|
+
# @return [Hash] GraphQL result
|
177
|
+
def as_json(only: nil, except: nil, context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
|
178
|
+
introspection_query = Introspection.query(
|
179
|
+
include_deprecated_args: include_deprecated_args,
|
180
|
+
include_schema_description: include_schema_description,
|
181
|
+
include_is_repeatable: include_is_repeatable,
|
182
|
+
include_is_one_of: include_is_one_of,
|
183
|
+
include_specified_by_url: include_specified_by_url,
|
184
|
+
)
|
185
|
+
|
186
|
+
execute(introspection_query, only: only, except: except, context: context).to_h
|
187
|
+
end
|
188
|
+
|
189
|
+
# Return the GraphQL IDL for the schema
|
190
|
+
# @param context [Hash]
|
191
|
+
# @param only [<#call(member, ctx)>]
|
192
|
+
# @param except [<#call(member, ctx)>]
|
193
|
+
# @return [String]
|
194
|
+
def to_definition(only: nil, except: nil, context: {})
|
195
|
+
GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Return the GraphQL::Language::Document IDL AST for the schema
|
199
|
+
# @return [GraphQL::Language::Document]
|
200
|
+
def to_document
|
201
|
+
GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
|
202
|
+
end
|
203
|
+
|
204
|
+
# @return [String, nil]
|
205
|
+
def description(new_description = nil)
|
206
|
+
if new_description
|
207
|
+
@description = new_description
|
208
|
+
elsif defined?(@description)
|
209
|
+
@description
|
434
210
|
else
|
435
|
-
nil
|
211
|
+
find_inherited_value(:description, nil)
|
436
212
|
end
|
437
213
|
end
|
438
|
-
end
|
439
|
-
|
440
|
-
# Fields for this type, after instrumentation is applied
|
441
|
-
# @return [Hash<String, GraphQL::Field>]
|
442
|
-
def get_fields(type)
|
443
|
-
@instrumented_field_map[type.graphql_name]
|
444
|
-
end
|
445
214
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
# @param context [GraphQL::Query::Context] The context for the current query
|
453
|
-
# @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
|
454
|
-
def possible_types(type_defn, context = GraphQL::Query::NullContext)
|
455
|
-
@possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
|
456
|
-
@possible_types.possible_types(type_defn, context)
|
457
|
-
end
|
458
|
-
|
459
|
-
# @see [GraphQL::Schema::Warden] Resticted access to root types
|
460
|
-
# @return [GraphQL::ObjectType, nil]
|
461
|
-
def root_type_for_operation(operation)
|
462
|
-
case operation
|
463
|
-
when "query"
|
464
|
-
query
|
465
|
-
when "mutation"
|
466
|
-
mutation
|
467
|
-
when "subscription"
|
468
|
-
subscription
|
469
|
-
else
|
470
|
-
raise ArgumentError, "unknown operation type: #{operation}"
|
215
|
+
def find(path)
|
216
|
+
if !@finder
|
217
|
+
@find_cache = {}
|
218
|
+
@finder ||= GraphQL::Schema::Finder.new(self)
|
219
|
+
end
|
220
|
+
@find_cache[path] ||= @finder.find(path)
|
471
221
|
end
|
472
|
-
end
|
473
222
|
|
474
|
-
|
475
|
-
|
476
|
-
when "query"
|
477
|
-
query_execution_strategy
|
478
|
-
when "mutation"
|
479
|
-
mutation_execution_strategy
|
480
|
-
when "subscription"
|
481
|
-
subscription_execution_strategy
|
482
|
-
else
|
483
|
-
raise ArgumentError, "unknown operation type: #{operation}"
|
223
|
+
def default_filter
|
224
|
+
GraphQL::Filter.new(except: default_mask)
|
484
225
|
end
|
485
|
-
end
|
486
226
|
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
# @param ctx [GraphQL::Query::Context] The context for the current query
|
493
|
-
# @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
|
494
|
-
def resolve_type(type, object, ctx = :__undefined__)
|
495
|
-
check_resolved_type(type, object, ctx) do |ok_type, ok_object, ok_ctx|
|
496
|
-
if @resolve_type_proc.nil?
|
497
|
-
raise(GraphQL::RequiredImplementationMissingError, "Can't determine GraphQL type for: #{ok_object.inspect}, define `resolve_type (type, obj, ctx) -> { ... }` inside `Schema.define`.")
|
227
|
+
def default_mask(new_mask = nil)
|
228
|
+
if new_mask
|
229
|
+
@own_default_mask = new_mask
|
230
|
+
else
|
231
|
+
@own_default_mask || find_inherited_value(:default_mask, Schema::NullMask)
|
498
232
|
end
|
499
|
-
@resolve_type_proc.call(ok_type, ok_object, ok_ctx)
|
500
|
-
end
|
501
|
-
end
|
502
|
-
|
503
|
-
# This is a compatibility hack so that instance-level and class-level
|
504
|
-
# methods can get correctness checks without calling one another
|
505
|
-
# @api private
|
506
|
-
def check_resolved_type(type, object, ctx = :__undefined__)
|
507
|
-
if ctx == :__undefined__
|
508
|
-
# Old method signature
|
509
|
-
ctx = object
|
510
|
-
object = type
|
511
|
-
type = nil
|
512
233
|
end
|
513
234
|
|
514
|
-
|
515
|
-
|
235
|
+
def static_validator
|
236
|
+
GraphQL::StaticValidation::Validator.new(schema: self)
|
516
237
|
end
|
517
238
|
|
518
|
-
|
519
|
-
|
239
|
+
def use(plugin, **kwargs)
|
240
|
+
if kwargs.any?
|
241
|
+
plugin.use(self, **kwargs)
|
242
|
+
else
|
243
|
+
plugin.use(self)
|
244
|
+
end
|
245
|
+
own_plugins << [plugin, kwargs]
|
520
246
|
end
|
521
247
|
|
522
|
-
|
523
|
-
|
524
|
-
type_result = if type_proc
|
525
|
-
type_proc.call(object, ctx)
|
526
|
-
else
|
527
|
-
yield(type, object, ctx)
|
248
|
+
def plugins
|
249
|
+
find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
|
528
250
|
end
|
529
251
|
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
if
|
538
|
-
|
539
|
-
|
252
|
+
# Build a map of `{ name => type }` and return it
|
253
|
+
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
254
|
+
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
255
|
+
def types(context = GraphQL::Query::NullContext)
|
256
|
+
all_types = non_introspection_types.merge(introspection_system.types)
|
257
|
+
visible_types = {}
|
258
|
+
all_types.each do |k, v|
|
259
|
+
visible_types[k] =if v.is_a?(Array)
|
260
|
+
visible_t = nil
|
261
|
+
v.each do |t|
|
262
|
+
if t.visible?(context)
|
263
|
+
if visible_t.nil?
|
264
|
+
visible_t = t
|
265
|
+
else
|
266
|
+
raise DuplicateNamesError.new(
|
267
|
+
duplicated_name: k, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
268
|
+
)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
visible_t
|
540
273
|
else
|
541
|
-
|
274
|
+
v
|
542
275
|
end
|
543
276
|
end
|
277
|
+
visible_types
|
544
278
|
end
|
545
|
-
end
|
546
279
|
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
280
|
+
# @param type_name [String]
|
281
|
+
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
282
|
+
def get_type(type_name, context = GraphQL::Query::NullContext)
|
283
|
+
local_entry = own_types[type_name]
|
284
|
+
type_defn = case local_entry
|
285
|
+
when nil
|
286
|
+
nil
|
287
|
+
when Array
|
288
|
+
visible_t = nil
|
289
|
+
warden = Warden.from_context(context)
|
290
|
+
local_entry.each do |t|
|
291
|
+
if warden.visible_type?(t, context)
|
292
|
+
if visible_t.nil?
|
293
|
+
visible_t = t
|
294
|
+
else
|
295
|
+
raise DuplicateNamesError.new(
|
296
|
+
duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
297
|
+
)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
visible_t
|
302
|
+
when Module
|
303
|
+
local_entry
|
304
|
+
else
|
305
|
+
raise "Invariant: unexpected own_types[#{type_name.inspect}]: #{local_entry.inspect}"
|
306
|
+
end
|
551
307
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
# @return [Any] The application object identified by `id`
|
556
|
-
def object_from_id(id, ctx)
|
557
|
-
if @object_from_id_proc.nil?
|
558
|
-
raise(GraphQL::RequiredImplementationMissingError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
|
559
|
-
else
|
560
|
-
@object_from_id_proc.call(id, ctx)
|
308
|
+
type_defn ||
|
309
|
+
introspection_system.types[type_name] || # todo context-specific introspection?
|
310
|
+
(superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
|
561
311
|
end
|
562
|
-
end
|
563
312
|
|
564
|
-
|
565
|
-
|
566
|
-
@object_from_id_proc = new_proc
|
567
|
-
end
|
313
|
+
# @api private
|
314
|
+
attr_writer :connections
|
568
315
|
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
# }
|
584
|
-
#
|
585
|
-
# @see {DefaultTypeError} is the default behavior.
|
586
|
-
# @param err [GraphQL::TypeError] The error encountered during execution
|
587
|
-
# @param ctx [GraphQL::Query::Context] The context for the field where the error occurred
|
588
|
-
# @return void
|
589
|
-
def type_error(err, ctx)
|
590
|
-
@type_error_proc.call(err, ctx)
|
591
|
-
end
|
592
|
-
|
593
|
-
# @param new_proc [#call] A new callable for handling type errors during execution
|
594
|
-
def type_error=(new_proc)
|
595
|
-
@type_error_proc = new_proc
|
596
|
-
end
|
597
|
-
|
598
|
-
# Can't delegate to `class`
|
599
|
-
alias :_schema_class :class
|
600
|
-
def_delegators :_schema_class, :visible?, :accessible?, :authorized?, :unauthorized_object, :unauthorized_field, :inaccessible_fields
|
601
|
-
def_delegators :_schema_class, :directive
|
602
|
-
def_delegators :_schema_class, :error_handler
|
603
|
-
|
604
|
-
# A function to call when {#execute} receives an invalid query string
|
605
|
-
#
|
606
|
-
# @see {DefaultParseError} is the default behavior.
|
607
|
-
# @param err [GraphQL::ParseError] The error encountered during parsing
|
608
|
-
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
609
|
-
# @return void
|
610
|
-
def parse_error(err, ctx)
|
611
|
-
@parse_error_proc.call(err, ctx)
|
612
|
-
end
|
613
|
-
|
614
|
-
# @param new_proc [#call] A new callable for handling parse errors during execution
|
615
|
-
def parse_error=(new_proc)
|
616
|
-
@parse_error_proc = new_proc
|
617
|
-
end
|
618
|
-
|
619
|
-
# Get a unique identifier from this object
|
620
|
-
# @param object [Any] An application object
|
621
|
-
# @param type [GraphQL::BaseType] The current type definition
|
622
|
-
# @param ctx [GraphQL::Query::Context] the context for the current query
|
623
|
-
# @return [String] a unique identifier for `object` which clients can use to refetch it
|
624
|
-
def id_from_object(object, type, ctx)
|
625
|
-
if @id_from_object_proc.nil?
|
626
|
-
raise(GraphQL::RequiredImplementationMissingError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
|
627
|
-
else
|
628
|
-
@id_from_object_proc.call(object, type, ctx)
|
316
|
+
# @return [GraphQL::Pagination::Connections] if installed
|
317
|
+
def connections
|
318
|
+
if defined?(@connections)
|
319
|
+
@connections
|
320
|
+
else
|
321
|
+
inherited_connections = find_inherited_value(:connections, nil)
|
322
|
+
# This schema is part of an inheritance chain which is using new connections,
|
323
|
+
# make a new instance, so we don't pollute the upstream one.
|
324
|
+
if inherited_connections
|
325
|
+
@connections = Pagination::Connections.new(schema: self)
|
326
|
+
else
|
327
|
+
nil
|
328
|
+
end
|
329
|
+
end
|
629
330
|
end
|
630
|
-
end
|
631
|
-
|
632
|
-
# @param new_proc [#call] A new callable for generating unique IDs
|
633
|
-
def id_from_object=(new_proc)
|
634
|
-
@id_from_object_proc = new_proc
|
635
|
-
end
|
636
|
-
|
637
|
-
# Create schema with the result of an introspection query.
|
638
|
-
# @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
|
639
|
-
# @return [GraphQL::Schema] the schema described by `input`
|
640
|
-
def self.from_introspection(introspection_result)
|
641
|
-
GraphQL::Schema::Loader.load(introspection_result)
|
642
|
-
end
|
643
|
-
|
644
|
-
# Create schema from an IDL schema or file containing an IDL definition.
|
645
|
-
# @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
|
646
|
-
# @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
|
647
|
-
# @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
|
648
|
-
# @return [GraphQL::Schema] the schema described by `document`
|
649
|
-
def self.from_definition(definition_or_path, default_resolve: BuildFromDefinition::DefaultResolve, parser: BuildFromDefinition::DefaultParser)
|
650
|
-
# If the file ends in `.graphql`, treat it like a filepath
|
651
|
-
definition = if definition_or_path.end_with?(".graphql")
|
652
|
-
File.read(definition_or_path)
|
653
|
-
else
|
654
|
-
definition_or_path
|
655
|
-
end
|
656
|
-
GraphQL::Schema::BuildFromDefinition.from_definition(definition, default_resolve: default_resolve, parser: parser)
|
657
|
-
end
|
658
|
-
|
659
|
-
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
660
|
-
class InvalidDocumentError < Error; end;
|
661
|
-
|
662
|
-
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
|
663
|
-
def lazy_method_name(obj)
|
664
|
-
@lazy_methods.get(obj)
|
665
|
-
end
|
666
331
|
|
667
|
-
|
668
|
-
|
669
|
-
!!lazy_method_name(obj)
|
670
|
-
end
|
671
|
-
|
672
|
-
# Return the GraphQL IDL for the schema
|
673
|
-
# @param context [Hash]
|
674
|
-
# @param only [<#call(member, ctx)>]
|
675
|
-
# @param except [<#call(member, ctx)>]
|
676
|
-
# @return [String]
|
677
|
-
def to_definition(only: nil, except: nil, context: {})
|
678
|
-
GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
|
679
|
-
end
|
680
|
-
|
681
|
-
# Return the GraphQL::Language::Document IDL AST for the schema
|
682
|
-
# @return [GraphQL::Language::Document]
|
683
|
-
def to_document
|
684
|
-
GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
|
685
|
-
end
|
686
|
-
|
687
|
-
# Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
|
688
|
-
# @param context [Hash]
|
689
|
-
# @param only [<#call(member, ctx)>]
|
690
|
-
# @param except [<#call(member, ctx)>]
|
691
|
-
# @return [Hash] GraphQL result
|
692
|
-
def as_json(only: nil, except: nil, context: {})
|
693
|
-
execute(Introspection::INTROSPECTION_QUERY, only: only, except: except, context: context).to_h
|
694
|
-
end
|
695
|
-
|
696
|
-
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
697
|
-
# @see {#as_json}
|
698
|
-
# @return [String]
|
699
|
-
def to_json(*args)
|
700
|
-
JSON.pretty_generate(as_json(*args))
|
701
|
-
end
|
702
|
-
|
703
|
-
class << self
|
704
|
-
extend Forwardable
|
705
|
-
# For compatibility, these methods all:
|
706
|
-
# - Cause the Schema instance to be created, if it hasn't been created yet
|
707
|
-
# - Delegate to that instance
|
708
|
-
# Eventually, the methods will be moved into this class, removing the need for the singleton.
|
709
|
-
def_delegators :graphql_definition,
|
710
|
-
# Schema structure
|
711
|
-
:as_json, :to_json, :to_document, :to_definition, :ast_node,
|
712
|
-
# Execution
|
713
|
-
:execute, :multiplex,
|
714
|
-
:static_validator, :introspection_system,
|
715
|
-
:query_analyzers, :tracers, :instrumenters,
|
716
|
-
:execution_strategy_for_operation,
|
717
|
-
:validate, :multiplex_analyzers, :lazy?, :lazy_method_name, :after_lazy, :sync_lazy,
|
718
|
-
# Configuration
|
719
|
-
:analysis_engine, :analysis_engine=, :using_ast_analysis?, :interpreter?,
|
720
|
-
:max_complexity=, :max_depth=,
|
721
|
-
:error_bubbling=,
|
722
|
-
:metadata,
|
723
|
-
:default_mask,
|
724
|
-
:default_filter, :redefine,
|
725
|
-
:id_from_object_proc, :object_from_id_proc,
|
726
|
-
:id_from_object=, :object_from_id=,
|
727
|
-
:remove_handler,
|
728
|
-
# Members
|
729
|
-
:types, :get_fields, :find,
|
730
|
-
:root_type_for_operation,
|
731
|
-
:subscriptions,
|
732
|
-
:union_memberships,
|
733
|
-
:get_field, :root_types, :references_to, :type_from_ast,
|
734
|
-
:possible_types,
|
735
|
-
:disable_introspection_entry_points=
|
736
|
-
|
737
|
-
def graphql_definition
|
738
|
-
@graphql_definition ||= to_graphql
|
739
|
-
end
|
740
|
-
|
741
|
-
def use(plugin, options = {})
|
742
|
-
own_plugins << [plugin, options]
|
332
|
+
def new_connections?
|
333
|
+
!!connections
|
743
334
|
end
|
744
335
|
|
745
|
-
def
|
746
|
-
|
336
|
+
def query(new_query_object = nil)
|
337
|
+
if new_query_object
|
338
|
+
if @query_object
|
339
|
+
raise GraphQL::Error, "Second definition of `query(...)` (#{new_query_object.inspect}) is invalid, already configured with #{@query_object.inspect}"
|
340
|
+
else
|
341
|
+
@query_object = new_query_object
|
342
|
+
add_type_and_traverse(new_query_object, root: true)
|
343
|
+
nil
|
344
|
+
end
|
345
|
+
else
|
346
|
+
@query_object || find_inherited_value(:query)
|
347
|
+
end
|
747
348
|
end
|
748
349
|
|
749
|
-
def
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
schema_defn.max_depth = max_depth
|
758
|
-
schema_defn.default_max_page_size = default_max_page_size
|
759
|
-
schema_defn.orphan_types = orphan_types
|
760
|
-
schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
|
761
|
-
|
762
|
-
prepped_dirs = {}
|
763
|
-
directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
|
764
|
-
schema_defn.directives = prepped_dirs
|
765
|
-
schema_defn.introspection_namespace = introspection
|
766
|
-
schema_defn.resolve_type = method(:resolve_type)
|
767
|
-
schema_defn.object_from_id = method(:object_from_id)
|
768
|
-
schema_defn.id_from_object = method(:id_from_object)
|
769
|
-
schema_defn.type_error = method(:type_error)
|
770
|
-
schema_defn.context_class = context_class
|
771
|
-
schema_defn.cursor_encoder = cursor_encoder
|
772
|
-
schema_defn.tracers.concat(tracers)
|
773
|
-
schema_defn.query_analyzers.concat(query_analyzers)
|
774
|
-
|
775
|
-
schema_defn.middleware.concat(all_middleware)
|
776
|
-
schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
|
777
|
-
schema_defn.query_execution_strategy = query_execution_strategy
|
778
|
-
schema_defn.mutation_execution_strategy = mutation_execution_strategy
|
779
|
-
schema_defn.subscription_execution_strategy = subscription_execution_strategy
|
780
|
-
all_instrumenters.each do |step, insts|
|
781
|
-
insts.each do |inst|
|
782
|
-
schema_defn.instrumenters[step] << inst
|
350
|
+
def mutation(new_mutation_object = nil)
|
351
|
+
if new_mutation_object
|
352
|
+
if @mutation_object
|
353
|
+
raise GraphQL::Error, "Second definition of `mutation(...)` (#{new_mutation_object.inspect}) is invalid, already configured with #{@mutation_object.inspect}"
|
354
|
+
else
|
355
|
+
@mutation_object = new_mutation_object
|
356
|
+
add_type_and_traverse(new_mutation_object, root: true)
|
357
|
+
nil
|
783
358
|
end
|
359
|
+
else
|
360
|
+
@mutation_object || find_inherited_value(:mutation)
|
784
361
|
end
|
785
|
-
|
786
|
-
|
362
|
+
end
|
363
|
+
|
364
|
+
def subscription(new_subscription_object = nil)
|
365
|
+
if new_subscription_object
|
366
|
+
if @subscription_object
|
367
|
+
raise GraphQL::Error, "Second definition of `subscription(...)` (#{new_subscription_object.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
|
368
|
+
else
|
369
|
+
@subscription_object = new_subscription_object
|
370
|
+
add_subscription_extension_if_necessary
|
371
|
+
add_type_and_traverse(new_subscription_object, root: true)
|
372
|
+
nil
|
373
|
+
end
|
374
|
+
else
|
375
|
+
@subscription_object || find_inherited_value(:subscription)
|
787
376
|
end
|
788
|
-
|
789
|
-
|
377
|
+
end
|
378
|
+
|
379
|
+
# @see [GraphQL::Schema::Warden] Restricted access to root types
|
380
|
+
# @return [GraphQL::ObjectType, nil]
|
381
|
+
def root_type_for_operation(operation)
|
382
|
+
case operation
|
383
|
+
when "query"
|
384
|
+
query
|
385
|
+
when "mutation"
|
386
|
+
mutation
|
387
|
+
when "subscription"
|
388
|
+
subscription
|
389
|
+
else
|
390
|
+
raise ArgumentError, "unknown operation type: #{operation}"
|
790
391
|
end
|
392
|
+
end
|
791
393
|
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
394
|
+
def root_types
|
395
|
+
@root_types
|
396
|
+
end
|
397
|
+
|
398
|
+
# @param type [Module] The type definition whose possible types you want to see
|
399
|
+
# @return [Hash<String, Module>] All possible types, if no `type` is given.
|
400
|
+
# @return [Array<Module>] Possible types for `type`, if it's given.
|
401
|
+
def possible_types(type = nil, context = GraphQL::Query::NullContext)
|
402
|
+
if type
|
403
|
+
# TODO duck-typing `.possible_types` would probably be nicer here
|
404
|
+
if type.kind.union?
|
405
|
+
type.possible_types(context: context)
|
406
|
+
else
|
407
|
+
stored_possible_types = own_possible_types[type.graphql_name]
|
408
|
+
visible_possible_types = if stored_possible_types && type.kind.interface?
|
409
|
+
stored_possible_types.select do |possible_type|
|
410
|
+
possible_type.interfaces(context).include?(type)
|
801
411
|
end
|
412
|
+
else
|
413
|
+
stored_possible_types
|
802
414
|
end
|
415
|
+
visible_possible_types ||
|
416
|
+
introspection_system.possible_types[type.graphql_name] ||
|
417
|
+
(
|
418
|
+
superclass.respond_to?(:possible_types) ?
|
419
|
+
superclass.possible_types(type, context) :
|
420
|
+
EMPTY_ARRAY
|
421
|
+
)
|
803
422
|
end
|
423
|
+
else
|
424
|
+
find_inherited_value(:possible_types, EMPTY_HASH)
|
425
|
+
.merge(own_possible_types)
|
426
|
+
.merge(introspection_system.possible_types)
|
804
427
|
end
|
805
|
-
|
806
|
-
|
807
|
-
|
428
|
+
end
|
429
|
+
|
430
|
+
def union_memberships(type = nil)
|
431
|
+
if type
|
432
|
+
own_um = own_union_memberships.fetch(type.graphql_name, EMPTY_ARRAY)
|
433
|
+
inherited_um = find_inherited_value(:union_memberships, EMPTY_HASH).fetch(type.graphql_name, EMPTY_ARRAY)
|
434
|
+
own_um + inherited_um
|
435
|
+
else
|
436
|
+
joined_um = own_union_memberships.dup
|
437
|
+
find_inherited_value(:union_memberhips, EMPTY_HASH).each do |k, v|
|
438
|
+
um = joined_um[k] ||= []
|
439
|
+
um.concat(v)
|
440
|
+
end
|
441
|
+
joined_um
|
808
442
|
end
|
809
|
-
|
443
|
+
end
|
810
444
|
|
811
|
-
|
445
|
+
# @api private
|
446
|
+
# @see GraphQL::Dataloader
|
447
|
+
def dataloader_class
|
448
|
+
@dataloader_class || GraphQL::Dataloader::NullDataloader
|
812
449
|
end
|
813
450
|
|
814
|
-
|
815
|
-
|
816
|
-
|
451
|
+
attr_writer :dataloader_class
|
452
|
+
|
453
|
+
def references_to(to_type = nil, from: nil)
|
454
|
+
@own_references_to ||= Hash.new { |h, k| h[k] = [] }
|
455
|
+
if to_type
|
456
|
+
if !to_type.is_a?(String)
|
457
|
+
to_type = to_type.graphql_name
|
458
|
+
end
|
459
|
+
|
460
|
+
if from
|
461
|
+
@own_references_to[to_type] << from
|
462
|
+
else
|
463
|
+
own_refs = @own_references_to[to_type]
|
464
|
+
inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
|
465
|
+
own_refs + inherited_refs
|
466
|
+
end
|
817
467
|
else
|
818
|
-
|
819
|
-
|
468
|
+
# `@own_references_to` can be quite large for big schemas,
|
469
|
+
# and generally speaking, we won't inherit any values.
|
470
|
+
# So optimize the most common case -- don't create a duplicate Hash.
|
471
|
+
inherited_value = find_inherited_value(:references_to, EMPTY_HASH)
|
472
|
+
if inherited_value.any?
|
473
|
+
inherited_value.merge(@own_references_to)
|
474
|
+
else
|
475
|
+
@own_references_to
|
476
|
+
end
|
820
477
|
end
|
821
478
|
end
|
822
479
|
|
823
|
-
def
|
824
|
-
|
825
|
-
|
480
|
+
def type_from_ast(ast_node, context: nil)
|
481
|
+
type_owner = context ? context.warden : self
|
482
|
+
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
483
|
+
end
|
484
|
+
|
485
|
+
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
|
486
|
+
parent_type = case type_or_name
|
487
|
+
when LateBoundType
|
488
|
+
get_type(type_or_name.name, context)
|
489
|
+
when String
|
490
|
+
get_type(type_or_name, context)
|
491
|
+
when Module
|
492
|
+
type_or_name
|
826
493
|
else
|
827
|
-
|
828
|
-
mutation_object.respond_to?(:graphql_definition) ? mutation_object.graphql_definition : mutation_object
|
494
|
+
raise GraphQL::InvariantError, "Unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
|
829
495
|
end
|
830
|
-
end
|
831
496
|
|
832
|
-
|
833
|
-
|
834
|
-
|
497
|
+
if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
|
498
|
+
field
|
499
|
+
elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
|
500
|
+
entry_point_field
|
501
|
+
elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
|
502
|
+
dynamic_field
|
835
503
|
else
|
836
|
-
|
837
|
-
subscription_object.respond_to?(:graphql_definition) ? subscription_object.graphql_definition : subscription_object
|
504
|
+
nil
|
838
505
|
end
|
839
506
|
end
|
840
507
|
|
508
|
+
def get_fields(type, context = GraphQL::Query::NullContext)
|
509
|
+
type.fields(context)
|
510
|
+
end
|
511
|
+
|
841
512
|
def introspection(new_introspection_namespace = nil)
|
842
513
|
if new_introspection_namespace
|
843
514
|
@introspection = new_introspection_namespace
|
515
|
+
# reset this cached value:
|
516
|
+
@introspection_system = nil
|
844
517
|
else
|
845
518
|
@introspection || find_inherited_value(:introspection)
|
846
519
|
end
|
847
520
|
end
|
848
521
|
|
522
|
+
def introspection_system
|
523
|
+
if !@introspection_system
|
524
|
+
@introspection_system = Schema::IntrospectionSystem.new(self)
|
525
|
+
@introspection_system.resolve_late_bindings
|
526
|
+
end
|
527
|
+
@introspection_system
|
528
|
+
end
|
529
|
+
|
849
530
|
def cursor_encoder(new_encoder = nil)
|
850
531
|
if new_encoder
|
851
532
|
@cursor_encoder = new_encoder
|
@@ -861,6 +542,14 @@ module GraphQL
|
|
861
542
|
end
|
862
543
|
end
|
863
544
|
|
545
|
+
def default_page_size(new_default_page_size = nil)
|
546
|
+
if new_default_page_size
|
547
|
+
@default_page_size = new_default_page_size
|
548
|
+
else
|
549
|
+
@default_page_size || find_inherited_value(:default_page_size)
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
864
553
|
def query_execution_strategy(new_query_execution_strategy = nil)
|
865
554
|
if new_query_execution_strategy
|
866
555
|
@query_execution_strategy = new_query_execution_strategy
|
@@ -885,14 +574,75 @@ module GraphQL
|
|
885
574
|
end
|
886
575
|
end
|
887
576
|
|
577
|
+
attr_writer :validate_timeout
|
578
|
+
|
579
|
+
def validate_timeout(new_validate_timeout = nil)
|
580
|
+
if new_validate_timeout
|
581
|
+
@validate_timeout = new_validate_timeout
|
582
|
+
elsif defined?(@validate_timeout)
|
583
|
+
@validate_timeout
|
584
|
+
else
|
585
|
+
find_inherited_value(:validate_timeout)
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
# Validate a query string according to this schema.
|
590
|
+
# @param string_or_document [String, GraphQL::Language::Nodes::Document]
|
591
|
+
# @return [Array<GraphQL::StaticValidation::Error >]
|
592
|
+
def validate(string_or_document, rules: nil, context: nil)
|
593
|
+
doc = if string_or_document.is_a?(String)
|
594
|
+
GraphQL.parse(string_or_document)
|
595
|
+
else
|
596
|
+
string_or_document
|
597
|
+
end
|
598
|
+
query = GraphQL::Query.new(self, document: doc, context: context)
|
599
|
+
validator_opts = { schema: self }
|
600
|
+
rules && (validator_opts[:rules] = rules)
|
601
|
+
validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
|
602
|
+
res = validator.validate(query, timeout: validate_timeout, max_errors: validate_max_errors)
|
603
|
+
res[:errors]
|
604
|
+
end
|
605
|
+
|
606
|
+
attr_writer :validate_max_errors
|
607
|
+
|
608
|
+
def validate_max_errors(new_validate_max_errors = nil)
|
609
|
+
if new_validate_max_errors
|
610
|
+
@validate_max_errors = new_validate_max_errors
|
611
|
+
elsif defined?(@validate_max_errors)
|
612
|
+
@validate_max_errors
|
613
|
+
else
|
614
|
+
find_inherited_value(:validate_max_errors)
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
attr_writer :max_complexity
|
619
|
+
|
888
620
|
def max_complexity(max_complexity = nil)
|
889
621
|
if max_complexity
|
890
622
|
@max_complexity = max_complexity
|
623
|
+
elsif defined?(@max_complexity)
|
624
|
+
@max_complexity
|
891
625
|
else
|
892
|
-
|
626
|
+
find_inherited_value(:max_complexity)
|
893
627
|
end
|
894
628
|
end
|
895
629
|
|
630
|
+
attr_writer :analysis_engine
|
631
|
+
|
632
|
+
def analysis_engine
|
633
|
+
@analysis_engine || find_inherited_value(:analysis_engine, self.default_analysis_engine)
|
634
|
+
end
|
635
|
+
|
636
|
+
def using_ast_analysis?
|
637
|
+
true
|
638
|
+
end
|
639
|
+
|
640
|
+
def interpreter?
|
641
|
+
true
|
642
|
+
end
|
643
|
+
|
644
|
+
attr_writer :interpreter
|
645
|
+
|
896
646
|
def error_bubbling(new_error_bubbling = nil)
|
897
647
|
if !new_error_bubbling.nil?
|
898
648
|
@error_bubbling = new_error_bubbling
|
@@ -901,16 +651,36 @@ module GraphQL
|
|
901
651
|
end
|
902
652
|
end
|
903
653
|
|
654
|
+
attr_writer :error_bubbling
|
655
|
+
|
656
|
+
attr_writer :max_depth
|
657
|
+
|
904
658
|
def max_depth(new_max_depth = nil)
|
905
659
|
if new_max_depth
|
906
660
|
@max_depth = new_max_depth
|
661
|
+
elsif defined?(@max_depth)
|
662
|
+
@max_depth
|
907
663
|
else
|
908
|
-
|
664
|
+
find_inherited_value(:max_depth)
|
909
665
|
end
|
910
666
|
end
|
911
667
|
|
912
668
|
def disable_introspection_entry_points
|
913
669
|
@disable_introspection_entry_points = true
|
670
|
+
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
671
|
+
@introspection_system = nil
|
672
|
+
end
|
673
|
+
|
674
|
+
def disable_schema_introspection_entry_point
|
675
|
+
@disable_schema_introspection_entry_point = true
|
676
|
+
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
677
|
+
@introspection_system = nil
|
678
|
+
end
|
679
|
+
|
680
|
+
def disable_type_introspection_entry_point
|
681
|
+
@disable_type_introspection_entry_point = true
|
682
|
+
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
683
|
+
@introspection_system = nil
|
914
684
|
end
|
915
685
|
|
916
686
|
def disable_introspection_entry_points?
|
@@ -921,8 +691,26 @@ module GraphQL
|
|
921
691
|
end
|
922
692
|
end
|
923
693
|
|
694
|
+
def disable_schema_introspection_entry_point?
|
695
|
+
if instance_variable_defined?(:@disable_schema_introspection_entry_point)
|
696
|
+
@disable_schema_introspection_entry_point
|
697
|
+
else
|
698
|
+
find_inherited_value(:disable_schema_introspection_entry_point?, false)
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
def disable_type_introspection_entry_point?
|
703
|
+
if instance_variable_defined?(:@disable_type_introspection_entry_point)
|
704
|
+
@disable_type_introspection_entry_point
|
705
|
+
else
|
706
|
+
find_inherited_value(:disable_type_introspection_entry_point?, false)
|
707
|
+
end
|
708
|
+
end
|
709
|
+
|
924
710
|
def orphan_types(*new_orphan_types)
|
925
711
|
if new_orphan_types.any?
|
712
|
+
new_orphan_types = new_orphan_types.flatten
|
713
|
+
add_type_and_traverse(new_orphan_types, root: false)
|
926
714
|
own_orphan_types.concat(new_orphan_types.flatten)
|
927
715
|
end
|
928
716
|
|
@@ -933,7 +721,15 @@ module GraphQL
|
|
933
721
|
if superclass <= GraphQL::Schema
|
934
722
|
superclass.default_execution_strategy
|
935
723
|
else
|
936
|
-
@default_execution_strategy ||= GraphQL::Execution::
|
724
|
+
@default_execution_strategy ||= GraphQL::Execution::Interpreter
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
728
|
+
def default_analysis_engine
|
729
|
+
if superclass <= GraphQL::Schema
|
730
|
+
superclass.default_analysis_engine
|
731
|
+
else
|
732
|
+
@default_analysis_engine ||= GraphQL::Analysis::AST
|
937
733
|
end
|
938
734
|
end
|
939
735
|
|
@@ -947,12 +743,68 @@ module GraphQL
|
|
947
743
|
|
948
744
|
def rescue_from(*err_classes, &handler_block)
|
949
745
|
err_classes.each do |err_class|
|
950
|
-
|
746
|
+
Execution::Errors.register_rescue_from(err_class, error_handlers[:subclass_handlers], handler_block)
|
951
747
|
end
|
952
748
|
end
|
953
749
|
|
954
|
-
|
955
|
-
|
750
|
+
NEW_HANDLER_HASH = ->(h, k) {
|
751
|
+
h[k] = {
|
752
|
+
class: k,
|
753
|
+
handler: nil,
|
754
|
+
subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
|
755
|
+
}
|
756
|
+
}
|
757
|
+
|
758
|
+
def error_handlers
|
759
|
+
@error_handlers ||= {
|
760
|
+
class: nil,
|
761
|
+
handler: nil,
|
762
|
+
subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
|
763
|
+
}
|
764
|
+
end
|
765
|
+
|
766
|
+
# @api private
|
767
|
+
def handle_or_reraise(context, err)
|
768
|
+
handler = Execution::Errors.find_handler_for(self, err.class)
|
769
|
+
if handler
|
770
|
+
obj = context[:current_object]
|
771
|
+
args = context[:current_arguments]
|
772
|
+
args = args && args.respond_to?(:keyword_arguments) ? args.keyword_arguments : nil
|
773
|
+
field = context[:current_field]
|
774
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
775
|
+
obj = obj.object
|
776
|
+
end
|
777
|
+
handler[:handler].call(err, obj, args, context, field)
|
778
|
+
else
|
779
|
+
raise err
|
780
|
+
end
|
781
|
+
end
|
782
|
+
|
783
|
+
# rubocop:disable Lint/DuplicateMethods
|
784
|
+
module ResolveTypeWithType
|
785
|
+
def resolve_type(type, obj, ctx)
|
786
|
+
maybe_lazy_resolve_type_result = if type.is_a?(Module) && type.respond_to?(:resolve_type)
|
787
|
+
type.resolve_type(obj, ctx)
|
788
|
+
else
|
789
|
+
super
|
790
|
+
end
|
791
|
+
|
792
|
+
after_lazy(maybe_lazy_resolve_type_result) do |resolve_type_result|
|
793
|
+
if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
|
794
|
+
resolved_type = resolve_type_result[0]
|
795
|
+
resolved_value = resolve_type_result[1]
|
796
|
+
else
|
797
|
+
resolved_type = resolve_type_result
|
798
|
+
resolved_value = obj
|
799
|
+
end
|
800
|
+
|
801
|
+
if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind))
|
802
|
+
[resolved_type, resolved_value]
|
803
|
+
else
|
804
|
+
raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
|
805
|
+
end
|
806
|
+
end
|
807
|
+
end
|
956
808
|
end
|
957
809
|
|
958
810
|
def resolve_type(type, obj, ctx)
|
@@ -962,6 +814,15 @@ module GraphQL
|
|
962
814
|
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types or Interface types (tried to resolve: #{type.name})"
|
963
815
|
end
|
964
816
|
end
|
817
|
+
# rubocop:enable Lint/DuplicateMethods
|
818
|
+
|
819
|
+
def inherited(child_class)
|
820
|
+
if self == GraphQL::Schema
|
821
|
+
child_class.directives(default_directives.values)
|
822
|
+
end
|
823
|
+
child_class.singleton_class.prepend(ResolveTypeWithType)
|
824
|
+
super
|
825
|
+
end
|
965
826
|
|
966
827
|
def object_from_id(node_id, ctx)
|
967
828
|
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(node_id, ctx) must be implemented to load by ID (tried to load from id `#{node_id}`)"
|
@@ -971,24 +832,17 @@ module GraphQL
|
|
971
832
|
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.id_from_object(object, type, ctx) must be implemented to create global ids (tried to create an id for `#{object.inspect}`)"
|
972
833
|
end
|
973
834
|
|
974
|
-
def visible?(member,
|
975
|
-
|
835
|
+
def visible?(member, ctx)
|
836
|
+
member.visible?(ctx)
|
976
837
|
end
|
977
838
|
|
978
|
-
def
|
979
|
-
|
839
|
+
def schema_directive(dir_class, **options)
|
840
|
+
@own_schema_directives ||= []
|
841
|
+
Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
|
980
842
|
end
|
981
843
|
|
982
|
-
|
983
|
-
|
984
|
-
#
|
985
|
-
# By default, an error is added to the response. Override this hook to
|
986
|
-
# track metrics or return a different error to the client.
|
987
|
-
#
|
988
|
-
# @param error [InaccessibleFieldsError] The analysis error for this check
|
989
|
-
# @return [AnalysisError, nil] Return an error to skip the query
|
990
|
-
def inaccessible_fields(error)
|
991
|
-
error
|
844
|
+
def schema_directives
|
845
|
+
Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
|
992
846
|
end
|
993
847
|
|
994
848
|
# This hook is called when an object fails an `authorized?` check.
|
@@ -1026,52 +880,68 @@ module GraphQL
|
|
1026
880
|
unauthorized_object(unauthorized_error)
|
1027
881
|
end
|
1028
882
|
|
1029
|
-
def type_error(
|
1030
|
-
|
883
|
+
def type_error(type_error, ctx)
|
884
|
+
case type_error
|
885
|
+
when GraphQL::InvalidNullError
|
886
|
+
ctx.errors << type_error
|
887
|
+
when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
|
888
|
+
raise type_error
|
889
|
+
when GraphQL::IntegerDecodingError
|
890
|
+
nil
|
891
|
+
end
|
1031
892
|
end
|
1032
893
|
|
1033
|
-
|
1034
|
-
|
1035
|
-
#
|
1036
|
-
|
1037
|
-
|
894
|
+
# A function to call when {#execute} receives an invalid query string
|
895
|
+
#
|
896
|
+
# The default is to add the error to `context.errors`
|
897
|
+
# @param parse_err [GraphQL::ParseError] The error encountered during parsing
|
898
|
+
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
899
|
+
# @return void
|
900
|
+
def parse_error(parse_err, ctx)
|
901
|
+
ctx.errors.push(parse_err)
|
1038
902
|
end
|
1039
903
|
|
1040
904
|
def lazy_resolve(lazy_class, value_method)
|
1041
|
-
|
905
|
+
lazy_methods.set(lazy_class, value_method)
|
1042
906
|
end
|
1043
907
|
|
1044
908
|
def instrument(instrument_step, instrumenter, options = {})
|
1045
|
-
|
1046
|
-
:field_after_built_ins
|
1047
|
-
else
|
1048
|
-
instrument_step
|
1049
|
-
end
|
1050
|
-
|
1051
|
-
own_instrumenters[step] << instrumenter
|
909
|
+
own_instrumenters[instrument_step] << instrumenter
|
1052
910
|
end
|
1053
911
|
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
912
|
+
# Add several directives at once
|
913
|
+
# @param new_directives [Class]
|
914
|
+
def directives(*new_directives)
|
915
|
+
if new_directives.any?
|
916
|
+
new_directives.flatten.each { |d| directive(d) }
|
1057
917
|
end
|
1058
918
|
|
1059
919
|
find_inherited_value(:directives, default_directives).merge(own_directives)
|
1060
920
|
end
|
1061
921
|
|
922
|
+
# Attach a single directive to this schema
|
923
|
+
# @param new_directive [Class]
|
924
|
+
# @return void
|
1062
925
|
def directive(new_directive)
|
1063
|
-
|
926
|
+
add_type_and_traverse(new_directive, root: false)
|
1064
927
|
end
|
1065
928
|
|
1066
929
|
def default_directives
|
1067
|
-
{
|
1068
|
-
"include" => GraphQL::Directive::
|
1069
|
-
"skip" => GraphQL::Directive::
|
1070
|
-
"deprecated" => GraphQL::Directive::
|
1071
|
-
|
930
|
+
@default_directives ||= {
|
931
|
+
"include" => GraphQL::Schema::Directive::Include,
|
932
|
+
"skip" => GraphQL::Schema::Directive::Skip,
|
933
|
+
"deprecated" => GraphQL::Schema::Directive::Deprecated,
|
934
|
+
"oneOf" => GraphQL::Schema::Directive::OneOf,
|
935
|
+
}.freeze
|
1072
936
|
end
|
1073
937
|
|
1074
938
|
def tracer(new_tracer)
|
939
|
+
if defined?(@trace_class) && !(@trace_class < GraphQL::Tracing::LegacyTrace)
|
940
|
+
raise ArgumentError, "Can't add tracer after configuring a `trace_class`, use GraphQL::Tracing::LegacyTrace to merge legacy tracers into a trace class instead."
|
941
|
+
elsif !defined?(@trace_class)
|
942
|
+
@trace_class = Class.new(GraphQL::Tracing::LegacyTrace)
|
943
|
+
end
|
944
|
+
|
1075
945
|
own_tracers << new_tracer
|
1076
946
|
end
|
1077
947
|
|
@@ -1079,10 +949,29 @@ module GraphQL
|
|
1079
949
|
find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
|
1080
950
|
end
|
1081
951
|
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
952
|
+
# Mix `trace_mod` into this schema's `Trace` class so that its methods
|
953
|
+
# will be called at runtime.
|
954
|
+
#
|
955
|
+
# @param trace_mod [Module] A module that implements tracing methods
|
956
|
+
# @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
|
957
|
+
# @return [void]
|
958
|
+
def trace_with(trace_mod, **options)
|
959
|
+
trace_options.merge!(options)
|
960
|
+
trace_class.include(trace_mod)
|
961
|
+
end
|
962
|
+
|
963
|
+
def trace_options
|
964
|
+
@trace_options ||= superclass.respond_to?(:trace_options) ? superclass.trace_options.dup : {}
|
965
|
+
end
|
966
|
+
|
967
|
+
def new_trace(**options)
|
968
|
+
if defined?(@trace_options)
|
969
|
+
options = trace_options.merge(options)
|
1085
970
|
end
|
971
|
+
trace_class.new(**options)
|
972
|
+
end
|
973
|
+
|
974
|
+
def query_analyzer(new_analyzer)
|
1086
975
|
own_query_analyzers << new_analyzer
|
1087
976
|
end
|
1088
977
|
|
@@ -1090,14 +979,6 @@ module GraphQL
|
|
1090
979
|
find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
|
1091
980
|
end
|
1092
981
|
|
1093
|
-
def middleware(new_middleware = nil)
|
1094
|
-
if new_middleware
|
1095
|
-
own_middleware << new_middleware
|
1096
|
-
else
|
1097
|
-
graphql_definition.middleware
|
1098
|
-
end
|
1099
|
-
end
|
1100
|
-
|
1101
982
|
def multiplex_analyzer(new_analyzer)
|
1102
983
|
own_multiplex_analyzers << new_analyzer
|
1103
984
|
end
|
@@ -1106,188 +987,251 @@ module GraphQL
|
|
1106
987
|
find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
|
1107
988
|
end
|
1108
989
|
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
def own_plugins
|
1116
|
-
@own_plugins ||= []
|
1117
|
-
end
|
1118
|
-
|
1119
|
-
def own_rescues
|
1120
|
-
@own_rescues ||= {}
|
990
|
+
def sanitized_printer(new_sanitized_printer = nil)
|
991
|
+
if new_sanitized_printer
|
992
|
+
@own_sanitized_printer = new_sanitized_printer
|
993
|
+
else
|
994
|
+
@own_sanitized_printer || GraphQL::Language::SanitizedPrinter
|
995
|
+
end
|
1121
996
|
end
|
1122
997
|
|
1123
|
-
|
1124
|
-
|
998
|
+
# Execute a query on itself.
|
999
|
+
# @see {Query#initialize} for arguments.
|
1000
|
+
# @return [Hash] query result, ready to be serialized as JSON
|
1001
|
+
def execute(query_str = nil, **kwargs)
|
1002
|
+
if query_str
|
1003
|
+
kwargs[:query] = query_str
|
1004
|
+
end
|
1005
|
+
# Some of the query context _should_ be passed to the multiplex, too
|
1006
|
+
multiplex_context = if (ctx = kwargs[:context])
|
1007
|
+
{
|
1008
|
+
backtrace: ctx[:backtrace],
|
1009
|
+
tracers: ctx[:tracers],
|
1010
|
+
dataloader: ctx[:dataloader],
|
1011
|
+
}
|
1012
|
+
else
|
1013
|
+
{}
|
1014
|
+
end
|
1015
|
+
# Since we're running one query, don't run a multiplex-level complexity analyzer
|
1016
|
+
all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
|
1017
|
+
all_results[0]
|
1125
1018
|
end
|
1126
1019
|
|
1127
|
-
|
1128
|
-
|
1020
|
+
# Execute several queries on itself, concurrently.
|
1021
|
+
#
|
1022
|
+
# @example Run several queries at once
|
1023
|
+
# context = { ... }
|
1024
|
+
# queries = [
|
1025
|
+
# { query: params[:query_1], variables: params[:variables_1], context: context },
|
1026
|
+
# { query: params[:query_2], variables: params[:variables_2], context: context },
|
1027
|
+
# ]
|
1028
|
+
# results = MySchema.multiplex(queries)
|
1029
|
+
# render json: {
|
1030
|
+
# result_1: results[0],
|
1031
|
+
# result_2: results[1],
|
1032
|
+
# }
|
1033
|
+
#
|
1034
|
+
# @see {Query#initialize} for query keyword arguments
|
1035
|
+
# @see {Execution::Multiplex#run_all} for multiplex keyword arguments
|
1036
|
+
# @param queries [Array<Hash>] Keyword arguments for each query
|
1037
|
+
# @param context [Hash] Multiplex-level context
|
1038
|
+
# @return [Array<Hash>] One result for each query in the input
|
1039
|
+
def multiplex(queries, **kwargs)
|
1040
|
+
GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
|
1129
1041
|
end
|
1130
1042
|
|
1131
|
-
def
|
1132
|
-
inherited_instrumenters = find_inherited_value(:
|
1043
|
+
def instrumenters
|
1044
|
+
inherited_instrumenters = find_inherited_value(:instrumenters) || Hash.new { |h,k| h[k] = [] }
|
1133
1045
|
inherited_instrumenters.merge(own_instrumenters) do |_step, inherited, own|
|
1134
1046
|
inherited + own
|
1135
1047
|
end
|
1136
1048
|
end
|
1137
1049
|
|
1138
|
-
|
1139
|
-
|
1050
|
+
# @api private
|
1051
|
+
def add_subscription_extension_if_necessary
|
1052
|
+
if !defined?(@subscription_extension_added) && subscription && self.subscriptions
|
1053
|
+
@subscription_extension_added = true
|
1054
|
+
subscription.all_field_definitions.each do |field|
|
1055
|
+
if !field.extensions.any? { |ext| ext.is_a?(Subscriptions::DefaultSubscriptionResolveExtension) }
|
1056
|
+
field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
|
1057
|
+
end
|
1058
|
+
end
|
1059
|
+
end
|
1140
1060
|
end
|
1141
1061
|
|
1142
|
-
def
|
1143
|
-
|
1062
|
+
def query_stack_error(query, err)
|
1063
|
+
query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
|
1144
1064
|
end
|
1145
1065
|
|
1146
|
-
|
1147
|
-
|
1066
|
+
# Call the given block at the right time, either:
|
1067
|
+
# - Right away, if `value` is not registered with `lazy_resolve`
|
1068
|
+
# - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
|
1069
|
+
# @api private
|
1070
|
+
def after_lazy(value, &block)
|
1071
|
+
if lazy?(value)
|
1072
|
+
GraphQL::Execution::Lazy.new do
|
1073
|
+
result = sync_lazy(value)
|
1074
|
+
# The returned result might also be lazy, so check it, too
|
1075
|
+
after_lazy(result, &block)
|
1076
|
+
end
|
1077
|
+
else
|
1078
|
+
yield(value) if block_given?
|
1079
|
+
end
|
1148
1080
|
end
|
1149
1081
|
|
1150
|
-
|
1151
|
-
|
1082
|
+
# Override this method to handle lazy objects in a custom way.
|
1083
|
+
# @param value [Object] an instance of a class registered with {.lazy_resolve}
|
1084
|
+
# @return [Object] A GraphQL-ready (non-lazy) object
|
1085
|
+
# @api private
|
1086
|
+
def sync_lazy(value)
|
1087
|
+
lazy_method = lazy_method_name(value)
|
1088
|
+
if lazy_method
|
1089
|
+
synced_value = value.public_send(lazy_method)
|
1090
|
+
sync_lazy(synced_value)
|
1091
|
+
else
|
1092
|
+
value
|
1093
|
+
end
|
1152
1094
|
end
|
1153
1095
|
|
1154
|
-
|
1155
|
-
|
1096
|
+
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
|
1097
|
+
def lazy_method_name(obj)
|
1098
|
+
lazy_methods.get(obj)
|
1156
1099
|
end
|
1157
1100
|
|
1158
|
-
|
1159
|
-
|
1101
|
+
# @return [Boolean] True if this object should be lazily resolved
|
1102
|
+
def lazy?(obj)
|
1103
|
+
!!lazy_method_name(obj)
|
1160
1104
|
end
|
1161
1105
|
|
1162
|
-
#
|
1163
|
-
#
|
1164
|
-
# @
|
1165
|
-
# @
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1106
|
+
# Return a lazy if any of `maybe_lazies` are lazy,
|
1107
|
+
# otherwise, call the block eagerly and return the result.
|
1108
|
+
# @param maybe_lazies [Array]
|
1109
|
+
# @api private
|
1110
|
+
def after_any_lazies(maybe_lazies)
|
1111
|
+
if maybe_lazies.any? { |l| lazy?(l) }
|
1112
|
+
GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
|
1113
|
+
yield result
|
1114
|
+
end
|
1170
1115
|
else
|
1171
|
-
|
1116
|
+
yield maybe_lazies
|
1172
1117
|
end
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
private
|
1173
1121
|
|
1174
|
-
|
1175
|
-
|
1122
|
+
# @param t [Module, Array<Module>]
|
1123
|
+
# @return [void]
|
1124
|
+
def add_type_and_traverse(t, root:)
|
1125
|
+
if root
|
1126
|
+
@root_types ||= []
|
1127
|
+
@root_types << t
|
1176
1128
|
end
|
1129
|
+
new_types = Array(t)
|
1130
|
+
addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
|
1131
|
+
addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
|
1132
|
+
if (prev_entry = own_types[name])
|
1133
|
+
prev_entries = case prev_entry
|
1134
|
+
when Array
|
1135
|
+
prev_entry
|
1136
|
+
when Module
|
1137
|
+
own_types[name] = [prev_entry]
|
1138
|
+
else
|
1139
|
+
raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
|
1140
|
+
end
|
1177
1141
|
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1142
|
+
case types_entry
|
1143
|
+
when Array
|
1144
|
+
prev_entries.concat(types_entry)
|
1145
|
+
prev_entries.uniq! # in case any are being re-visited
|
1146
|
+
when Module
|
1147
|
+
if !prev_entries.include?(types_entry)
|
1148
|
+
prev_entries << types_entry
|
1149
|
+
end
|
1150
|
+
else
|
1151
|
+
raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
|
1152
|
+
end
|
1153
|
+
else
|
1154
|
+
if types_entry.is_a?(Array)
|
1155
|
+
types_entry.uniq!
|
1156
|
+
end
|
1157
|
+
own_types[name] = types_entry
|
1158
|
+
end
|
1182
1159
|
end
|
1183
|
-
end
|
1184
|
-
end
|
1185
1160
|
|
1161
|
+
own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
|
1162
|
+
own_union_memberships.merge!(addition.union_memberships)
|
1186
1163
|
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1164
|
+
addition.references.each { |thing, pointers|
|
1165
|
+
pointers.each { |pointer| references_to(thing, from: pointer) }
|
1166
|
+
}
|
1167
|
+
|
1168
|
+
addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
|
1192
1169
|
|
1193
|
-
|
1194
|
-
|
1195
|
-
def resolve_type(type, obj, ctx = :__undefined__)
|
1196
|
-
graphql_definition.check_resolved_type(type, obj, ctx) do |ok_type, ok_obj, ok_ctx|
|
1197
|
-
super(ok_type, ok_obj, ok_ctx)
|
1170
|
+
addition.arguments_with_default_values.each do |arg|
|
1171
|
+
arg.validate_default_value
|
1198
1172
|
end
|
1199
1173
|
end
|
1200
|
-
end
|
1201
1174
|
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
after_lazy(result) do |final_result|
|
1212
|
-
yield(final_result) if block_given?
|
1175
|
+
def lazy_methods
|
1176
|
+
if !defined?(@lazy_methods)
|
1177
|
+
if inherited_map = find_inherited_value(:lazy_methods)
|
1178
|
+
# this isn't _completely_ inherited :S (Things added after `dup` won't work)
|
1179
|
+
@lazy_methods = inherited_map.dup
|
1180
|
+
else
|
1181
|
+
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
1182
|
+
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
1183
|
+
@lazy_methods.set(GraphQL::Dataloader::Request, :load)
|
1213
1184
|
end
|
1214
1185
|
end
|
1215
|
-
|
1216
|
-
yield(value) if block_given?
|
1186
|
+
@lazy_methods
|
1217
1187
|
end
|
1218
|
-
end
|
1219
1188
|
|
1220
|
-
|
1221
|
-
|
1222
|
-
# @param ctx [GraphQL::Query::Context] the context for this query
|
1223
|
-
# @return [Object] A GraphQL-ready (non-lazy) object
|
1224
|
-
def self.sync_lazy(value)
|
1225
|
-
if block_given?
|
1226
|
-
# This was already hit by the instance, just give it back
|
1227
|
-
yield(value)
|
1228
|
-
else
|
1229
|
-
# This was called directly on the class, hit the instance
|
1230
|
-
# which has the lazy method map
|
1231
|
-
self.graphql_definition.sync_lazy(value)
|
1189
|
+
def own_types
|
1190
|
+
@own_types ||= {}
|
1232
1191
|
end
|
1233
|
-
end
|
1234
1192
|
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
self.class.sync_lazy(value) { |v|
|
1239
|
-
lazy_method = lazy_method_name(v)
|
1240
|
-
if lazy_method
|
1241
|
-
synced_value = value.public_send(lazy_method)
|
1242
|
-
sync_lazy(synced_value)
|
1243
|
-
else
|
1244
|
-
v
|
1245
|
-
end
|
1246
|
-
}
|
1247
|
-
end
|
1193
|
+
def non_introspection_types
|
1194
|
+
find_inherited_value(:non_introspection_types, EMPTY_HASH).merge(own_types)
|
1195
|
+
end
|
1248
1196
|
|
1249
|
-
|
1197
|
+
def own_plugins
|
1198
|
+
@own_plugins ||= []
|
1199
|
+
end
|
1250
1200
|
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1201
|
+
def own_orphan_types
|
1202
|
+
@own_orphan_types ||= []
|
1203
|
+
end
|
1254
1204
|
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
@rescue_middleware ||= GraphQL::Schema::RescueMiddleware.new.tap { |m| middleware.insert(0, m) }
|
1259
|
-
end
|
1205
|
+
def own_possible_types
|
1206
|
+
@own_possible_types ||= {}
|
1207
|
+
end
|
1260
1208
|
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
if @rebuilding_artifacts
|
1265
|
-
raise CyclicalDefinitionError, "Part of the schema build process re-triggered the schema build process, causing an infinite loop. Avoid using Schema#types, Schema#possible_types, and Schema#get_field during schema build."
|
1266
|
-
else
|
1267
|
-
@rebuilding_artifacts = true
|
1268
|
-
@introspection_system = Schema::IntrospectionSystem.new(self)
|
1269
|
-
traversal = Traversal.new(self)
|
1270
|
-
@types = traversal.type_map
|
1271
|
-
@root_types = [query, mutation, subscription]
|
1272
|
-
@instrumented_field_map = traversal.instrumented_field_map
|
1273
|
-
@type_reference_map = traversal.type_reference_map
|
1274
|
-
@union_memberships = traversal.union_memberships
|
1275
|
-
@find_cache = {}
|
1276
|
-
@finder = Finder.new(self)
|
1277
|
-
end
|
1278
|
-
ensure
|
1279
|
-
@rebuilding_artifacts = false
|
1280
|
-
end
|
1209
|
+
def own_union_memberships
|
1210
|
+
@own_union_memberships ||= {}
|
1211
|
+
end
|
1281
1212
|
|
1282
|
-
|
1283
|
-
|
1213
|
+
def own_directives
|
1214
|
+
@own_directives ||= {}
|
1215
|
+
end
|
1284
1216
|
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1217
|
+
def own_instrumenters
|
1218
|
+
@own_instrumenters ||= Hash.new { |h,k| h[k] = [] }
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
def own_tracers
|
1222
|
+
@own_tracers ||= []
|
1223
|
+
end
|
1224
|
+
|
1225
|
+
def own_query_analyzers
|
1226
|
+
@defined_query_analyzers ||= []
|
1227
|
+
end
|
1228
|
+
|
1229
|
+
def own_multiplex_analyzers
|
1230
|
+
@own_multiplex_analyzers ||= []
|
1290
1231
|
end
|
1291
1232
|
end
|
1233
|
+
|
1234
|
+
# Install these here so that subclasses will also install it.
|
1235
|
+
self.connections = GraphQL::Pagination::Connections.new(schema: self)
|
1292
1236
|
end
|
1293
1237
|
end
|