graphql 1.12.12 → 2.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +3 -8
- data/lib/generators/graphql/enum_generator.rb +4 -10
- data/lib/generators/graphql/field_extractor.rb +31 -0
- data/lib/generators/graphql/input_generator.rb +50 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
- data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
- data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +14 -4
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +5 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +10 -38
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +23 -12
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +6 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +5 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +4 -2
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +3 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/object.erb +4 -2
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +3 -1
- data/lib/generators/graphql/templates/schema.erb +19 -2
- data/lib/generators/graphql/templates/union.erb +4 -2
- data/lib/generators/graphql/type_generator.rb +46 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/ast/analyzer.rb +7 -0
- data/lib/graphql/analysis/ast/field_usage.rb +55 -1
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +88 -140
- data/lib/graphql/analysis/ast/query_depth.rb +7 -3
- data/lib/graphql/analysis/ast/visitor.rb +50 -42
- data/lib/graphql/analysis/ast.rb +26 -23
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/table.rb +4 -22
- data/lib/graphql/backtrace/trace.rb +93 -0
- data/lib/graphql/backtrace/tracer.rb +8 -6
- data/lib/graphql/backtrace.rb +3 -8
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +85 -0
- data/lib/graphql/dataloader/null_dataloader.rb +3 -1
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +120 -31
- data/lib/graphql/dataloader.rb +168 -142
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/errors.rb +12 -81
- data/lib/graphql/execution/interpreter/arguments.rb +2 -2
- data/lib/graphql/execution/interpreter/arguments_cache.rb +36 -34
- data/lib/graphql/execution/interpreter/resolve.rb +32 -2
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
- data/lib/graphql/execution/interpreter/runtime.rb +414 -341
- data/lib/graphql/execution/interpreter.rb +122 -80
- data/lib/graphql/execution/lazy.rb +11 -21
- data/lib/graphql/execution/lookahead.rb +125 -54
- data/lib/graphql/execution/multiplex.rb +4 -172
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +5 -3
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +11 -18
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +3 -3
- data/lib/graphql/introspection/input_value_type.rb +10 -4
- data/lib/graphql/introspection/schema_type.rb +12 -5
- data/lib/graphql/introspection/type_type.rb +25 -12
- data/lib/graphql/introspection.rb +6 -2
- data/lib/graphql/language/block_string.rb +37 -25
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +78 -65
- data/lib/graphql/language/lexer.rb +345 -1467
- data/lib/graphql/language/nodes.rb +145 -91
- data/lib/graphql/language/parser.rb +701 -1921
- data/lib/graphql/language/printer.rb +351 -155
- data/lib/graphql/language/sanitized_printer.rb +25 -27
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/language/visitor.rb +188 -141
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/name_validator.rb +0 -4
- data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
- data/lib/graphql/pagination/array_connection.rb +8 -6
- data/lib/graphql/pagination/connection.rb +61 -7
- data/lib/graphql/pagination/connections.rb +22 -23
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +60 -28
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +109 -189
- data/lib/graphql/query/input_validation_result.rb +10 -1
- data/lib/graphql/query/null_context.rb +14 -29
- data/lib/graphql/query/validation_pipeline.rb +15 -39
- data/lib/graphql/query/variable_validation_error.rb +2 -2
- data/lib/graphql/query/variables.rb +35 -17
- data/lib/graphql/query.rb +78 -65
- data/lib/graphql/railtie.rb +8 -109
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +30 -11
- data/lib/graphql/relay/range_add.rb +9 -16
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/schema/addition.rb +78 -45
- data/lib/graphql/schema/always_visible.rb +10 -0
- data/lib/graphql/schema/argument.rb +134 -80
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +60 -38
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +2 -2
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +2 -2
- data/lib/graphql/schema/directive.rb +33 -21
- data/lib/graphql/schema/enum.rb +93 -46
- data/lib/graphql/schema/enum_value.rb +4 -21
- data/lib/graphql/schema/field/connection_extension.rb +6 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +432 -337
- data/lib/graphql/schema/field_extension.rb +86 -2
- data/lib/graphql/schema/find_inherited_value.rb +3 -7
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/has_single_input_argument.rb +156 -0
- data/lib/graphql/schema/input_object.rb +88 -90
- data/lib/graphql/schema/interface.rb +19 -59
- data/lib/graphql/schema/introspection_system.rb +6 -9
- data/lib/graphql/schema/late_bound_type.rb +8 -2
- data/lib/graphql/schema/list.rb +18 -7
- data/lib/graphql/schema/loader.rb +3 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -19
- data/lib/graphql/schema/member/build_type.rb +16 -13
- data/lib/graphql/schema/member/has_arguments.rb +288 -84
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +149 -31
- data/lib/graphql/schema/member/has_interfaces.rb +143 -0
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
- data/lib/graphql/schema/member/validates_input.rb +6 -6
- data/lib/graphql/schema/member.rb +1 -6
- data/lib/graphql/schema/mutation.rb +0 -9
- data/lib/graphql/schema/non_null.rb +7 -7
- data/lib/graphql/schema/object.rb +30 -119
- data/lib/graphql/schema/printer.rb +23 -25
- data/lib/graphql/schema/relay_classic_mutation.rb +13 -90
- data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
- data/lib/graphql/schema/resolver.rb +101 -102
- data/lib/graphql/schema/scalar.rb +20 -21
- data/lib/graphql/schema/subscription.rb +45 -17
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +21 -4
- data/lib/graphql/schema/union.rb +15 -15
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/format_validator.rb +4 -5
- data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/length_validator.rb +5 -3
- data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
- data/lib/graphql/schema/validator/required_validator.rb +29 -15
- data/lib/graphql/schema/validator.rb +35 -27
- data/lib/graphql/schema/warden.rb +259 -132
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +658 -989
- data/lib/graphql/static_validation/all_rules.rb +3 -1
- data/lib/graphql/static_validation/base_visitor.rb +14 -28
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +21 -4
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +13 -13
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +54 -28
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -3
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
- data/lib/graphql/static_validation/validation_context.rb +16 -6
- data/lib/graphql/static_validation/validator.rb +11 -27
- data/lib/graphql/static_validation.rb +0 -3
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +46 -9
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
- data/lib/graphql/subscriptions/event.rb +75 -37
- data/lib/graphql/subscriptions/serialize.rb +25 -3
- data/lib/graphql/subscriptions.rb +59 -47
- data/lib/graphql/testing/helpers.rb +129 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
- data/lib/graphql/tracing/appoptics_trace.rb +251 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
- data/lib/graphql/tracing/data_dog_trace.rb +183 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +25 -15
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
- data/lib/graphql/tracing/legacy_trace.rb +69 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +45 -0
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_trace.rb +118 -0
- data/lib/graphql/tracing/platform_tracing.rb +46 -49
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/trace.rb +76 -0
- data/lib/graphql/tracing.rb +20 -41
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/big_int.rb +5 -1
- data/lib/graphql/types/int.rb +1 -1
- data/lib/graphql/types/iso_8601_date.rb +17 -6
- data/lib/graphql/types/iso_8601_date_time.rb +12 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +16 -6
- data/lib/graphql/types/relay/connection_behaviors.rb +82 -32
- data/lib/graphql/types/relay/edge_behaviors.rb +36 -7
- data/lib/graphql/types/relay/has_node_field.rb +2 -2
- data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
- data/lib/graphql/types/relay/node_behaviors.rb +12 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
- data/lib/graphql/types/relay.rb +0 -3
- data/lib/graphql/types/string.rb +2 -2
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +33 -95
- data/readme.md +13 -6
- metadata +102 -185
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/field_usage.rb +0 -45
- data/lib/graphql/analysis/max_query_complexity.rb +0 -26
- data/lib/graphql/analysis/max_query_depth.rb +0 -26
- data/lib/graphql/analysis/query_complexity.rb +0 -88
- data/lib/graphql/analysis/query_depth.rb +0 -43
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -230
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -240
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -47
- data/lib/graphql/deprecation.rb +0 -13
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -111
- data/lib/graphql/enum_type.rb +0 -129
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -262
- data/lib/graphql/language/parser.y +0 -543
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -41
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -40
- data/lib/graphql/relay/global_id_resolve.rb +0 -18
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/member/accepts_definition.rb +0 -152
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/instrumentation.rb +0 -79
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/default_relay.rb +0 -27
- data/lib/graphql/types/relay/node_field.rb +0 -25
- data/lib/graphql/types/relay/nodes_field.rb +0 -27
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
@@ -5,7 +5,7 @@ module GraphQL
|
|
5
5
|
module AST
|
6
6
|
class QueryComplexity < Analyzer
|
7
7
|
# State for the query complexity calculation:
|
8
|
-
# - `complexities_on_type` holds complexity scores for each type
|
8
|
+
# - `complexities_on_type` holds complexity scores for each type
|
9
9
|
def initialize(query)
|
10
10
|
super
|
11
11
|
@complexities_on_type_by_query = {}
|
@@ -16,50 +16,33 @@ module GraphQL
|
|
16
16
|
max_possible_complexity
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
# ScopedTypeComplexity models a tree of GraphQL types mapped to inner selections, ie:
|
20
|
+
# Hash<GraphQL::BaseType, Hash<String, ScopedTypeComplexity>>
|
21
|
+
class ScopedTypeComplexity < Hash
|
22
|
+
# A proc for defaulting empty namespace requests as a new scope hash.
|
23
|
+
DEFAULT_PROC = ->(h, k) { h[k] = {} }
|
23
24
|
|
24
25
|
attr_reader :field_definition, :response_path, :query
|
25
26
|
|
26
|
-
# @param
|
27
|
+
# @param parent_type [Class] The owner of `field_definition`
|
27
28
|
# @param field_definition [GraphQL::Field, GraphQL::Schema::Field] Used for getting the `.complexity` configuration
|
28
29
|
# @param query [GraphQL::Query] Used for `query.possible_types`
|
29
30
|
# @param response_path [Array<String>] The path to the response key for the field
|
30
|
-
|
31
|
-
|
31
|
+
# @return [Hash<GraphQL::BaseType, Hash<String, ScopedTypeComplexity>>]
|
32
|
+
def initialize(parent_type, field_definition, query, response_path)
|
33
|
+
super(&DEFAULT_PROC)
|
34
|
+
@parent_type = parent_type
|
32
35
|
@field_definition = field_definition
|
33
36
|
@query = query
|
34
37
|
@response_path = response_path
|
35
|
-
@
|
38
|
+
@nodes = []
|
36
39
|
end
|
37
40
|
|
38
|
-
#
|
39
|
-
|
40
|
-
def terminal?
|
41
|
-
@scoped_children.nil?
|
42
|
-
end
|
43
|
-
|
44
|
-
# This value is only calculated when asked for to avoid needless hash allocations.
|
45
|
-
# Also, if it's never asked for, we determine that this scope complexity
|
46
|
-
# is a scalar field ({#terminal?}).
|
47
|
-
# @return [Hash<Hash<Class => ScopedTypeComplexity>]
|
48
|
-
def scoped_children
|
49
|
-
@scoped_children ||= Hash.new(&HASH_CHILDREN)
|
50
|
-
end
|
41
|
+
# @return [Array<GraphQL::Language::Nodes::Field>]
|
42
|
+
attr_reader :nodes
|
51
43
|
|
52
44
|
def own_complexity(child_complexity)
|
53
|
-
|
54
|
-
case defined_complexity
|
55
|
-
when Proc
|
56
|
-
arguments = @query.arguments_for(@node, @field_definition)
|
57
|
-
defined_complexity.call(@query.context, arguments.keyword_arguments, child_complexity)
|
58
|
-
when Numeric
|
59
|
-
defined_complexity + child_complexity
|
60
|
-
else
|
61
|
-
raise("Invalid complexity: #{defined_complexity.inspect} on #{@field_definition.name}")
|
62
|
-
end
|
45
|
+
@field_definition.calculate_complexity(query: @query, nodes: @nodes, child_complexity: child_complexity)
|
63
46
|
end
|
64
47
|
end
|
65
48
|
|
@@ -70,18 +53,14 @@ module GraphQL
|
|
70
53
|
return if visitor.skipping?
|
71
54
|
parent_type = visitor.parent_type_definition
|
72
55
|
field_key = node.alias || node.name
|
73
|
-
|
74
|
-
#
|
75
|
-
|
76
|
-
|
77
|
-
#
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
complexity = complexities_on_type.last.scoped_children[parent_type][field_key] ||= ScopedTypeComplexity.new(node, visitor.field_definition, visitor.query, visitor.response_path)
|
83
|
-
# Push it on the stack.
|
84
|
-
complexities_on_type.push(complexity)
|
56
|
+
|
57
|
+
# Find or create a complexity scope stack for this query.
|
58
|
+
scopes_stack = @complexities_on_type_by_query[visitor.query] ||= [ScopedTypeComplexity.new(nil, nil, query, visitor.response_path)]
|
59
|
+
|
60
|
+
# Find or create the complexity costing node for this field.
|
61
|
+
scope = scopes_stack.last[parent_type][field_key] ||= ScopedTypeComplexity.new(parent_type, visitor.field_definition, visitor.query, visitor.response_path)
|
62
|
+
scope.nodes.push(node)
|
63
|
+
scopes_stack.push(scope)
|
85
64
|
end
|
86
65
|
|
87
66
|
def on_leave_field(node, parent, visitor)
|
@@ -89,89 +68,61 @@ module GraphQL
|
|
89
68
|
# we'll visit them when we hit the spreads instead
|
90
69
|
return if visitor.visiting_fragment_definition?
|
91
70
|
return if visitor.skipping?
|
92
|
-
|
93
|
-
|
71
|
+
scopes_stack = @complexities_on_type_by_query[visitor.query]
|
72
|
+
scopes_stack.pop
|
94
73
|
end
|
95
74
|
|
96
75
|
private
|
97
76
|
|
98
77
|
# @return [Integer]
|
99
78
|
def max_possible_complexity
|
100
|
-
@complexities_on_type_by_query.reduce(0) do |total, (query,
|
101
|
-
|
102
|
-
# Use this entry point to calculate the total complexity
|
103
|
-
total_complexity_for_query = merged_max_complexity_for_scopes(query, [root_complexity.scoped_children])
|
104
|
-
total + total_complexity_for_query
|
79
|
+
@complexities_on_type_by_query.reduce(0) do |total, (query, scopes_stack)|
|
80
|
+
total + merged_max_complexity_for_scopes(query, [scopes_stack.first])
|
105
81
|
end
|
106
82
|
end
|
107
83
|
|
108
84
|
# @param query [GraphQL::Query] Used for `query.possible_types`
|
109
|
-
# @param
|
85
|
+
# @param scopes [Array<ScopedTypeComplexity>] Array of scoped type complexities
|
110
86
|
# @return [Integer]
|
111
|
-
def merged_max_complexity_for_scopes(query,
|
112
|
-
#
|
87
|
+
def merged_max_complexity_for_scopes(query, scopes)
|
88
|
+
# Aggregate a set of all possible scope types encountered (scope keys).
|
113
89
|
# Use a hash, but ignore the values; it's just a fast way to work with the keys.
|
114
|
-
|
115
|
-
|
116
|
-
all_scopes.merge!(h)
|
90
|
+
possible_scope_types = scopes.each_with_object({}) do |scope, memo|
|
91
|
+
memo.merge!(scope)
|
117
92
|
end
|
118
93
|
|
119
|
-
#
|
120
|
-
#
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
missing_concrete_types = query.possible_types(scope).select { |t| !all_scopes.key?(t) }
|
128
|
-
# This concrete type is possible _only_ as a member of the abstract type.
|
129
|
-
# So, attribute to it the complexity which belongs to the abstract type.
|
130
|
-
missing_concrete_types.each do |concrete_scope|
|
131
|
-
all_scopes[concrete_scope] = all_scopes[scope]
|
94
|
+
# Expand abstract scope types into their concrete implementations;
|
95
|
+
# overlapping abstracts coalesce through their intersecting types.
|
96
|
+
possible_scope_types.keys.each do |possible_scope_type|
|
97
|
+
next unless possible_scope_type.kind.abstract?
|
98
|
+
|
99
|
+
query.possible_types(possible_scope_type).each do |impl_type|
|
100
|
+
possible_scope_types[impl_type] ||= true
|
132
101
|
end
|
133
|
-
|
102
|
+
possible_scope_types.delete(possible_scope_type)
|
134
103
|
end
|
135
104
|
|
136
|
-
#
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
# as a set and calculate the complexity for them as a unit
|
144
|
-
all_scopes.each do |scope, _|
|
145
|
-
# These will be the selections on `scope`
|
146
|
-
children_for_scope = []
|
147
|
-
scoped_children_hashes.each do |sc_h|
|
148
|
-
sc_h.each do |inner_scope, children_hash|
|
149
|
-
if applies_to?(query, scope, inner_scope)
|
150
|
-
children_for_scope << children_hash
|
151
|
-
end
|
105
|
+
# Aggregate the lexical selections that may apply to each possible type,
|
106
|
+
# and then return the maximum cost among possible typed selections.
|
107
|
+
possible_scope_types.each_key.reduce(0) do |max, possible_scope_type|
|
108
|
+
# Collect inner selections from all scopes that intersect with this possible type.
|
109
|
+
all_inner_selections = scopes.each_with_object([]) do |scope, memo|
|
110
|
+
scope.each do |scope_type, inner_selections|
|
111
|
+
memo << inner_selections if types_intersect?(query, scope_type, possible_scope_type)
|
152
112
|
end
|
153
113
|
end
|
154
114
|
|
155
|
-
#
|
156
|
-
|
157
|
-
|
158
|
-
complexity_by_scope[scope] = complexity_value
|
115
|
+
# Find the maximum complexity for the scope type among possible lexical branches.
|
116
|
+
complexity = merged_max_complexity(query, all_inner_selections)
|
117
|
+
complexity > max ? complexity : max
|
159
118
|
end
|
160
|
-
|
161
|
-
# Return the max complexity among all scopes
|
162
|
-
complexity_by_scope.each_value.max
|
163
119
|
end
|
164
120
|
|
165
|
-
def
|
166
|
-
if
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
# Check if these two scopes have _any_ types in common.
|
171
|
-
possible_right_types = query.possible_types(right_scope)
|
172
|
-
possible_left_types = query.possible_types(left_scope)
|
173
|
-
!(possible_right_types & possible_left_types).empty?
|
174
|
-
end
|
121
|
+
def types_intersect?(query, a, b)
|
122
|
+
return true if a == b
|
123
|
+
|
124
|
+
a_types = query.possible_types(a)
|
125
|
+
query.possible_types(b).any? { |t| a_types.include?(t) }
|
175
126
|
end
|
176
127
|
|
177
128
|
# A hook which is called whenever a field's max complexity is calculated.
|
@@ -183,50 +134,47 @@ module GraphQL
|
|
183
134
|
def field_complexity(scoped_type_complexity, max_complexity:, child_complexity: nil)
|
184
135
|
end
|
185
136
|
|
186
|
-
# @param
|
187
|
-
#
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
137
|
+
# @param inner_selections [Array<Hash<String, ScopedTypeComplexity>>] Field selections for a scope
|
138
|
+
# @return [Integer] Total complexity value for all these selections in the parent scope
|
139
|
+
def merged_max_complexity(query, inner_selections)
|
140
|
+
# Aggregate a set of all unique field selection keys across all scopes.
|
141
|
+
# Use a hash, but ignore the values; it's just a fast way to work with the keys.
|
142
|
+
unique_field_keys = inner_selections.each_with_object({}) do |inner_selection, memo|
|
143
|
+
memo.merge!(inner_selection)
|
193
144
|
end
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
field_complexity(complexity_for_key, max_complexity: complexity, child_complexity: nil)
|
145
|
+
|
146
|
+
# Add up the total cost for each unique field name's coalesced selections
|
147
|
+
unique_field_keys.each_key.reduce(0) do |total, field_key|
|
148
|
+
composite_scopes = nil
|
149
|
+
field_cost = 0
|
150
|
+
|
151
|
+
# Collect composite selection scopes for further aggregation,
|
152
|
+
# leaf selections report their costs directly.
|
153
|
+
inner_selections.each do |inner_selection|
|
154
|
+
child_scope = inner_selection[field_key]
|
155
|
+
next unless child_scope
|
156
|
+
|
157
|
+
# Empty child scopes are leaf nodes with zero child complexity.
|
158
|
+
if child_scope.empty?
|
159
|
+
field_cost = child_scope.own_complexity(0)
|
160
|
+
field_complexity(child_scope, max_complexity: field_cost, child_complexity: nil)
|
211
161
|
else
|
212
|
-
|
213
|
-
|
162
|
+
composite_scopes ||= []
|
163
|
+
composite_scopes << child_scope
|
214
164
|
end
|
215
165
|
end
|
216
166
|
|
217
|
-
|
167
|
+
if composite_scopes
|
168
|
+
child_complexity = merged_max_complexity_for_scopes(query, composite_scopes)
|
218
169
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
170
|
+
# This is the last composite scope visited; assume it's representative (for backwards compatibility).
|
171
|
+
# Note: it would be more correct to score each composite scope and use the maximum possibility.
|
172
|
+
field_cost = composite_scopes.last.own_complexity(child_complexity)
|
173
|
+
field_complexity(composite_scopes.last, max_complexity: field_cost, child_complexity: child_complexity)
|
174
|
+
end
|
224
175
|
|
225
|
-
|
176
|
+
total + field_cost
|
226
177
|
end
|
227
|
-
|
228
|
-
# Calculate the child complexity by summing the complexity of all selections
|
229
|
-
complexity_for_keys.each_value.inject(0, &:+)
|
230
178
|
end
|
231
179
|
end
|
232
180
|
end
|
@@ -15,7 +15,6 @@ module GraphQL
|
|
15
15
|
# # In your Schema file:
|
16
16
|
#
|
17
17
|
# class MySchema < GraphQL::Schema
|
18
|
-
# use GraphQL::Analysis::AST
|
19
18
|
# query_analyzer LogQueryDepth
|
20
19
|
# end
|
21
20
|
#
|
@@ -29,17 +28,22 @@ module GraphQL
|
|
29
28
|
def initialize(query)
|
30
29
|
@max_depth = 0
|
31
30
|
@current_depth = 0
|
31
|
+
@count_introspection_fields = query.schema.count_introspection_fields
|
32
32
|
super
|
33
33
|
end
|
34
34
|
|
35
35
|
def on_enter_field(node, parent, visitor)
|
36
|
-
return if visitor.skipping? ||
|
36
|
+
return if visitor.skipping? ||
|
37
|
+
visitor.visiting_fragment_definition? ||
|
38
|
+
(@count_introspection_fields == false && visitor.field_definition.introspection?)
|
37
39
|
|
38
40
|
@current_depth += 1
|
39
41
|
end
|
40
42
|
|
41
43
|
def on_leave_field(node, parent, visitor)
|
42
|
-
return if visitor.skipping? ||
|
44
|
+
return if visitor.skipping? ||
|
45
|
+
visitor.visiting_fragment_definition? ||
|
46
|
+
(@count_introspection_fields == false && visitor.field_definition.introspection?)
|
43
47
|
|
44
48
|
if @max_depth < @current_depth
|
45
49
|
@max_depth = @current_depth
|
@@ -5,12 +5,12 @@ module GraphQL
|
|
5
5
|
# Depth first traversal through a query AST, calling AST analyzers
|
6
6
|
# along the way.
|
7
7
|
#
|
8
|
-
# The visitor is a special case of GraphQL::Language::
|
8
|
+
# The visitor is a special case of GraphQL::Language::StaticVisitor, visiting
|
9
9
|
# only the selected operation, providing helpers for common use cases such
|
10
10
|
# as skipped fields and visiting fragment spreads.
|
11
11
|
#
|
12
12
|
# @see {GraphQL::Analysis::AST::Analyzer} AST Analyzers for queries
|
13
|
-
class Visitor < GraphQL::Language::
|
13
|
+
class Visitor < GraphQL::Language::StaticVisitor
|
14
14
|
def initialize(query:, analyzers:)
|
15
15
|
@analyzers = analyzers
|
16
16
|
@path = []
|
@@ -43,7 +43,7 @@ module GraphQL
|
|
43
43
|
|
44
44
|
# Visit Helpers
|
45
45
|
|
46
|
-
# @return [GraphQL::
|
46
|
+
# @return [GraphQL::Execution::Interpreter::Arguments] Arguments for this node, merging default values, literal values and query variables
|
47
47
|
# @see {GraphQL::Query#arguments_for}
|
48
48
|
def arguments_for(ast_node, field_definition)
|
49
49
|
@query.arguments_for(ast_node, field_definition)
|
@@ -65,14 +65,41 @@ module GraphQL
|
|
65
65
|
end
|
66
66
|
|
67
67
|
# Visitor Hooks
|
68
|
+
[
|
69
|
+
:operation_definition, :fragment_definition,
|
70
|
+
:inline_fragment, :field, :directive, :argument, :fragment_spread
|
71
|
+
].each do |node_type|
|
72
|
+
module_eval <<-RUBY, __FILE__, __LINE__
|
73
|
+
def call_on_enter_#{node_type}(node, parent)
|
74
|
+
@analyzers.each do |a|
|
75
|
+
begin
|
76
|
+
a.on_enter_#{node_type}(node, parent, self)
|
77
|
+
rescue AnalysisError => err
|
78
|
+
@rescued_errors << err
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def call_on_leave_#{node_type}(node, parent)
|
84
|
+
@analyzers.each do |a|
|
85
|
+
begin
|
86
|
+
a.on_leave_#{node_type}(node, parent, self)
|
87
|
+
rescue AnalysisError => err
|
88
|
+
@rescued_errors << err
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
RUBY
|
94
|
+
end
|
68
95
|
|
69
96
|
def on_operation_definition(node, parent)
|
70
97
|
object_type = @schema.root_type_for_operation(node.operation_type)
|
71
98
|
@object_types.push(object_type)
|
72
99
|
@path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
|
73
|
-
|
100
|
+
call_on_enter_operation_definition(node, parent)
|
74
101
|
super
|
75
|
-
|
102
|
+
call_on_leave_operation_definition(node, parent)
|
76
103
|
@object_types.pop
|
77
104
|
@path.pop
|
78
105
|
end
|
@@ -81,26 +108,27 @@ module GraphQL
|
|
81
108
|
on_fragment_with_type(node) do
|
82
109
|
@path.push("fragment #{node.name}")
|
83
110
|
@in_fragment_def = false
|
84
|
-
|
111
|
+
call_on_enter_fragment_definition(node, parent)
|
85
112
|
super
|
86
113
|
@in_fragment_def = false
|
87
|
-
|
114
|
+
call_on_leave_fragment_definition(node, parent)
|
88
115
|
end
|
89
116
|
end
|
90
117
|
|
91
118
|
def on_inline_fragment(node, parent)
|
92
119
|
on_fragment_with_type(node) do
|
93
120
|
@path.push("...#{node.type ? " on #{node.type.name}" : ""}")
|
94
|
-
|
121
|
+
call_on_enter_inline_fragment(node, parent)
|
95
122
|
super
|
96
|
-
|
123
|
+
call_on_leave_inline_fragment(node, parent)
|
97
124
|
end
|
98
125
|
end
|
99
126
|
|
100
127
|
def on_field(node, parent)
|
101
128
|
@response_path.push(node.alias || node.name)
|
102
129
|
parent_type = @object_types.last
|
103
|
-
|
130
|
+
# This could be nil if the previous field wasn't found:
|
131
|
+
field_definition = parent_type && @schema.get_field(parent_type, node.name, @query.context)
|
104
132
|
@field_definitions.push(field_definition)
|
105
133
|
if !field_definition.nil?
|
106
134
|
next_object_type = field_definition.type.unwrap
|
@@ -113,12 +141,10 @@ module GraphQL
|
|
113
141
|
@skipping = @skip_stack.last || skip?(node)
|
114
142
|
@skip_stack << @skipping
|
115
143
|
|
116
|
-
|
144
|
+
call_on_enter_field(node, parent)
|
117
145
|
super
|
118
|
-
|
119
146
|
@skipping = @skip_stack.pop
|
120
|
-
|
121
|
-
call_analyzers(:on_leave_field, node, parent)
|
147
|
+
call_on_leave_field(node, parent)
|
122
148
|
@response_path.pop
|
123
149
|
@field_definitions.pop
|
124
150
|
@object_types.pop
|
@@ -128,9 +154,9 @@ module GraphQL
|
|
128
154
|
def on_directive(node, parent)
|
129
155
|
directive_defn = @schema.directives[node.name]
|
130
156
|
@directive_definitions.push(directive_defn)
|
131
|
-
|
157
|
+
call_on_enter_directive(node, parent)
|
132
158
|
super
|
133
|
-
|
159
|
+
call_on_leave_directive(node, parent)
|
134
160
|
@directive_definitions.pop
|
135
161
|
end
|
136
162
|
|
@@ -138,43 +164,37 @@ module GraphQL
|
|
138
164
|
argument_defn = if (arg = @argument_definitions.last)
|
139
165
|
arg_type = arg.type.unwrap
|
140
166
|
if arg_type.kind.input_object?
|
141
|
-
arg_type.
|
167
|
+
arg_type.get_argument(node.name, @query.context)
|
142
168
|
else
|
143
169
|
nil
|
144
170
|
end
|
145
171
|
elsif (directive_defn = @directive_definitions.last)
|
146
|
-
directive_defn.
|
172
|
+
directive_defn.get_argument(node.name, @query.context)
|
147
173
|
elsif (field_defn = @field_definitions.last)
|
148
|
-
field_defn.
|
174
|
+
field_defn.get_argument(node.name, @query.context)
|
149
175
|
else
|
150
176
|
nil
|
151
177
|
end
|
152
178
|
|
153
179
|
@argument_definitions.push(argument_defn)
|
154
180
|
@path.push(node.name)
|
155
|
-
|
181
|
+
call_on_enter_argument(node, parent)
|
156
182
|
super
|
157
|
-
|
183
|
+
call_on_leave_argument(node, parent)
|
158
184
|
@argument_definitions.pop
|
159
185
|
@path.pop
|
160
186
|
end
|
161
187
|
|
162
188
|
def on_fragment_spread(node, parent)
|
163
189
|
@path.push("... #{node.name}")
|
164
|
-
|
190
|
+
call_on_enter_fragment_spread(node, parent)
|
165
191
|
enter_fragment_spread_inline(node)
|
166
192
|
super
|
167
193
|
leave_fragment_spread_inline(node)
|
168
|
-
|
194
|
+
call_on_leave_fragment_spread(node, parent)
|
169
195
|
@path.pop
|
170
196
|
end
|
171
197
|
|
172
|
-
def on_abstract_node(node, parent)
|
173
|
-
call_analyzers(:on_enter_abstract_node, node, parent)
|
174
|
-
super
|
175
|
-
call_analyzers(:on_leave_abstract_node, node, parent)
|
176
|
-
end
|
177
|
-
|
178
198
|
# @return [GraphQL::BaseType] The current object type
|
179
199
|
def type_definition
|
180
200
|
@object_types.last
|
@@ -225,9 +245,7 @@ module GraphQL
|
|
225
245
|
|
226
246
|
object_types << object_type
|
227
247
|
|
228
|
-
fragment_def
|
229
|
-
visit_node(selection, fragment_def)
|
230
|
-
end
|
248
|
+
on_fragment_definition_children(fragment_def)
|
231
249
|
end
|
232
250
|
|
233
251
|
# Visit a fragment spread inline instead of visiting the definition
|
@@ -241,16 +259,6 @@ module GraphQL
|
|
241
259
|
dir.any? && !GraphQL::Execution::DirectiveChecks.include?(dir, query)
|
242
260
|
end
|
243
261
|
|
244
|
-
def call_analyzers(method, node, parent)
|
245
|
-
@analyzers.each do |analyzer|
|
246
|
-
begin
|
247
|
-
analyzer.public_send(method, node, parent, self)
|
248
|
-
rescue AnalysisError => err
|
249
|
-
@rescued_errors << err
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
262
|
def on_fragment_with_type(node)
|
255
263
|
object_type = if node.type
|
256
264
|
@query.warden.get_type(node.type.name)
|
data/lib/graphql/analysis/ast.rb
CHANGED
@@ -6,21 +6,12 @@ require "graphql/analysis/ast/query_complexity"
|
|
6
6
|
require "graphql/analysis/ast/max_query_complexity"
|
7
7
|
require "graphql/analysis/ast/query_depth"
|
8
8
|
require "graphql/analysis/ast/max_query_depth"
|
9
|
+
require "timeout"
|
9
10
|
|
10
11
|
module GraphQL
|
11
12
|
module Analysis
|
12
13
|
module AST
|
13
14
|
module_function
|
14
|
-
|
15
|
-
def use(schema_class)
|
16
|
-
if schema_class.analysis_engine == self
|
17
|
-
definition_line = caller(2, 1).first
|
18
|
-
GraphQL::Deprecation.warn("GraphQL::Analysis::AST is now the default; remove `use GraphQL::Analysis::AST` from the schema definition (#{definition_line})")
|
19
|
-
else
|
20
|
-
schema_class.analysis_engine = self
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
15
|
# Analyze a multiplex, and all queries within.
|
25
16
|
# Multiplex analyzers are ran for all queries, keeping state.
|
26
17
|
# Query analyzers are ran per query, without carrying state between queries.
|
@@ -31,7 +22,7 @@ module GraphQL
|
|
31
22
|
def analyze_multiplex(multiplex, analyzers)
|
32
23
|
multiplex_analyzers = analyzers.map { |analyzer| analyzer.new(multiplex) }
|
33
24
|
|
34
|
-
multiplex.
|
25
|
+
multiplex.current_trace.analyze_multiplex(multiplex: multiplex) do
|
35
26
|
query_results = multiplex.queries.map do |query|
|
36
27
|
if query.valid?
|
37
28
|
analyze_query(
|
@@ -58,33 +49,45 @@ module GraphQL
|
|
58
49
|
# @param analyzers [Array<GraphQL::Analysis::AST::Analyzer>]
|
59
50
|
# @return [Array<Any>] Results from those analyzers
|
60
51
|
def analyze_query(query, analyzers, multiplex_analyzers: [])
|
61
|
-
query.
|
52
|
+
query.current_trace.analyze_query(query: query) do
|
62
53
|
query_analyzers = analyzers
|
63
54
|
.map { |analyzer| analyzer.new(query) }
|
64
|
-
.
|
55
|
+
.tap { _1.select!(&:analyze?) }
|
65
56
|
|
66
57
|
analyzers_to_run = query_analyzers + multiplex_analyzers
|
67
58
|
if analyzers_to_run.any?
|
68
|
-
visitor = GraphQL::Analysis::AST::Visitor.new(
|
69
|
-
query: query,
|
70
|
-
analyzers: analyzers_to_run
|
71
|
-
)
|
72
59
|
|
73
|
-
|
60
|
+
analyzers_to_run.select!(&:visit?)
|
61
|
+
if analyzers_to_run.any?
|
62
|
+
visitor = GraphQL::Analysis::AST::Visitor.new(
|
63
|
+
query: query,
|
64
|
+
analyzers: analyzers_to_run
|
65
|
+
)
|
74
66
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
67
|
+
# `nil` or `0` causes no timeout
|
68
|
+
Timeout::timeout(query.validate_timeout_remaining) do
|
69
|
+
visitor.visit
|
70
|
+
end
|
71
|
+
|
72
|
+
if visitor.rescued_errors.any?
|
73
|
+
return visitor.rescued_errors
|
74
|
+
end
|
79
75
|
end
|
76
|
+
|
77
|
+
query_analyzers.map(&:result)
|
80
78
|
else
|
81
79
|
[]
|
82
80
|
end
|
83
81
|
end
|
82
|
+
rescue Timeout::Error
|
83
|
+
[GraphQL::AnalysisError.new("Timeout on validation of query")]
|
84
|
+
rescue GraphQL::UnauthorizedError
|
85
|
+
# This error was raised during analysis and will be returned the client before execution
|
86
|
+
[]
|
84
87
|
end
|
85
88
|
|
86
89
|
def analysis_errors(results)
|
87
|
-
results.flatten.select { |r| r.is_a?(GraphQL::AnalysisError) }
|
90
|
+
results.flatten.tap { _1.select! { |r| r.is_a?(GraphQL::AnalysisError) } }
|
88
91
|
end
|
89
92
|
end
|
90
93
|
end
|
data/lib/graphql/analysis.rb
CHANGED
@@ -1,9 +1,2 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "graphql/analysis/ast"
|
3
|
-
require "graphql/analysis/max_query_complexity"
|
4
|
-
require "graphql/analysis/max_query_depth"
|
5
|
-
require "graphql/analysis/query_complexity"
|
6
|
-
require "graphql/analysis/query_depth"
|
7
|
-
require "graphql/analysis/reducer_state"
|
8
|
-
require "graphql/analysis/analyze_query"
|
9
|
-
require "graphql/analysis/field_usage"
|