graphql 2.2.5 → 2.3.1
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/templates/schema.erb +3 -0
- data/lib/graphql/analysis/ast/field_usage.rb +36 -9
- data/lib/graphql/analysis/ast/visitor.rb +8 -0
- data/lib/graphql/analysis/ast.rb +10 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/runtime.rb +9 -0
- data/lib/graphql/execution/interpreter.rb +90 -150
- data/lib/graphql/introspection/entry_points.rb +9 -3
- data/lib/graphql/introspection/schema_type.rb +3 -1
- data/lib/graphql/language/document_from_schema_definition.rb +2 -3
- data/lib/graphql/language/lexer.rb +48 -30
- data/lib/graphql/language/nodes.rb +1 -1
- data/lib/graphql/language/parser.rb +25 -11
- data/lib/graphql/language/printer.rb +4 -0
- data/lib/graphql/language.rb +60 -0
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/query/context.rb +30 -33
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +3 -3
- data/lib/graphql/schema/argument.rb +1 -0
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +9 -1
- data/lib/graphql/schema/field.rb +33 -30
- data/lib/graphql/schema/input_object.rb +1 -2
- data/lib/graphql/schema/interface.rb +5 -1
- data/lib/graphql/schema/loader.rb +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +2 -2
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/resolver.rb +19 -10
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema.rb +119 -28
- data/lib/graphql/static_validation/literal_validator.rb +1 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
- data/lib/graphql/static_validation/validator.rb +3 -0
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +0 -3
- data/lib/graphql/testing/helpers.rb +32 -6
- data/lib/graphql/tracing/data_dog_trace.rb +21 -34
- data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/prometheus_trace.rb +2 -2
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing.rb +3 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +10 -2
- metadata +38 -23
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
| @@ -215,8 +215,7 @@ module GraphQL | |
| 215 215 | 
             
                        if resolved_arguments.is_a?(GraphQL::Error)
         | 
| 216 216 | 
             
                          raise resolved_arguments
         | 
| 217 217 | 
             
                        else
         | 
| 218 | 
            -
                           | 
| 219 | 
            -
                          input_obj_instance.prepare
         | 
| 218 | 
            +
                          self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
         | 
| 220 219 | 
             
                        end
         | 
| 221 220 | 
             
                      end
         | 
| 222 221 | 
             
                    end
         | 
| @@ -69,7 +69,11 @@ module GraphQL | |
| 69 69 | 
             
                        end
         | 
| 70 70 | 
             
                      elsif child_class < GraphQL::Schema::Object
         | 
| 71 71 | 
             
                        # This is being included into an object type, make sure it's using `implements(...)`
         | 
| 72 | 
            -
                        backtrace_line =  | 
| 72 | 
            +
                        backtrace_line = caller_locations(0, 10).find do |location|
         | 
| 73 | 
            +
                          location.base_label == "implements" &&
         | 
| 74 | 
            +
                            location.path.end_with?("schema/member/has_interfaces.rb")
         | 
| 75 | 
            +
                        end
         | 
| 76 | 
            +
             | 
| 73 77 | 
             
                        if !backtrace_line
         | 
| 74 78 | 
             
                          raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
         | 
| 75 79 | 
             
                        end
         | 
| @@ -32,7 +32,8 @@ module GraphQL | |
| 32 32 | 
             
                    end
         | 
| 33 33 |  | 
| 34 34 | 
             
                    Class.new(GraphQL::Schema) do
         | 
| 35 | 
            -
                       | 
| 35 | 
            +
                      add_type_and_traverse(types.values, root: false)
         | 
| 36 | 
            +
                      orphan_types(types.values.select { |t| t.kind.object? })
         | 
| 36 37 | 
             
                      directives(directives)
         | 
| 37 38 | 
             
                      description(schema["description"])
         | 
| 38 39 |  | 
| @@ -50,7 +50,7 @@ module GraphQL | |
| 50 50 | 
             
                        if loads && arg_defn.type.list?
         | 
| 51 51 | 
             
                          class_eval <<-RUBY, __FILE__, __LINE__ + 1
         | 
| 52 52 | 
             
                          def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
         | 
| 53 | 
            -
                            argument = get_argument("#{arg_defn.graphql_name}")
         | 
| 53 | 
            +
                            argument = get_argument("#{arg_defn.graphql_name}", context || self.context)
         | 
| 54 54 | 
             
                            (context || self.context).query.after_lazy(values) do |values2|
         | 
| 55 55 | 
             
                              GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
         | 
| 56 56 | 
             
                            end
         | 
| @@ -59,7 +59,7 @@ module GraphQL | |
| 59 59 | 
             
                        elsif loads
         | 
| 60 60 | 
             
                          class_eval <<-RUBY, __FILE__, __LINE__ + 1
         | 
| 61 61 | 
             
                          def #{method_owner}load_#{arg_defn.keyword}(value, context = nil)
         | 
| 62 | 
            -
                            argument = get_argument("#{arg_defn.graphql_name}")
         | 
| 62 | 
            +
                            argument = get_argument("#{arg_defn.graphql_name}", context || self.context)
         | 
| 63 63 | 
             
                            load_application_object(argument, value, context || self.context)
         | 
| 64 64 | 
             
                          end
         | 
| 65 65 | 
             
                          RUBY
         | 
| @@ -62,6 +62,13 @@ module GraphQL | |
| 62 62 | 
             
                  extend GraphQL::Schema::Member::HasFields
         | 
| 63 63 | 
             
                  extend GraphQL::Schema::Resolver::HasPayloadType
         | 
| 64 64 |  | 
| 65 | 
            +
                  # @api private
         | 
| 66 | 
            +
                  def call_resolve(_args_hash)
         | 
| 67 | 
            +
                    # Clear any cached values from `loads` or authorization:
         | 
| 68 | 
            +
                    dataloader.clear_cache
         | 
| 69 | 
            +
                    super
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 65 72 | 
             
                  class << self
         | 
| 66 73 | 
             
                    def visible?(context)
         | 
| 67 74 | 
             
                      true
         | 
| @@ -103,11 +103,7 @@ module GraphQL | |
| 103 103 | 
             
                              end
         | 
| 104 104 | 
             
                            elsif authorized_val
         | 
| 105 105 | 
             
                              # Finally, all the hooks have passed, so resolve it
         | 
| 106 | 
            -
                               | 
| 107 | 
            -
                                public_send(self.class.resolve_method, **loaded_args)
         | 
| 108 | 
            -
                              else
         | 
| 109 | 
            -
                                public_send(self.class.resolve_method)
         | 
| 110 | 
            -
                              end
         | 
| 106 | 
            +
                              call_resolve(loaded_args)
         | 
| 111 107 | 
             
                            else
         | 
| 112 108 | 
             
                              raise GraphQL::UnauthorizedFieldError.new(context: context, object: object, type: field.owner, field: field)
         | 
| 113 109 | 
             
                            end
         | 
| @@ -117,6 +113,15 @@ module GraphQL | |
| 117 113 | 
             
                    end
         | 
| 118 114 | 
             
                  end
         | 
| 119 115 |  | 
| 116 | 
            +
                  # @api private {GraphQL::Schema::Mutation} uses this to clear the dataloader cache
         | 
| 117 | 
            +
                  def call_resolve(args_hash)
         | 
| 118 | 
            +
                    if args_hash.any?
         | 
| 119 | 
            +
                      public_send(self.class.resolve_method, **args_hash)
         | 
| 120 | 
            +
                    else
         | 
| 121 | 
            +
                      public_send(self.class.resolve_method)
         | 
| 122 | 
            +
                    end
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 120 125 | 
             
                  # Do the work. Everything happens here.
         | 
| 121 126 | 
             
                  # @return [Object] An object corresponding to the return type
         | 
| 122 127 | 
             
                  def resolve(**args)
         | 
| @@ -166,11 +171,15 @@ module GraphQL | |
| 166 171 | 
             
                    args.each_value do |argument|
         | 
| 167 172 | 
             
                      arg_keyword = argument.keyword
         | 
| 168 173 | 
             
                      if inputs.key?(arg_keyword) && !(arg_value = inputs[arg_keyword]).nil? && (arg_value != argument.default_value)
         | 
| 169 | 
            -
                         | 
| 170 | 
            -
                        if  | 
| 171 | 
            -
                          return  | 
| 172 | 
            -
             | 
| 173 | 
            -
                           | 
| 174 | 
            +
                        auth_result = argument.authorized?(self, arg_value, context)
         | 
| 175 | 
            +
                        if auth_result.is_a?(Array)
         | 
| 176 | 
            +
                          # only return this second value if the application returned a second value
         | 
| 177 | 
            +
                          arg_auth, err = auth_result
         | 
| 178 | 
            +
                          if !arg_auth
         | 
| 179 | 
            +
                            return arg_auth, err
         | 
| 180 | 
            +
                          end
         | 
| 181 | 
            +
                        elsif auth_result == false
         | 
| 182 | 
            +
                          return auth_result
         | 
| 174 183 | 
             
                        end
         | 
| 175 184 | 
             
                      else
         | 
| 176 185 | 
             
                        true
         | 
    
        data/lib/graphql/schema.rb
    CHANGED
    
    | @@ -63,10 +63,6 @@ module GraphQL | |
| 63 63 | 
             
              # Schemas can restrict large incoming queries with `max_depth` and `max_complexity` configurations.
         | 
| 64 64 | 
             
              # (These configurations can be overridden by specific calls to {Schema#execute})
         | 
| 65 65 | 
             
              #
         | 
| 66 | 
            -
              # Schemas can specify how queries should be executed against them.
         | 
| 67 | 
            -
              # `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
         | 
| 68 | 
            -
              # each apply to corresponding root types.
         | 
| 69 | 
            -
              #
         | 
| 70 66 | 
             
              # @example defining a schema
         | 
| 71 67 | 
             
              #   class MySchema < GraphQL::Schema
         | 
| 72 68 | 
             
              #     query QueryType
         | 
| @@ -162,18 +158,29 @@ module GraphQL | |
| 162 158 |  | 
| 163 159 | 
             
                  def trace_class(new_class = nil)
         | 
| 164 160 | 
             
                    if new_class
         | 
| 161 | 
            +
                      # If any modules were already added for `:default`,
         | 
| 162 | 
            +
                      # re-apply them here
         | 
| 163 | 
            +
                      mods = trace_modules_for(:default)
         | 
| 164 | 
            +
                      mods.each { |mod| new_class.include(mod) }
         | 
| 165 165 | 
             
                      trace_mode(:default, new_class)
         | 
| 166 166 | 
             
                      backtrace_class = Class.new(new_class)
         | 
| 167 167 | 
             
                      backtrace_class.include(GraphQL::Backtrace::Trace)
         | 
| 168 168 | 
             
                      trace_mode(:default_backtrace, backtrace_class)
         | 
| 169 169 | 
             
                    end
         | 
| 170 | 
            -
                    trace_class_for(:default)
         | 
| 170 | 
            +
                    trace_class_for(:default, build: true)
         | 
| 171 171 | 
             
                  end
         | 
| 172 172 |  | 
| 173 173 | 
             
                  # @return [Class] Return the trace class to use for this mode, looking one up on the superclass if this Schema doesn't have one defined.
         | 
| 174 | 
            -
                  def trace_class_for(mode, build:  | 
| 175 | 
            -
                    own_trace_modes[mode] | 
| 176 | 
            -
                       | 
| 174 | 
            +
                  def trace_class_for(mode, build: false)
         | 
| 175 | 
            +
                    if (trace_class = own_trace_modes[mode])
         | 
| 176 | 
            +
                      trace_class
         | 
| 177 | 
            +
                    elsif superclass.respond_to?(:trace_class_for) && (trace_class = superclass.trace_class_for(mode, build: false))
         | 
| 178 | 
            +
                      trace_class
         | 
| 179 | 
            +
                    elsif build
         | 
| 180 | 
            +
                      own_trace_modes[mode] = build_trace_mode(mode)
         | 
| 181 | 
            +
                    else
         | 
| 182 | 
            +
                      nil
         | 
| 183 | 
            +
                    end
         | 
| 177 184 | 
             
                  end
         | 
| 178 185 |  | 
| 179 186 | 
             
                  # Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
         | 
| @@ -211,20 +218,24 @@ module GraphQL | |
| 211 218 | 
             
                        include DefaultTraceClass
         | 
| 212 219 | 
             
                      end
         | 
| 213 220 | 
             
                    when :default_backtrace
         | 
| 214 | 
            -
                      schema_base_class = trace_class_for(:default)
         | 
| 221 | 
            +
                      schema_base_class = trace_class_for(:default, build: true)
         | 
| 215 222 | 
             
                      Class.new(schema_base_class) do
         | 
| 216 223 | 
             
                        include(GraphQL::Backtrace::Trace)
         | 
| 217 224 | 
             
                      end
         | 
| 218 225 | 
             
                    else
         | 
| 219 226 | 
             
                      # First, see if the superclass has a custom-defined class for this.
         | 
| 220 227 | 
             
                      # Then, if it doesn't, use this class's default trace
         | 
| 221 | 
            -
                      base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode | 
| 228 | 
            +
                      base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || trace_class_for(:default, build: true)
         | 
| 222 229 | 
             
                      # Prepare the default trace class if it hasn't been initialized yet
         | 
| 223 230 | 
             
                      base_class ||= (own_trace_modes[:default] = build_trace_mode(:default))
         | 
| 224 231 | 
             
                      mods = trace_modules_for(mode)
         | 
| 225 232 | 
             
                      if base_class < DefaultTraceClass
         | 
| 226 233 | 
             
                        mods = trace_modules_for(:default) + mods
         | 
| 227 234 | 
             
                      end
         | 
| 235 | 
            +
                      # Copy the existing default options into this mode's options
         | 
| 236 | 
            +
                      default_options = trace_options_for(:default)
         | 
| 237 | 
            +
                      add_trace_options_for(mode, default_options)
         | 
| 238 | 
            +
             | 
| 228 239 | 
             
                      Class.new(base_class) do
         | 
| 229 240 | 
             
                        mods.any? && include(*mods)
         | 
| 230 241 | 
             
                      end
         | 
| @@ -632,6 +643,17 @@ module GraphQL | |
| 632 643 | 
             
                    end
         | 
| 633 644 | 
             
                  end
         | 
| 634 645 |  | 
| 646 | 
            +
                  # A limit on the number of tokens to accept on incoming query strings.
         | 
| 647 | 
            +
                  # Use this to prevent parsing maliciously-large query strings.
         | 
| 648 | 
            +
                  # @return [nil, Integer]
         | 
| 649 | 
            +
                  def max_query_string_tokens(new_max_tokens = NOT_CONFIGURED)
         | 
| 650 | 
            +
                    if NOT_CONFIGURED.equal?(new_max_tokens)
         | 
| 651 | 
            +
                      defined?(@max_query_string_tokens) ? @max_query_string_tokens : find_inherited_value(:max_query_string_tokens)
         | 
| 652 | 
            +
                    else
         | 
| 653 | 
            +
                      @max_query_string_tokens = new_max_tokens
         | 
| 654 | 
            +
                    end
         | 
| 655 | 
            +
                  end
         | 
| 656 | 
            +
             | 
| 635 657 | 
             
                  def default_page_size(new_default_page_size = nil)
         | 
| 636 658 | 
             
                    if new_default_page_size
         | 
| 637 659 | 
             
                      @default_page_size = new_default_page_size
         | 
| @@ -640,27 +662,39 @@ module GraphQL | |
| 640 662 | 
             
                    end
         | 
| 641 663 | 
             
                  end
         | 
| 642 664 |  | 
| 643 | 
            -
                  def query_execution_strategy(new_query_execution_strategy = nil)
         | 
| 665 | 
            +
                  def query_execution_strategy(new_query_execution_strategy = nil, deprecation_warning: true)
         | 
| 666 | 
            +
                    if deprecation_warning
         | 
| 667 | 
            +
                      warn "GraphQL::Schema.query_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
         | 
| 668 | 
            +
                      warn "  #{caller(1, 1).first}"
         | 
| 669 | 
            +
                    end
         | 
| 644 670 | 
             
                    if new_query_execution_strategy
         | 
| 645 671 | 
             
                      @query_execution_strategy = new_query_execution_strategy
         | 
| 646 672 | 
             
                    else
         | 
| 647 | 
            -
                      @query_execution_strategy ||  | 
| 673 | 
            +
                      @query_execution_strategy || (superclass.respond_to?(:query_execution_strategy) ? superclass.query_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
         | 
| 648 674 | 
             
                    end
         | 
| 649 675 | 
             
                  end
         | 
| 650 676 |  | 
| 651 | 
            -
                  def mutation_execution_strategy(new_mutation_execution_strategy = nil)
         | 
| 677 | 
            +
                  def mutation_execution_strategy(new_mutation_execution_strategy = nil, deprecation_warning: true)
         | 
| 678 | 
            +
                    if deprecation_warning
         | 
| 679 | 
            +
                      warn "GraphQL::Schema.mutation_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
         | 
| 680 | 
            +
                        warn "  #{caller(1, 1).first}"
         | 
| 681 | 
            +
                    end
         | 
| 652 682 | 
             
                    if new_mutation_execution_strategy
         | 
| 653 683 | 
             
                      @mutation_execution_strategy = new_mutation_execution_strategy
         | 
| 654 684 | 
             
                    else
         | 
| 655 | 
            -
                      @mutation_execution_strategy ||  | 
| 685 | 
            +
                      @mutation_execution_strategy || (superclass.respond_to?(:mutation_execution_strategy) ? superclass.mutation_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
         | 
| 656 686 | 
             
                    end
         | 
| 657 687 | 
             
                  end
         | 
| 658 688 |  | 
| 659 | 
            -
                  def subscription_execution_strategy(new_subscription_execution_strategy = nil)
         | 
| 689 | 
            +
                  def subscription_execution_strategy(new_subscription_execution_strategy = nil, deprecation_warning: true)
         | 
| 690 | 
            +
                    if deprecation_warning
         | 
| 691 | 
            +
                      warn "GraphQL::Schema.subscription_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
         | 
| 692 | 
            +
                      warn "  #{caller(1, 1).first}"
         | 
| 693 | 
            +
                    end
         | 
| 660 694 | 
             
                    if new_subscription_execution_strategy
         | 
| 661 695 | 
             
                      @subscription_execution_strategy = new_subscription_execution_strategy
         | 
| 662 696 | 
             
                    else
         | 
| 663 | 
            -
                      @subscription_execution_strategy ||  | 
| 697 | 
            +
                      @subscription_execution_strategy || (superclass.respond_to?(:subscription_execution_strategy) ? superclass.subscription_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
         | 
| 664 698 | 
             
                    end
         | 
| 665 699 | 
             
                  end
         | 
| 666 700 |  | 
| @@ -743,6 +777,7 @@ module GraphQL | |
| 743 777 |  | 
| 744 778 | 
             
                  def error_bubbling(new_error_bubbling = nil)
         | 
| 745 779 | 
             
                    if !new_error_bubbling.nil?
         | 
| 780 | 
            +
                      warn("error_bubbling(#{new_error_bubbling.inspect}) is deprecated; the default value of `false` will be the only option in GraphQL-Ruby 3.0")
         | 
| 746 781 | 
             
                      @error_bubbling = new_error_bubbling
         | 
| 747 782 | 
             
                    else
         | 
| 748 783 | 
             
                      @error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
         | 
| @@ -814,9 +849,40 @@ module GraphQL | |
| 814 849 | 
             
                    end
         | 
| 815 850 | 
             
                  end
         | 
| 816 851 |  | 
| 852 | 
            +
                  # @param new_extra_types [Module] Type definitions to include in printing and introspection, even though they aren't referenced in the schema
         | 
| 853 | 
            +
                  # @return [Array<Module>] Type definitions added to this schema
         | 
| 854 | 
            +
                  def extra_types(*new_extra_types)
         | 
| 855 | 
            +
                    if new_extra_types.any?
         | 
| 856 | 
            +
                      new_extra_types = new_extra_types.flatten
         | 
| 857 | 
            +
                      @own_extra_types ||= []
         | 
| 858 | 
            +
                      @own_extra_types.concat(new_extra_types)
         | 
| 859 | 
            +
                    end
         | 
| 860 | 
            +
                    inherited_et = find_inherited_value(:extra_types, nil)
         | 
| 861 | 
            +
                    if inherited_et
         | 
| 862 | 
            +
                      if @own_extra_types
         | 
| 863 | 
            +
                        inherited_et + @own_extra_types
         | 
| 864 | 
            +
                      else
         | 
| 865 | 
            +
                        inherited_et
         | 
| 866 | 
            +
                      end
         | 
| 867 | 
            +
                    else
         | 
| 868 | 
            +
                      @own_extra_types || EMPTY_ARRAY
         | 
| 869 | 
            +
                    end
         | 
| 870 | 
            +
                  end
         | 
| 871 | 
            +
             | 
| 817 872 | 
             
                  def orphan_types(*new_orphan_types)
         | 
| 818 873 | 
             
                    if new_orphan_types.any?
         | 
| 819 874 | 
             
                      new_orphan_types = new_orphan_types.flatten
         | 
| 875 | 
            +
                      non_object_types = new_orphan_types.reject { |ot| ot.is_a?(Class) && ot < GraphQL::Schema::Object }
         | 
| 876 | 
            +
                      if non_object_types.any?
         | 
| 877 | 
            +
                        raise ArgumentError, <<~ERR
         | 
| 878 | 
            +
                          Only object type classes should be added as `orphan_types(...)`.
         | 
| 879 | 
            +
             | 
| 880 | 
            +
                          - Remove these no-op types from `orphan_types`: #{non_object_types.map { |t| "#{t.inspect} (#{t.kind.name})"}.join(", ")}
         | 
| 881 | 
            +
                          - See https://graphql-ruby.org/type_definitions/interfaces.html#orphan-types
         | 
| 882 | 
            +
             | 
| 883 | 
            +
                          To add other types to your schema, you might want `extra_types`: https://graphql-ruby.org/schema/definition.html#extra-types
         | 
| 884 | 
            +
                        ERR
         | 
| 885 | 
            +
                      end
         | 
| 820 886 | 
             
                      add_type_and_traverse(new_orphan_types, root: false)
         | 
| 821 887 | 
             
                      own_orphan_types.concat(new_orphan_types.flatten)
         | 
| 822 888 | 
             
                    end
         | 
| @@ -1044,6 +1110,12 @@ module GraphQL | |
| 1044 1110 | 
             
                  end
         | 
| 1045 1111 |  | 
| 1046 1112 | 
             
                  def instrument(instrument_step, instrumenter, options = {})
         | 
| 1113 | 
            +
                    warn <<~WARN
         | 
| 1114 | 
            +
                    Schema.instrument is deprecated, use `trace_with` instead: https://graphql-ruby.org/queries/tracing.html"
         | 
| 1115 | 
            +
                      (From `#{self}.instrument(#{instrument_step}, #{instrumenter})` at #{caller(1, 1).first})
         | 
| 1116 | 
            +
             | 
| 1117 | 
            +
                    WARN
         | 
| 1118 | 
            +
                    trace_with(Tracing::LegacyHooksTrace)
         | 
| 1047 1119 | 
             
                    own_instrumenters[instrument_step] << instrumenter
         | 
| 1048 1120 | 
             
                  end
         | 
| 1049 1121 |  | 
| @@ -1079,8 +1151,12 @@ module GraphQL | |
| 1079 1151 | 
             
                    }.freeze
         | 
| 1080 1152 | 
             
                  end
         | 
| 1081 1153 |  | 
| 1082 | 
            -
                  def tracer(new_tracer)
         | 
| 1083 | 
            -
                     | 
| 1154 | 
            +
                  def tracer(new_tracer, silence_deprecation_warning: false)
         | 
| 1155 | 
            +
                    if !silence_deprecation_warning
         | 
| 1156 | 
            +
                      warn("`Schema.tracer(#{new_tracer.inspect})` is deprecated; use module-based `trace_with` instead. See: https://graphql-ruby.org/queries/tracing.html")
         | 
| 1157 | 
            +
                      warn "  #{caller(1, 1).first}"
         | 
| 1158 | 
            +
                    end
         | 
| 1159 | 
            +
                    default_trace = trace_class_for(:default, build: true)
         | 
| 1084 1160 | 
             
                    if default_trace.nil? || !(default_trace < GraphQL::Tracing::CallLegacyTracers)
         | 
| 1085 1161 | 
             
                      trace_with(GraphQL::Tracing::CallLegacyTracers)
         | 
| 1086 1162 | 
             
                    end
         | 
| @@ -1106,20 +1182,23 @@ module GraphQL | |
| 1106 1182 | 
             
                      tc = own_trace_modes[mode] ||= build_trace_mode(mode)
         | 
| 1107 1183 | 
             
                      tc.include(trace_mod)
         | 
| 1108 1184 | 
             
                      own_trace_modules[mode] << trace_mod
         | 
| 1109 | 
            -
             | 
| 1185 | 
            +
                      add_trace_options_for(mode, options)
         | 
| 1110 1186 | 
             
                      if mode == :default
         | 
| 1111 1187 | 
             
                        # This module is being added as a default tracer. If any other mode classes
         | 
| 1112 1188 | 
             
                        # have already been created, but get their default behavior from a superclass,
         | 
| 1113 1189 | 
             
                        # Then mix this into this schema's subclass.
         | 
| 1114 1190 | 
             
                        # (But don't mix it into mode classes that aren't default-based.)
         | 
| 1115 1191 | 
             
                        own_trace_modes.each do |other_mode_name, other_mode_class|
         | 
| 1116 | 
            -
                          if other_mode_class < DefaultTraceClass | 
| 1117 | 
            -
                             | 
| 1192 | 
            +
                          if other_mode_class < DefaultTraceClass
         | 
| 1193 | 
            +
                            # Don't add it back to the inheritance tree if it's already there
         | 
| 1194 | 
            +
                            if !(other_mode_class < trace_mod)
         | 
| 1195 | 
            +
                              other_mode_class.include(trace_mod)
         | 
| 1196 | 
            +
                            end
         | 
| 1197 | 
            +
                            # Add any options so they'll be available
         | 
| 1198 | 
            +
                            add_trace_options_for(other_mode_name, options)
         | 
| 1118 1199 | 
             
                          end
         | 
| 1119 1200 | 
             
                        end
         | 
| 1120 1201 | 
             
                      end
         | 
| 1121 | 
            -
                      t_opts = trace_options_for(mode)
         | 
| 1122 | 
            -
                      t_opts.merge!(options)
         | 
| 1123 1202 | 
             
                    end
         | 
| 1124 1203 | 
             
                    nil
         | 
| 1125 1204 | 
             
                  end
         | 
| @@ -1129,10 +1208,14 @@ module GraphQL | |
| 1129 1208 | 
             
                  def trace_options_for(mode)
         | 
| 1130 1209 | 
             
                    @trace_options_for_mode ||= {}
         | 
| 1131 1210 | 
             
                    @trace_options_for_mode[mode] ||= begin
         | 
| 1211 | 
            +
                      # It may be time to create an options hash for a mode that wasn't registered yet.
         | 
| 1212 | 
            +
                      # Mix in the default options in that case.
         | 
| 1213 | 
            +
                      default_options = mode == :default ? EMPTY_HASH : trace_options_for(:default)
         | 
| 1214 | 
            +
                      # Make sure this returns a new object so that other hashes aren't modified later
         | 
| 1132 1215 | 
             
                      if superclass.respond_to?(:trace_options_for)
         | 
| 1133 | 
            -
                        superclass.trace_options_for(mode). | 
| 1216 | 
            +
                        superclass.trace_options_for(mode).merge(default_options)
         | 
| 1134 1217 | 
             
                      else
         | 
| 1135 | 
            -
                         | 
| 1218 | 
            +
                        default_options.dup
         | 
| 1136 1219 | 
             
                      end
         | 
| 1137 1220 | 
             
                    end
         | 
| 1138 1221 | 
             
                  end
         | 
| @@ -1155,15 +1238,17 @@ module GraphQL | |
| 1155 1238 | 
             
                        raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
         | 
| 1156 1239 | 
             
                      else
         | 
| 1157 1240 | 
             
                        own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
         | 
| 1241 | 
            +
                        options_trace_mode = :default
         | 
| 1158 1242 | 
             
                        :default_backtrace
         | 
| 1159 1243 | 
             
                      end
         | 
| 1160 1244 | 
             
                    else
         | 
| 1161 1245 | 
             
                      default_trace_mode
         | 
| 1162 1246 | 
             
                    end
         | 
| 1163 1247 |  | 
| 1164 | 
            -
                     | 
| 1248 | 
            +
                    options_trace_mode ||= trace_mode
         | 
| 1249 | 
            +
                    base_trace_options = trace_options_for(options_trace_mode)
         | 
| 1165 1250 | 
             
                    trace_options = base_trace_options.merge(options)
         | 
| 1166 | 
            -
                    trace_class_for_mode = trace_class_for(trace_mode | 
| 1251 | 
            +
                    trace_class_for_mode = trace_class_for(trace_mode, build: true)
         | 
| 1167 1252 | 
             
                    trace_class_for_mode.new(**trace_options)
         | 
| 1168 1253 | 
             
                  end
         | 
| 1169 1254 |  | 
| @@ -1317,6 +1402,12 @@ module GraphQL | |
| 1317 1402 |  | 
| 1318 1403 | 
             
                  private
         | 
| 1319 1404 |  | 
| 1405 | 
            +
                  def add_trace_options_for(mode, new_options)
         | 
| 1406 | 
            +
                    t_opts = trace_options_for(mode)
         | 
| 1407 | 
            +
                    t_opts.merge!(new_options)
         | 
| 1408 | 
            +
                    nil
         | 
| 1409 | 
            +
                  end
         | 
| 1410 | 
            +
             | 
| 1320 1411 | 
             
                  # @param t [Module, Array<Module>]
         | 
| 1321 1412 | 
             
                  # @return [void]
         | 
| 1322 1413 | 
             
                  def add_type_and_traverse(t, root:)
         | 
| @@ -1378,7 +1469,7 @@ module GraphQL | |
| 1378 1469 | 
             
                      else
         | 
| 1379 1470 | 
             
                        @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
         | 
| 1380 1471 | 
             
                        @lazy_methods.set(GraphQL::Execution::Lazy, :value)
         | 
| 1381 | 
            -
                        @lazy_methods.set(GraphQL::Dataloader::Request, : | 
| 1472 | 
            +
                        @lazy_methods.set(GraphQL::Dataloader::Request, :load_with_deprecation_warning)
         | 
| 1382 1473 | 
             
                      end
         | 
| 1383 1474 | 
             
                    end
         | 
| 1384 1475 | 
             
                    @lazy_methods
         | 
| @@ -110,7 +110,7 @@ module GraphQL | |
| 110 110 | 
             
                    # TODO - would be nice to use these to create an error message so the caller knows
         | 
| 111 111 | 
             
                    # that required fields are missing
         | 
| 112 112 | 
             
                    required_field_names = @warden.arguments(type)
         | 
| 113 | 
            -
                      .select { |argument| argument.type.kind.non_null? &&  | 
| 113 | 
            +
                      .select { |argument| argument.type.kind.non_null? && !argument.default_value? }
         | 
| 114 114 | 
             
                      .map!(&:name)
         | 
| 115 115 |  | 
| 116 116 | 
             
                    present_field_names = ast_node.arguments.map(&:name)
         | 
| @@ -122,7 +122,6 @@ module GraphQL | |
| 122 122 | 
             
                        arg_type = @warden.get_argument(type, name).type
         | 
| 123 123 | 
             
                        recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
         | 
| 124 124 | 
             
                      end
         | 
| 125 | 
            -
             | 
| 126 125 | 
             
                      if type.one_of? && ast_node.arguments.size != 1
         | 
| 127 126 | 
             
                        results << Query::InputValidationResult.from_problem("`#{type.graphql_name}` is a OneOf type, so only one argument may be given (instead of #{ast_node.arguments.size})")
         | 
| 128 127 | 
             
                      end
         | 
| @@ -35,7 +35,7 @@ module GraphQL | |
| 35 35 | 
             
                    return unless parent_type && parent_type.kind.input_object?
         | 
| 36 36 |  | 
| 37 37 | 
             
                    required_fields = context.warden.arguments(parent_type)
         | 
| 38 | 
            -
                      .select{|arg| arg.type.kind.non_null?}
         | 
| 38 | 
            +
                      .select{ |arg| arg.type.kind.non_null? && !arg.default_value? }
         | 
| 39 39 | 
             
                      .map!(&:graphql_name)
         | 
| 40 40 |  | 
| 41 41 | 
             
                    present_fields = ast_node.arguments.map(&:name)
         | 
| @@ -28,6 +28,7 @@ module GraphQL | |
| 28 28 | 
             
                  # @return [Array<Hash>]
         | 
| 29 29 | 
             
                  def validate(query, validate: true, timeout: nil, max_errors: nil)
         | 
| 30 30 | 
             
                    query.current_trace.validate(validate: validate, query: query) do
         | 
| 31 | 
            +
                      begin_t = Time.now
         | 
| 31 32 | 
             
                      errors = if validate == false
         | 
| 32 33 | 
             
                        []
         | 
| 33 34 | 
             
                      else
         | 
| @@ -52,11 +53,13 @@ module GraphQL | |
| 52 53 | 
             
                      end
         | 
| 53 54 |  | 
| 54 55 | 
             
                      {
         | 
| 56 | 
            +
                        remaining_timeout: timeout ? (timeout - (Time.now - begin_t)) : nil,
         | 
| 55 57 | 
             
                        errors: errors,
         | 
| 56 58 | 
             
                      }
         | 
| 57 59 | 
             
                    end
         | 
| 58 60 | 
             
                  rescue GraphQL::ExecutionError => e
         | 
| 59 61 | 
             
                    {
         | 
| 62 | 
            +
                      remaining_timeout: nil,
         | 
| 60 63 | 
             
                      errors: [e],
         | 
| 61 64 | 
             
                    }
         | 
| 62 65 | 
             
                  end
         | 
| @@ -148,6 +148,8 @@ module GraphQL | |
| 148 148 | 
             
                        { TIMESTAMP_KEY => [obj.class.name, obj.strftime(TIMESTAMP_FORMAT)] }
         | 
| 149 149 | 
             
                      elsif obj.is_a?(OpenStruct)
         | 
| 150 150 | 
             
                        { OPEN_STRUCT_KEY => dump_value(obj.to_h) }
         | 
| 151 | 
            +
                      elsif defined?(ActiveRecord::Relation) && obj.is_a?(ActiveRecord::Relation)
         | 
| 152 | 
            +
                        dump_value(obj.to_a)
         | 
| 151 153 | 
             
                      else
         | 
| 152 154 | 
             
                        obj
         | 
| 153 155 | 
             
                      end
         | 
| @@ -2,7 +2,6 @@ | |
| 2 2 | 
             
            require "securerandom"
         | 
| 3 3 | 
             
            require "graphql/subscriptions/broadcast_analyzer"
         | 
| 4 4 | 
             
            require "graphql/subscriptions/event"
         | 
| 5 | 
            -
            require "graphql/subscriptions/instrumentation"
         | 
| 6 5 | 
             
            require "graphql/subscriptions/serialize"
         | 
| 7 6 | 
             
            require "graphql/subscriptions/action_cable_subscriptions"
         | 
| 8 7 | 
             
            require "graphql/subscriptions/default_subscription_resolve_extension"
         | 
| @@ -30,8 +29,6 @@ module GraphQL | |
| 30 29 | 
             
                    raise ArgumentError, "Can't reinstall subscriptions. #{schema} is using #{schema.subscriptions}, can't also add #{self}"
         | 
| 31 30 | 
             
                  end
         | 
| 32 31 |  | 
| 33 | 
            -
                  instrumentation = Subscriptions::Instrumentation.new(schema: schema)
         | 
| 34 | 
            -
                  defn.instrument(:query, instrumentation)
         | 
| 35 32 | 
             
                  options[:schema] = schema
         | 
| 36 33 | 
             
                  schema.subscriptions = self.new(**options)
         | 
| 37 34 | 
             
                  schema.add_subscription_extension_if_necessary
         | 
| @@ -5,10 +5,7 @@ module GraphQL | |
| 5 5 | 
             
                  # @param schema_class [Class<GraphQL::Schema>]
         | 
| 6 6 | 
             
                  # @return [Module] A helpers module which always uses the given schema
         | 
| 7 7 | 
             
                  def self.for(schema_class)
         | 
| 8 | 
            -
                     | 
| 9 | 
            -
                      include SchemaHelpers
         | 
| 10 | 
            -
                      @@schema_class_for_helpers = schema_class
         | 
| 11 | 
            -
                    end
         | 
| 8 | 
            +
                    SchemaHelpers.for(schema_class)
         | 
| 12 9 | 
             
                  end
         | 
| 13 10 |  | 
| 14 11 | 
             
                  class Error < GraphQL::Error
         | 
| @@ -42,9 +39,9 @@ module GraphQL | |
| 42 39 | 
             
                    end
         | 
| 43 40 | 
             
                  end
         | 
| 44 41 |  | 
| 45 | 
            -
                  def run_graphql_field(schema, field_path, object, arguments: {}, context: {})
         | 
| 42 | 
            +
                  def run_graphql_field(schema, field_path, object, arguments: {}, context: {}, ast_node: nil, lookahead: nil)
         | 
| 46 43 | 
             
                    type_name, *field_names = field_path.split(".")
         | 
| 47 | 
            -
                    dummy_query = GraphQL::Query.new(schema, context: context)
         | 
| 44 | 
            +
                    dummy_query = GraphQL::Query.new(schema, "{ __typename }", context: context)
         | 
| 48 45 | 
             
                    query_context = dummy_query.context
         | 
| 49 46 | 
             
                    object_type = dummy_query.get_type(type_name) # rubocop:disable Development/ContextIsPassedCop
         | 
| 50 47 | 
             
                    if object_type
         | 
| @@ -60,6 +57,28 @@ module GraphQL | |
| 60 57 | 
             
                          dummy_query.context.dataloader.run_isolated {
         | 
| 61 58 | 
             
                            field_args = visible_field.coerce_arguments(graphql_result, arguments, query_context)
         | 
| 62 59 | 
             
                            field_args = schema.sync_lazy(field_args)
         | 
| 60 | 
            +
                            if visible_field.extras.any?
         | 
| 61 | 
            +
                              extra_args = {}
         | 
| 62 | 
            +
                              visible_field.extras.each do |extra|
         | 
| 63 | 
            +
                                extra_args[extra] = case extra
         | 
| 64 | 
            +
                                when :ast_node
         | 
| 65 | 
            +
                                  ast_node ||= GraphQL::Language::Nodes::Field.new(name: visible_field.graphql_name)
         | 
| 66 | 
            +
                                when :lookahead
         | 
| 67 | 
            +
                                  lookahead ||= begin
         | 
| 68 | 
            +
                                    ast_node ||= GraphQL::Language::Nodes::Field.new(name: visible_field.graphql_name)
         | 
| 69 | 
            +
                                    Execution::Lookahead.new(
         | 
| 70 | 
            +
                                      query: dummy_query,
         | 
| 71 | 
            +
                                      ast_nodes: [ast_node],
         | 
| 72 | 
            +
                                      field: visible_field,
         | 
| 73 | 
            +
                                    )
         | 
| 74 | 
            +
                                  end
         | 
| 75 | 
            +
                                else
         | 
| 76 | 
            +
                                  raise ArgumentError, "This extra isn't supported in `run_graphql_field` yet: `#{extra.inspect}`. Open an issue on GitHub to request it: https://github.com/rmosolgo/graphql-ruby/issues/new"
         | 
| 77 | 
            +
                                end
         | 
| 78 | 
            +
                              end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                              field_args = field_args.merge_extras(extra_args)
         | 
| 81 | 
            +
                            end
         | 
| 63 82 | 
             
                            graphql_result = visible_field.resolve(graphql_result, field_args.keyword_arguments, query_context)
         | 
| 64 83 | 
             
                            graphql_result = schema.sync_lazy(graphql_result)
         | 
| 65 84 | 
             
                          }
         | 
| @@ -119,6 +138,13 @@ module GraphQL | |
| 119 138 | 
             
                      # schema will be added later
         | 
| 120 139 | 
             
                      super(nil, *args, **kwargs, &block)
         | 
| 121 140 | 
             
                    end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                    def self.for(schema_class)
         | 
| 143 | 
            +
                      Module.new do
         | 
| 144 | 
            +
                        include SchemaHelpers
         | 
| 145 | 
            +
                        @@schema_class_for_helpers = schema_class
         | 
| 146 | 
            +
                      end
         | 
| 147 | 
            +
                    end
         | 
| 122 148 | 
             
                  end
         | 
| 123 149 | 
             
                end
         | 
| 124 150 | 
             
              end
         |