graphql 2.0.32 → 2.5.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/graphql/detailed_trace_generator.rb +77 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +49 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +8 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +5 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyzer.rb +90 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +263 -0
- data/lib/graphql/analysis/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +95 -1
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/current.rb +57 -0
- data/lib/graphql/dashboard/application_controller.rb +41 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/landings_controller.rb +9 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/statics_controller.rb +31 -0
- data/lib/graphql/dashboard/subscriptions.rb +97 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +24 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +96 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +112 -0
- data/lib/graphql/dataloader/null_dataloader.rb +55 -10
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +35 -12
- data/lib/graphql/dataloader.rb +224 -149
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +23 -25
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +228 -0
- data/lib/graphql/execution/interpreter/runtime.rb +363 -434
- data/lib/graphql/execution/interpreter.rb +91 -164
- data/lib/graphql/execution/lookahead.rb +105 -31
- data/lib/graphql/execution/multiplex.rb +7 -6
- data/lib/graphql/execution/next/field_resolve_step.rb +711 -0
- data/lib/graphql/execution/next/load_argument_step.rb +60 -0
- data/lib/graphql/execution/next/prepare_object_step.rb +129 -0
- data/lib/graphql/execution/next/runner.rb +389 -0
- data/lib/graphql/execution/next/selections_step.rb +37 -0
- data/lib/graphql/execution/next.rb +70 -0
- data/lib/graphql/execution.rb +1 -0
- data/lib/graphql/execution_error.rb +13 -10
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +7 -3
- data/lib/graphql/introspection/dynamic_fields.rb +5 -1
- data/lib/graphql/introspection/entry_points.rb +20 -6
- data/lib/graphql/introspection/enum_value_type.rb +5 -5
- data/lib/graphql/introspection/field_type.rb +13 -5
- data/lib/graphql/introspection/input_value_type.rb +21 -13
- data/lib/graphql/introspection/schema_type.rb +8 -11
- data/lib/graphql/introspection/type_type.rb +64 -28
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +26 -17
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +90 -61
- data/lib/graphql/language/lexer.rb +319 -193
- data/lib/graphql/language/nodes.rb +136 -77
- data/lib/graphql/language/parser.rb +807 -1985
- data/lib/graphql/language/printer.rb +324 -151
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +171 -0
- data/lib/graphql/language/visitor.rb +23 -83
- data/lib/graphql/language.rb +71 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +30 -1
- data/lib/graphql/pagination/connections.rb +32 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +82 -144
- data/lib/graphql/query/null_context.rb +15 -18
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +4 -4
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +126 -81
- data/lib/graphql/railtie.rb +16 -6
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +26 -13
- data/lib/graphql/schema/always_visible.rb +7 -2
- data/lib/graphql/schema/argument.rb +75 -9
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +123 -60
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive.rb +54 -2
- data/lib/graphql/schema/enum.rb +110 -27
- data/lib/graphql/schema/enum_value.rb +10 -2
- data/lib/graphql/schema/field/connection_extension.rb +15 -49
- data/lib/graphql/schema/field/scope_extension.rb +23 -7
- data/lib/graphql/schema/field.rb +245 -118
- data/lib/graphql/schema/field_extension.rb +34 -1
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +116 -60
- data/lib/graphql/schema/interface.rb +34 -16
- data/lib/graphql/schema/introspection_system.rb +8 -17
- data/lib/graphql/schema/late_bound_type.rb +4 -0
- data/lib/graphql/schema/list.rb +3 -3
- data/lib/graphql/schema/loader.rb +3 -4
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -2
- data/lib/graphql/schema/member/has_arguments.rb +132 -100
- data/lib/graphql/schema/member/has_authorization.rb +35 -0
- data/lib/graphql/schema/member/has_dataloader.rb +99 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +115 -15
- data/lib/graphql/schema/member/has_interfaces.rb +26 -12
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +34 -8
- data/lib/graphql/schema/printer.rb +9 -7
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -129
- data/lib/graphql/schema/resolver.rb +90 -32
- data/lib/graphql/schema/scalar.rb +4 -9
- data/lib/graphql/schema/subscription.rb +63 -10
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/union.rb +2 -2
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +92 -11
- data/lib/graphql/schema/validator.rb +3 -1
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +445 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +311 -0
- data/lib/graphql/schema/warden.rb +275 -103
- data/lib/graphql/schema.rb +950 -210
- data/lib/graphql/static_validation/all_rules.rb +3 -3
- data/lib/graphql/static_validation/base_visitor.rb +7 -6
- data/lib/graphql/static_validation/literal_validator.rb +6 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +21 -5
- data/lib/graphql/static_validation/validator.rb +9 -1
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -5
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +21 -4
- data/lib/graphql/subscriptions/serialize.rb +3 -1
- data/lib/graphql/subscriptions.rb +21 -17
- data/lib/graphql/testing/helpers.rb +161 -0
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +3 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +7 -3
- data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
- data/lib/graphql/tracing/appsignal_trace.rb +32 -59
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +46 -162
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +156 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +75 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +183 -37
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +864 -0
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +5 -1
- data/lib/graphql/tracing/prometheus_trace.rb +73 -73
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -58
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +82 -0
- data/lib/graphql/tracing/statsd_trace.rb +33 -45
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +112 -1
- data/lib/graphql/tracing.rb +31 -28
- data/lib/graphql/type_kinds.rb +2 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +44 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +18 -0
- data/lib/graphql/types/relay/has_node_field.rb +13 -8
- data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
- data/lib/graphql/types/relay/node_behaviors.rb +13 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/types.rb +18 -10
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/unauthorized_error.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +71 -54
- data/readme.md +12 -2
- metadata +233 -37
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -276
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/trace.rb +0 -96
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/language/parser.y +0 -560
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 453860aab49f87d8b8771b00cc50b34a4567e7c80d7ce15b95c1b4fa82b23286
|
|
4
|
+
data.tar.gz: f33d534cbbccfcfb89ba8e6f553ea17d71199ca3fc898ab75c5f3ace08aba820
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3c2c8b87e60b9312ce5fb3848cb9a8112b6d050b6ee9c31eee5720932a2cf754f97f6f7bef273b491199aaa46c7551348e07294270585e79a1e35d176126bdfb
|
|
7
|
+
data.tar.gz: b679a8434d195d513f97963b2fe70b296cb2106ceda4ae2b7c756d1127d8ee4c56f2e3106b4a01c609498904622ada5d569f489bf97a13f8627e7b6a6a1d83fd
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'rails/generators/active_record'
|
|
3
|
+
|
|
4
|
+
module Graphql
|
|
5
|
+
module Generators
|
|
6
|
+
class DetailedTraceGenerator < ::Rails::Generators::Base
|
|
7
|
+
include ::Rails::Generators::Migration
|
|
8
|
+
desc "Install GraphQL::Tracing::DetailedTrace for your schema"
|
|
9
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
10
|
+
|
|
11
|
+
class_option :redis,
|
|
12
|
+
type: :boolean,
|
|
13
|
+
default: false,
|
|
14
|
+
desc: "Use Redis for persistence instead of ActiveRecord"
|
|
15
|
+
|
|
16
|
+
def self.next_migration_number(dirname)
|
|
17
|
+
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def install_detailed_traces
|
|
21
|
+
|
|
22
|
+
schema_glob = File.expand_path("app/graphql/*_schema.rb", destination_root)
|
|
23
|
+
schema_file = Dir.glob(schema_glob).first
|
|
24
|
+
if !schema_file
|
|
25
|
+
raise ArgumentError, "Failed to find schema definition file (checked: #{schema_glob.inspect})"
|
|
26
|
+
end
|
|
27
|
+
schema_file_match = /( *)class ([A-Za-z:]+) < GraphQL::Schema/.match(File.read(schema_file))
|
|
28
|
+
schema_name = schema_file_match[2]
|
|
29
|
+
indent = schema_file_match[1] + " "
|
|
30
|
+
|
|
31
|
+
if !options.redis?
|
|
32
|
+
migration_template 'create_graphql_detailed_traces.erb', 'db/migrate/create_graphql_detailed_traces.rb'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
log :add_detailed_traces_plugin
|
|
36
|
+
sentinel = /< GraphQL::Schema\s*\n/m
|
|
37
|
+
code = <<-RUBY
|
|
38
|
+
#{indent}use GraphQL::Tracing::DetailedTrace#{options.redis? ? ", redis: raise(\"TODO: pass a connection to a persistent redis database\")" : ""}, limit: 50
|
|
39
|
+
|
|
40
|
+
#{indent}# When this returns true, DetailedTrace will trace the query
|
|
41
|
+
#{indent}# Could use `query.context`, `query.selected_operation_name`, `query.query_string` here
|
|
42
|
+
#{indent}# Could call out to Flipper, etc
|
|
43
|
+
#{indent}def self.detailed_trace?(query)
|
|
44
|
+
#{indent} rand <= 0.000_1 # one in ten thousand
|
|
45
|
+
#{indent}end
|
|
46
|
+
|
|
47
|
+
RUBY
|
|
48
|
+
|
|
49
|
+
in_root do
|
|
50
|
+
inject_into_file schema_file, code, after: sentinel, force: false
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
routes_source = File.read(File.expand_path("config/routes.rb", destination_root))
|
|
54
|
+
already_has_dashboard = routes_source.include?("GraphQL::Dashboard") ||
|
|
55
|
+
routes_source.include?("Schema.dashboard") ||
|
|
56
|
+
routes_source.include?("GraphQL::Pro::Routes::Lazy")
|
|
57
|
+
|
|
58
|
+
if (!already_has_dashboard || behavior == :revoke)
|
|
59
|
+
log :route, "GraphQL::Dashboard"
|
|
60
|
+
shell.mute do
|
|
61
|
+
route <<~RUBY
|
|
62
|
+
# TODO: add authorization to this route and expose it in production
|
|
63
|
+
# See https://graphql-ruby.org/pro/dashboard.html#authorizing-the-dashboard
|
|
64
|
+
if Rails.env.development?
|
|
65
|
+
mount GraphQL::Dashboard, at: "/graphql/dashboard", schema: #{schema_name.inspect}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
RUBY
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
gem("google-protobuf")
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -9,7 +9,7 @@ module Graphql
|
|
|
9
9
|
class MutationRootGenerator < Rails::Generators::Base
|
|
10
10
|
include Core
|
|
11
11
|
|
|
12
|
-
desc "Create mutation base type, mutation root
|
|
12
|
+
desc "Create mutation base type, mutation root type, and adds the latter to the schema"
|
|
13
13
|
source_root File.expand_path('../templates', __FILE__)
|
|
14
14
|
|
|
15
15
|
class_option :schema,
|
|
@@ -31,4 +31,4 @@ module Graphql
|
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
|
-
end
|
|
34
|
+
end
|
|
@@ -45,6 +45,13 @@ module Graphql
|
|
|
45
45
|
# post "/graphql", to: "graphql#execute"
|
|
46
46
|
# ```
|
|
47
47
|
#
|
|
48
|
+
# Add ActiveRecord::QueryLogs metadata:
|
|
49
|
+
# ```ruby
|
|
50
|
+
# current_graphql_operation: -> { GraphQL::Current.operation_name },
|
|
51
|
+
# current_graphql_field: -> { GraphQL::Current.field&.path },
|
|
52
|
+
# current_dataloader_source: -> { GraphQL::Current.dataloader_source_class },
|
|
53
|
+
# ```
|
|
54
|
+
#
|
|
48
55
|
# Accept a `--batch` option which adds `GraphQL::Batch` setup.
|
|
49
56
|
#
|
|
50
57
|
# Use `--skip-graphiql` to skip `graphiql-rails` installation.
|
|
@@ -92,6 +99,11 @@ module Graphql
|
|
|
92
99
|
default: false,
|
|
93
100
|
desc: "Use GraphQL Playground over Graphiql as IDE"
|
|
94
101
|
|
|
102
|
+
class_option :skip_query_logs,
|
|
103
|
+
type: :boolean,
|
|
104
|
+
default: false,
|
|
105
|
+
desc: "Skip ActiveRecord::QueryLogs hooks in config/application.rb"
|
|
106
|
+
|
|
95
107
|
# These two options are taken from Rails' own generators'
|
|
96
108
|
class_option :api,
|
|
97
109
|
type: :boolean,
|
|
@@ -105,6 +117,9 @@ module Graphql
|
|
|
105
117
|
template("#{base_type}.erb", "#{options[:directory]}/types/#{base_type}.rb")
|
|
106
118
|
end
|
|
107
119
|
|
|
120
|
+
# All resolvers are defined as living in their own module, including this class.
|
|
121
|
+
template("base_resolver.erb", "#{options[:directory]}/resolvers/base_resolver.rb")
|
|
122
|
+
|
|
108
123
|
# Note: You can't have a schema without the query type, otherwise introspection breaks
|
|
109
124
|
template("query_type.erb", "#{options[:directory]}/types/query_type.rb")
|
|
110
125
|
insert_root_type('query', 'QueryType')
|
|
@@ -177,6 +192,40 @@ RUBY
|
|
|
177
192
|
install_relay
|
|
178
193
|
end
|
|
179
194
|
|
|
195
|
+
if !options[:skip_query_logs]
|
|
196
|
+
config_file = "config/application.rb"
|
|
197
|
+
current_app_rb = File.read(Rails.root.join(config_file))
|
|
198
|
+
existing_log_tags_pattern = /config.active_record.query_log_tags = \[\n?(\s*:[a-z_]+,?\s*\n?|\s*#[^\]]*\n)*/m
|
|
199
|
+
existing_log_tags = existing_log_tags_pattern.match(current_app_rb)
|
|
200
|
+
if existing_log_tags && behavior == :invoke
|
|
201
|
+
code = <<-RUBY
|
|
202
|
+
# GraphQL-Ruby query log tags:
|
|
203
|
+
current_graphql_operation: -> { GraphQL::Current.operation_name },
|
|
204
|
+
current_graphql_field: -> { GraphQL::Current.field&.path },
|
|
205
|
+
current_dataloader_source: -> { GraphQL::Current.dataloader_source_class },
|
|
206
|
+
RUBY
|
|
207
|
+
if !existing_log_tags.to_s.end_with?(",")
|
|
208
|
+
code = ",\n#{code} "
|
|
209
|
+
end
|
|
210
|
+
# Try to insert this code _after_ any plain symbol entries in the array of query log tags:
|
|
211
|
+
after_code = existing_log_tags_pattern
|
|
212
|
+
else
|
|
213
|
+
code = <<-RUBY
|
|
214
|
+
config.active_record.query_log_tags_enabled = true
|
|
215
|
+
config.active_record.query_log_tags = [
|
|
216
|
+
# Rails query log tags:
|
|
217
|
+
:application, :controller, :action, :job,
|
|
218
|
+
# GraphQL-Ruby query log tags:
|
|
219
|
+
current_graphql_operation: -> { GraphQL::Current.operation_name },
|
|
220
|
+
current_graphql_field: -> { GraphQL::Current.field&.path },
|
|
221
|
+
current_dataloader_source: -> { GraphQL::Current.dataloader_source_class },
|
|
222
|
+
]
|
|
223
|
+
RUBY
|
|
224
|
+
after_code = "class Application < Rails::Application\n"
|
|
225
|
+
end
|
|
226
|
+
insert_into_file(config_file, code, after: after_code)
|
|
227
|
+
end
|
|
228
|
+
|
|
180
229
|
if gemfile_modified?
|
|
181
230
|
say "Gemfile has been modified, make sure you `bundle install`"
|
|
182
231
|
end
|
|
@@ -18,7 +18,7 @@ module Graphql
|
|
|
18
18
|
class_option :orm, banner: "NAME", type: :string, required: true,
|
|
19
19
|
desc: "ORM to generate the controller for"
|
|
20
20
|
|
|
21
|
-
class_option
|
|
21
|
+
class_option :namespaced_types,
|
|
22
22
|
type: :boolean,
|
|
23
23
|
required: false,
|
|
24
24
|
default: false,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class CreateGraphqlDetailedTraces < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
2
|
+
def change
|
|
3
|
+
create_table :graphql_detailed_traces, force: true do |t|
|
|
4
|
+
t.bigint :begin_ms, null: false
|
|
5
|
+
t.float :duration_ms, null: false
|
|
6
|
+
t.binary :trace_data, null: false
|
|
7
|
+
t.string :operation_name, null: false
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
<% module_namespacing_when_supported do -%>
|
|
2
4
|
class <%= schema_name %> < GraphQL::Schema
|
|
3
5
|
query(Types::QueryType)
|
|
@@ -24,6 +26,9 @@ class <%= schema_name %> < GraphQL::Schema
|
|
|
24
26
|
raise(GraphQL::RequiredImplementationMissingError)
|
|
25
27
|
end
|
|
26
28
|
|
|
29
|
+
# Limit the size of incoming queries:
|
|
30
|
+
max_query_string_tokens(5000)
|
|
31
|
+
|
|
27
32
|
# Stop validating when it encounters this many errors:
|
|
28
33
|
validate_max_errors(100)
|
|
29
34
|
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
module Analysis
|
|
4
|
+
# Query analyzer for query ASTs. Query analyzers respond to visitor style methods
|
|
5
|
+
# but are prefixed by `enter` and `leave`.
|
|
6
|
+
#
|
|
7
|
+
# When an analyzer is initialized with a Multiplex, you can always get the current query from
|
|
8
|
+
# `visitor.query` in the visit methods.
|
|
9
|
+
#
|
|
10
|
+
# @param [GraphQL::Query, GraphQL::Execution::Multiplex] The query or multiplex to analyze
|
|
11
|
+
class Analyzer
|
|
12
|
+
def initialize(subject)
|
|
13
|
+
@subject = subject
|
|
14
|
+
|
|
15
|
+
if subject.is_a?(GraphQL::Query)
|
|
16
|
+
@query = subject
|
|
17
|
+
@multiplex = nil
|
|
18
|
+
else
|
|
19
|
+
@multiplex = subject
|
|
20
|
+
@query = nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Analyzer hook to decide at analysis time whether a query should
|
|
25
|
+
# be analyzed or not.
|
|
26
|
+
# @return [Boolean] If the query should be analyzed or not
|
|
27
|
+
def analyze?
|
|
28
|
+
true
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Analyzer hook to decide at analysis time whether analysis
|
|
32
|
+
# requires a visitor pass; can be disabled for precomputed results.
|
|
33
|
+
# @return [Boolean] If analysis requires visitation or not
|
|
34
|
+
def visit?
|
|
35
|
+
true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The result for this analyzer. Returning {GraphQL::AnalysisError} results
|
|
39
|
+
# in a query error.
|
|
40
|
+
# @return [Any] The analyzer result
|
|
41
|
+
def result
|
|
42
|
+
raise GraphQL::RequiredImplementationMissingError
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
|
46
|
+
class << self
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def build_visitor_hooks(member_name)
|
|
50
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
|
51
|
+
def on_enter_#{member_name}(node, parent, visitor)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def on_leave_#{member_name}(node, parent, visitor)
|
|
55
|
+
end
|
|
56
|
+
EOS
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
build_visitor_hooks :argument
|
|
61
|
+
build_visitor_hooks :directive
|
|
62
|
+
build_visitor_hooks :document
|
|
63
|
+
build_visitor_hooks :enum
|
|
64
|
+
build_visitor_hooks :field
|
|
65
|
+
build_visitor_hooks :fragment_spread
|
|
66
|
+
build_visitor_hooks :inline_fragment
|
|
67
|
+
build_visitor_hooks :input_object
|
|
68
|
+
build_visitor_hooks :list_type
|
|
69
|
+
build_visitor_hooks :non_null_type
|
|
70
|
+
build_visitor_hooks :null_value
|
|
71
|
+
build_visitor_hooks :operation_definition
|
|
72
|
+
build_visitor_hooks :type_name
|
|
73
|
+
build_visitor_hooks :variable_definition
|
|
74
|
+
build_visitor_hooks :variable_identifier
|
|
75
|
+
build_visitor_hooks :abstract_node
|
|
76
|
+
# rubocop:enable Development/NoEvalCop
|
|
77
|
+
protected
|
|
78
|
+
|
|
79
|
+
# @return [GraphQL::Query, GraphQL::Execution::Multiplex] Whatever this analyzer is analyzing
|
|
80
|
+
attr_reader :subject
|
|
81
|
+
|
|
82
|
+
# @return [GraphQL::Query, nil] `nil` if this analyzer is visiting a multiplex
|
|
83
|
+
# (When this is `nil`, use `visitor.query` inside visit methods to get the current query)
|
|
84
|
+
attr_reader :query
|
|
85
|
+
|
|
86
|
+
# @return [GraphQL::Execution::Multiplex, nil] `nil` if this analyzer is visiting a query
|
|
87
|
+
attr_reader :multiplex
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
module Analysis
|
|
4
|
+
class FieldUsage < Analyzer
|
|
5
|
+
def initialize(query)
|
|
6
|
+
super
|
|
7
|
+
@used_fields = Set.new
|
|
8
|
+
@used_deprecated_fields = Set.new
|
|
9
|
+
@used_deprecated_arguments = Set.new
|
|
10
|
+
@used_deprecated_enum_values = Set.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def on_leave_field(node, parent, visitor)
|
|
14
|
+
field_defn = visitor.field_definition
|
|
15
|
+
field = "#{visitor.parent_type_definition.graphql_name}.#{field_defn.graphql_name}"
|
|
16
|
+
@used_fields << field
|
|
17
|
+
@used_deprecated_fields << field if field_defn.deprecation_reason
|
|
18
|
+
arguments = visitor.query.arguments_for(node, field_defn)
|
|
19
|
+
# If there was an error when preparing this argument object,
|
|
20
|
+
# then this might be an error or something:
|
|
21
|
+
if arguments.respond_to?(:argument_values)
|
|
22
|
+
extract_deprecated_arguments(arguments.argument_values)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def result
|
|
27
|
+
{
|
|
28
|
+
used_fields: @used_fields.to_a,
|
|
29
|
+
used_deprecated_fields: @used_deprecated_fields.to_a,
|
|
30
|
+
used_deprecated_arguments: @used_deprecated_arguments.to_a,
|
|
31
|
+
used_deprecated_enum_values: @used_deprecated_enum_values.to_a,
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def extract_deprecated_arguments(argument_values)
|
|
38
|
+
argument_values.each_pair do |_argument_name, argument|
|
|
39
|
+
if argument.definition.deprecation_reason
|
|
40
|
+
@used_deprecated_arguments << argument.definition.path
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
arg_val = argument.value
|
|
44
|
+
|
|
45
|
+
next if arg_val.nil?
|
|
46
|
+
|
|
47
|
+
argument_type = argument.definition.type
|
|
48
|
+
if argument_type.non_null?
|
|
49
|
+
argument_type = argument_type.of_type
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if argument_type.kind.input_object?
|
|
53
|
+
extract_deprecated_arguments(argument.original_value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
|
|
54
|
+
elsif argument_type.kind.enum?
|
|
55
|
+
extract_deprecated_enum_value(argument_type, arg_val)
|
|
56
|
+
elsif argument_type.list?
|
|
57
|
+
inner_type = argument_type.unwrap
|
|
58
|
+
case inner_type.kind
|
|
59
|
+
when TypeKinds::INPUT_OBJECT
|
|
60
|
+
argument.original_value.each do |value|
|
|
61
|
+
extract_deprecated_arguments(value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
|
|
62
|
+
end
|
|
63
|
+
when TypeKinds::ENUM
|
|
64
|
+
arg_val.each do |value|
|
|
65
|
+
extract_deprecated_enum_value(inner_type, value)
|
|
66
|
+
end
|
|
67
|
+
else
|
|
68
|
+
# Not a kind of input that we track
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def extract_deprecated_enum_value(enum_type, value)
|
|
75
|
+
enum_value = @query.types.enum_values(enum_type).find { |ev| ev.value == value }
|
|
76
|
+
if enum_value&.deprecation_reason
|
|
77
|
+
@used_deprecated_enum_values << enum_value.path
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
module Analysis
|
|
4
|
+
# Used under the hood to implement complexity validation,
|
|
5
|
+
# see {Schema#max_complexity} and {Query#max_complexity}
|
|
6
|
+
class MaxQueryComplexity < QueryComplexity
|
|
7
|
+
def result
|
|
8
|
+
return if subject.max_complexity.nil?
|
|
9
|
+
|
|
10
|
+
total_complexity = max_possible_complexity
|
|
11
|
+
|
|
12
|
+
if total_complexity > subject.max_complexity
|
|
13
|
+
GraphQL::AnalysisError.new("Query has complexity of #{total_complexity}, which exceeds max complexity of #{subject.max_complexity}")
|
|
14
|
+
else
|
|
15
|
+
nil
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
module Analysis
|
|
4
|
+
class MaxQueryDepth < QueryDepth
|
|
5
|
+
def result
|
|
6
|
+
configured_max_depth = if query
|
|
7
|
+
query.max_depth
|
|
8
|
+
else
|
|
9
|
+
multiplex.schema.max_depth
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
if configured_max_depth && @max_depth > configured_max_depth
|
|
13
|
+
GraphQL::AnalysisError.new("Query has depth of #{@max_depth}, which exceeds max depth of #{configured_max_depth}")
|
|
14
|
+
else
|
|
15
|
+
nil
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|