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