graphql_cody 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +5 -0
- data/MIT-LICENSE +20 -0
- data/lib/generators/graphql/core.rb +74 -0
- data/lib/generators/graphql/enum_generator.rb +33 -0
- data/lib/generators/graphql/install_generator.rb +190 -0
- data/lib/generators/graphql/interface_generator.rb +27 -0
- data/lib/generators/graphql/loader_generator.rb +21 -0
- data/lib/generators/graphql/mutation_generator.rb +55 -0
- data/lib/generators/graphql/object_generator.rb +79 -0
- data/lib/generators/graphql/relay.rb +63 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/scalar_generator.rb +20 -0
- data/lib/generators/graphql/templates/base_argument.erb +6 -0
- data/lib/generators/graphql/templates/base_connection.erb +8 -0
- data/lib/generators/graphql/templates/base_edge.erb +8 -0
- data/lib/generators/graphql/templates/base_enum.erb +6 -0
- data/lib/generators/graphql/templates/base_field.erb +7 -0
- data/lib/generators/graphql/templates/base_input_object.erb +7 -0
- data/lib/generators/graphql/templates/base_interface.erb +9 -0
- data/lib/generators/graphql/templates/base_mutation.erb +10 -0
- data/lib/generators/graphql/templates/base_object.erb +7 -0
- data/lib/generators/graphql/templates/base_scalar.erb +6 -0
- data/lib/generators/graphql/templates/base_union.erb +6 -0
- data/lib/generators/graphql/templates/enum.erb +7 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +52 -0
- data/lib/generators/graphql/templates/interface.erb +8 -0
- data/lib/generators/graphql/templates/loader.erb +19 -0
- data/lib/generators/graphql/templates/mutation.erb +16 -0
- data/lib/generators/graphql/templates/mutation_type.erb +12 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +8 -0
- data/lib/generators/graphql/templates/query_type.erb +15 -0
- data/lib/generators/graphql/templates/scalar.erb +15 -0
- data/lib/generators/graphql/templates/schema.erb +27 -0
- data/lib/generators/graphql/templates/union.erb +7 -0
- data/lib/generators/graphql/type_generator.rb +98 -0
- data/lib/generators/graphql/union_generator.rb +33 -0
- data/lib/graphql/analysis/analyze_query.rb +98 -0
- data/lib/graphql/analysis/ast/analyzer.rb +84 -0
- data/lib/graphql/analysis/ast/field_usage.rb +51 -0
- data/lib/graphql/analysis/ast/max_query_complexity.rb +23 -0
- data/lib/graphql/analysis/ast/max_query_depth.rb +22 -0
- data/lib/graphql/analysis/ast/query_complexity.rb +230 -0
- data/lib/graphql/analysis/ast/query_depth.rb +56 -0
- data/lib/graphql/analysis/ast/visitor.rb +268 -0
- data/lib/graphql/analysis/ast.rb +91 -0
- data/lib/graphql/analysis/field_usage.rb +45 -0
- data/lib/graphql/analysis/max_query_complexity.rb +26 -0
- data/lib/graphql/analysis/max_query_depth.rb +26 -0
- data/lib/graphql/analysis/query_complexity.rb +88 -0
- data/lib/graphql/analysis/query_depth.rb +43 -0
- data/lib/graphql/analysis/reducer_state.rb +48 -0
- data/lib/graphql/analysis.rb +9 -0
- data/lib/graphql/analysis_error.rb +5 -0
- data/lib/graphql/argument.rb +131 -0
- data/lib/graphql/authorization.rb +82 -0
- data/lib/graphql/backtrace/inspect_result.rb +50 -0
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +159 -0
- data/lib/graphql/backtrace/traced_error.rb +54 -0
- data/lib/graphql/backtrace/tracer.rb +81 -0
- data/lib/graphql/backtrace.rb +64 -0
- data/lib/graphql/backwards_compatibility.rb +61 -0
- data/lib/graphql/base_type.rb +230 -0
- data/lib/graphql/boolean_type.rb +2 -0
- data/lib/graphql/coercion_error.rb +13 -0
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +53 -0
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +200 -0
- data/lib/graphql/compatibility/execution_specification.rb +436 -0
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +111 -0
- data/lib/graphql/compatibility/lazy_execution_specification.rb +215 -0
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +87 -0
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +79 -0
- data/lib/graphql/compatibility/query_parser_specification.rb +266 -0
- data/lib/graphql/compatibility/schema_parser_specification.rb +682 -0
- data/lib/graphql/compatibility.rb +5 -0
- data/lib/graphql/dataloader/null_dataloader.rb +22 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +155 -0
- data/lib/graphql/dataloader.rb +308 -0
- data/lib/graphql/define/assign_argument.rb +12 -0
- data/lib/graphql/define/assign_connection.rb +13 -0
- data/lib/graphql/define/assign_enum_value.rb +18 -0
- data/lib/graphql/define/assign_global_id_field.rb +11 -0
- data/lib/graphql/define/assign_mutation_function.rb +34 -0
- data/lib/graphql/define/assign_object_field.rb +42 -0
- data/lib/graphql/define/defined_object_proxy.rb +53 -0
- data/lib/graphql/define/instance_definable.rb +240 -0
- data/lib/graphql/define/no_definition_error.rb +7 -0
- data/lib/graphql/define/non_null_with_bang.rb +16 -0
- data/lib/graphql/define/type_definer.rb +31 -0
- data/lib/graphql/define.rb +31 -0
- data/lib/graphql/deprecated_dsl.rb +55 -0
- data/lib/graphql/deprecation.rb +9 -0
- data/lib/graphql/dig.rb +19 -0
- data/lib/graphql/directive/deprecated_directive.rb +2 -0
- data/lib/graphql/directive/include_directive.rb +2 -0
- data/lib/graphql/directive/skip_directive.rb +2 -0
- data/lib/graphql/directive.rb +107 -0
- data/lib/graphql/enum_type.rb +133 -0
- data/lib/graphql/execution/directive_checks.rb +37 -0
- data/lib/graphql/execution/errors.rb +163 -0
- data/lib/graphql/execution/execute.rb +333 -0
- data/lib/graphql/execution/flatten.rb +40 -0
- data/lib/graphql/execution/instrumentation.rb +92 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +88 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +103 -0
- data/lib/graphql/execution/interpreter/execution_errors.rb +29 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
- data/lib/graphql/execution/interpreter/resolve.rb +70 -0
- data/lib/graphql/execution/interpreter/runtime.rb +949 -0
- data/lib/graphql/execution/interpreter.rb +122 -0
- data/lib/graphql/execution/lazy/lazy_method_map.rb +98 -0
- data/lib/graphql/execution/lazy/resolve.rb +91 -0
- data/lib/graphql/execution/lazy.rb +83 -0
- data/lib/graphql/execution/lookahead.rb +307 -0
- data/lib/graphql/execution/multiplex.rb +214 -0
- data/lib/graphql/execution/typecast.rb +50 -0
- data/lib/graphql/execution.rb +11 -0
- data/lib/graphql/execution_error.rb +58 -0
- data/lib/graphql/field/resolve.rb +59 -0
- data/lib/graphql/field.rb +226 -0
- data/lib/graphql/filter.rb +53 -0
- data/lib/graphql/float_type.rb +2 -0
- data/lib/graphql/function.rb +128 -0
- data/lib/graphql/id_type.rb +2 -0
- data/lib/graphql/input_object_type.rb +138 -0
- data/lib/graphql/int_type.rb +2 -0
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +36 -0
- data/lib/graphql/interface_type.rb +72 -0
- data/lib/graphql/internal_representation/document.rb +27 -0
- data/lib/graphql/internal_representation/node.rb +206 -0
- data/lib/graphql/internal_representation/print.rb +51 -0
- data/lib/graphql/internal_representation/rewrite.rb +184 -0
- data/lib/graphql/internal_representation/scope.rb +88 -0
- data/lib/graphql/internal_representation/visit.rb +36 -0
- data/lib/graphql/internal_representation.rb +7 -0
- data/lib/graphql/introspection/base_object.rb +13 -0
- data/lib/graphql/introspection/directive_location_enum.rb +15 -0
- data/lib/graphql/introspection/directive_type.rb +29 -0
- data/lib/graphql/introspection/dynamic_fields.rb +17 -0
- data/lib/graphql/introspection/entry_points.rb +35 -0
- data/lib/graphql/introspection/enum_value_type.rb +23 -0
- data/lib/graphql/introspection/field_type.rb +28 -0
- data/lib/graphql/introspection/input_value_type.rb +67 -0
- data/lib/graphql/introspection/introspection_query.rb +7 -0
- data/lib/graphql/introspection/schema_type.rb +44 -0
- data/lib/graphql/introspection/type_kind_enum.rb +13 -0
- data/lib/graphql/introspection/type_type.rb +95 -0
- data/lib/graphql/introspection.rb +114 -0
- data/lib/graphql/invalid_name_error.rb +11 -0
- data/lib/graphql/invalid_null_error.rb +50 -0
- data/lib/graphql/language/block_string.rb +99 -0
- data/lib/graphql/language/cache.rb +37 -0
- data/lib/graphql/language/definition_slice.rb +41 -0
- data/lib/graphql/language/document_from_schema_definition.rb +347 -0
- data/lib/graphql/language/generation.rb +24 -0
- data/lib/graphql/language/lexer.rb +1467 -0
- data/lib/graphql/language/lexer.rl +258 -0
- data/lib/graphql/language/nodes.rb +707 -0
- data/lib/graphql/language/parser.rb +1974 -0
- data/lib/graphql/language/parser.y +544 -0
- data/lib/graphql/language/printer.rb +366 -0
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/token.rb +34 -0
- data/lib/graphql/language/visitor.rb +242 -0
- data/lib/graphql/language.rb +36 -0
- data/lib/graphql/list_type.rb +80 -0
- data/lib/graphql/load_application_object_failed_error.rb +22 -0
- data/lib/graphql/name_validator.rb +11 -0
- data/lib/graphql/non_null_type.rb +71 -0
- data/lib/graphql/object_type.rb +130 -0
- data/lib/graphql/pagination/active_record_relation_connection.rb +48 -0
- data/lib/graphql/pagination/array_connection.rb +77 -0
- data/lib/graphql/pagination/connection.rb +226 -0
- data/lib/graphql/pagination/connections.rb +160 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +196 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/parse_error.rb +24 -0
- data/lib/graphql/query/arguments.rb +189 -0
- data/lib/graphql/query/arguments_cache.rb +24 -0
- data/lib/graphql/query/context.rb +371 -0
- data/lib/graphql/query/executor.rb +52 -0
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +43 -0
- data/lib/graphql/query/literal_input.rb +136 -0
- data/lib/graphql/query/null_context.rb +55 -0
- data/lib/graphql/query/result.rb +63 -0
- data/lib/graphql/query/serial_execution/field_resolution.rb +92 -0
- data/lib/graphql/query/serial_execution/operation_resolution.rb +19 -0
- data/lib/graphql/query/serial_execution/selection_resolution.rb +23 -0
- data/lib/graphql/query/serial_execution/value_resolution.rb +87 -0
- data/lib/graphql/query/serial_execution.rb +40 -0
- data/lib/graphql/query/validation_pipeline.rb +139 -0
- data/lib/graphql/query/variable_validation_error.rb +44 -0
- data/lib/graphql/query/variables.rb +78 -0
- data/lib/graphql/query.rb +454 -0
- data/lib/graphql/railtie.rb +117 -0
- data/lib/graphql/rake_task/validate.rb +63 -0
- data/lib/graphql/rake_task.rb +145 -0
- data/lib/graphql/relay/array_connection.rb +83 -0
- data/lib/graphql/relay/base_connection.rb +189 -0
- data/lib/graphql/relay/connection_instrumentation.rb +54 -0
- data/lib/graphql/relay/connection_resolve.rb +43 -0
- data/lib/graphql/relay/connection_type.rb +41 -0
- data/lib/graphql/relay/edge.rb +27 -0
- data/lib/graphql/relay/edge_type.rb +19 -0
- data/lib/graphql/relay/edges_instrumentation.rb +39 -0
- data/lib/graphql/relay/global_id_resolve.rb +18 -0
- data/lib/graphql/relay/mongo_relation_connection.rb +50 -0
- data/lib/graphql/relay/mutation/instrumentation.rb +23 -0
- data/lib/graphql/relay/mutation/resolve.rb +56 -0
- data/lib/graphql/relay/mutation/result.rb +38 -0
- data/lib/graphql/relay/mutation.rb +106 -0
- data/lib/graphql/relay/node.rb +39 -0
- data/lib/graphql/relay/page_info.rb +7 -0
- data/lib/graphql/relay/range_add.rb +59 -0
- data/lib/graphql/relay/relation_connection.rb +188 -0
- data/lib/graphql/relay/type_extensions.rb +32 -0
- data/lib/graphql/relay.rb +18 -0
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/runtime_type_error.rb +5 -0
- data/lib/graphql/scalar_type.rb +91 -0
- data/lib/graphql/schema/addition.rb +247 -0
- data/lib/graphql/schema/argument.rb +383 -0
- data/lib/graphql/schema/base_64_bp.rb +26 -0
- data/lib/graphql/schema/base_64_encoder.rb +21 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +47 -0
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +78 -0
- data/lib/graphql/schema/build_from_definition.rb +477 -0
- data/lib/graphql/schema/built_in_types.rb +12 -0
- data/lib/graphql/schema/catchall_middleware.rb +35 -0
- data/lib/graphql/schema/default_parse_error.rb +10 -0
- data/lib/graphql/schema/default_type_error.rb +17 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/feature.rb +66 -0
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive/include.rb +25 -0
- data/lib/graphql/schema/directive/skip.rb +25 -0
- data/lib/graphql/schema/directive/transform.rb +60 -0
- data/lib/graphql/schema/directive.rb +210 -0
- data/lib/graphql/schema/enum.rb +193 -0
- data/lib/graphql/schema/enum_value.rb +97 -0
- data/lib/graphql/schema/field/connection_extension.rb +76 -0
- data/lib/graphql/schema/field/scope_extension.rb +22 -0
- data/lib/graphql/schema/field.rb +880 -0
- data/lib/graphql/schema/field_extension.rb +69 -0
- data/lib/graphql/schema/find_inherited_value.rb +36 -0
- data/lib/graphql/schema/finder.rb +155 -0
- data/lib/graphql/schema/input_object.rb +253 -0
- data/lib/graphql/schema/interface.rb +136 -0
- data/lib/graphql/schema/introspection_system.rb +169 -0
- data/lib/graphql/schema/invalid_type_error.rb +7 -0
- data/lib/graphql/schema/late_bound_type.rb +33 -0
- data/lib/graphql/schema/list.rb +75 -0
- data/lib/graphql/schema/loader.rb +226 -0
- data/lib/graphql/schema/member/accepts_definition.rb +159 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +129 -0
- data/lib/graphql/schema/member/build_type.rb +180 -0
- data/lib/graphql/schema/member/cached_graphql_definition.rb +31 -0
- data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
- data/lib/graphql/schema/member/has_arguments.rb +332 -0
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
- data/lib/graphql/schema/member/has_directives.rb +98 -0
- data/lib/graphql/schema/member/has_fields.rb +163 -0
- data/lib/graphql/schema/member/has_interfaces.rb +90 -0
- data/lib/graphql/schema/member/has_path.rb +25 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/has_validators.rb +31 -0
- data/lib/graphql/schema/member/instrumentation.rb +131 -0
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -0
- data/lib/graphql/schema/member/scoped.rb +21 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +38 -0
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +161 -0
- data/lib/graphql/schema/middleware_chain.rb +82 -0
- data/lib/graphql/schema/mutation.rb +94 -0
- data/lib/graphql/schema/non_null.rb +67 -0
- data/lib/graphql/schema/null_mask.rb +11 -0
- data/lib/graphql/schema/object.rb +150 -0
- data/lib/graphql/schema/possible_types.rb +44 -0
- data/lib/graphql/schema/printer.rb +100 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +160 -0
- data/lib/graphql/schema/rescue_middleware.rb +60 -0
- data/lib/graphql/schema/resolver/has_payload_type.rb +96 -0
- data/lib/graphql/schema/resolver.rb +397 -0
- data/lib/graphql/schema/scalar.rb +69 -0
- data/lib/graphql/schema/subscription.rb +155 -0
- data/lib/graphql/schema/timeout.rb +123 -0
- data/lib/graphql/schema/timeout_middleware.rb +88 -0
- data/lib/graphql/schema/traversal.rb +228 -0
- data/lib/graphql/schema/type_expression.rb +43 -0
- data/lib/graphql/schema/type_membership.rb +48 -0
- data/lib/graphql/schema/union.rb +95 -0
- data/lib/graphql/schema/unique_within_type.rb +34 -0
- data/lib/graphql/schema/validation.rb +313 -0
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/format_validator.rb +48 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
- data/lib/graphql/schema/validator/length_validator.rb +59 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
- data/lib/graphql/schema/validator/required_validator.rb +68 -0
- data/lib/graphql/schema/validator.rb +174 -0
- data/lib/graphql/schema/warden.rb +409 -0
- data/lib/graphql/schema/wrapper.rb +29 -0
- data/lib/graphql/schema.rb +1945 -0
- data/lib/graphql/static_validation/all_rules.rb +40 -0
- data/lib/graphql/static_validation/base_visitor.rb +217 -0
- data/lib/graphql/static_validation/default_visitor.rb +15 -0
- data/lib/graphql/static_validation/definition_dependencies.rb +198 -0
- data/lib/graphql/static_validation/error.rb +46 -0
- data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
- data/lib/graphql/static_validation/literal_validator.rb +139 -0
- data/lib/graphql/static_validation/no_validate_visitor.rb +10 -0
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +66 -0
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +48 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +31 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +71 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +37 -0
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +23 -0
- data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +65 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +30 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +73 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +418 -0
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +53 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +73 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +39 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +21 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_named.rb +16 -0
- data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +37 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +32 -0
- data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +41 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +36 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +37 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +59 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +50 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +46 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +24 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +153 -0
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +39 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +155 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
- data/lib/graphql/static_validation/type_stack.rb +216 -0
- data/lib/graphql/static_validation/validation_context.rb +49 -0
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +96 -0
- data/lib/graphql/static_validation.rb +19 -0
- data/lib/graphql/string_encoding_error.rb +20 -0
- data/lib/graphql/string_type.rb +2 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +245 -0
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
- data/lib/graphql/subscriptions/event.rb +144 -0
- data/lib/graphql/subscriptions/instrumentation.rb +79 -0
- data/lib/graphql/subscriptions/serialize.rb +138 -0
- data/lib/graphql/subscriptions/subscription_root.rb +76 -0
- data/lib/graphql/subscriptions.rb +299 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +35 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +51 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +76 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +51 -0
- data/lib/graphql/tracing/platform_tracing.rb +139 -0
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +32 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +67 -0
- data/lib/graphql/tracing/scout_tracing.rb +54 -0
- data/lib/graphql/tracing/skylight_tracing.rb +70 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +95 -0
- data/lib/graphql/type_kinds.rb +77 -0
- data/lib/graphql/types/big_int.rb +23 -0
- data/lib/graphql/types/boolean.rb +18 -0
- data/lib/graphql/types/float.rb +19 -0
- data/lib/graphql/types/id.rb +24 -0
- data/lib/graphql/types/int.rb +36 -0
- data/lib/graphql/types/iso_8601_date.rb +34 -0
- data/lib/graphql/types/iso_8601_date_time.rb +65 -0
- data/lib/graphql/types/json.rb +25 -0
- data/lib/graphql/types/relay/base_connection.rb +39 -0
- data/lib/graphql/types/relay/base_edge.rb +29 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +156 -0
- data/lib/graphql/types/relay/default_relay.rb +27 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +53 -0
- data/lib/graphql/types/relay/has_node_field.rb +41 -0
- data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
- data/lib/graphql/types/relay/node.rb +15 -0
- data/lib/graphql/types/relay/node_behaviors.rb +15 -0
- data/lib/graphql/types/relay/node_field.rb +25 -0
- data/lib/graphql/types/relay/nodes_field.rb +27 -0
- data/lib/graphql/types/relay/page_info.rb +11 -0
- data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
- data/lib/graphql/types/relay.rb +41 -0
- data/lib/graphql/types/string.rb +29 -0
- data/lib/graphql/types.rb +11 -0
- data/lib/graphql/unauthorized_error.rb +29 -0
- data/lib/graphql/unauthorized_field_error.rb +23 -0
- data/lib/graphql/union_type.rb +115 -0
- data/lib/graphql/unresolved_type_error.rb +35 -0
- data/lib/graphql/upgrader/member.rb +937 -0
- data/lib/graphql/upgrader/schema.rb +38 -0
- data/lib/graphql/version.rb +4 -0
- data/lib/graphql.rb +168 -0
- data/readme.md +49 -0
- metadata +714 -0
@@ -0,0 +1,1945 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "graphql/schema/addition"
|
3
|
+
require "graphql/schema/base_64_encoder"
|
4
|
+
require "graphql/schema/catchall_middleware"
|
5
|
+
require "graphql/schema/default_parse_error"
|
6
|
+
require "graphql/schema/default_type_error"
|
7
|
+
require "graphql/schema/find_inherited_value"
|
8
|
+
require "graphql/schema/finder"
|
9
|
+
require "graphql/schema/invalid_type_error"
|
10
|
+
require "graphql/schema/introspection_system"
|
11
|
+
require "graphql/schema/late_bound_type"
|
12
|
+
require "graphql/schema/middleware_chain"
|
13
|
+
require "graphql/schema/null_mask"
|
14
|
+
require "graphql/schema/possible_types"
|
15
|
+
require "graphql/schema/rescue_middleware"
|
16
|
+
require "graphql/schema/timeout"
|
17
|
+
require "graphql/schema/timeout_middleware"
|
18
|
+
require "graphql/schema/traversal"
|
19
|
+
require "graphql/schema/type_expression"
|
20
|
+
require "graphql/schema/unique_within_type"
|
21
|
+
require "graphql/schema/validation"
|
22
|
+
require "graphql/schema/warden"
|
23
|
+
require "graphql/schema/build_from_definition"
|
24
|
+
|
25
|
+
require "graphql/schema/validator"
|
26
|
+
require "graphql/schema/member"
|
27
|
+
require "graphql/schema/wrapper"
|
28
|
+
require "graphql/schema/list"
|
29
|
+
require "graphql/schema/non_null"
|
30
|
+
require "graphql/schema/argument"
|
31
|
+
require "graphql/schema/enum_value"
|
32
|
+
require "graphql/schema/enum"
|
33
|
+
require "graphql/schema/field_extension"
|
34
|
+
require "graphql/schema/field"
|
35
|
+
require "graphql/schema/input_object"
|
36
|
+
require "graphql/schema/interface"
|
37
|
+
require "graphql/schema/scalar"
|
38
|
+
require "graphql/schema/object"
|
39
|
+
require "graphql/schema/union"
|
40
|
+
require "graphql/schema/directive"
|
41
|
+
require "graphql/schema/directive/deprecated"
|
42
|
+
require "graphql/schema/directive/include"
|
43
|
+
require "graphql/schema/directive/skip"
|
44
|
+
require "graphql/schema/directive/feature"
|
45
|
+
require "graphql/schema/directive/flagged"
|
46
|
+
require "graphql/schema/directive/transform"
|
47
|
+
require "graphql/schema/type_membership"
|
48
|
+
|
49
|
+
require "graphql/schema/resolver"
|
50
|
+
require "graphql/schema/mutation"
|
51
|
+
require "graphql/schema/relay_classic_mutation"
|
52
|
+
require "graphql/schema/subscription"
|
53
|
+
|
54
|
+
module GraphQL
|
55
|
+
# A GraphQL schema which may be queried with {GraphQL::Query}.
|
56
|
+
#
|
57
|
+
# The {Schema} contains:
|
58
|
+
#
|
59
|
+
# - types for exposing your application
|
60
|
+
# - query analyzers for assessing incoming queries (including max depth & max complexity restrictions)
|
61
|
+
# - execution strategies for running incoming queries
|
62
|
+
#
|
63
|
+
# Schemas start with root types, {Schema#query}, {Schema#mutation} and {Schema#subscription}.
|
64
|
+
# The schema will traverse the tree of fields & types, using those as starting points.
|
65
|
+
# Any undiscoverable types may be provided with the `types` configuration.
|
66
|
+
#
|
67
|
+
# Schemas can restrict large incoming queries with `max_depth` and `max_complexity` configurations.
|
68
|
+
# (These configurations can be overridden by specific calls to {Schema#execute})
|
69
|
+
#
|
70
|
+
# Schemas can specify how queries should be executed against them.
|
71
|
+
# `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
|
72
|
+
# each apply to corresponding root types.
|
73
|
+
# #
|
74
|
+
# @example defining a schema
|
75
|
+
# class MySchema < GraphQL::Schema
|
76
|
+
# query QueryType
|
77
|
+
# # If types are only connected by way of interfaces, they must be added here
|
78
|
+
# orphan_types ImageType, AudioType
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
class Schema
|
82
|
+
extend Forwardable
|
83
|
+
extend GraphQL::Schema::Member::AcceptsDefinition
|
84
|
+
extend GraphQL::Schema::Member::HasAstNode
|
85
|
+
include GraphQL::Define::InstanceDefinable
|
86
|
+
extend GraphQL::Define::InstanceDefinable::DeprecatedDefine
|
87
|
+
extend GraphQL::Schema::FindInheritedValue
|
88
|
+
|
89
|
+
class DuplicateTypeNamesError < GraphQL::Error
|
90
|
+
def initialize(type_name:, first_definition:, second_definition:, path:)
|
91
|
+
super("Multiple definitions for `#{type_name}`. Previously found #{first_definition.inspect} (#{first_definition.class}), then found #{second_definition.inspect} (#{second_definition.class}) at #{path.join(".")}")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class DuplicateNamesError < GraphQL::Error; end
|
96
|
+
|
97
|
+
class UnresolvedLateBoundTypeError < GraphQL::Error
|
98
|
+
attr_reader :type
|
99
|
+
def initialize(type:)
|
100
|
+
@type = type
|
101
|
+
super("Late bound type was never found: #{type.inspect}")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
module LazyHandlingMethods
|
106
|
+
# Call the given block at the right time, either:
|
107
|
+
# - Right away, if `value` is not registered with `lazy_resolve`
|
108
|
+
# - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
|
109
|
+
# @api private
|
110
|
+
def after_lazy(value, &block)
|
111
|
+
if lazy?(value)
|
112
|
+
GraphQL::Execution::Lazy.new do
|
113
|
+
result = sync_lazy(value)
|
114
|
+
# The returned result might also be lazy, so check it, too
|
115
|
+
after_lazy(result, &block)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
yield(value) if block_given?
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Override this method to handle lazy objects in a custom way.
|
123
|
+
# @param value [Object] an instance of a class registered with {.lazy_resolve}
|
124
|
+
# @return [Object] A GraphQL-ready (non-lazy) object
|
125
|
+
# @api private
|
126
|
+
def sync_lazy(value)
|
127
|
+
lazy_method = lazy_method_name(value)
|
128
|
+
if lazy_method
|
129
|
+
synced_value = value.public_send(lazy_method)
|
130
|
+
sync_lazy(synced_value)
|
131
|
+
else
|
132
|
+
value
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
|
137
|
+
def lazy_method_name(obj)
|
138
|
+
lazy_methods.get(obj)
|
139
|
+
end
|
140
|
+
|
141
|
+
# @return [Boolean] True if this object should be lazily resolved
|
142
|
+
def lazy?(obj)
|
143
|
+
!!lazy_method_name(obj)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Return a lazy if any of `maybe_lazies` are lazy,
|
147
|
+
# otherwise, call the block eagerly and return the result.
|
148
|
+
# @param maybe_lazies [Array]
|
149
|
+
# @api private
|
150
|
+
def after_any_lazies(maybe_lazies)
|
151
|
+
if maybe_lazies.any? { |l| lazy?(l) }
|
152
|
+
GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
|
153
|
+
yield result
|
154
|
+
end
|
155
|
+
else
|
156
|
+
yield maybe_lazies
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
include LazyHandlingMethods
|
162
|
+
extend LazyHandlingMethods
|
163
|
+
|
164
|
+
accepts_definitions \
|
165
|
+
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
166
|
+
:validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
|
167
|
+
:orphan_types, :resolve_type, :type_error, :parse_error,
|
168
|
+
:error_bubbling,
|
169
|
+
:raise_definition_error,
|
170
|
+
:object_from_id, :id_from_object,
|
171
|
+
:default_mask,
|
172
|
+
:cursor_encoder,
|
173
|
+
# If these are given as classes, normalize them. Accept `nil` when building from string.
|
174
|
+
query: ->(schema, t) { schema.query = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
175
|
+
mutation: ->(schema, t) { schema.mutation = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
176
|
+
subscription: ->(schema, t) { schema.subscription = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
177
|
+
disable_introspection_entry_points: ->(schema) { schema.disable_introspection_entry_points = true },
|
178
|
+
disable_schema_introspection_entry_point: ->(schema) { schema.disable_schema_introspection_entry_point = true },
|
179
|
+
disable_type_introspection_entry_point: ->(schema) { schema.disable_type_introspection_entry_point = true },
|
180
|
+
directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.graphql_name] = d; m } },
|
181
|
+
directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
|
182
|
+
instrument: ->(schema, type, instrumenter, after_built_ins: false) {
|
183
|
+
if type == :field && after_built_ins
|
184
|
+
type = :field_after_built_ins
|
185
|
+
end
|
186
|
+
schema.instrumenters[type] << instrumenter
|
187
|
+
},
|
188
|
+
query_analyzer: ->(schema, analyzer) {
|
189
|
+
if analyzer == GraphQL::Authorization::Analyzer
|
190
|
+
GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
|
191
|
+
end
|
192
|
+
schema.query_analyzers << analyzer
|
193
|
+
},
|
194
|
+
multiplex_analyzer: ->(schema, analyzer) { schema.multiplex_analyzers << analyzer },
|
195
|
+
middleware: ->(schema, middleware) { schema.middleware << middleware },
|
196
|
+
lazy_resolve: ->(schema, lazy_class, lazy_value_method) { schema.lazy_methods.set(lazy_class, lazy_value_method) },
|
197
|
+
rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block) },
|
198
|
+
tracer: ->(schema, tracer) { schema.tracers.push(tracer) }
|
199
|
+
|
200
|
+
ensure_defined :introspection_system
|
201
|
+
|
202
|
+
attr_accessor \
|
203
|
+
:query, :mutation, :subscription,
|
204
|
+
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
205
|
+
:validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
|
206
|
+
:orphan_types, :directives,
|
207
|
+
:query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
|
208
|
+
:cursor_encoder,
|
209
|
+
:ast_node,
|
210
|
+
:raise_definition_error,
|
211
|
+
:introspection_namespace,
|
212
|
+
:analysis_engine
|
213
|
+
|
214
|
+
# [Boolean] True if this object bubbles validation errors up from a field into its parent InputObject, if there is one.
|
215
|
+
attr_accessor :error_bubbling
|
216
|
+
|
217
|
+
# Single, long-lived instance of the provided subscriptions class, if there is one.
|
218
|
+
# @return [GraphQL::Subscriptions]
|
219
|
+
attr_accessor :subscriptions
|
220
|
+
|
221
|
+
# @return [MiddlewareChain] MiddlewareChain which is applied to fields during execution
|
222
|
+
attr_accessor :middleware
|
223
|
+
|
224
|
+
# @return [<#call(member, ctx)>] A callable for filtering members of the schema
|
225
|
+
# @see {Query.new} for query-specific filters with `except:`
|
226
|
+
attr_accessor :default_mask
|
227
|
+
|
228
|
+
# @see {GraphQL::Query::Context} The parent class of these classes
|
229
|
+
# @return [Class] Instantiated for each query
|
230
|
+
attr_accessor :context_class
|
231
|
+
|
232
|
+
# [Boolean] True if this object disables the introspection entry point fields
|
233
|
+
attr_accessor :disable_introspection_entry_points
|
234
|
+
|
235
|
+
def disable_introspection_entry_points?
|
236
|
+
!!@disable_introspection_entry_points
|
237
|
+
end
|
238
|
+
|
239
|
+
# [Boolean] True if this object disables the __schema introspection entry point field
|
240
|
+
attr_accessor :disable_schema_introspection_entry_point
|
241
|
+
|
242
|
+
def disable_schema_introspection_entry_point?
|
243
|
+
!!@disable_schema_introspection_entry_point
|
244
|
+
end
|
245
|
+
|
246
|
+
# [Boolean] True if this object disables the __type introspection entry point field
|
247
|
+
attr_accessor :disable_type_introspection_entry_point
|
248
|
+
|
249
|
+
def disable_type_introspection_entry_point?
|
250
|
+
!!@disable_type_introspection_entry_point
|
251
|
+
end
|
252
|
+
|
253
|
+
class << self
|
254
|
+
attr_writer :default_execution_strategy
|
255
|
+
end
|
256
|
+
|
257
|
+
def default_filter
|
258
|
+
GraphQL::Filter.new(except: default_mask)
|
259
|
+
end
|
260
|
+
|
261
|
+
# @return [Array<#trace(key, data)>] Tracers applied to every query
|
262
|
+
# @see {Query#tracers} for query-specific tracers
|
263
|
+
attr_reader :tracers
|
264
|
+
|
265
|
+
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"].freeze
|
266
|
+
|
267
|
+
attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
|
268
|
+
|
269
|
+
def initialize
|
270
|
+
@tracers = []
|
271
|
+
@definition_error = nil
|
272
|
+
@orphan_types = []
|
273
|
+
@directives = {}
|
274
|
+
self.class.default_directives.each do |name, dir|
|
275
|
+
@directives[name] = dir.graphql_definition
|
276
|
+
end
|
277
|
+
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
278
|
+
@middleware = MiddlewareChain.new(final_step: GraphQL::Execution::Execute::FieldResolveStep)
|
279
|
+
@query_analyzers = []
|
280
|
+
@multiplex_analyzers = []
|
281
|
+
@resolve_type_proc = nil
|
282
|
+
@object_from_id_proc = nil
|
283
|
+
@id_from_object_proc = nil
|
284
|
+
@type_error_proc = DefaultTypeError
|
285
|
+
@parse_error_proc = DefaultParseError
|
286
|
+
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
287
|
+
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
288
|
+
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
289
|
+
@cursor_encoder = Base64Encoder
|
290
|
+
# For schema instances, default to legacy runtime modules
|
291
|
+
@analysis_engine = GraphQL::Analysis
|
292
|
+
@query_execution_strategy = GraphQL::Execution::Execute
|
293
|
+
@mutation_execution_strategy = GraphQL::Execution::Execute
|
294
|
+
@subscription_execution_strategy = GraphQL::Execution::Execute
|
295
|
+
@default_mask = GraphQL::Schema::NullMask
|
296
|
+
@rebuilding_artifacts = false
|
297
|
+
@context_class = GraphQL::Query::Context
|
298
|
+
@introspection_namespace = nil
|
299
|
+
@introspection_system = nil
|
300
|
+
@interpreter = false
|
301
|
+
@error_bubbling = false
|
302
|
+
@disable_introspection_entry_points = false
|
303
|
+
@disable_schema_introspection_entry_point = false
|
304
|
+
@disable_type_introspection_entry_point = false
|
305
|
+
end
|
306
|
+
|
307
|
+
# @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
|
308
|
+
def interpreter?
|
309
|
+
query_execution_strategy == GraphQL::Execution::Interpreter &&
|
310
|
+
mutation_execution_strategy == GraphQL::Execution::Interpreter &&
|
311
|
+
subscription_execution_strategy == GraphQL::Execution::Interpreter
|
312
|
+
end
|
313
|
+
|
314
|
+
def inspect
|
315
|
+
"#<#{self.class.name} ...>"
|
316
|
+
end
|
317
|
+
|
318
|
+
def initialize_copy(other)
|
319
|
+
super
|
320
|
+
@orphan_types = other.orphan_types.dup
|
321
|
+
@directives = other.directives.dup
|
322
|
+
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
323
|
+
@middleware = other.middleware.dup
|
324
|
+
@query_analyzers = other.query_analyzers.dup
|
325
|
+
@multiplex_analyzers = other.multiplex_analyzers.dup
|
326
|
+
@tracers = other.tracers.dup
|
327
|
+
@possible_types = GraphQL::Schema::PossibleTypes.new(self)
|
328
|
+
|
329
|
+
@lazy_methods = other.lazy_methods.dup
|
330
|
+
|
331
|
+
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
332
|
+
other.instrumenters.each do |key, insts|
|
333
|
+
@instrumenters[key].concat(insts)
|
334
|
+
end
|
335
|
+
|
336
|
+
if other.rescues?
|
337
|
+
@rescue_middleware = other.rescue_middleware
|
338
|
+
end
|
339
|
+
|
340
|
+
# This will be rebuilt when it's requested
|
341
|
+
# or during a later `define` call
|
342
|
+
@types = nil
|
343
|
+
@introspection_system = nil
|
344
|
+
end
|
345
|
+
|
346
|
+
def rescue_from(*args, &block)
|
347
|
+
rescue_middleware.rescue_from(*args, &block)
|
348
|
+
end
|
349
|
+
|
350
|
+
def remove_handler(*args, &block)
|
351
|
+
rescue_middleware.remove_handler(*args, &block)
|
352
|
+
end
|
353
|
+
|
354
|
+
def using_ast_analysis?
|
355
|
+
@analysis_engine == GraphQL::Analysis::AST
|
356
|
+
end
|
357
|
+
|
358
|
+
# For forwards-compatibility with Schema classes
|
359
|
+
alias :graphql_definition :itself
|
360
|
+
|
361
|
+
def deprecated_define(**kwargs, &block)
|
362
|
+
super
|
363
|
+
ensure_defined
|
364
|
+
# Assert that all necessary configs are present:
|
365
|
+
validation_error = Validation.validate(self)
|
366
|
+
validation_error && raise(GraphQL::RequiredImplementationMissingError, validation_error)
|
367
|
+
rebuild_artifacts
|
368
|
+
|
369
|
+
@definition_error = nil
|
370
|
+
nil
|
371
|
+
rescue StandardError => err
|
372
|
+
if @raise_definition_error || err.is_a?(CyclicalDefinitionError) || err.is_a?(GraphQL::RequiredImplementationMissingError)
|
373
|
+
raise
|
374
|
+
else
|
375
|
+
# Raise this error _later_ to avoid messing with Rails constant loading
|
376
|
+
@definition_error = err
|
377
|
+
end
|
378
|
+
nil
|
379
|
+
end
|
380
|
+
|
381
|
+
# Attach `instrumenter` to this schema for instrumenting events of `instrumentation_type`.
|
382
|
+
# @param instrumentation_type [Symbol]
|
383
|
+
# @param instrumenter
|
384
|
+
# @return [void]
|
385
|
+
def instrument(instrumentation_type, instrumenter)
|
386
|
+
@instrumenters[instrumentation_type] << instrumenter
|
387
|
+
if instrumentation_type == :field
|
388
|
+
rebuild_artifacts
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# @return [Array<GraphQL::BaseType>] The root types of this schema
|
393
|
+
def root_types
|
394
|
+
@root_types ||= begin
|
395
|
+
rebuild_artifacts
|
396
|
+
@root_types
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
401
|
+
# @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
|
402
|
+
def types
|
403
|
+
@types ||= begin
|
404
|
+
rebuild_artifacts
|
405
|
+
@types
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
def get_type(type_name)
|
410
|
+
@types[type_name]
|
411
|
+
end
|
412
|
+
|
413
|
+
# @api private
|
414
|
+
def introspection_system
|
415
|
+
@introspection_system ||= begin
|
416
|
+
rebuild_artifacts
|
417
|
+
@introspection_system
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
# Returns a list of Arguments and Fields referencing a certain type
|
422
|
+
# @param type_name [String]
|
423
|
+
# @return [Hash]
|
424
|
+
def references_to(type_name = nil)
|
425
|
+
rebuild_artifacts unless defined?(@type_reference_map)
|
426
|
+
if type_name
|
427
|
+
@type_reference_map.fetch(type_name, [])
|
428
|
+
else
|
429
|
+
@type_reference_map
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
# Returns a list of Union types in which a type is a member
|
434
|
+
# @param type [GraphQL::ObjectType]
|
435
|
+
# @return [Array<GraphQL::UnionType>] list of union types of which the type is a member
|
436
|
+
def union_memberships(type)
|
437
|
+
rebuild_artifacts unless defined?(@union_memberships)
|
438
|
+
@union_memberships.fetch(type.name, [])
|
439
|
+
end
|
440
|
+
|
441
|
+
# Execute a query on itself. Raises an error if the schema definition is invalid.
|
442
|
+
# @see {Query#initialize} for arguments.
|
443
|
+
# @return [Hash] query result, ready to be serialized as JSON
|
444
|
+
def execute(query_str = nil, **kwargs)
|
445
|
+
if query_str
|
446
|
+
kwargs[:query] = query_str
|
447
|
+
end
|
448
|
+
# Some of the query context _should_ be passed to the multiplex, too
|
449
|
+
multiplex_context = if (ctx = kwargs[:context])
|
450
|
+
{
|
451
|
+
backtrace: ctx[:backtrace],
|
452
|
+
tracers: ctx[:tracers],
|
453
|
+
}
|
454
|
+
else
|
455
|
+
{}
|
456
|
+
end
|
457
|
+
# Since we're running one query, don't run a multiplex-level complexity analyzer
|
458
|
+
all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
|
459
|
+
all_results[0]
|
460
|
+
end
|
461
|
+
|
462
|
+
# Execute several queries on itself. Raises an error if the schema definition is invalid.
|
463
|
+
# @example Run several queries at once
|
464
|
+
# context = { ... }
|
465
|
+
# queries = [
|
466
|
+
# { query: params[:query_1], variables: params[:variables_1], context: context },
|
467
|
+
# { query: params[:query_2], variables: params[:variables_2], context: context },
|
468
|
+
# ]
|
469
|
+
# results = MySchema.multiplex(queries)
|
470
|
+
# render json: {
|
471
|
+
# result_1: results[0],
|
472
|
+
# result_2: results[1],
|
473
|
+
# }
|
474
|
+
#
|
475
|
+
# @see {Query#initialize} for query keyword arguments
|
476
|
+
# @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
|
477
|
+
# @param queries [Array<Hash>] Keyword arguments for each query
|
478
|
+
# @param context [Hash] Multiplex-level context
|
479
|
+
# @return [Array<Hash>] One result for each query in the input
|
480
|
+
def multiplex(queries, **kwargs)
|
481
|
+
with_definition_error_check {
|
482
|
+
GraphQL::Execution::Multiplex.run_all(self, queries, **kwargs)
|
483
|
+
}
|
484
|
+
end
|
485
|
+
|
486
|
+
# Search for a schema member using a string path
|
487
|
+
# @example Finding a Field
|
488
|
+
# Schema.find("Ensemble.musicians")
|
489
|
+
#
|
490
|
+
# @see {GraphQL::Schema::Finder} for more examples
|
491
|
+
# @param path [String] A dot-separated path to the member
|
492
|
+
# @raise [Schema::Finder::MemberNotFoundError] if path could not be found
|
493
|
+
# @return [GraphQL::BaseType, GraphQL::Field, GraphQL::Argument, GraphQL::Directive] A GraphQL Schema Member
|
494
|
+
def find(path)
|
495
|
+
rebuild_artifacts unless defined?(@finder)
|
496
|
+
@find_cache[path] ||= @finder.find(path)
|
497
|
+
end
|
498
|
+
|
499
|
+
# Resolve field named `field_name` for type `parent_type`.
|
500
|
+
# Handles dynamic fields `__typename`, `__type` and `__schema`, too
|
501
|
+
# @param parent_type [String, GraphQL::BaseType]
|
502
|
+
# @param field_name [String]
|
503
|
+
# @return [GraphQL::Field, nil] The field named `field_name` on `parent_type`
|
504
|
+
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
505
|
+
def get_field(parent_type, field_name)
|
506
|
+
with_definition_error_check do
|
507
|
+
parent_type_name = case parent_type
|
508
|
+
when GraphQL::BaseType, Class, Module
|
509
|
+
parent_type.graphql_name
|
510
|
+
when String
|
511
|
+
parent_type
|
512
|
+
else
|
513
|
+
raise "Unexpected parent_type: #{parent_type}"
|
514
|
+
end
|
515
|
+
|
516
|
+
defined_field = @instrumented_field_map[parent_type_name][field_name]
|
517
|
+
if defined_field
|
518
|
+
defined_field
|
519
|
+
elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
|
520
|
+
entry_point_field
|
521
|
+
elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
|
522
|
+
dynamic_field
|
523
|
+
else
|
524
|
+
nil
|
525
|
+
end
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
# Fields for this type, after instrumentation is applied
|
530
|
+
# @return [Hash<String, GraphQL::Field>]
|
531
|
+
def get_fields(type)
|
532
|
+
@instrumented_field_map[type.graphql_name]
|
533
|
+
end
|
534
|
+
|
535
|
+
def type_from_ast(ast_node, context:)
|
536
|
+
GraphQL::Schema::TypeExpression.build_type(self, ast_node)
|
537
|
+
end
|
538
|
+
|
539
|
+
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
540
|
+
# @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
|
541
|
+
# @param context [GraphQL::Query::Context] The context for the current query
|
542
|
+
# @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
|
543
|
+
def possible_types(type_defn, context = GraphQL::Query::NullContext)
|
544
|
+
if context == GraphQL::Query::NullContext
|
545
|
+
@possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
|
546
|
+
@possible_types.possible_types(type_defn, context)
|
547
|
+
else
|
548
|
+
# Use the incoming context to cache this instance --
|
549
|
+
# if it were cached on the schema, we'd have a memory leak
|
550
|
+
# https://github.com/rmosolgo/graphql-ruby/issues/2878
|
551
|
+
ns = context.namespace(:possible_types)
|
552
|
+
per_query_possible_types = ns[:possible_types] ||= GraphQL::Schema::PossibleTypes.new(self)
|
553
|
+
per_query_possible_types.possible_types(type_defn, context)
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
# @see [GraphQL::Schema::Warden] Restricted access to root types
|
558
|
+
# @return [GraphQL::ObjectType, nil]
|
559
|
+
def root_type_for_operation(operation)
|
560
|
+
case operation
|
561
|
+
when "query"
|
562
|
+
query
|
563
|
+
when "mutation"
|
564
|
+
mutation
|
565
|
+
when "subscription"
|
566
|
+
subscription
|
567
|
+
else
|
568
|
+
raise ArgumentError, "unknown operation type: #{operation}"
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
def execution_strategy_for_operation(operation)
|
573
|
+
case operation
|
574
|
+
when "query"
|
575
|
+
query_execution_strategy
|
576
|
+
when "mutation"
|
577
|
+
mutation_execution_strategy
|
578
|
+
when "subscription"
|
579
|
+
subscription_execution_strategy
|
580
|
+
else
|
581
|
+
raise ArgumentError, "unknown operation type: #{operation}"
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
# Determine the GraphQL type for a given object.
|
586
|
+
# This is required for unions and interfaces (including Relay's `Node` interface)
|
587
|
+
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
588
|
+
# @param type [GraphQL::UnionType, GraphQL:InterfaceType] the abstract type which is being resolved
|
589
|
+
# @param object [Any] An application object which GraphQL is currently resolving on
|
590
|
+
# @param ctx [GraphQL::Query::Context] The context for the current query
|
591
|
+
# @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
|
592
|
+
def resolve_type(type, object, ctx = :__undefined__)
|
593
|
+
check_resolved_type(type, object, ctx) do |ok_type, ok_object, ok_ctx|
|
594
|
+
if @resolve_type_proc.nil?
|
595
|
+
raise(GraphQL::RequiredImplementationMissingError, "Can't determine GraphQL type for: #{ok_object.inspect}, define `resolve_type (type, obj, ctx) -> { ... }` inside `Schema.define`.")
|
596
|
+
end
|
597
|
+
@resolve_type_proc.call(ok_type, ok_object, ok_ctx)
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
# This is a compatibility hack so that instance-level and class-level
|
602
|
+
# methods can get correctness checks without calling one another
|
603
|
+
# @api private
|
604
|
+
def check_resolved_type(type, object, ctx = :__undefined__)
|
605
|
+
if ctx == :__undefined__
|
606
|
+
# Old method signature
|
607
|
+
ctx = object
|
608
|
+
object = type
|
609
|
+
type = nil
|
610
|
+
end
|
611
|
+
|
612
|
+
if object.is_a?(GraphQL::Schema::Object)
|
613
|
+
object = object.object
|
614
|
+
end
|
615
|
+
|
616
|
+
if type.respond_to?(:graphql_definition)
|
617
|
+
type = type.graphql_definition
|
618
|
+
end
|
619
|
+
|
620
|
+
# Prefer a type-local function; fall back to the schema-level function
|
621
|
+
type_proc = type && type.resolve_type_proc
|
622
|
+
type_result = if type_proc
|
623
|
+
type_proc.call(object, ctx)
|
624
|
+
else
|
625
|
+
yield(type, object, ctx)
|
626
|
+
end
|
627
|
+
|
628
|
+
if type_result.nil?
|
629
|
+
nil
|
630
|
+
else
|
631
|
+
after_lazy(type_result) do |resolved_type_result|
|
632
|
+
if resolved_type_result.respond_to?(:graphql_definition)
|
633
|
+
resolved_type_result = resolved_type_result.graphql_definition
|
634
|
+
end
|
635
|
+
if !resolved_type_result.is_a?(GraphQL::BaseType)
|
636
|
+
type_str = "#{resolved_type_result} (#{resolved_type_result.class.name})"
|
637
|
+
raise "resolve_type(#{object}) returned #{type_str}, but it should return a GraphQL type"
|
638
|
+
else
|
639
|
+
resolved_type_result
|
640
|
+
end
|
641
|
+
end
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
def resolve_type=(new_resolve_type_proc)
|
646
|
+
callable = GraphQL::BackwardsCompatibility.wrap_arity(new_resolve_type_proc, from: 2, to: 3, last: true, name: "Schema#resolve_type(type, obj, ctx)")
|
647
|
+
@resolve_type_proc = callable
|
648
|
+
end
|
649
|
+
|
650
|
+
# Fetch an application object by its unique id
|
651
|
+
# @param id [String] A unique identifier, provided previously by this GraphQL schema
|
652
|
+
# @param ctx [GraphQL::Query::Context] The context for the current query
|
653
|
+
# @return [Any] The application object identified by `id`
|
654
|
+
def object_from_id(id, ctx)
|
655
|
+
if @object_from_id_proc.nil?
|
656
|
+
raise(GraphQL::RequiredImplementationMissingError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
|
657
|
+
else
|
658
|
+
@object_from_id_proc.call(id, ctx)
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
# @param new_proc [#call] A new callable for fetching objects by ID
|
663
|
+
def object_from_id=(new_proc)
|
664
|
+
@object_from_id_proc = new_proc
|
665
|
+
end
|
666
|
+
|
667
|
+
# When we encounter a type error during query execution, we call this hook.
|
668
|
+
#
|
669
|
+
# You can use this hook to write a log entry,
|
670
|
+
# add a {GraphQL::ExecutionError} to the response (with `ctx.add_error`)
|
671
|
+
# or raise an exception and halt query execution.
|
672
|
+
#
|
673
|
+
# @example A `nil` is encountered by a non-null field
|
674
|
+
# type_error ->(err, query_ctx) {
|
675
|
+
# err.is_a?(GraphQL::InvalidNullError) # => true
|
676
|
+
# }
|
677
|
+
#
|
678
|
+
# @example An object doesn't resolve to one of a {UnionType}'s members
|
679
|
+
# type_error ->(err, query_ctx) {
|
680
|
+
# err.is_a?(GraphQL::UnresolvedTypeError) # => true
|
681
|
+
# }
|
682
|
+
#
|
683
|
+
# @see {DefaultTypeError} is the default behavior.
|
684
|
+
# @param err [GraphQL::TypeError] The error encountered during execution
|
685
|
+
# @param ctx [GraphQL::Query::Context] The context for the field where the error occurred
|
686
|
+
# @return void
|
687
|
+
def type_error(err, ctx)
|
688
|
+
@type_error_proc.call(err, ctx)
|
689
|
+
end
|
690
|
+
|
691
|
+
# @param new_proc [#call] A new callable for handling type errors during execution
|
692
|
+
def type_error=(new_proc)
|
693
|
+
@type_error_proc = new_proc
|
694
|
+
end
|
695
|
+
|
696
|
+
# Can't delegate to `class`
|
697
|
+
alias :_schema_class :class
|
698
|
+
def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
|
699
|
+
def_delegators :_schema_class, :directive
|
700
|
+
def_delegators :_schema_class, :error_handler
|
701
|
+
def_delegators :_schema_class, :validate
|
702
|
+
|
703
|
+
|
704
|
+
# Given this schema member, find the class-based definition object
|
705
|
+
# whose `method_name` should be treated as an application hook
|
706
|
+
# @see {.visible?}
|
707
|
+
# @see {.accessible?}
|
708
|
+
def call_on_type_class(member, method_name, context, default:)
|
709
|
+
member = if member.respond_to?(:type_class)
|
710
|
+
member.type_class
|
711
|
+
else
|
712
|
+
member
|
713
|
+
end
|
714
|
+
|
715
|
+
if member.respond_to?(:relay_node_type) && (t = member.relay_node_type)
|
716
|
+
member = t
|
717
|
+
end
|
718
|
+
|
719
|
+
if member.respond_to?(method_name)
|
720
|
+
member.public_send(method_name, context)
|
721
|
+
else
|
722
|
+
default
|
723
|
+
end
|
724
|
+
end
|
725
|
+
|
726
|
+
def visible?(member, context)
|
727
|
+
call_on_type_class(member, :visible?, context, default: true)
|
728
|
+
end
|
729
|
+
|
730
|
+
def accessible?(member, context)
|
731
|
+
call_on_type_class(member, :accessible?, context, default: true)
|
732
|
+
end
|
733
|
+
|
734
|
+
# A function to call when {#execute} receives an invalid query string
|
735
|
+
#
|
736
|
+
# @see {DefaultParseError} is the default behavior.
|
737
|
+
# @param err [GraphQL::ParseError] The error encountered during parsing
|
738
|
+
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
739
|
+
# @return void
|
740
|
+
def parse_error(err, ctx)
|
741
|
+
@parse_error_proc.call(err, ctx)
|
742
|
+
end
|
743
|
+
|
744
|
+
# @param new_proc [#call] A new callable for handling parse errors during execution
|
745
|
+
def parse_error=(new_proc)
|
746
|
+
@parse_error_proc = new_proc
|
747
|
+
end
|
748
|
+
|
749
|
+
# Get a unique identifier from this object
|
750
|
+
# @param object [Any] An application object
|
751
|
+
# @param type [GraphQL::BaseType] The current type definition
|
752
|
+
# @param ctx [GraphQL::Query::Context] the context for the current query
|
753
|
+
# @return [String] a unique identifier for `object` which clients can use to refetch it
|
754
|
+
def id_from_object(object, type, ctx)
|
755
|
+
if @id_from_object_proc.nil?
|
756
|
+
raise(GraphQL::RequiredImplementationMissingError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
|
757
|
+
else
|
758
|
+
@id_from_object_proc.call(object, type, ctx)
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
# @param new_proc [#call] A new callable for generating unique IDs
|
763
|
+
def id_from_object=(new_proc)
|
764
|
+
@id_from_object_proc = new_proc
|
765
|
+
end
|
766
|
+
|
767
|
+
# Create schema with the result of an introspection query.
|
768
|
+
# @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
|
769
|
+
# @return [GraphQL::Schema] the schema described by `input`
|
770
|
+
def self.from_introspection(introspection_result)
|
771
|
+
GraphQL::Schema::Loader.load(introspection_result)
|
772
|
+
end
|
773
|
+
|
774
|
+
# Create schema from an IDL schema or file containing an IDL definition.
|
775
|
+
# @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
|
776
|
+
# @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
|
777
|
+
# @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
|
778
|
+
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
779
|
+
# @return [Class] the schema described by `document`
|
780
|
+
def self.from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
|
781
|
+
# If the file ends in `.graphql`, treat it like a filepath
|
782
|
+
if definition_or_path.end_with?(".graphql")
|
783
|
+
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
784
|
+
definition_or_path,
|
785
|
+
default_resolve: default_resolve,
|
786
|
+
parser: parser,
|
787
|
+
using: using,
|
788
|
+
)
|
789
|
+
else
|
790
|
+
GraphQL::Schema::BuildFromDefinition.from_definition(
|
791
|
+
definition_or_path,
|
792
|
+
default_resolve: default_resolve,
|
793
|
+
parser: parser,
|
794
|
+
using: using,
|
795
|
+
)
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
800
|
+
class InvalidDocumentError < Error; end;
|
801
|
+
|
802
|
+
# Return the GraphQL IDL for the schema
|
803
|
+
# @param context [Hash]
|
804
|
+
# @param only [<#call(member, ctx)>]
|
805
|
+
# @param except [<#call(member, ctx)>]
|
806
|
+
# @return [String]
|
807
|
+
def to_definition(only: nil, except: nil, context: {})
|
808
|
+
GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
|
809
|
+
end
|
810
|
+
|
811
|
+
# Return the GraphQL::Language::Document IDL AST for the schema
|
812
|
+
# @param context [Hash]
|
813
|
+
# @param only [<#call(member, ctx)>]
|
814
|
+
# @param except [<#call(member, ctx)>]
|
815
|
+
# @return [GraphQL::Language::Document]
|
816
|
+
def to_document(only: nil, except: nil, context: {})
|
817
|
+
GraphQL::Language::DocumentFromSchemaDefinition.new(self, only: only, except: except, context: context).document
|
818
|
+
end
|
819
|
+
|
820
|
+
# Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
|
821
|
+
# @param context [Hash]
|
822
|
+
# @param only [<#call(member, ctx)>]
|
823
|
+
# @param except [<#call(member, ctx)>]
|
824
|
+
# @return [Hash] GraphQL result
|
825
|
+
def as_json(only: nil, except: nil, context: {})
|
826
|
+
execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
|
827
|
+
end
|
828
|
+
|
829
|
+
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
830
|
+
# @see {#as_json}
|
831
|
+
# @return [String]
|
832
|
+
def to_json(*args)
|
833
|
+
JSON.pretty_generate(as_json(*args))
|
834
|
+
end
|
835
|
+
|
836
|
+
def new_connections?
|
837
|
+
!!connections
|
838
|
+
end
|
839
|
+
|
840
|
+
attr_accessor :connections
|
841
|
+
|
842
|
+
class << self
|
843
|
+
extend Forwardable
|
844
|
+
# For compatibility, these methods all:
|
845
|
+
# - Cause the Schema instance to be created, if it hasn't been created yet
|
846
|
+
# - Delegate to that instance
|
847
|
+
# Eventually, the methods will be moved into this class, removing the need for the singleton.
|
848
|
+
def_delegators :graphql_definition,
|
849
|
+
# Execution
|
850
|
+
:execution_strategy_for_operation,
|
851
|
+
# Configuration
|
852
|
+
:metadata, :redefine,
|
853
|
+
:id_from_object_proc, :object_from_id_proc,
|
854
|
+
:id_from_object=, :object_from_id=,
|
855
|
+
:remove_handler
|
856
|
+
|
857
|
+
# @return [GraphQL::Subscriptions]
|
858
|
+
attr_accessor :subscriptions
|
859
|
+
|
860
|
+
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
861
|
+
# @see {#as_json}
|
862
|
+
# @return [String]
|
863
|
+
def to_json(**args)
|
864
|
+
JSON.pretty_generate(as_json(**args))
|
865
|
+
end
|
866
|
+
|
867
|
+
# Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
|
868
|
+
# @param context [Hash]
|
869
|
+
# @param only [<#call(member, ctx)>]
|
870
|
+
# @param except [<#call(member, ctx)>]
|
871
|
+
# @return [Hash] GraphQL result
|
872
|
+
def as_json(only: nil, except: nil, context: {})
|
873
|
+
execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
|
874
|
+
end
|
875
|
+
|
876
|
+
# Return the GraphQL IDL for the schema
|
877
|
+
# @param context [Hash]
|
878
|
+
# @param only [<#call(member, ctx)>]
|
879
|
+
# @param except [<#call(member, ctx)>]
|
880
|
+
# @return [String]
|
881
|
+
def to_definition(only: nil, except: nil, context: {})
|
882
|
+
GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
|
883
|
+
end
|
884
|
+
|
885
|
+
# Return the GraphQL::Language::Document IDL AST for the schema
|
886
|
+
# @return [GraphQL::Language::Document]
|
887
|
+
def to_document
|
888
|
+
GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
|
889
|
+
end
|
890
|
+
|
891
|
+
def find(path)
|
892
|
+
if !@finder
|
893
|
+
@find_cache = {}
|
894
|
+
@finder ||= GraphQL::Schema::Finder.new(self)
|
895
|
+
end
|
896
|
+
@find_cache[path] ||= @finder.find(path)
|
897
|
+
end
|
898
|
+
|
899
|
+
def graphql_definition
|
900
|
+
@graphql_definition ||= to_graphql
|
901
|
+
end
|
902
|
+
|
903
|
+
def default_filter
|
904
|
+
GraphQL::Filter.new(except: default_mask)
|
905
|
+
end
|
906
|
+
|
907
|
+
def default_mask(new_mask = nil)
|
908
|
+
if new_mask
|
909
|
+
@own_default_mask = new_mask
|
910
|
+
else
|
911
|
+
@own_default_mask || find_inherited_value(:default_mask, Schema::NullMask)
|
912
|
+
end
|
913
|
+
end
|
914
|
+
|
915
|
+
def static_validator
|
916
|
+
GraphQL::StaticValidation::Validator.new(schema: self)
|
917
|
+
end
|
918
|
+
|
919
|
+
def use(plugin, **kwargs)
|
920
|
+
if kwargs.any?
|
921
|
+
plugin.use(self, **kwargs)
|
922
|
+
else
|
923
|
+
plugin.use(self)
|
924
|
+
end
|
925
|
+
own_plugins << [plugin, kwargs]
|
926
|
+
end
|
927
|
+
|
928
|
+
def plugins
|
929
|
+
find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
|
930
|
+
end
|
931
|
+
|
932
|
+
def to_graphql
|
933
|
+
schema_defn = self.new
|
934
|
+
schema_defn.raise_definition_error = true
|
935
|
+
schema_defn.query = query && query.graphql_definition
|
936
|
+
schema_defn.mutation = mutation && mutation.graphql_definition
|
937
|
+
schema_defn.subscription = subscription && subscription.graphql_definition
|
938
|
+
schema_defn.validate_timeout = validate_timeout
|
939
|
+
schema_defn.validate_max_errors = validate_max_errors
|
940
|
+
schema_defn.max_complexity = max_complexity
|
941
|
+
schema_defn.error_bubbling = error_bubbling
|
942
|
+
schema_defn.max_depth = max_depth
|
943
|
+
schema_defn.default_max_page_size = default_max_page_size
|
944
|
+
schema_defn.orphan_types = orphan_types.map(&:graphql_definition)
|
945
|
+
schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
|
946
|
+
schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
|
947
|
+
schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
|
948
|
+
|
949
|
+
prepped_dirs = {}
|
950
|
+
directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
|
951
|
+
schema_defn.directives = prepped_dirs
|
952
|
+
schema_defn.introspection_namespace = introspection
|
953
|
+
schema_defn.resolve_type = method(:resolve_type)
|
954
|
+
schema_defn.object_from_id = method(:object_from_id)
|
955
|
+
schema_defn.id_from_object = method(:id_from_object)
|
956
|
+
schema_defn.type_error = method(:type_error)
|
957
|
+
schema_defn.context_class = context_class
|
958
|
+
schema_defn.cursor_encoder = cursor_encoder
|
959
|
+
schema_defn.tracers.concat(tracers)
|
960
|
+
schema_defn.query_analyzers.concat(query_analyzers)
|
961
|
+
schema_defn.analysis_engine = analysis_engine
|
962
|
+
|
963
|
+
schema_defn.middleware.concat(all_middleware)
|
964
|
+
schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
|
965
|
+
schema_defn.query_execution_strategy = query_execution_strategy
|
966
|
+
schema_defn.mutation_execution_strategy = mutation_execution_strategy
|
967
|
+
schema_defn.subscription_execution_strategy = subscription_execution_strategy
|
968
|
+
schema_defn.default_mask = default_mask
|
969
|
+
instrumenters.each do |step, insts|
|
970
|
+
insts.each do |inst|
|
971
|
+
schema_defn.instrumenters[step] << inst
|
972
|
+
end
|
973
|
+
end
|
974
|
+
|
975
|
+
lazy_methods.each do |lazy_class, value_method|
|
976
|
+
schema_defn.lazy_methods.set(lazy_class, value_method)
|
977
|
+
end
|
978
|
+
|
979
|
+
error_handler.each_rescue do |err_class, handler|
|
980
|
+
schema_defn.rescue_from(err_class, &handler)
|
981
|
+
end
|
982
|
+
|
983
|
+
schema_defn.subscriptions ||= self.subscriptions
|
984
|
+
|
985
|
+
if !schema_defn.interpreter?
|
986
|
+
schema_defn.instrumenters[:query] << GraphQL::Schema::Member::Instrumentation
|
987
|
+
end
|
988
|
+
|
989
|
+
if new_connections?
|
990
|
+
schema_defn.connections = self.connections
|
991
|
+
end
|
992
|
+
|
993
|
+
schema_defn.send(:rebuild_artifacts)
|
994
|
+
|
995
|
+
schema_defn
|
996
|
+
end
|
997
|
+
|
998
|
+
# Build a map of `{ name => type }` and return it
|
999
|
+
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
1000
|
+
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
1001
|
+
def types(context = GraphQL::Query::NullContext)
|
1002
|
+
all_types = non_introspection_types.merge(introspection_system.types)
|
1003
|
+
visible_types = {}
|
1004
|
+
all_types.each do |k, v|
|
1005
|
+
visible_types[k] =if v.is_a?(Array)
|
1006
|
+
visible_t = nil
|
1007
|
+
v.each do |t|
|
1008
|
+
if t.visible?(context)
|
1009
|
+
if visible_t.nil?
|
1010
|
+
visible_t = t
|
1011
|
+
else
|
1012
|
+
raise DuplicateNamesError, "Found two visible type definitions for `#{k}`: #{visible_t.inspect}, #{t.inspect}"
|
1013
|
+
end
|
1014
|
+
end
|
1015
|
+
end
|
1016
|
+
visible_t
|
1017
|
+
else
|
1018
|
+
v
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
visible_types
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
# @param type_name [String]
|
1025
|
+
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
1026
|
+
def get_type(type_name, context = GraphQL::Query::NullContext)
|
1027
|
+
local_entry = own_types[type_name]
|
1028
|
+
type_defn = case local_entry
|
1029
|
+
when nil
|
1030
|
+
nil
|
1031
|
+
when Array
|
1032
|
+
visible_t = nil
|
1033
|
+
warden = Warden.from_context(context)
|
1034
|
+
local_entry.each do |t|
|
1035
|
+
if warden.visible_type?(t, context)
|
1036
|
+
if visible_t.nil?
|
1037
|
+
visible_t = t
|
1038
|
+
else
|
1039
|
+
raise DuplicateNamesError, "Found two visible type definitions for `#{type_name}`: #{visible_t.inspect}, #{t.inspect}"
|
1040
|
+
end
|
1041
|
+
end
|
1042
|
+
end
|
1043
|
+
visible_t
|
1044
|
+
when Module
|
1045
|
+
local_entry
|
1046
|
+
else
|
1047
|
+
raise "Invariant: unexpected own_types[#{type_name.inspect}]: #{local_entry.inspect}"
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
type_defn ||
|
1051
|
+
introspection_system.types[type_name] || # todo context-specific introspection?
|
1052
|
+
(superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
# @api private
|
1056
|
+
attr_writer :connections
|
1057
|
+
|
1058
|
+
# @return [GraphQL::Pagination::Connections] if installed
|
1059
|
+
def connections
|
1060
|
+
if defined?(@connections)
|
1061
|
+
@connections
|
1062
|
+
else
|
1063
|
+
inherited_connections = find_inherited_value(:connections, nil)
|
1064
|
+
# This schema is part of an inheritance chain which is using new connections,
|
1065
|
+
# make a new instance, so we don't pollute the upstream one.
|
1066
|
+
if inherited_connections
|
1067
|
+
@connections = Pagination::Connections.new(schema: self)
|
1068
|
+
else
|
1069
|
+
nil
|
1070
|
+
end
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
def new_connections?
|
1075
|
+
!!connections
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
def query(new_query_object = nil)
|
1079
|
+
if new_query_object
|
1080
|
+
if @query_object
|
1081
|
+
raise GraphQL::Error, "Second definition of `query(...)` (#{new_query_object.inspect}) is invalid, already configured with #{@query_object.inspect}"
|
1082
|
+
else
|
1083
|
+
@query_object = new_query_object
|
1084
|
+
add_type_and_traverse(new_query_object, root: true)
|
1085
|
+
nil
|
1086
|
+
end
|
1087
|
+
else
|
1088
|
+
@query_object || find_inherited_value(:query)
|
1089
|
+
end
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
def mutation(new_mutation_object = nil)
|
1093
|
+
if new_mutation_object
|
1094
|
+
if @mutation_object
|
1095
|
+
raise GraphQL::Error, "Second definition of `mutation(...)` (#{new_mutation_object.inspect}) is invalid, already configured with #{@mutation_object.inspect}"
|
1096
|
+
else
|
1097
|
+
@mutation_object = new_mutation_object
|
1098
|
+
add_type_and_traverse(new_mutation_object, root: true)
|
1099
|
+
nil
|
1100
|
+
end
|
1101
|
+
else
|
1102
|
+
@mutation_object || find_inherited_value(:mutation)
|
1103
|
+
end
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
def subscription(new_subscription_object = nil)
|
1107
|
+
if new_subscription_object
|
1108
|
+
if @subscription_object
|
1109
|
+
raise GraphQL::Error, "Second definition of `subscription(...)` (#{new_subscription_object.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
|
1110
|
+
else
|
1111
|
+
@subscription_object = new_subscription_object
|
1112
|
+
add_subscription_extension_if_necessary
|
1113
|
+
add_type_and_traverse(new_subscription_object, root: true)
|
1114
|
+
nil
|
1115
|
+
end
|
1116
|
+
else
|
1117
|
+
@subscription_object || find_inherited_value(:subscription)
|
1118
|
+
end
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
# @see [GraphQL::Schema::Warden] Restricted access to root types
|
1122
|
+
# @return [GraphQL::ObjectType, nil]
|
1123
|
+
def root_type_for_operation(operation)
|
1124
|
+
case operation
|
1125
|
+
when "query"
|
1126
|
+
query
|
1127
|
+
when "mutation"
|
1128
|
+
mutation
|
1129
|
+
when "subscription"
|
1130
|
+
subscription
|
1131
|
+
else
|
1132
|
+
raise ArgumentError, "unknown operation type: #{operation}"
|
1133
|
+
end
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
def root_types
|
1137
|
+
@root_types
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
# @param type [Module] The type definition whose possible types you want to see
|
1141
|
+
# @return [Hash<String, Module>] All possible types, if no `type` is given.
|
1142
|
+
# @return [Array<Module>] Possible types for `type`, if it's given.
|
1143
|
+
def possible_types(type = nil, context = GraphQL::Query::NullContext)
|
1144
|
+
if type
|
1145
|
+
# TODO duck-typing `.possible_types` would probably be nicer here
|
1146
|
+
if type.kind.union?
|
1147
|
+
type.possible_types(context: context)
|
1148
|
+
else
|
1149
|
+
stored_possible_types = own_possible_types[type.graphql_name]
|
1150
|
+
visible_possible_types = if stored_possible_types && type.kind.interface?
|
1151
|
+
stored_possible_types.select do |possible_type|
|
1152
|
+
# Use `.graphql_name` comparison to match legacy vs class-based types.
|
1153
|
+
# When we don't need to support legacy `.define` types, use `.include?(type)` instead.
|
1154
|
+
possible_type.interfaces(context).any? { |interface| interface.graphql_name == type.graphql_name }
|
1155
|
+
end
|
1156
|
+
else
|
1157
|
+
stored_possible_types
|
1158
|
+
end
|
1159
|
+
visible_possible_types ||
|
1160
|
+
introspection_system.possible_types[type.graphql_name] ||
|
1161
|
+
(
|
1162
|
+
superclass.respond_to?(:possible_types) ?
|
1163
|
+
superclass.possible_types(type, context) :
|
1164
|
+
EMPTY_ARRAY
|
1165
|
+
)
|
1166
|
+
end
|
1167
|
+
else
|
1168
|
+
find_inherited_value(:possible_types, EMPTY_HASH)
|
1169
|
+
.merge(own_possible_types)
|
1170
|
+
.merge(introspection_system.possible_types)
|
1171
|
+
end
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
def union_memberships(type = nil)
|
1175
|
+
if type
|
1176
|
+
own_um = own_union_memberships.fetch(type.graphql_name, EMPTY_ARRAY)
|
1177
|
+
inherited_um = find_inherited_value(:union_memberships, EMPTY_HASH).fetch(type.graphql_name, EMPTY_ARRAY)
|
1178
|
+
own_um + inherited_um
|
1179
|
+
else
|
1180
|
+
joined_um = own_union_memberships.dup
|
1181
|
+
find_inherited_value(:union_memberhips, EMPTY_HASH).each do |k, v|
|
1182
|
+
um = joined_um[k] ||= []
|
1183
|
+
um.concat(v)
|
1184
|
+
end
|
1185
|
+
joined_um
|
1186
|
+
end
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
# @api private
|
1190
|
+
# @see GraphQL::Dataloader
|
1191
|
+
def dataloader_class
|
1192
|
+
@dataloader_class || GraphQL::Dataloader::NullDataloader
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
attr_writer :dataloader_class
|
1196
|
+
|
1197
|
+
def references_to(to_type = nil, from: nil)
|
1198
|
+
@own_references_to ||= Hash.new { |h, k| h[k] = [] }
|
1199
|
+
if to_type
|
1200
|
+
if !to_type.is_a?(String)
|
1201
|
+
to_type = to_type.graphql_name
|
1202
|
+
end
|
1203
|
+
|
1204
|
+
if from
|
1205
|
+
@own_references_to[to_type] << from
|
1206
|
+
else
|
1207
|
+
own_refs = @own_references_to[to_type]
|
1208
|
+
inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
|
1209
|
+
own_refs + inherited_refs
|
1210
|
+
end
|
1211
|
+
else
|
1212
|
+
# `@own_references_to` can be quite large for big schemas,
|
1213
|
+
# and generally speaking, we won't inherit any values.
|
1214
|
+
# So optimize the most common case -- don't create a duplicate Hash.
|
1215
|
+
inherited_value = find_inherited_value(:references_to, EMPTY_HASH)
|
1216
|
+
if inherited_value.any?
|
1217
|
+
inherited_value.merge(@own_references_to)
|
1218
|
+
else
|
1219
|
+
@own_references_to
|
1220
|
+
end
|
1221
|
+
end
|
1222
|
+
end
|
1223
|
+
|
1224
|
+
def type_from_ast(ast_node, context: nil)
|
1225
|
+
type_owner = context ? context.warden : self
|
1226
|
+
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
1227
|
+
end
|
1228
|
+
|
1229
|
+
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
|
1230
|
+
parent_type = case type_or_name
|
1231
|
+
when LateBoundType
|
1232
|
+
get_type(type_or_name.name, context)
|
1233
|
+
when String
|
1234
|
+
get_type(type_or_name, context)
|
1235
|
+
when Module
|
1236
|
+
type_or_name
|
1237
|
+
else
|
1238
|
+
raise ArgumentError, "unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
|
1242
|
+
field
|
1243
|
+
elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
|
1244
|
+
entry_point_field
|
1245
|
+
elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
|
1246
|
+
dynamic_field
|
1247
|
+
else
|
1248
|
+
nil
|
1249
|
+
end
|
1250
|
+
end
|
1251
|
+
|
1252
|
+
def get_fields(type, context = GraphQL::Query::NullContext)
|
1253
|
+
type.fields(context)
|
1254
|
+
end
|
1255
|
+
|
1256
|
+
def introspection(new_introspection_namespace = nil)
|
1257
|
+
if new_introspection_namespace
|
1258
|
+
@introspection = new_introspection_namespace
|
1259
|
+
# reset this cached value:
|
1260
|
+
@introspection_system = nil
|
1261
|
+
else
|
1262
|
+
@introspection || find_inherited_value(:introspection)
|
1263
|
+
end
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
def introspection_system
|
1267
|
+
if !@introspection_system
|
1268
|
+
@introspection_system = Schema::IntrospectionSystem.new(self)
|
1269
|
+
@introspection_system.resolve_late_bindings
|
1270
|
+
end
|
1271
|
+
@introspection_system
|
1272
|
+
end
|
1273
|
+
|
1274
|
+
def cursor_encoder(new_encoder = nil)
|
1275
|
+
if new_encoder
|
1276
|
+
@cursor_encoder = new_encoder
|
1277
|
+
end
|
1278
|
+
@cursor_encoder || find_inherited_value(:cursor_encoder, Base64Encoder)
|
1279
|
+
end
|
1280
|
+
|
1281
|
+
def default_max_page_size(new_default_max_page_size = nil)
|
1282
|
+
if new_default_max_page_size
|
1283
|
+
@default_max_page_size = new_default_max_page_size
|
1284
|
+
else
|
1285
|
+
@default_max_page_size || find_inherited_value(:default_max_page_size)
|
1286
|
+
end
|
1287
|
+
end
|
1288
|
+
|
1289
|
+
def query_execution_strategy(new_query_execution_strategy = nil)
|
1290
|
+
if new_query_execution_strategy
|
1291
|
+
@query_execution_strategy = new_query_execution_strategy
|
1292
|
+
else
|
1293
|
+
@query_execution_strategy || find_inherited_value(:query_execution_strategy, self.default_execution_strategy)
|
1294
|
+
end
|
1295
|
+
end
|
1296
|
+
|
1297
|
+
def mutation_execution_strategy(new_mutation_execution_strategy = nil)
|
1298
|
+
if new_mutation_execution_strategy
|
1299
|
+
@mutation_execution_strategy = new_mutation_execution_strategy
|
1300
|
+
else
|
1301
|
+
@mutation_execution_strategy || find_inherited_value(:mutation_execution_strategy, self.default_execution_strategy)
|
1302
|
+
end
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
def subscription_execution_strategy(new_subscription_execution_strategy = nil)
|
1306
|
+
if new_subscription_execution_strategy
|
1307
|
+
@subscription_execution_strategy = new_subscription_execution_strategy
|
1308
|
+
else
|
1309
|
+
@subscription_execution_strategy || find_inherited_value(:subscription_execution_strategy, self.default_execution_strategy)
|
1310
|
+
end
|
1311
|
+
end
|
1312
|
+
|
1313
|
+
attr_writer :validate_timeout
|
1314
|
+
|
1315
|
+
def validate_timeout(new_validate_timeout = nil)
|
1316
|
+
if new_validate_timeout
|
1317
|
+
@validate_timeout = new_validate_timeout
|
1318
|
+
elsif defined?(@validate_timeout)
|
1319
|
+
@validate_timeout
|
1320
|
+
else
|
1321
|
+
find_inherited_value(:validate_timeout)
|
1322
|
+
end
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
# Validate a query string according to this schema.
|
1326
|
+
# @param string_or_document [String, GraphQL::Language::Nodes::Document]
|
1327
|
+
# @return [Array<GraphQL::StaticValidation::Error >]
|
1328
|
+
def validate(string_or_document, rules: nil, context: nil)
|
1329
|
+
doc = if string_or_document.is_a?(String)
|
1330
|
+
GraphQL.parse(string_or_document)
|
1331
|
+
else
|
1332
|
+
string_or_document
|
1333
|
+
end
|
1334
|
+
query = GraphQL::Query.new(self, document: doc, context: context)
|
1335
|
+
validator_opts = { schema: self }
|
1336
|
+
rules && (validator_opts[:rules] = rules)
|
1337
|
+
validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
|
1338
|
+
res = validator.validate(query, timeout: validate_timeout, max_errors: validate_max_errors)
|
1339
|
+
res[:errors]
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
attr_writer :validate_max_errors
|
1343
|
+
|
1344
|
+
def validate_max_errors(new_validate_max_errors = nil)
|
1345
|
+
if new_validate_max_errors
|
1346
|
+
@validate_max_errors = new_validate_max_errors
|
1347
|
+
elsif defined?(@validate_max_errors)
|
1348
|
+
@validate_max_errors
|
1349
|
+
else
|
1350
|
+
find_inherited_value(:validate_max_errors)
|
1351
|
+
end
|
1352
|
+
end
|
1353
|
+
|
1354
|
+
attr_writer :max_complexity
|
1355
|
+
|
1356
|
+
def max_complexity(max_complexity = nil)
|
1357
|
+
if max_complexity
|
1358
|
+
@max_complexity = max_complexity
|
1359
|
+
elsif defined?(@max_complexity)
|
1360
|
+
@max_complexity
|
1361
|
+
else
|
1362
|
+
find_inherited_value(:max_complexity)
|
1363
|
+
end
|
1364
|
+
end
|
1365
|
+
|
1366
|
+
attr_writer :analysis_engine
|
1367
|
+
|
1368
|
+
def analysis_engine
|
1369
|
+
@analysis_engine || find_inherited_value(:analysis_engine, self.default_analysis_engine)
|
1370
|
+
end
|
1371
|
+
|
1372
|
+
def using_ast_analysis?
|
1373
|
+
analysis_engine == GraphQL::Analysis::AST
|
1374
|
+
end
|
1375
|
+
|
1376
|
+
def interpreter?
|
1377
|
+
query_execution_strategy == GraphQL::Execution::Interpreter &&
|
1378
|
+
mutation_execution_strategy == GraphQL::Execution::Interpreter &&
|
1379
|
+
subscription_execution_strategy == GraphQL::Execution::Interpreter
|
1380
|
+
end
|
1381
|
+
|
1382
|
+
attr_writer :interpreter
|
1383
|
+
|
1384
|
+
def error_bubbling(new_error_bubbling = nil)
|
1385
|
+
if !new_error_bubbling.nil?
|
1386
|
+
@error_bubbling = new_error_bubbling
|
1387
|
+
else
|
1388
|
+
@error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
|
1389
|
+
end
|
1390
|
+
end
|
1391
|
+
|
1392
|
+
attr_writer :error_bubbling
|
1393
|
+
|
1394
|
+
attr_writer :max_depth
|
1395
|
+
|
1396
|
+
def max_depth(new_max_depth = nil)
|
1397
|
+
if new_max_depth
|
1398
|
+
@max_depth = new_max_depth
|
1399
|
+
elsif defined?(@max_depth)
|
1400
|
+
@max_depth
|
1401
|
+
else
|
1402
|
+
find_inherited_value(:max_depth)
|
1403
|
+
end
|
1404
|
+
end
|
1405
|
+
|
1406
|
+
def disable_introspection_entry_points
|
1407
|
+
@disable_introspection_entry_points = true
|
1408
|
+
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
1409
|
+
@introspection_system = nil
|
1410
|
+
end
|
1411
|
+
|
1412
|
+
def disable_schema_introspection_entry_point
|
1413
|
+
@disable_schema_introspection_entry_point = true
|
1414
|
+
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
1415
|
+
@introspection_system = nil
|
1416
|
+
end
|
1417
|
+
|
1418
|
+
def disable_type_introspection_entry_point
|
1419
|
+
@disable_type_introspection_entry_point = true
|
1420
|
+
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
1421
|
+
@introspection_system = nil
|
1422
|
+
end
|
1423
|
+
|
1424
|
+
def disable_introspection_entry_points?
|
1425
|
+
if instance_variable_defined?(:@disable_introspection_entry_points)
|
1426
|
+
@disable_introspection_entry_points
|
1427
|
+
else
|
1428
|
+
find_inherited_value(:disable_introspection_entry_points?, false)
|
1429
|
+
end
|
1430
|
+
end
|
1431
|
+
|
1432
|
+
def disable_schema_introspection_entry_point?
|
1433
|
+
if instance_variable_defined?(:@disable_schema_introspection_entry_point)
|
1434
|
+
@disable_schema_introspection_entry_point
|
1435
|
+
else
|
1436
|
+
find_inherited_value(:disable_schema_introspection_entry_point?, false)
|
1437
|
+
end
|
1438
|
+
end
|
1439
|
+
|
1440
|
+
def disable_type_introspection_entry_point?
|
1441
|
+
if instance_variable_defined?(:@disable_type_introspection_entry_point)
|
1442
|
+
@disable_type_introspection_entry_point
|
1443
|
+
else
|
1444
|
+
find_inherited_value(:disable_type_introspection_entry_point?, false)
|
1445
|
+
end
|
1446
|
+
end
|
1447
|
+
|
1448
|
+
def orphan_types(*new_orphan_types)
|
1449
|
+
if new_orphan_types.any?
|
1450
|
+
new_orphan_types = new_orphan_types.flatten
|
1451
|
+
add_type_and_traverse(new_orphan_types, root: false)
|
1452
|
+
own_orphan_types.concat(new_orphan_types.flatten)
|
1453
|
+
end
|
1454
|
+
|
1455
|
+
find_inherited_value(:orphan_types, EMPTY_ARRAY) + own_orphan_types
|
1456
|
+
end
|
1457
|
+
|
1458
|
+
def default_execution_strategy
|
1459
|
+
if superclass <= GraphQL::Schema
|
1460
|
+
superclass.default_execution_strategy
|
1461
|
+
else
|
1462
|
+
@default_execution_strategy ||= GraphQL::Execution::Interpreter
|
1463
|
+
end
|
1464
|
+
end
|
1465
|
+
|
1466
|
+
def default_analysis_engine
|
1467
|
+
if superclass <= GraphQL::Schema
|
1468
|
+
superclass.default_analysis_engine
|
1469
|
+
else
|
1470
|
+
@default_analysis_engine ||= GraphQL::Analysis::AST
|
1471
|
+
end
|
1472
|
+
end
|
1473
|
+
|
1474
|
+
def context_class(new_context_class = nil)
|
1475
|
+
if new_context_class
|
1476
|
+
@context_class = new_context_class
|
1477
|
+
else
|
1478
|
+
@context_class || find_inherited_value(:context_class, GraphQL::Query::Context)
|
1479
|
+
end
|
1480
|
+
end
|
1481
|
+
|
1482
|
+
def rescue_from(*err_classes, &handler_block)
|
1483
|
+
err_classes.each do |err_class|
|
1484
|
+
error_handler.rescue_from(err_class, handler_block)
|
1485
|
+
end
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
# rubocop:disable Lint/DuplicateMethods
|
1489
|
+
module ResolveTypeWithType
|
1490
|
+
def resolve_type(type, obj, ctx)
|
1491
|
+
first_resolved_type, resolved_value = if type.is_a?(Module) && type.respond_to?(:resolve_type)
|
1492
|
+
type.resolve_type(obj, ctx)
|
1493
|
+
else
|
1494
|
+
super
|
1495
|
+
end
|
1496
|
+
|
1497
|
+
after_lazy(first_resolved_type) do |resolved_type|
|
1498
|
+
if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind)) || resolved_type.is_a?(GraphQL::BaseType)
|
1499
|
+
if resolved_value
|
1500
|
+
[resolved_type, resolved_value]
|
1501
|
+
else
|
1502
|
+
resolved_type
|
1503
|
+
end
|
1504
|
+
else
|
1505
|
+
raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
|
1506
|
+
end
|
1507
|
+
end
|
1508
|
+
end
|
1509
|
+
end
|
1510
|
+
|
1511
|
+
def resolve_type(type, obj, ctx)
|
1512
|
+
if type.kind.object?
|
1513
|
+
type
|
1514
|
+
else
|
1515
|
+
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})"
|
1516
|
+
end
|
1517
|
+
end
|
1518
|
+
# rubocop:enable Lint/DuplicateMethods
|
1519
|
+
|
1520
|
+
def inherited(child_class)
|
1521
|
+
if self == GraphQL::Schema
|
1522
|
+
child_class.directives(default_directives.values)
|
1523
|
+
end
|
1524
|
+
child_class.singleton_class.prepend(ResolveTypeWithType)
|
1525
|
+
super
|
1526
|
+
end
|
1527
|
+
|
1528
|
+
def object_from_id(node_id, ctx)
|
1529
|
+
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}`)"
|
1530
|
+
end
|
1531
|
+
|
1532
|
+
def id_from_object(object, type, ctx)
|
1533
|
+
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}`)"
|
1534
|
+
end
|
1535
|
+
|
1536
|
+
def visible?(member, ctx)
|
1537
|
+
member.type_class.visible?(ctx)
|
1538
|
+
end
|
1539
|
+
|
1540
|
+
def accessible?(member, ctx)
|
1541
|
+
member.type_class.accessible?(ctx)
|
1542
|
+
end
|
1543
|
+
|
1544
|
+
# This hook is called when a client tries to access one or more
|
1545
|
+
# fields that fail the `accessible?` check.
|
1546
|
+
#
|
1547
|
+
# By default, an error is added to the response. Override this hook to
|
1548
|
+
# track metrics or return a different error to the client.
|
1549
|
+
#
|
1550
|
+
# @param error [InaccessibleFieldsError] The analysis error for this check
|
1551
|
+
# @return [AnalysisError, nil] Return an error to skip the query
|
1552
|
+
def inaccessible_fields(error)
|
1553
|
+
error
|
1554
|
+
end
|
1555
|
+
|
1556
|
+
# This hook is called when an object fails an `authorized?` check.
|
1557
|
+
# You might report to your bug tracker here, so you can correct
|
1558
|
+
# the field resolvers not to return unauthorized objects.
|
1559
|
+
#
|
1560
|
+
# By default, this hook just replaces the unauthorized object with `nil`.
|
1561
|
+
#
|
1562
|
+
# Whatever value is returned from this method will be used instead of the
|
1563
|
+
# unauthorized object (accessible as `unauthorized_error.object`). If an
|
1564
|
+
# error is raised, then `nil` will be used.
|
1565
|
+
#
|
1566
|
+
# If you want to add an error to the `"errors"` key, raise a {GraphQL::ExecutionError}
|
1567
|
+
# in this hook.
|
1568
|
+
#
|
1569
|
+
# @param unauthorized_error [GraphQL::UnauthorizedError]
|
1570
|
+
# @return [Object] The returned object will be put in the GraphQL response
|
1571
|
+
def unauthorized_object(unauthorized_error)
|
1572
|
+
nil
|
1573
|
+
end
|
1574
|
+
|
1575
|
+
# This hook is called when a field fails an `authorized?` check.
|
1576
|
+
#
|
1577
|
+
# By default, this hook implements the same behavior as unauthorized_object.
|
1578
|
+
#
|
1579
|
+
# Whatever value is returned from this method will be used instead of the
|
1580
|
+
# unauthorized field . If an error is raised, then `nil` will be used.
|
1581
|
+
#
|
1582
|
+
# If you want to add an error to the `"errors"` key, raise a {GraphQL::ExecutionError}
|
1583
|
+
# in this hook.
|
1584
|
+
#
|
1585
|
+
# @param unauthorized_error [GraphQL::UnauthorizedFieldError]
|
1586
|
+
# @return [Field] The returned field will be put in the GraphQL response
|
1587
|
+
def unauthorized_field(unauthorized_error)
|
1588
|
+
unauthorized_object(unauthorized_error)
|
1589
|
+
end
|
1590
|
+
|
1591
|
+
def type_error(type_err, ctx)
|
1592
|
+
DefaultTypeError.call(type_err, ctx)
|
1593
|
+
end
|
1594
|
+
|
1595
|
+
# A function to call when {#execute} receives an invalid query string
|
1596
|
+
#
|
1597
|
+
# The default is to add the error to `context.errors`
|
1598
|
+
# @param err [GraphQL::ParseError] The error encountered during parsing
|
1599
|
+
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
1600
|
+
# @return void
|
1601
|
+
def parse_error(parse_err, ctx)
|
1602
|
+
ctx.errors.push(parse_err)
|
1603
|
+
end
|
1604
|
+
|
1605
|
+
# @return [GraphQL::Execution::Errors]
|
1606
|
+
def error_handler
|
1607
|
+
@error_handler ||= GraphQL::Execution::Errors.new(self)
|
1608
|
+
end
|
1609
|
+
|
1610
|
+
def lazy_resolve(lazy_class, value_method)
|
1611
|
+
lazy_methods.set(lazy_class, value_method)
|
1612
|
+
end
|
1613
|
+
|
1614
|
+
def instrument(instrument_step, instrumenter, options = {})
|
1615
|
+
if instrument_step == :field
|
1616
|
+
GraphQL::Deprecation.warn "Field instrumentation (#{instrumenter.inspect}) will be removed in GraphQL-Ruby 2.0, please upgrade to field extensions: https://graphql-ruby.org/type_definitions/field_extensions.html"
|
1617
|
+
end
|
1618
|
+
|
1619
|
+
step = if instrument_step == :field && options[:after_built_ins]
|
1620
|
+
:field_after_built_ins
|
1621
|
+
else
|
1622
|
+
instrument_step
|
1623
|
+
end
|
1624
|
+
|
1625
|
+
own_instrumenters[step] << instrumenter
|
1626
|
+
end
|
1627
|
+
|
1628
|
+
# Add several directives at once
|
1629
|
+
# @param new_directives [Class]
|
1630
|
+
def directives(*new_directives)
|
1631
|
+
if new_directives.any?
|
1632
|
+
new_directives.flatten.each { |d| directive(d) }
|
1633
|
+
end
|
1634
|
+
|
1635
|
+
find_inherited_value(:directives, default_directives).merge(own_directives)
|
1636
|
+
end
|
1637
|
+
|
1638
|
+
# Attach a single directive to this schema
|
1639
|
+
# @param new_directive [Class]
|
1640
|
+
# @return void
|
1641
|
+
def directive(new_directive)
|
1642
|
+
add_type_and_traverse(new_directive, root: false)
|
1643
|
+
end
|
1644
|
+
|
1645
|
+
def default_directives
|
1646
|
+
@default_directives ||= {
|
1647
|
+
"include" => GraphQL::Schema::Directive::Include,
|
1648
|
+
"skip" => GraphQL::Schema::Directive::Skip,
|
1649
|
+
"deprecated" => GraphQL::Schema::Directive::Deprecated,
|
1650
|
+
}.freeze
|
1651
|
+
end
|
1652
|
+
|
1653
|
+
def tracer(new_tracer)
|
1654
|
+
own_tracers << new_tracer
|
1655
|
+
end
|
1656
|
+
|
1657
|
+
def tracers
|
1658
|
+
find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
|
1659
|
+
end
|
1660
|
+
|
1661
|
+
def query_analyzer(new_analyzer)
|
1662
|
+
if new_analyzer == GraphQL::Authorization::Analyzer
|
1663
|
+
GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
|
1664
|
+
end
|
1665
|
+
own_query_analyzers << new_analyzer
|
1666
|
+
end
|
1667
|
+
|
1668
|
+
def query_analyzers
|
1669
|
+
find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
|
1670
|
+
end
|
1671
|
+
|
1672
|
+
def middleware(new_middleware = nil)
|
1673
|
+
if new_middleware
|
1674
|
+
GraphQL::Deprecation.warn "Middleware will be removed in GraphQL-Ruby 2.0, please upgrade to Field Extensions: https://graphql-ruby.org/type_definitions/field_extensions.html"
|
1675
|
+
own_middleware << new_middleware
|
1676
|
+
else
|
1677
|
+
# TODO make sure this is cached when running a query
|
1678
|
+
MiddlewareChain.new(steps: all_middleware, final_step: GraphQL::Execution::Execute::FieldResolveStep)
|
1679
|
+
end
|
1680
|
+
end
|
1681
|
+
|
1682
|
+
def multiplex_analyzer(new_analyzer)
|
1683
|
+
own_multiplex_analyzers << new_analyzer
|
1684
|
+
end
|
1685
|
+
|
1686
|
+
def multiplex_analyzers
|
1687
|
+
find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
|
1688
|
+
end
|
1689
|
+
|
1690
|
+
def sanitized_printer(new_sanitized_printer = nil)
|
1691
|
+
if new_sanitized_printer
|
1692
|
+
@own_sanitized_printer = new_sanitized_printer
|
1693
|
+
else
|
1694
|
+
@own_sanitized_printer || GraphQL::Language::SanitizedPrinter
|
1695
|
+
end
|
1696
|
+
end
|
1697
|
+
|
1698
|
+
# Execute a query on itself.
|
1699
|
+
# @see {Query#initialize} for arguments.
|
1700
|
+
# @return [Hash] query result, ready to be serialized as JSON
|
1701
|
+
def execute(query_str = nil, **kwargs)
|
1702
|
+
if query_str
|
1703
|
+
kwargs[:query] = query_str
|
1704
|
+
end
|
1705
|
+
# Some of the query context _should_ be passed to the multiplex, too
|
1706
|
+
multiplex_context = if (ctx = kwargs[:context])
|
1707
|
+
{
|
1708
|
+
backtrace: ctx[:backtrace],
|
1709
|
+
tracers: ctx[:tracers],
|
1710
|
+
}
|
1711
|
+
else
|
1712
|
+
{}
|
1713
|
+
end
|
1714
|
+
# Since we're running one query, don't run a multiplex-level complexity analyzer
|
1715
|
+
all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
|
1716
|
+
all_results[0]
|
1717
|
+
end
|
1718
|
+
|
1719
|
+
# Execute several queries on itself, concurrently.
|
1720
|
+
#
|
1721
|
+
# @example Run several queries at once
|
1722
|
+
# context = { ... }
|
1723
|
+
# queries = [
|
1724
|
+
# { query: params[:query_1], variables: params[:variables_1], context: context },
|
1725
|
+
# { query: params[:query_2], variables: params[:variables_2], context: context },
|
1726
|
+
# ]
|
1727
|
+
# results = MySchema.multiplex(queries)
|
1728
|
+
# render json: {
|
1729
|
+
# result_1: results[0],
|
1730
|
+
# result_2: results[1],
|
1731
|
+
# }
|
1732
|
+
#
|
1733
|
+
# @see {Query#initialize} for query keyword arguments
|
1734
|
+
# @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
|
1735
|
+
# @param queries [Array<Hash>] Keyword arguments for each query
|
1736
|
+
# @param context [Hash] Multiplex-level context
|
1737
|
+
# @return [Array<Hash>] One result for each query in the input
|
1738
|
+
def multiplex(queries, **kwargs)
|
1739
|
+
schema = if interpreter?
|
1740
|
+
self
|
1741
|
+
else
|
1742
|
+
graphql_definition
|
1743
|
+
end
|
1744
|
+
GraphQL::Execution::Multiplex.run_all(schema, queries, **kwargs)
|
1745
|
+
end
|
1746
|
+
|
1747
|
+
def instrumenters
|
1748
|
+
inherited_instrumenters = find_inherited_value(:instrumenters) || Hash.new { |h,k| h[k] = [] }
|
1749
|
+
inherited_instrumenters.merge(own_instrumenters) do |_step, inherited, own|
|
1750
|
+
inherited + own
|
1751
|
+
end
|
1752
|
+
end
|
1753
|
+
|
1754
|
+
# @api private
|
1755
|
+
def add_subscription_extension_if_necessary
|
1756
|
+
if interpreter? && !defined?(@subscription_extension_added) && subscription && self.subscriptions
|
1757
|
+
@subscription_extension_added = true
|
1758
|
+
if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
|
1759
|
+
GraphQL::Deprecation.warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
|
1760
|
+
else
|
1761
|
+
subscription.all_field_definitions.each do |field|
|
1762
|
+
field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
|
1763
|
+
end
|
1764
|
+
end
|
1765
|
+
end
|
1766
|
+
end
|
1767
|
+
|
1768
|
+
def query_stack_error(query, err)
|
1769
|
+
query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
|
1770
|
+
end
|
1771
|
+
|
1772
|
+
private
|
1773
|
+
|
1774
|
+
# @param t [Module, Array<Module>]
|
1775
|
+
# @return [void]
|
1776
|
+
def add_type_and_traverse(t, root:)
|
1777
|
+
if root
|
1778
|
+
@root_types ||= []
|
1779
|
+
@root_types << t
|
1780
|
+
end
|
1781
|
+
new_types = Array(t)
|
1782
|
+
addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
|
1783
|
+
addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
|
1784
|
+
if (prev_entry = own_types[name])
|
1785
|
+
prev_entries = case prev_entry
|
1786
|
+
when Array
|
1787
|
+
prev_entry
|
1788
|
+
when Module
|
1789
|
+
own_types[name] = [prev_entry]
|
1790
|
+
else
|
1791
|
+
raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
|
1792
|
+
end
|
1793
|
+
|
1794
|
+
case types_entry
|
1795
|
+
when Array
|
1796
|
+
prev_entries.concat(types_entry)
|
1797
|
+
prev_entries.uniq! # in case any are being re-visited
|
1798
|
+
when Module
|
1799
|
+
if !prev_entries.include?(types_entry)
|
1800
|
+
prev_entries << types_entry
|
1801
|
+
end
|
1802
|
+
else
|
1803
|
+
raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
|
1804
|
+
end
|
1805
|
+
else
|
1806
|
+
if types_entry.is_a?(Array)
|
1807
|
+
types_entry.uniq!
|
1808
|
+
end
|
1809
|
+
own_types[name] = types_entry
|
1810
|
+
end
|
1811
|
+
end
|
1812
|
+
|
1813
|
+
own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
|
1814
|
+
own_union_memberships.merge!(addition.union_memberships)
|
1815
|
+
|
1816
|
+
addition.references.each { |thing, pointers|
|
1817
|
+
pointers.each { |pointer| references_to(thing, from: pointer) }
|
1818
|
+
}
|
1819
|
+
|
1820
|
+
addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
|
1821
|
+
|
1822
|
+
addition.arguments_with_default_values.each do |arg|
|
1823
|
+
arg.validate_default_value
|
1824
|
+
end
|
1825
|
+
end
|
1826
|
+
|
1827
|
+
def lazy_methods
|
1828
|
+
if !defined?(@lazy_methods)
|
1829
|
+
if inherited_map = find_inherited_value(:lazy_methods)
|
1830
|
+
# this isn't _completely_ inherited :S (Things added after `dup` won't work)
|
1831
|
+
@lazy_methods = inherited_map.dup
|
1832
|
+
else
|
1833
|
+
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
1834
|
+
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
1835
|
+
@lazy_methods.set(GraphQL::Dataloader::Request, :load)
|
1836
|
+
end
|
1837
|
+
end
|
1838
|
+
@lazy_methods
|
1839
|
+
end
|
1840
|
+
|
1841
|
+
def own_types
|
1842
|
+
@own_types ||= {}
|
1843
|
+
end
|
1844
|
+
|
1845
|
+
def non_introspection_types
|
1846
|
+
find_inherited_value(:non_introspection_types, EMPTY_HASH).merge(own_types)
|
1847
|
+
end
|
1848
|
+
|
1849
|
+
def own_plugins
|
1850
|
+
@own_plugins ||= []
|
1851
|
+
end
|
1852
|
+
|
1853
|
+
def own_orphan_types
|
1854
|
+
@own_orphan_types ||= []
|
1855
|
+
end
|
1856
|
+
|
1857
|
+
def own_possible_types
|
1858
|
+
@own_possible_types ||= {}
|
1859
|
+
end
|
1860
|
+
|
1861
|
+
def own_union_memberships
|
1862
|
+
@own_union_memberships ||= {}
|
1863
|
+
end
|
1864
|
+
|
1865
|
+
def own_directives
|
1866
|
+
@own_directives ||= {}
|
1867
|
+
end
|
1868
|
+
|
1869
|
+
def own_instrumenters
|
1870
|
+
@own_instrumenters ||= Hash.new { |h,k| h[k] = [] }
|
1871
|
+
end
|
1872
|
+
|
1873
|
+
def own_tracers
|
1874
|
+
@own_tracers ||= []
|
1875
|
+
end
|
1876
|
+
|
1877
|
+
def own_query_analyzers
|
1878
|
+
@defined_query_analyzers ||= []
|
1879
|
+
end
|
1880
|
+
|
1881
|
+
def all_middleware
|
1882
|
+
find_inherited_value(:all_middleware, EMPTY_ARRAY) + own_middleware
|
1883
|
+
end
|
1884
|
+
|
1885
|
+
def own_middleware
|
1886
|
+
@own_middleware ||= []
|
1887
|
+
end
|
1888
|
+
|
1889
|
+
def own_multiplex_analyzers
|
1890
|
+
@own_multiplex_analyzers ||= []
|
1891
|
+
end
|
1892
|
+
end
|
1893
|
+
|
1894
|
+
def dataloader_class
|
1895
|
+
self.class.dataloader_class
|
1896
|
+
end
|
1897
|
+
|
1898
|
+
# Install these here so that subclasses will also install it.
|
1899
|
+
use(GraphQL::Pagination::Connections)
|
1900
|
+
|
1901
|
+
protected
|
1902
|
+
|
1903
|
+
def rescues?
|
1904
|
+
!!@rescue_middleware
|
1905
|
+
end
|
1906
|
+
|
1907
|
+
# Lazily create a middleware and add it to the schema
|
1908
|
+
# (Don't add it if it's not used)
|
1909
|
+
def rescue_middleware
|
1910
|
+
@rescue_middleware ||= GraphQL::Schema::RescueMiddleware.new.tap { |m| middleware.insert(0, m) }
|
1911
|
+
end
|
1912
|
+
|
1913
|
+
private
|
1914
|
+
|
1915
|
+
def rebuild_artifacts
|
1916
|
+
if @rebuilding_artifacts
|
1917
|
+
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."
|
1918
|
+
else
|
1919
|
+
@rebuilding_artifacts = true
|
1920
|
+
@introspection_system = Schema::IntrospectionSystem.new(self)
|
1921
|
+
traversal = Traversal.new(self)
|
1922
|
+
@types = traversal.type_map
|
1923
|
+
@root_types = [query, mutation, subscription]
|
1924
|
+
@instrumented_field_map = traversal.instrumented_field_map
|
1925
|
+
@type_reference_map = traversal.type_reference_map
|
1926
|
+
@union_memberships = traversal.union_memberships
|
1927
|
+
@find_cache = {}
|
1928
|
+
@finder = Finder.new(self)
|
1929
|
+
end
|
1930
|
+
ensure
|
1931
|
+
@rebuilding_artifacts = false
|
1932
|
+
end
|
1933
|
+
|
1934
|
+
class CyclicalDefinitionError < GraphQL::Error
|
1935
|
+
end
|
1936
|
+
|
1937
|
+
def with_definition_error_check
|
1938
|
+
if @definition_error
|
1939
|
+
raise @definition_error
|
1940
|
+
else
|
1941
|
+
yield
|
1942
|
+
end
|
1943
|
+
end
|
1944
|
+
end
|
1945
|
+
end
|