graphql 2.0.0 → 2.0.3
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/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/dataloader/null_dataloader.rb +3 -1
- data/lib/graphql/execution/errors.rb +12 -74
- data/lib/graphql/execution/interpreter/runtime.rb +35 -38
- data/lib/graphql/query/context.rb +96 -9
- data/lib/graphql/query/input_validation_result.rb +10 -1
- data/lib/graphql/query/null_context.rb +0 -3
- data/lib/graphql/query.rb +2 -5
- data/lib/graphql/relay/range_add.rb +9 -16
- data/lib/graphql/schema/addition.rb +5 -0
- data/lib/graphql/schema/argument.rb +13 -4
- data/lib/graphql/schema/enum.rb +3 -5
- data/lib/graphql/schema/field.rb +164 -130
- data/lib/graphql/schema/input_object.rb +12 -12
- data/lib/graphql/schema/list.rb +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +36 -6
- data/lib/graphql/schema/member/has_directives.rb +1 -1
- data/lib/graphql/schema/member/has_interfaces.rb +1 -1
- data/lib/graphql/schema/member/relay_shortcuts.rb +28 -2
- data/lib/graphql/schema/member/validates_input.rb +2 -2
- data/lib/graphql/schema/object.rb +14 -9
- data/lib/graphql/schema/relay_classic_mutation.rb +32 -14
- data/lib/graphql/schema/resolver/has_payload_type.rb +11 -1
- data/lib/graphql/schema/resolver.rb +23 -45
- data/lib/graphql/schema/scalar.rb +7 -7
- data/lib/graphql/schema/subscription.rb +0 -7
- data/lib/graphql/schema/warden.rb +1 -1
- data/lib/graphql/schema.rb +35 -6
- data/lib/graphql/subscriptions.rb +10 -3
- data/lib/graphql/tracing/data_dog_tracing.rb +3 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +0 -16
- data/lib/graphql/version.rb +1 -1
- metadata +6 -7
- data/lib/graphql/query/literal_input.rb +0 -131
| @@ -8,7 +8,15 @@ module GraphQL | |
| 8 8 | 
             
                      if new_edge_type_class
         | 
| 9 9 | 
             
                        @edge_type_class = new_edge_type_class
         | 
| 10 10 | 
             
                      else
         | 
| 11 | 
            -
                         | 
| 11 | 
            +
                        # Don't call `ancestor.edge_type_class`
         | 
| 12 | 
            +
                        # because we don't want a fallback from any ancestors --
         | 
| 13 | 
            +
                        # only apply the fallback if _no_ ancestor has a configured value!
         | 
| 14 | 
            +
                        for ancestor in self.ancestors
         | 
| 15 | 
            +
                          if ancestor.respond_to?(:configured_edge_type_class, true) && (etc = ancestor.configured_edge_type_class)
         | 
| 16 | 
            +
                            return etc
         | 
| 17 | 
            +
                          end
         | 
| 18 | 
            +
                        end
         | 
| 19 | 
            +
                        Types::Relay::BaseEdge
         | 
| 12 20 | 
             
                      end
         | 
| 13 21 | 
             
                    end
         | 
| 14 22 |  | 
| @@ -16,7 +24,15 @@ module GraphQL | |
| 16 24 | 
             
                      if new_connection_type_class
         | 
| 17 25 | 
             
                        @connection_type_class = new_connection_type_class
         | 
| 18 26 | 
             
                      else
         | 
| 19 | 
            -
                         | 
| 27 | 
            +
                        # Don't call `ancestor.connection_type_class`
         | 
| 28 | 
            +
                        # because we don't want a fallback from any ancestors --
         | 
| 29 | 
            +
                        # only apply the fallback if _no_ ancestor has a configured value!
         | 
| 30 | 
            +
                        for ancestor in self.ancestors
         | 
| 31 | 
            +
                          if ancestor.respond_to?(:configured_connection_type_class, true) && (ctc = ancestor.configured_connection_type_class)
         | 
| 32 | 
            +
                            return ctc
         | 
| 33 | 
            +
                          end
         | 
| 34 | 
            +
                        end
         | 
| 35 | 
            +
                        Types::Relay::BaseConnection
         | 
| 20 36 | 
             
                      end
         | 
| 21 37 | 
             
                    end
         | 
| 22 38 |  | 
| @@ -41,6 +57,16 @@ module GraphQL | |
| 41 57 | 
             
                        end
         | 
| 42 58 | 
             
                      end
         | 
| 43 59 | 
             
                    end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    protected
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    def configured_connection_type_class
         | 
| 64 | 
            +
                      @connection_type_class
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                    def configured_edge_type_class
         | 
| 68 | 
            +
                      @edge_type_class
         | 
| 69 | 
            +
                    end
         | 
| 44 70 | 
             
                  end
         | 
| 45 71 | 
             
                end
         | 
| 46 72 | 
             
              end
         | 
| @@ -10,9 +10,9 @@ module GraphQL | |
| 10 10 |  | 
| 11 11 | 
             
                    def validate_input(val, ctx)
         | 
| 12 12 | 
             
                      if val.nil?
         | 
| 13 | 
            -
                         | 
| 13 | 
            +
                        Query::InputValidationResult::VALID
         | 
| 14 14 | 
             
                      else
         | 
| 15 | 
            -
                        validate_non_null_input(val, ctx)
         | 
| 15 | 
            +
                        validate_non_null_input(val, ctx) || Query::InputValidationResult::VALID
         | 
| 16 16 | 
             
                      end
         | 
| 17 17 | 
             
                    end
         | 
| 18 18 |  | 
| @@ -51,12 +51,12 @@ module GraphQL | |
| 51 51 | 
             
                      trace_payload = { context: context, type: self, object: object, path: context[:current_path] }
         | 
| 52 52 |  | 
| 53 53 | 
             
                      maybe_lazy_auth_val = context.query.trace("authorized", trace_payload) do
         | 
| 54 | 
            -
                         | 
| 55 | 
            -
                           | 
| 56 | 
            -
             | 
| 57 | 
            -
                           | 
| 58 | 
            -
             | 
| 59 | 
            -
                           | 
| 54 | 
            +
                        begin
         | 
| 55 | 
            +
                          authorized?(object, context)
         | 
| 56 | 
            +
                        rescue GraphQL::UnauthorizedError => err
         | 
| 57 | 
            +
                          context.schema.unauthorized_object(err)
         | 
| 58 | 
            +
                        rescue StandardError => err
         | 
| 59 | 
            +
                          context.query.handle_or_reraise(err)
         | 
| 60 60 | 
             
                        end
         | 
| 61 61 | 
             
                      end
         | 
| 62 62 |  | 
| @@ -98,9 +98,14 @@ module GraphQL | |
| 98 98 | 
             
                  class << self
         | 
| 99 99 | 
             
                    # Set up a type-specific invalid null error to use when this object's non-null fields wrongly return `nil`.
         | 
| 100 100 | 
             
                    # It should help with debugging and bug tracker integrations.
         | 
| 101 | 
            -
                    def  | 
| 102 | 
            -
                       | 
| 103 | 
            -
             | 
| 101 | 
            +
                    def const_missing(name)
         | 
| 102 | 
            +
                      if name == :InvalidNullError
         | 
| 103 | 
            +
                        custom_err_class = GraphQL::InvalidNullError.subclass_for(self)
         | 
| 104 | 
            +
                        const_set(:InvalidNullError, custom_err_class)
         | 
| 105 | 
            +
                        custom_err_class
         | 
| 106 | 
            +
                      else
         | 
| 107 | 
            +
                        super
         | 
| 108 | 
            +
                      end
         | 
| 104 109 | 
             
                    end
         | 
| 105 110 |  | 
| 106 111 | 
             
                    def kind
         | 
| @@ -70,11 +70,32 @@ module GraphQL | |
| 70 70 | 
             
                  end
         | 
| 71 71 |  | 
| 72 72 | 
             
                  class << self
         | 
| 73 | 
            +
                    def dummy
         | 
| 74 | 
            +
                      @dummy ||= begin
         | 
| 75 | 
            +
                        d = Class.new(GraphQL::Schema::Resolver)
         | 
| 76 | 
            +
                        d.argument_class(self.argument_class)
         | 
| 77 | 
            +
                        # TODO make this lazier?
         | 
| 78 | 
            +
                        d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
         | 
| 79 | 
            +
                        d
         | 
| 80 | 
            +
                      end
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    def field_arguments(context = GraphQL::Query::NullContext)
         | 
| 84 | 
            +
                      dummy.arguments(context)
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    def get_field_argument(name, context = GraphQL::Query::NullContext)
         | 
| 88 | 
            +
                      dummy.get_argument(name, context)
         | 
| 89 | 
            +
                    end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                    def own_field_arguments
         | 
| 92 | 
            +
                      dummy.own_arguments
         | 
| 93 | 
            +
                    end
         | 
| 73 94 |  | 
| 74 95 | 
             
                    # Also apply this argument to the input type:
         | 
| 75 | 
            -
                    def argument(*args, **kwargs, &block)
         | 
| 96 | 
            +
                    def argument(*args, own_argument: false, **kwargs, &block)
         | 
| 76 97 | 
             
                      it = input_type # make sure any inherited arguments are already added to it
         | 
| 77 | 
            -
                      arg = super
         | 
| 98 | 
            +
                      arg = super(*args, **kwargs, &block)
         | 
| 78 99 |  | 
| 79 100 | 
             
                      # This definition might be overriding something inherited;
         | 
| 80 101 | 
             
                      # if it is, remove the inherited definition so it's not confused at runtime as having multiple definitions
         | 
| @@ -114,15 +135,6 @@ module GraphQL | |
| 114 135 | 
             
                      @input_type ||= generate_input_type
         | 
| 115 136 | 
             
                    end
         | 
| 116 137 |  | 
| 117 | 
            -
                    # Extend {Schema::Mutation.field_options} to add the `input` argument
         | 
| 118 | 
            -
                    def field_options
         | 
| 119 | 
            -
                      sig = super
         | 
| 120 | 
            -
                      # Arguments were added at the root, but they should be nested
         | 
| 121 | 
            -
                      sig[:arguments].clear
         | 
| 122 | 
            -
                      sig[:arguments][:input] = { type: input_type, required: true, description: "Parameters for #{graphql_name}" }
         | 
| 123 | 
            -
                      sig
         | 
| 124 | 
            -
                    end
         | 
| 125 | 
            -
             | 
| 126 138 | 
             
                    private
         | 
| 127 139 |  | 
| 128 140 | 
             
                    # Generate the input type for the `input:` argument
         | 
| @@ -130,11 +142,17 @@ module GraphQL | |
| 130 142 | 
             
                    # @return [Class] a subclass of {.input_object_class}
         | 
| 131 143 | 
             
                    def generate_input_type
         | 
| 132 144 | 
             
                      mutation_args = all_argument_definitions
         | 
| 133 | 
            -
                      mutation_name = graphql_name
         | 
| 134 145 | 
             
                      mutation_class = self
         | 
| 135 146 | 
             
                      Class.new(input_object_class) do
         | 
| 136 | 
            -
                         | 
| 137 | 
            -
             | 
| 147 | 
            +
                        class << self
         | 
| 148 | 
            +
                          def default_graphql_name
         | 
| 149 | 
            +
                            "#{self.mutation.graphql_name}Input"
         | 
| 150 | 
            +
                          end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                          def description(new_desc = nil)
         | 
| 153 | 
            +
                            super || "Autogenerated input type of #{self.mutation.graphql_name}"
         | 
| 154 | 
            +
                          end
         | 
| 155 | 
            +
                        end
         | 
| 138 156 | 
             
                        mutation(mutation_class)
         | 
| 139 157 | 
             
                        # these might be inherited:
         | 
| 140 158 | 
             
                        mutation_args.each do |arg|
         | 
| @@ -20,7 +20,17 @@ module GraphQL | |
| 20 20 | 
             
                      @payload_type ||= generate_payload_type
         | 
| 21 21 | 
             
                    end
         | 
| 22 22 |  | 
| 23 | 
            -
                     | 
| 23 | 
            +
                    def type(new_type = nil, null: nil)
         | 
| 24 | 
            +
                      if new_type
         | 
| 25 | 
            +
                        payload_type(new_type)
         | 
| 26 | 
            +
                        if !null.nil?
         | 
| 27 | 
            +
                          self.null(null)
         | 
| 28 | 
            +
                        end
         | 
| 29 | 
            +
                      else
         | 
| 30 | 
            +
                        super()
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
             | 
| 24 34 | 
             
                    alias :type_expr :payload_type
         | 
| 25 35 |  | 
| 26 36 | 
             
                    def field_class(new_class = nil)
         | 
| @@ -15,8 +15,6 @@ module GraphQL | |
| 15 15 | 
             
                #
         | 
| 16 16 | 
             
                # A resolver's configuration may be overridden with other keywords in the `field(...)` call.
         | 
| 17 17 | 
             
                #
         | 
| 18 | 
            -
                # See the {.field_options} to see how a Resolver becomes a set of field configuration options.
         | 
| 19 | 
            -
                #
         | 
| 20 18 | 
             
                # @see {GraphQL::Schema::Mutation} for a concrete subclass of `Resolver`.
         | 
| 21 19 | 
             
                # @see {GraphQL::Function} `Resolver` is a replacement for `GraphQL::Function`
         | 
| 22 20 | 
             
                class Resolver
         | 
| @@ -210,6 +208,18 @@ module GraphQL | |
| 210 208 | 
             
                  end
         | 
| 211 209 |  | 
| 212 210 | 
             
                  class << self
         | 
| 211 | 
            +
                    def field_arguments(context = GraphQL::Query::NullContext)
         | 
| 212 | 
            +
                      arguments(context)
         | 
| 213 | 
            +
                    end
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                    def get_field_argument(name, context = GraphQL::Query::NullContext)
         | 
| 216 | 
            +
                      get_argument(name, context)
         | 
| 217 | 
            +
                    end
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                    def own_field_arguments
         | 
| 220 | 
            +
                      own_arguments
         | 
| 221 | 
            +
                    end
         | 
| 222 | 
            +
             | 
| 213 223 | 
             
                    # Default `:resolve` set below.
         | 
| 214 224 | 
             
                    # @return [Symbol] The method to call on instances of this object to resolve the field
         | 
| 215 225 | 
             
                    def resolve_method(new_method = nil)
         | 
| @@ -242,6 +252,14 @@ module GraphQL | |
| 242 252 | 
             
                      @null.nil? ? (superclass.respond_to?(:null) ? superclass.null : true) : @null
         | 
| 243 253 | 
             
                    end
         | 
| 244 254 |  | 
| 255 | 
            +
                    def resolver_method(new_method_name = nil)
         | 
| 256 | 
            +
                      if new_method_name
         | 
| 257 | 
            +
                        @resolver_method = new_method_name
         | 
| 258 | 
            +
                      else
         | 
| 259 | 
            +
                        @resolver_method || :resolve_with_support
         | 
| 260 | 
            +
                      end
         | 
| 261 | 
            +
                    end
         | 
| 262 | 
            +
             | 
| 245 263 | 
             
                    # Call this method to get the return type of the field,
         | 
| 246 264 | 
             
                    # or use it as a configuration method to assign a return type
         | 
| 247 265 | 
             
                    # instead of generating one.
         | 
| @@ -257,8 +275,8 @@ module GraphQL | |
| 257 275 | 
             
                        @type_expr = new_type
         | 
| 258 276 | 
             
                        @null = null
         | 
| 259 277 | 
             
                      else
         | 
| 260 | 
            -
                        if  | 
| 261 | 
            -
                          GraphQL::Schema::Member::BuildType.parse_type( | 
| 278 | 
            +
                        if type_expr
         | 
| 279 | 
            +
                          GraphQL::Schema::Member::BuildType.parse_type(type_expr, null: self.null)
         | 
| 262 280 | 
             
                        elsif superclass.respond_to?(:type)
         | 
| 263 281 | 
             
                          superclass.type
         | 
| 264 282 | 
             
                        else
         | 
| @@ -307,47 +325,7 @@ module GraphQL | |
| 307 325 |  | 
| 308 326 | 
             
                    # @return [Boolean] `true` if this resolver or a superclass has an assigned `max_page_size`
         | 
| 309 327 | 
             
                    def has_max_page_size?
         | 
| 310 | 
            -
                      defined?(@max_page_size) || (superclass.respond_to?(:has_max_page_size?) && superclass.has_max_page_size?)
         | 
| 311 | 
            -
                    end
         | 
| 312 | 
            -
             | 
| 313 | 
            -
                    def field_options
         | 
| 314 | 
            -
             | 
| 315 | 
            -
                      all_args = {}
         | 
| 316 | 
            -
                      all_argument_definitions.each do |arg|
         | 
| 317 | 
            -
                        if (prev_entry = all_args[arg.graphql_name])
         | 
| 318 | 
            -
                          if prev_entry.is_a?(Array)
         | 
| 319 | 
            -
                            prev_entry << arg
         | 
| 320 | 
            -
                          else
         | 
| 321 | 
            -
                            all_args[arg.graphql_name] = [prev_entry, arg]
         | 
| 322 | 
            -
                          end
         | 
| 323 | 
            -
                        else
         | 
| 324 | 
            -
                          all_args[arg.graphql_name] = arg
         | 
| 325 | 
            -
                        end
         | 
| 326 | 
            -
                      end
         | 
| 327 | 
            -
             | 
| 328 | 
            -
                      field_opts = {
         | 
| 329 | 
            -
                        type: type_expr,
         | 
| 330 | 
            -
                        description: description,
         | 
| 331 | 
            -
                        extras: extras,
         | 
| 332 | 
            -
                        resolver_method: :resolve_with_support,
         | 
| 333 | 
            -
                        resolver_class: self,
         | 
| 334 | 
            -
                        arguments: all_args,
         | 
| 335 | 
            -
                        null: null,
         | 
| 336 | 
            -
                        complexity: complexity,
         | 
| 337 | 
            -
                        broadcastable: broadcastable?,
         | 
| 338 | 
            -
                      }
         | 
| 339 | 
            -
             | 
| 340 | 
            -
                      # If there aren't any, then the returned array is `[].freeze`,
         | 
| 341 | 
            -
                      # but passing that along breaks some user code.
         | 
| 342 | 
            -
                      if (exts = extensions).any?
         | 
| 343 | 
            -
                        field_opts[:extensions] = exts
         | 
| 344 | 
            -
                      end
         | 
| 345 | 
            -
             | 
| 346 | 
            -
                      if has_max_page_size?
         | 
| 347 | 
            -
                        field_opts[:max_page_size] = max_page_size
         | 
| 348 | 
            -
                      end
         | 
| 349 | 
            -
             | 
| 350 | 
            -
                      field_opts
         | 
| 328 | 
            +
                      (!!defined?(@max_page_size)) || (superclass.respond_to?(:has_max_page_size?) && superclass.has_max_page_size?)
         | 
| 351 329 | 
             
                    end
         | 
| 352 330 |  | 
| 353 331 | 
             
                    # A non-normalized type configuration, without `null` applied
         | 
| @@ -41,13 +41,12 @@ module GraphQL | |
| 41 41 | 
             
                    end
         | 
| 42 42 |  | 
| 43 43 | 
             
                    def validate_non_null_input(value, ctx)
         | 
| 44 | 
            -
                      result = Query::InputValidationResult.new
         | 
| 45 44 | 
             
                      coerced_result = begin
         | 
| 46 | 
            -
                        ctx | 
| 47 | 
            -
                          coerce_input(value, ctx)
         | 
| 48 | 
            -
                        end
         | 
| 45 | 
            +
                        coerce_input(value, ctx)
         | 
| 49 46 | 
             
                      rescue GraphQL::CoercionError => err
         | 
| 50 47 | 
             
                        err
         | 
| 48 | 
            +
                      rescue StandardError => err
         | 
| 49 | 
            +
                        ctx.query.handle_or_reraise(err)
         | 
| 51 50 | 
             
                      end
         | 
| 52 51 |  | 
| 53 52 | 
             
                      if coerced_result.nil?
         | 
| @@ -56,11 +55,12 @@ module GraphQL | |
| 56 55 | 
             
                        else
         | 
| 57 56 | 
             
                          " #{GraphQL::Language.serialize(value)}"
         | 
| 58 57 | 
             
                        end
         | 
| 59 | 
            -
                         | 
| 58 | 
            +
                        Query::InputValidationResult.from_problem("Could not coerce value#{str_value} to #{graphql_name}")
         | 
| 60 59 | 
             
                      elsif coerced_result.is_a?(GraphQL::CoercionError)
         | 
| 61 | 
            -
                         | 
| 60 | 
            +
                        Query::InputValidationResult.from_problem(coerced_result.message, message: coerced_result.message, extensions: coerced_result.extensions)
         | 
| 61 | 
            +
                      else
         | 
| 62 | 
            +
                        nil
         | 
| 62 63 | 
             
                      end
         | 
| 63 | 
            -
                      result
         | 
| 64 64 | 
             
                    end
         | 
| 65 65 | 
             
                  end
         | 
| 66 66 | 
             
                end
         | 
| @@ -143,13 +143,6 @@ module GraphQL | |
| 143 143 | 
             
                  def self.topic_for(arguments:, field:, scope:)
         | 
| 144 144 | 
             
                    Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])
         | 
| 145 145 | 
             
                  end
         | 
| 146 | 
            -
             | 
| 147 | 
            -
                  # Overriding Resolver#field_options to include subscription_scope
         | 
| 148 | 
            -
                  def self.field_options
         | 
| 149 | 
            -
                    super.merge(
         | 
| 150 | 
            -
                      subscription_scope: subscription_scope
         | 
| 151 | 
            -
                    )
         | 
| 152 | 
            -
                  end
         | 
| 153 146 | 
             
                end
         | 
| 154 147 | 
             
              end
         | 
| 155 148 | 
             
            end
         | 
| @@ -10,7 +10,7 @@ module GraphQL | |
| 10 10 | 
             
                # should go through a warden. If you access the schema directly,
         | 
| 11 11 | 
             
                # you may show a client something that it shouldn't be allowed to see.
         | 
| 12 12 | 
             
                #
         | 
| 13 | 
            -
                # @example  | 
| 13 | 
            +
                # @example Hiding private fields
         | 
| 14 14 | 
             
                #   private_members = -> (member, ctx) { member.metadata[:private] }
         | 
| 15 15 | 
             
                #   result = Schema.execute(query_string, except: private_members)
         | 
| 16 16 | 
             
                #
         | 
    
        data/lib/graphql/schema.rb
    CHANGED
    
    | @@ -693,7 +693,41 @@ module GraphQL | |
| 693 693 |  | 
| 694 694 | 
             
                  def rescue_from(*err_classes, &handler_block)
         | 
| 695 695 | 
             
                    err_classes.each do |err_class|
         | 
| 696 | 
            -
                       | 
| 696 | 
            +
                      Execution::Errors.register_rescue_from(err_class, error_handlers[:subclass_handlers], handler_block)
         | 
| 697 | 
            +
                    end
         | 
| 698 | 
            +
                  end
         | 
| 699 | 
            +
             | 
| 700 | 
            +
                  NEW_HANDLER_HASH = ->(h, k) {
         | 
| 701 | 
            +
                    h[k] = {
         | 
| 702 | 
            +
                      class: k,
         | 
| 703 | 
            +
                      handler: nil,
         | 
| 704 | 
            +
                      subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
         | 
| 705 | 
            +
                     }
         | 
| 706 | 
            +
                  }
         | 
| 707 | 
            +
             | 
| 708 | 
            +
                  def error_handlers
         | 
| 709 | 
            +
                    @error_handlers ||= {
         | 
| 710 | 
            +
                      class: nil,
         | 
| 711 | 
            +
                      handler: nil,
         | 
| 712 | 
            +
                      subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
         | 
| 713 | 
            +
                    }
         | 
| 714 | 
            +
                  end
         | 
| 715 | 
            +
             | 
| 716 | 
            +
                  # @api private
         | 
| 717 | 
            +
                  def handle_or_reraise(context, err)
         | 
| 718 | 
            +
                    handler = Execution::Errors.find_handler_for(self, err.class)
         | 
| 719 | 
            +
                    if handler
         | 
| 720 | 
            +
                      runtime_info = context.namespace(:interpreter) || {}
         | 
| 721 | 
            +
                      obj = runtime_info[:current_object]
         | 
| 722 | 
            +
                      args = runtime_info[:current_arguments]
         | 
| 723 | 
            +
                      args = args && args.keyword_arguments
         | 
| 724 | 
            +
                      field = runtime_info[:current_field]
         | 
| 725 | 
            +
                      if obj.is_a?(GraphQL::Schema::Object)
         | 
| 726 | 
            +
                        obj = obj.object
         | 
| 727 | 
            +
                      end
         | 
| 728 | 
            +
                      handler[:handler].call(err, obj, args, context, field)
         | 
| 729 | 
            +
                    else
         | 
| 730 | 
            +
                      raise err
         | 
| 697 731 | 
             
                    end
         | 
| 698 732 | 
             
                  end
         | 
| 699 733 |  | 
| @@ -821,11 +855,6 @@ module GraphQL | |
| 821 855 | 
             
                    ctx.errors.push(parse_err)
         | 
| 822 856 | 
             
                  end
         | 
| 823 857 |  | 
| 824 | 
            -
                  # @return [GraphQL::Execution::Errors]
         | 
| 825 | 
            -
                  def error_handler
         | 
| 826 | 
            -
                    @error_handler ||= GraphQL::Execution::Errors.new(self)
         | 
| 827 | 
            -
                  end
         | 
| 828 | 
            -
             | 
| 829 858 | 
             
                  def lazy_resolve(lazy_class, value_method)
         | 
| 830 859 | 
             
                    lazy_methods.set(lazy_class, value_method)
         | 
| 831 860 | 
             
                  end
         | 
| @@ -56,17 +56,24 @@ module GraphQL | |
| 56 56 | 
             
                # @param args [Hash<String, Symbol => Object]
         | 
| 57 57 | 
             
                # @param object [Object]
         | 
| 58 58 | 
             
                # @param scope [Symbol, String]
         | 
| 59 | 
            +
                # @param context [Hash]
         | 
| 59 60 | 
             
                # @return [void]
         | 
| 60 | 
            -
                def trigger(event_name, args, object, scope: nil)
         | 
| 61 | 
            +
                def trigger(event_name, args, object, scope: nil, context: {})
         | 
| 62 | 
            +
                  # Make something as context-like as possible, even though there isn't a current query:
         | 
| 63 | 
            +
                  context = @schema.context_class.new(
         | 
| 64 | 
            +
                    query: GraphQL::Query.new(@schema, "", validate: false),
         | 
| 65 | 
            +
                    object: nil,
         | 
| 66 | 
            +
                    values: context
         | 
| 67 | 
            +
                  )
         | 
| 61 68 | 
             
                  event_name = event_name.to_s
         | 
| 62 69 |  | 
| 63 70 | 
             
                  # Try with the verbatim input first:
         | 
| 64 | 
            -
                  field = @schema.get_field(@schema.subscription, event_name)
         | 
| 71 | 
            +
                  field = @schema.get_field(@schema.subscription, event_name, context)
         | 
| 65 72 |  | 
| 66 73 | 
             
                  if field.nil?
         | 
| 67 74 | 
             
                    # And if it wasn't found, normalize it:
         | 
| 68 75 | 
             
                    normalized_event_name = normalize_name(event_name)
         | 
| 69 | 
            -
                    field = @schema.get_field(@schema.subscription, normalized_event_name)
         | 
| 76 | 
            +
                    field = @schema.get_field(@schema.subscription, normalized_event_name, context)
         | 
| 70 77 | 
             
                    if field.nil?
         | 
| 71 78 | 
             
                      raise InvalidTriggerError, "No subscription matching trigger: #{event_name} (looked for #{@schema.subscription.graphql_name}.#{normalized_event_name})"
         | 
| 72 79 | 
             
                    end
         | 
| @@ -148,22 +148,6 @@ module GraphQL | |
| 148 148 | 
             
                        obj_type.field :page_info, GraphQL::Types::Relay::PageInfo, null: false, description: "Information to aid in pagination."
         | 
| 149 149 | 
             
                      end
         | 
| 150 150 | 
             
                    end
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                    # By default this calls through to the ConnectionWrapper's edge nodes method,
         | 
| 153 | 
            -
                    # but sometimes you need to override it to support the `nodes` field
         | 
| 154 | 
            -
                    def nodes
         | 
| 155 | 
            -
                      @object.edge_nodes
         | 
| 156 | 
            -
                    end
         | 
| 157 | 
            -
             | 
| 158 | 
            -
                    def edges
         | 
| 159 | 
            -
                      if @object.is_a?(GraphQL::Pagination::Connection)
         | 
| 160 | 
            -
                        @object.edges
         | 
| 161 | 
            -
                      else
         | 
| 162 | 
            -
                        context.schema.after_lazy(object.edge_nodes) do |nodes|
         | 
| 163 | 
            -
                          nodes.map { |n| self.class.edge_class.new(n, object) }
         | 
| 164 | 
            -
                        end
         | 
| 165 | 
            -
                      end
         | 
| 166 | 
            -
                    end
         | 
| 167 151 | 
             
                  end
         | 
| 168 152 | 
             
                end
         | 
| 169 153 | 
             
              end
         | 
    
        data/lib/graphql/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: graphql
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2.0. | 
| 4 | 
            +
              version: 2.0.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Robert Mosolgo
         | 
| 8 | 
            -
            autorequire: | 
| 8 | 
            +
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022- | 
| 11 | 
            +
            date: 2022-03-21 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: benchmark-ips
         | 
| @@ -366,7 +366,6 @@ files: | |
| 366 366 | 
             
            - lib/graphql/query/context.rb
         | 
| 367 367 | 
             
            - lib/graphql/query/fingerprint.rb
         | 
| 368 368 | 
             
            - lib/graphql/query/input_validation_result.rb
         | 
| 369 | 
            -
            - lib/graphql/query/literal_input.rb
         | 
| 370 369 | 
             
            - lib/graphql/query/null_context.rb
         | 
| 371 370 | 
             
            - lib/graphql/query/result.rb
         | 
| 372 371 | 
             
            - lib/graphql/query/validation_pipeline.rb
         | 
| @@ -582,7 +581,7 @@ metadata: | |
| 582 581 | 
             
              source_code_uri: https://github.com/rmosolgo/graphql-ruby
         | 
| 583 582 | 
             
              bug_tracker_uri: https://github.com/rmosolgo/graphql-ruby/issues
         | 
| 584 583 | 
             
              mailing_list_uri: https://tinyletter.com/graphql-ruby
         | 
| 585 | 
            -
            post_install_message: | 
| 584 | 
            +
            post_install_message:
         | 
| 586 585 | 
             
            rdoc_options: []
         | 
| 587 586 | 
             
            require_paths:
         | 
| 588 587 | 
             
            - lib
         | 
| @@ -597,8 +596,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 597 596 | 
             
                - !ruby/object:Gem::Version
         | 
| 598 597 | 
             
                  version: '0'
         | 
| 599 598 | 
             
            requirements: []
         | 
| 600 | 
            -
            rubygems_version: 3. | 
| 601 | 
            -
            signing_key: | 
| 599 | 
            +
            rubygems_version: 3.3.3
         | 
| 600 | 
            +
            signing_key:
         | 
| 602 601 | 
             
            specification_version: 4
         | 
| 603 602 | 
             
            summary: A GraphQL language and runtime for Ruby
         | 
| 604 603 | 
             
            test_files: []
         | 
| @@ -1,131 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
            module GraphQL
         | 
| 3 | 
            -
              class Query
         | 
| 4 | 
            -
                # Turn query string values into something useful for query execution
         | 
| 5 | 
            -
                class LiteralInput
         | 
| 6 | 
            -
                  def self.coerce(type, ast_node, variables)
         | 
| 7 | 
            -
                    case ast_node
         | 
| 8 | 
            -
                    when nil
         | 
| 9 | 
            -
                      nil
         | 
| 10 | 
            -
                    when Language::Nodes::NullValue
         | 
| 11 | 
            -
                      nil
         | 
| 12 | 
            -
                    when Language::Nodes::VariableIdentifier
         | 
| 13 | 
            -
                      variables[ast_node.name]
         | 
| 14 | 
            -
                    else
         | 
| 15 | 
            -
                      case type.kind.name
         | 
| 16 | 
            -
                      when "SCALAR"
         | 
| 17 | 
            -
                        # TODO smell
         | 
| 18 | 
            -
                        # This gets used for plain values during subscriber.trigger
         | 
| 19 | 
            -
                        if variables
         | 
| 20 | 
            -
                          type.coerce_input(ast_node, variables.context)
         | 
| 21 | 
            -
                        else
         | 
| 22 | 
            -
                          type.coerce_isolated_input(ast_node)
         | 
| 23 | 
            -
                        end
         | 
| 24 | 
            -
                      when "ENUM"
         | 
| 25 | 
            -
                        # TODO smell
         | 
| 26 | 
            -
                        # This gets used for plain values sometimes
         | 
| 27 | 
            -
                        v = ast_node.is_a?(GraphQL::Language::Nodes::Enum) ? ast_node.name : ast_node
         | 
| 28 | 
            -
                        if variables
         | 
| 29 | 
            -
                          type.coerce_input(v, variables.context)
         | 
| 30 | 
            -
                        else
         | 
| 31 | 
            -
                          type.coerce_isolated_input(v)
         | 
| 32 | 
            -
                        end
         | 
| 33 | 
            -
                      when "NON_NULL"
         | 
| 34 | 
            -
                        LiteralInput.coerce(type.of_type, ast_node, variables)
         | 
| 35 | 
            -
                      when "LIST"
         | 
| 36 | 
            -
                        if ast_node.is_a?(Array)
         | 
| 37 | 
            -
                          ast_node.map { |element_ast| LiteralInput.coerce(type.of_type, element_ast, variables) }
         | 
| 38 | 
            -
                        else
         | 
| 39 | 
            -
                          [LiteralInput.coerce(type.of_type, ast_node, variables)]
         | 
| 40 | 
            -
                        end
         | 
| 41 | 
            -
                      when "INPUT_OBJECT"
         | 
| 42 | 
            -
                        # TODO smell: handling AST vs handling plain Ruby
         | 
| 43 | 
            -
                        next_args = ast_node.is_a?(Hash) ? ast_node : ast_node.arguments
         | 
| 44 | 
            -
                        from_arguments(next_args, type, variables)
         | 
| 45 | 
            -
                      else
         | 
| 46 | 
            -
                        raise "Invariant: unexpected type to coerce to: #{type}"
         | 
| 47 | 
            -
                      end
         | 
| 48 | 
            -
                    end
         | 
| 49 | 
            -
                  end
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                  def self.from_arguments(ast_arguments, argument_owner, variables)
         | 
| 52 | 
            -
                    context = variables ? variables.context : nil
         | 
| 53 | 
            -
                    values_hash = {}
         | 
| 54 | 
            -
                    defaults_used = Set.new
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                    indexed_arguments = case ast_arguments
         | 
| 57 | 
            -
                    when Hash
         | 
| 58 | 
            -
                      ast_arguments
         | 
| 59 | 
            -
                    when Array
         | 
| 60 | 
            -
                      ast_arguments.each_with_object({}) { |a, memo| memo[a.name] = a }
         | 
| 61 | 
            -
                    else
         | 
| 62 | 
            -
                      raise ArgumentError, "Unexpected ast_arguments: #{ast_arguments}"
         | 
| 63 | 
            -
                    end
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                    argument_defns = argument_owner.arguments(context || GraphQL::Query::NullContext)
         | 
| 66 | 
            -
                    argument_defns.each do |arg_name, arg_defn|
         | 
| 67 | 
            -
                      ast_arg = indexed_arguments[arg_name]
         | 
| 68 | 
            -
                      # First, check the argument in the AST.
         | 
| 69 | 
            -
                      # If the value is a variable,
         | 
| 70 | 
            -
                      # only add a value if the variable is actually present.
         | 
| 71 | 
            -
                      # Otherwise, coerce the value in the AST, prepare the value and add it.
         | 
| 72 | 
            -
                      #
         | 
| 73 | 
            -
                      # TODO: since indexed_arguments can come from a plain Ruby hash,
         | 
| 74 | 
            -
                      # have to check for `false` or `nil` as hash values. This is getting smelly :S
         | 
| 75 | 
            -
                      if indexed_arguments.key?(arg_name)
         | 
| 76 | 
            -
                        arg_value = ast_arg.is_a?(GraphQL::Language::Nodes::Argument) ? ast_arg.value : ast_arg
         | 
| 77 | 
            -
             | 
| 78 | 
            -
                        value_is_a_variable = arg_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                        if (!value_is_a_variable || (value_is_a_variable && variables.key?(arg_value.name)))
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                          value = coerce(arg_defn.type, arg_value, variables)
         | 
| 83 | 
            -
                          # Legacy `prepare` application
         | 
| 84 | 
            -
                          if arg_defn.is_a?(GraphQL::Argument)
         | 
| 85 | 
            -
                            value = arg_defn.prepare(value, context)
         | 
| 86 | 
            -
                          end
         | 
| 87 | 
            -
             | 
| 88 | 
            -
                          if value.is_a?(GraphQL::ExecutionError)
         | 
| 89 | 
            -
                            value.ast_node = ast_arg
         | 
| 90 | 
            -
                            raise value
         | 
| 91 | 
            -
                          end
         | 
| 92 | 
            -
             | 
| 93 | 
            -
                          values_hash[arg_name] = value
         | 
| 94 | 
            -
                        end
         | 
| 95 | 
            -
                      end
         | 
| 96 | 
            -
             | 
| 97 | 
            -
                      # Then, the definition for a default value.
         | 
| 98 | 
            -
                      # If the definition has a default value and
         | 
| 99 | 
            -
                      # a value wasn't provided from the AST,
         | 
| 100 | 
            -
                      # then add the default value.
         | 
| 101 | 
            -
                      if arg_defn.default_value? && !values_hash.key?(arg_name)
         | 
| 102 | 
            -
                        value = arg_defn.default_value
         | 
| 103 | 
            -
                        defaults_used << arg_name
         | 
| 104 | 
            -
                        # `context` isn't present when pre-calculating defaults
         | 
| 105 | 
            -
                        if context
         | 
| 106 | 
            -
                          if arg_defn.is_a?(GraphQL::Argument)
         | 
| 107 | 
            -
                            value = arg_defn.prepare(value, context)
         | 
| 108 | 
            -
                          end
         | 
| 109 | 
            -
                          if value.is_a?(GraphQL::ExecutionError)
         | 
| 110 | 
            -
                            value.ast_node = ast_arg
         | 
| 111 | 
            -
                            raise value
         | 
| 112 | 
            -
                          end
         | 
| 113 | 
            -
                        end
         | 
| 114 | 
            -
                        values_hash[arg_name] = value
         | 
| 115 | 
            -
                      end
         | 
| 116 | 
            -
                    end
         | 
| 117 | 
            -
             | 
| 118 | 
            -
                    # A Schema::InputObject, Schema::GraphQL::Field, Schema::Directive, logic from Interpreter::Arguments
         | 
| 119 | 
            -
                    ruby_kwargs = {}
         | 
| 120 | 
            -
                    values_hash.each do |key, value|
         | 
| 121 | 
            -
                      ruby_kwargs[Schema::Member::BuildType.underscore(key).to_sym] = value
         | 
| 122 | 
            -
                    end
         | 
| 123 | 
            -
                    if argument_owner.is_a?(Class) && argument_owner < GraphQL::Schema::InputObject
         | 
| 124 | 
            -
                      argument_owner.new(ruby_kwargs: ruby_kwargs, context: context, defaults_used: defaults_used)
         | 
| 125 | 
            -
                    else
         | 
| 126 | 
            -
                      ruby_kwargs
         | 
| 127 | 
            -
                    end
         | 
| 128 | 
            -
                  end
         | 
| 129 | 
            -
                end
         | 
| 130 | 
            -
              end
         | 
| 131 | 
            -
            end
         |