graphql 1.13.2 → 1.13.6
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/field_usage.rb +6 -2
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +4 -2
- data/lib/graphql/execution/interpreter/runtime.rb +33 -17
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +2 -0
- data/lib/graphql/introspection/schema_type.rb +5 -0
- data/lib/graphql/introspection/type_type.rb +9 -3
- data/lib/graphql/introspection.rb +3 -0
- data/lib/graphql/language/document_from_schema_definition.rb +8 -3
- data/lib/graphql/language/lexer.rb +50 -25
- data/lib/graphql/language/lexer.rl +2 -0
- data/lib/graphql/language/nodes.rb +2 -2
- data/lib/graphql/language/parser.rb +829 -816
- data/lib/graphql/language/parser.y +8 -2
- data/lib/graphql/language/printer.rb +4 -0
- data/lib/graphql/pagination/active_record_relation_connection.rb +43 -6
- data/lib/graphql/pagination/relation_connection.rb +59 -29
- data/lib/graphql/schema/argument.rb +6 -10
- data/lib/graphql/schema/build_from_definition.rb +1 -0
- data/lib/graphql/schema/directive.rb +15 -0
- data/lib/graphql/schema/field.rb +103 -39
- data/lib/graphql/schema/field_extension.rb +37 -0
- data/lib/graphql/schema/input_object.rb +15 -0
- data/lib/graphql/schema/loader.rb +3 -0
- data/lib/graphql/schema/non_null.rb +4 -0
- data/lib/graphql/schema/scalar.rb +12 -0
- data/lib/graphql/schema/validator/required_validator.rb +29 -15
- data/lib/graphql/schema.rb +16 -1
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
- data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +6 -0
- data/lib/graphql/static_validation/validation_context.rb +4 -0
- data/lib/graphql/subscriptions/serialize.rb +22 -2
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
- data/lib/graphql/tracing/data_dog_tracing.rb +6 -1
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_tracing.rb +11 -6
- data/lib/graphql/types/iso_8601_date.rb +13 -5
- data/lib/graphql/types/relay/node_field.rb +2 -3
- data/lib/graphql/types/relay/nodes_field.rb +19 -3
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -0
- metadata +10 -6
| @@ -14,7 +14,7 @@ module GraphQL | |
| 14 14 | 
             
                  #     argument :ingredient_id, ID, required: true
         | 
| 15 15 | 
             
                  #     argument :cups, Integer, required: false
         | 
| 16 16 | 
             
                  #     argument :tablespoons, Integer, required: false
         | 
| 17 | 
            -
                  #     argument :teaspoons, Integer, required:  | 
| 17 | 
            +
                  #     argument :teaspoons, Integer, required: false
         | 
| 18 18 | 
             
                  #     validates required: { one_of: [:cups, :tablespoons, :teaspoons] }
         | 
| 19 19 | 
             
                  #   end
         | 
| 20 20 | 
             
                  #
         | 
| @@ -28,11 +28,23 @@ module GraphQL | |
| 28 28 | 
             
                  #    validates required: { one_of: [:node_id, [:object_type, :object_id]] }
         | 
| 29 29 | 
             
                  #  end
         | 
| 30 30 | 
             
                  #
         | 
| 31 | 
            +
                  # @example require _some_ value for an argument, even if it's null
         | 
| 32 | 
            +
                  #   field :update_settings, AccountSettings do
         | 
| 33 | 
            +
                  #     # `required: :nullable` means this argument must be given, but may be `null`
         | 
| 34 | 
            +
                  #     argument :age, Integer, required: :nullable
         | 
| 35 | 
            +
                  #   end
         | 
| 36 | 
            +
                  #
         | 
| 31 37 | 
             
                  class RequiredValidator < Validator
         | 
| 32 38 | 
             
                    # @param one_of [Symbol, Array<Symbol>] An argument, or a list of arguments, that represents a valid set of inputs for this field
         | 
| 33 39 | 
             
                    # @param message [String]
         | 
| 34 | 
            -
                    def initialize(one_of | 
| 35 | 
            -
                      @one_of = one_of
         | 
| 40 | 
            +
                    def initialize(one_of: nil, argument: nil, message: "%{validated} has the wrong arguments", **default_options)
         | 
| 41 | 
            +
                      @one_of = if one_of
         | 
| 42 | 
            +
                        one_of
         | 
| 43 | 
            +
                      elsif argument
         | 
| 44 | 
            +
                        [argument]
         | 
| 45 | 
            +
                      else
         | 
| 46 | 
            +
                        raise ArgumentError, "`one_of:` or `argument:` must be given in `validates required: {...}`"
         | 
| 47 | 
            +
                      end
         | 
| 36 48 | 
             
                      @message = message
         | 
| 37 49 | 
             
                      super(**default_options)
         | 
| 38 50 | 
             
                    end
         | 
| @@ -40,19 +52,21 @@ module GraphQL | |
| 40 52 | 
             
                    def validate(_object, _context, value)
         | 
| 41 53 | 
             
                      matched_conditions = 0
         | 
| 42 54 |  | 
| 43 | 
            -
                       | 
| 44 | 
            -
                         | 
| 45 | 
            -
             | 
| 46 | 
            -
                           | 
| 47 | 
            -
                             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
                           | 
| 51 | 
            -
                             | 
| 52 | 
            -
             | 
| 55 | 
            +
                      if !value.nil?
         | 
| 56 | 
            +
                        @one_of.each do |one_of_condition|
         | 
| 57 | 
            +
                          case one_of_condition
         | 
| 58 | 
            +
                          when Symbol
         | 
| 59 | 
            +
                            if value.key?(one_of_condition)
         | 
| 60 | 
            +
                              matched_conditions += 1
         | 
| 61 | 
            +
                            end
         | 
| 62 | 
            +
                          when Array
         | 
| 63 | 
            +
                            if one_of_condition.all? { |k| value.key?(k) }
         | 
| 64 | 
            +
                              matched_conditions += 1
         | 
| 65 | 
            +
                              break
         | 
| 66 | 
            +
                            end
         | 
| 67 | 
            +
                          else
         | 
| 68 | 
            +
                            raise ArgumentError, "Unknown one_of condition: #{one_of_condition.inspect}"
         | 
| 53 69 | 
             
                          end
         | 
| 54 | 
            -
                        else
         | 
| 55 | 
            -
                          raise ArgumentError, "Unknown one_of condition: #{one_of_condition.inspect}"
         | 
| 56 70 | 
             
                        end
         | 
| 57 71 | 
             
                      end
         | 
| 58 72 |  | 
    
        data/lib/graphql/schema.rb
    CHANGED
    
    | @@ -892,6 +892,17 @@ module GraphQL | |
| 892 892 | 
             
                    GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
         | 
| 893 893 | 
             
                  end
         | 
| 894 894 |  | 
| 895 | 
            +
                  # @return [String, nil]
         | 
| 896 | 
            +
                  def description(new_description = nil)
         | 
| 897 | 
            +
                    if new_description
         | 
| 898 | 
            +
                      @description = new_description
         | 
| 899 | 
            +
                    elsif defined?(@description)
         | 
| 900 | 
            +
                      @description
         | 
| 901 | 
            +
                    else
         | 
| 902 | 
            +
                      find_inherited_value(:description, nil)
         | 
| 903 | 
            +
                    end
         | 
| 904 | 
            +
                  end
         | 
| 905 | 
            +
             | 
| 895 906 | 
             
                  def find(path)
         | 
| 896 907 | 
             
                    if !@finder
         | 
| 897 908 | 
             
                      @find_cache = {}
         | 
| @@ -1247,7 +1258,11 @@ module GraphQL | |
| 1247 1258 | 
             
                    when Module
         | 
| 1248 1259 | 
             
                      type_or_name
         | 
| 1249 1260 | 
             
                    else
         | 
| 1250 | 
            -
                      raise ArgumentError,  | 
| 1261 | 
            +
                      raise ArgumentError, <<-ERR
         | 
| 1262 | 
            +
            Invariant: unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})
         | 
| 1263 | 
            +
             | 
| 1264 | 
            +
            This is probably a bug in GraphQL-Ruby, please report this error on GitHub: https://github.com/rmosolgo/graphql-ruby/issues/new?template=bug_report.md
         | 
| 1265 | 
            +
            ERR
         | 
| 1251 1266 | 
             
                    end
         | 
| 1252 1267 |  | 
| 1253 1268 | 
             
                    if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
         | 
| @@ -33,6 +33,7 @@ module GraphQL | |
| 33 33 | 
             
                  GraphQL::StaticValidation::VariablesAreUsedAndDefined,
         | 
| 34 34 | 
             
                  GraphQL::StaticValidation::VariableUsagesAreAllowed,
         | 
| 35 35 | 
             
                  GraphQL::StaticValidation::MutationRootExists,
         | 
| 36 | 
            +
                  GraphQL::StaticValidation::QueryRootExists,
         | 
| 36 37 | 
             
                  GraphQL::StaticValidation::SubscriptionRootExists,
         | 
| 37 38 | 
             
                  GraphQL::StaticValidation::InputObjectNamesAreUnique,
         | 
| 38 39 | 
             
                ]
         | 
| @@ -110,7 +110,7 @@ module GraphQL | |
| 110 110 | 
             
                    end
         | 
| 111 111 |  | 
| 112 112 | 
             
                    def on_directive(node, parent)
         | 
| 113 | 
            -
                      directive_defn = @ | 
| 113 | 
            +
                      directive_defn = @context.schema_directives[node.name]
         | 
| 114 114 | 
             
                      @directive_definitions.push(directive_defn)
         | 
| 115 115 | 
             
                      super
         | 
| 116 116 | 
             
                      @directive_definitions.pop
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
            module GraphQL
         | 
| 3 | 
            +
              module StaticValidation
         | 
| 4 | 
            +
                module QueryRootExists
         | 
| 5 | 
            +
                  def on_operation_definition(node, _parent)
         | 
| 6 | 
            +
                    if (node.operation_type == 'query' || node.operation_type.nil?) && context.warden.root_type_for_operation("query").nil?
         | 
| 7 | 
            +
                      add_error(GraphQL::StaticValidation::QueryRootExistsError.new(
         | 
| 8 | 
            +
                        'Schema is not configured for queries',
         | 
| 9 | 
            +
                        nodes: node
         | 
| 10 | 
            +
                      ))
         | 
| 11 | 
            +
                    else
         | 
| 12 | 
            +
                      super
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
            module GraphQL
         | 
| 3 | 
            +
              module StaticValidation
         | 
| 4 | 
            +
                class QueryRootExistsError < StaticValidation::Error
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(message, path: nil, nodes: [])
         | 
| 7 | 
            +
                    super(message, path: path, nodes: nodes)
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  # A hash representation of this Message
         | 
| 11 | 
            +
                  def to_h
         | 
| 12 | 
            +
                    extensions = {
         | 
| 13 | 
            +
                      "code" => code,
         | 
| 14 | 
            +
                    }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    super.merge({
         | 
| 17 | 
            +
                      "extensions" => extensions
         | 
| 18 | 
            +
                    })
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def code
         | 
| 22 | 
            +
                    "missingQueryConfiguration"
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -40,7 +40,7 @@ module GraphQL | |
| 40 40 | 
             
                          nodes: [used_directives[directive_name], ast_directive],
         | 
| 41 41 | 
             
                          directive: directive_name,
         | 
| 42 42 | 
             
                        ))
         | 
| 43 | 
            -
                       | 
| 43 | 
            +
                      elsif !((dir_defn = context.schema_directives[directive_name]) && dir_defn.repeatable?)
         | 
| 44 44 | 
             
                        used_directives[directive_name] = ast_directive
         | 
| 45 45 | 
             
                      end
         | 
| 46 46 | 
             
                    end
         | 
| @@ -68,6 +68,12 @@ module GraphQL | |
| 68 68 | 
             
                    arg_defn = context.warden.get_argument(argument_owner, arg_node.name)
         | 
| 69 69 | 
             
                    arg_defn_type = arg_defn.type
         | 
| 70 70 |  | 
| 71 | 
            +
                    # If the argument is non-null, but it was given a default value,
         | 
| 72 | 
            +
                    # then treat it as nullable in practice, see https://github.com/rmosolgo/graphql-ruby/issues/3793
         | 
| 73 | 
            +
                    if arg_defn_type.non_null? && arg_defn.default_value?
         | 
| 74 | 
            +
                      arg_defn_type = arg_defn_type.of_type
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
             | 
| 71 77 | 
             
                    var_inner_type = var_type.unwrap
         | 
| 72 78 | 
             
                    arg_inner_type = arg_defn_type.unwrap
         | 
| 73 79 |  | 
| @@ -71,9 +71,17 @@ module GraphQL | |
| 71 71 | 
             
                          when SYMBOL_KEY
         | 
| 72 72 | 
             
                            value[SYMBOL_KEY].to_sym
         | 
| 73 73 | 
             
                          when TIMESTAMP_KEY
         | 
| 74 | 
            -
                            timestamp_class_name,  | 
| 74 | 
            +
                            timestamp_class_name, *timestamp_args = value[TIMESTAMP_KEY]
         | 
| 75 75 | 
             
                            timestamp_class = Object.const_get(timestamp_class_name)
         | 
| 76 | 
            -
                             | 
| 76 | 
            +
                            if defined?(ActiveSupport::TimeWithZone) && timestamp_class <= ActiveSupport::TimeWithZone
         | 
| 77 | 
            +
                              zone_name, timestamp_s = timestamp_args
         | 
| 78 | 
            +
                              zone = ActiveSupport::TimeZone[zone_name]
         | 
| 79 | 
            +
                              raise "Zone #{zone_name} not found, unable to deserialize" unless zone
         | 
| 80 | 
            +
                              zone.strptime(timestamp_s, TIMESTAMP_FORMAT)
         | 
| 81 | 
            +
                            else
         | 
| 82 | 
            +
                              timestamp_s = timestamp_args.first
         | 
| 83 | 
            +
                              timestamp_class.strptime(timestamp_s, TIMESTAMP_FORMAT)
         | 
| 84 | 
            +
                            end
         | 
| 77 85 | 
             
                          when OPEN_STRUCT_KEY
         | 
| 78 86 | 
             
                            ostruct_values = load_value(value[OPEN_STRUCT_KEY])
         | 
| 79 87 | 
             
                            OpenStruct.new(ostruct_values)
         | 
| @@ -123,6 +131,18 @@ module GraphQL | |
| 123 131 | 
             
                        { SYMBOL_KEY => obj.to_s }
         | 
| 124 132 | 
             
                      elsif obj.respond_to?(:to_gid_param)
         | 
| 125 133 | 
             
                        {GLOBALID_KEY => obj.to_gid_param}
         | 
| 134 | 
            +
                      elsif defined?(ActiveSupport::TimeWithZone) && obj.is_a?(ActiveSupport::TimeWithZone) && obj.class.name != Time.name
         | 
| 135 | 
            +
                        # This handles a case where Rails prior to 7 would
         | 
| 136 | 
            +
                        # make the class ActiveSupport::TimeWithZone return "Time" for
         | 
| 137 | 
            +
                        # its name. In Rails 7, it will now return "ActiveSupport::TimeWithZone",
         | 
| 138 | 
            +
                        # which happens to be incompatible with expectations we have
         | 
| 139 | 
            +
                        # with what a Time class supports ( notably, strptime in `load_value` ).
         | 
| 140 | 
            +
                        #
         | 
| 141 | 
            +
                        # This now passes along the name of the zone, such that a future deserialization
         | 
| 142 | 
            +
                        # of this string will use the correct time zone from the ActiveSupport TimeZone
         | 
| 143 | 
            +
                        # list to produce the time.
         | 
| 144 | 
            +
                        #
         | 
| 145 | 
            +
                        { TIMESTAMP_KEY => [obj.class.name, obj.time_zone.name, obj.strftime(TIMESTAMP_FORMAT)] }
         | 
| 126 146 | 
             
                      elsif obj.is_a?(Date) || obj.is_a?(Time)
         | 
| 127 147 | 
             
                        # DateTime extends Date; for TimeWithZone, call `.utc` first.
         | 
| 128 148 | 
             
                        { TIMESTAMP_KEY => [obj.class.name, obj.strftime(TIMESTAMP_FORMAT)] }
         | 
| @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'graphql/tracing/notifications_tracing'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            module GraphQL
         | 
| 4 6 | 
             
              module Tracing
         | 
| 5 7 | 
             
                # This implementation forwards events to ActiveSupport::Notifications
         | 
| @@ -8,27 +10,11 @@ module GraphQL | |
| 8 10 | 
             
                # @see KEYS for event names
         | 
| 9 11 | 
             
                module ActiveSupportNotificationsTracing
         | 
| 10 12 | 
             
                  # A cache of frequently-used keys to avoid needless string allocations
         | 
| 11 | 
            -
                  KEYS =  | 
| 12 | 
            -
             | 
| 13 | 
            -
                    "parse" => "parse.graphql",
         | 
| 14 | 
            -
                    "validate" => "validate.graphql",
         | 
| 15 | 
            -
                    "analyze_multiplex" => "analyze_multiplex.graphql",
         | 
| 16 | 
            -
                    "analyze_query" => "analyze_query.graphql",
         | 
| 17 | 
            -
                    "execute_query" => "execute_query.graphql",
         | 
| 18 | 
            -
                    "execute_query_lazy" => "execute_query_lazy.graphql",
         | 
| 19 | 
            -
                    "execute_field" => "execute_field.graphql",
         | 
| 20 | 
            -
                    "execute_field_lazy" => "execute_field_lazy.graphql",
         | 
| 21 | 
            -
                    "authorized" => "authorized.graphql",
         | 
| 22 | 
            -
                    "authorized_lazy" => "authorized_lazy.graphql",
         | 
| 23 | 
            -
                    "resolve_type" => "resolve_type.graphql",
         | 
| 24 | 
            -
                    "resolve_type_lazy" => "resolve_type.graphql",
         | 
| 25 | 
            -
                  }
         | 
| 13 | 
            +
                  KEYS = NotificationsTracing::KEYS
         | 
| 14 | 
            +
                  NOTIFICATIONS_ENGINE = NotificationsTracing.new(ActiveSupport::Notifications) if defined?(ActiveSupport::Notifications)
         | 
| 26 15 |  | 
| 27 | 
            -
                  def self.trace(key, metadata)
         | 
| 28 | 
            -
                     | 
| 29 | 
            -
                    ActiveSupport::Notifications.instrument(prefixed_key, metadata) do
         | 
| 30 | 
            -
                      yield
         | 
| 31 | 
            -
                    end
         | 
| 16 | 
            +
                  def self.trace(key, metadata, &blk)
         | 
| 17 | 
            +
                    NOTIFICATIONS_ENGINE.trace(key, metadata, &blk)
         | 
| 32 18 | 
             
                  end
         | 
| 33 19 | 
             
                end
         | 
| 34 20 | 
             
              end
         | 
| @@ -20,7 +20,12 @@ module GraphQL | |
| 20 20 |  | 
| 21 21 | 
             
                      if key == 'execute_multiplex'
         | 
| 22 22 | 
             
                        operations = data[:multiplex].queries.map(&:selected_operation_name).join(', ')
         | 
| 23 | 
            -
                        span.resource =  | 
| 23 | 
            +
                        span.resource = if operations.empty?
         | 
| 24 | 
            +
                          first_query = data[:multiplex].queries.first
         | 
| 25 | 
            +
                          fallback_transaction_name(first_query && first_query.context)
         | 
| 26 | 
            +
                        else
         | 
| 27 | 
            +
                          operations
         | 
| 28 | 
            +
                        end
         | 
| 24 29 |  | 
| 25 30 | 
             
                        # For top span of query, set the analytics sample rate tag, if available.
         | 
| 26 31 | 
             
                        if analytics_enabled?
         | 
| @@ -0,0 +1,59 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module GraphQL
         | 
| 4 | 
            +
              module Tracing
         | 
| 5 | 
            +
                # This implementation forwards events to a notification handler (i.e.
         | 
| 6 | 
            +
                # ActiveSupport::Notifications or Dry::Monitor::Notifications)
         | 
| 7 | 
            +
                # with a `graphql` suffix.
         | 
| 8 | 
            +
                #
         | 
| 9 | 
            +
                # @see KEYS for event names
         | 
| 10 | 
            +
                class NotificationsTracing
         | 
| 11 | 
            +
                  # A cache of frequently-used keys to avoid needless string allocations
         | 
| 12 | 
            +
                  KEYS = {
         | 
| 13 | 
            +
                    "lex" => "lex.graphql",
         | 
| 14 | 
            +
                    "parse" => "parse.graphql",
         | 
| 15 | 
            +
                    "validate" => "validate.graphql",
         | 
| 16 | 
            +
                    "analyze_multiplex" => "analyze_multiplex.graphql",
         | 
| 17 | 
            +
                    "analyze_query" => "analyze_query.graphql",
         | 
| 18 | 
            +
                    "execute_query" => "execute_query.graphql",
         | 
| 19 | 
            +
                    "execute_query_lazy" => "execute_query_lazy.graphql",
         | 
| 20 | 
            +
                    "execute_field" => "execute_field.graphql",
         | 
| 21 | 
            +
                    "execute_field_lazy" => "execute_field_lazy.graphql",
         | 
| 22 | 
            +
                    "authorized" => "authorized.graphql",
         | 
| 23 | 
            +
                    "authorized_lazy" => "authorized_lazy.graphql",
         | 
| 24 | 
            +
                    "resolve_type" => "resolve_type.graphql",
         | 
| 25 | 
            +
                    "resolve_type_lazy" => "resolve_type.graphql",
         | 
| 26 | 
            +
                  }
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  MAX_KEYS_SIZE = 100
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  # Initialize a new NotificationsTracing instance
         | 
| 31 | 
            +
                  #
         | 
| 32 | 
            +
                  # @param [Object] notifications_engine The notifications engine to use
         | 
| 33 | 
            +
                  def initialize(notifications_engine)
         | 
| 34 | 
            +
                    @notifications_engine = notifications_engine
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  # Sends a GraphQL tracing event to the notification handler
         | 
| 38 | 
            +
                  #
         | 
| 39 | 
            +
                  # @example
         | 
| 40 | 
            +
                  # . notifications_engine = Dry::Monitor::Notifications.new(:graphql)
         | 
| 41 | 
            +
                  # . tracer = GraphQL::Tracing::NotificationsTracing.new(notifications_engine)
         | 
| 42 | 
            +
                  # . tracer.trace("lex") { ... }
         | 
| 43 | 
            +
                  #
         | 
| 44 | 
            +
                  # @param [string] key The key for the event
         | 
| 45 | 
            +
                  # @param [Hash] metadata The metadata for the event
         | 
| 46 | 
            +
                  # @yield The block to execute for the event
         | 
| 47 | 
            +
                  def trace(key, metadata, &blk)
         | 
| 48 | 
            +
                    prefixed_key = KEYS[key] || "#{key}.graphql"
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    # Cache the new keys while making sure not to induce a memory leak
         | 
| 51 | 
            +
                    if KEYS.size < MAX_KEYS_SIZE
         | 
| 52 | 
            +
                      KEYS[key] ||= prefixed_key
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    @notifications_engine.instrument(prefixed_key, metadata, &blk)
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
            end
         | 
| @@ -104,17 +104,22 @@ module GraphQL | |
| 104 104 |  | 
| 105 105 | 
             
                  private
         | 
| 106 106 |  | 
| 107 | 
            -
                  # Get the transaction name based on the operation type and name
         | 
| 107 | 
            +
                  # Get the transaction name based on the operation type and name if possible, or fall back to a user provided
         | 
| 108 | 
            +
                  # one. Useful for anonymous queries.
         | 
| 108 109 | 
             
                  def transaction_name(query)
         | 
| 109 110 | 
             
                    selected_op = query.selected_operation
         | 
| 110 | 
            -
                    if selected_op
         | 
| 111 | 
            +
                    txn_name = if selected_op
         | 
| 111 112 | 
             
                      op_type = selected_op.operation_type
         | 
| 112 | 
            -
                      op_name = selected_op.name || "anonymous"
         | 
| 113 | 
            +
                      op_name = selected_op.name || fallback_transaction_name(query.context) || "anonymous"
         | 
| 114 | 
            +
                      "#{op_type}.#{op_name}"
         | 
| 113 115 | 
             
                    else
         | 
| 114 | 
            -
                       | 
| 115 | 
            -
                      op_name = "anonymous"
         | 
| 116 | 
            +
                      "query.anonymous"
         | 
| 116 117 | 
             
                    end
         | 
| 117 | 
            -
                    "GraphQL/#{ | 
| 118 | 
            +
                    "GraphQL/#{txn_name}"
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  def fallback_transaction_name(context)
         | 
| 122 | 
            +
                    context[:tracing_fallback_transaction_name]
         | 
| 118 123 | 
             
                  end
         | 
| 119 124 |  | 
| 120 125 | 
             
                  attr_reader :options
         | 
| @@ -21,13 +21,21 @@ module GraphQL | |
| 21 21 | 
             
                    Date.parse(value.to_s).iso8601
         | 
| 22 22 | 
             
                  end
         | 
| 23 23 |  | 
| 24 | 
            -
                  # @param str_value [String]
         | 
| 24 | 
            +
                  # @param str_value [String, Date, DateTime, Time]
         | 
| 25 25 | 
             
                  # @return [Date]
         | 
| 26 | 
            -
                  def self.coerce_input( | 
| 27 | 
            -
                     | 
| 26 | 
            +
                  def self.coerce_input(value, ctx)
         | 
| 27 | 
            +
                    if value.is_a?(::Date)
         | 
| 28 | 
            +
                      value
         | 
| 29 | 
            +
                    elsif value.is_a?(::DateTime)
         | 
| 30 | 
            +
                      value.to_date
         | 
| 31 | 
            +
                    elsif value.is_a?(::Time)
         | 
| 32 | 
            +
                      value.to_date
         | 
| 33 | 
            +
                    else
         | 
| 34 | 
            +
                      Date.iso8601(value)
         | 
| 35 | 
            +
                    end
         | 
| 28 36 | 
             
                  rescue ArgumentError, TypeError
         | 
| 29 | 
            -
                     | 
| 30 | 
            -
                     | 
| 37 | 
            +
                    err = GraphQL::DateEncodingError.new(value)
         | 
| 38 | 
            +
                    ctx.schema.type_error(err, ctx)
         | 
| 31 39 | 
             
                  end
         | 
| 32 40 | 
             
                end
         | 
| 33 41 | 
             
              end
         | 
| @@ -2,8 +2,7 @@ | |
| 2 2 | 
             
            module GraphQL
         | 
| 3 3 | 
             
              module Types
         | 
| 4 4 | 
             
                module Relay
         | 
| 5 | 
            -
                  #  | 
| 6 | 
            -
                  # or use it for inspiration for your own field definition.
         | 
| 5 | 
            +
                  # Don't use this field directly, instead, use one of these approaches:
         | 
| 7 6 | 
             
                  #
         | 
| 8 7 | 
             
                  # @example Adding this field directly
         | 
| 9 8 | 
             
                  #   include GraphQL::Types::Relay::HasNodeField
         | 
| @@ -19,7 +18,7 @@ module GraphQL | |
| 19 18 | 
             
                  #     context.schema.object_from_id(id, context)
         | 
| 20 19 | 
             
                  #   end
         | 
| 21 20 | 
             
                  #
         | 
| 22 | 
            -
                   | 
| 21 | 
            +
                  DeprecatedNodeField = GraphQL::Schema::Field.new(owner: nil, **HasNodeField.field_options, &HasNodeField.field_block)
         | 
| 23 22 | 
             
                end
         | 
| 24 23 | 
             
              end
         | 
| 25 24 | 
             
            end
         | 
| @@ -2,8 +2,7 @@ | |
| 2 2 | 
             
            module GraphQL
         | 
| 3 3 | 
             
              module Types
         | 
| 4 4 | 
             
                module Relay
         | 
| 5 | 
            -
                  #  | 
| 6 | 
            -
                  # or use it for inspiration for your own field definition.
         | 
| 5 | 
            +
                  # Don't use this directly, instead, use one of these:
         | 
| 7 6 | 
             
                  #
         | 
| 8 7 | 
             
                  # @example Adding this field directly
         | 
| 9 8 | 
             
                  #   include GraphQL::Types::Relay::HasNodesField
         | 
| @@ -21,7 +20,24 @@ module GraphQL | |
| 21 20 | 
             
                  #     end
         | 
| 22 21 | 
             
                  #   end
         | 
| 23 22 | 
             
                  #
         | 
| 24 | 
            -
                   | 
| 23 | 
            +
                  def self.const_missing(const_name)
         | 
| 24 | 
            +
                    if const_name == :NodesField
         | 
| 25 | 
            +
                      message = "NodesField is deprecated, use `include GraphQL::Types::Relay::HasNodesField` instead."
         | 
| 26 | 
            +
                      message += "\n(referenced from #{caller(1, 1).first})"
         | 
| 27 | 
            +
                      GraphQL::Deprecation.warn(message)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                      DeprecatedNodesField
         | 
| 30 | 
            +
                    elsif const_name == :NodeField
         | 
| 31 | 
            +
                      message = "NodeField is deprecated, use `include GraphQL::Types::Relay::HasNodeField` instead."
         | 
| 32 | 
            +
                      message += "\n(referenced from #{caller(1, 1).first})"
         | 
| 33 | 
            +
                      GraphQL::Deprecation.warn(message)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                      DeprecatedNodeField
         | 
| 36 | 
            +
                    else
         | 
| 37 | 
            +
                      super
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                  DeprecatedNodesField = GraphQL::Schema::Field.new(owner: nil, **HasNodesField.field_options, &HasNodesField.field_block)
         | 
| 25 41 | 
             
                end
         | 
| 26 42 | 
             
              end
         | 
| 27 43 | 
             
            end
         | 
    
        data/lib/graphql/version.rb
    CHANGED
    
    
    
        data/lib/graphql.rb
    CHANGED
    
    | @@ -69,6 +69,7 @@ require "graphql/invalid_name_error" | |
| 69 69 | 
             
            require "graphql/integer_decoding_error"
         | 
| 70 70 | 
             
            require "graphql/integer_encoding_error"
         | 
| 71 71 | 
             
            require "graphql/string_encoding_error"
         | 
| 72 | 
            +
            require "graphql/date_encoding_error"
         | 
| 72 73 |  | 
| 73 74 | 
             
            require "graphql/define"
         | 
| 74 75 | 
             
            require "graphql/base_type"
         | 
    
        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: 1.13. | 
| 4 | 
            +
              version: 1.13.6
         | 
| 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:  | 
| 11 | 
            +
            date: 2022-01-20 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: benchmark-ips
         | 
| @@ -323,6 +323,7 @@ files: | |
| 323 323 | 
             
            - lib/graphql/dataloader/request.rb
         | 
| 324 324 | 
             
            - lib/graphql/dataloader/request_all.rb
         | 
| 325 325 | 
             
            - lib/graphql/dataloader/source.rb
         | 
| 326 | 
            +
            - lib/graphql/date_encoding_error.rb
         | 
| 326 327 | 
             
            - lib/graphql/define.rb
         | 
| 327 328 | 
             
            - lib/graphql/define/assign_argument.rb
         | 
| 328 329 | 
             
            - lib/graphql/define/assign_connection.rb
         | 
| @@ -606,6 +607,8 @@ files: | |
| 606 607 | 
             
            - lib/graphql/static_validation/rules/no_definitions_are_present_error.rb
         | 
| 607 608 | 
             
            - lib/graphql/static_validation/rules/operation_names_are_valid.rb
         | 
| 608 609 | 
             
            - lib/graphql/static_validation/rules/operation_names_are_valid_error.rb
         | 
| 610 | 
            +
            - lib/graphql/static_validation/rules/query_root_exists.rb
         | 
| 611 | 
            +
            - lib/graphql/static_validation/rules/query_root_exists_error.rb
         | 
| 609 612 | 
             
            - lib/graphql/static_validation/rules/required_arguments_are_present.rb
         | 
| 610 613 | 
             
            - lib/graphql/static_validation/rules/required_arguments_are_present_error.rb
         | 
| 611 614 | 
             
            - lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb
         | 
| @@ -644,6 +647,7 @@ files: | |
| 644 647 | 
             
            - lib/graphql/tracing/appsignal_tracing.rb
         | 
| 645 648 | 
             
            - lib/graphql/tracing/data_dog_tracing.rb
         | 
| 646 649 | 
             
            - lib/graphql/tracing/new_relic_tracing.rb
         | 
| 650 | 
            +
            - lib/graphql/tracing/notifications_tracing.rb
         | 
| 647 651 | 
             
            - lib/graphql/tracing/platform_tracing.rb
         | 
| 648 652 | 
             
            - lib/graphql/tracing/prometheus_tracing.rb
         | 
| 649 653 | 
             
            - lib/graphql/tracing/prometheus_tracing/graphql_collector.rb
         | 
| @@ -692,7 +696,7 @@ metadata: | |
| 692 696 | 
             
              source_code_uri: https://github.com/rmosolgo/graphql-ruby
         | 
| 693 697 | 
             
              bug_tracker_uri: https://github.com/rmosolgo/graphql-ruby/issues
         | 
| 694 698 | 
             
              mailing_list_uri: https://tinyletter.com/graphql-ruby
         | 
| 695 | 
            -
            post_install_message:
         | 
| 699 | 
            +
            post_install_message: 
         | 
| 696 700 | 
             
            rdoc_options: []
         | 
| 697 701 | 
             
            require_paths:
         | 
| 698 702 | 
             
            - lib
         | 
| @@ -707,8 +711,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 707 711 | 
             
                - !ruby/object:Gem::Version
         | 
| 708 712 | 
             
                  version: '0'
         | 
| 709 713 | 
             
            requirements: []
         | 
| 710 | 
            -
            rubygems_version: 3. | 
| 711 | 
            -
            signing_key:
         | 
| 714 | 
            +
            rubygems_version: 3.1.6
         | 
| 715 | 
            +
            signing_key: 
         | 
| 712 716 | 
             
            specification_version: 4
         | 
| 713 717 | 
             
            summary: A GraphQL language and runtime for Ruby
         | 
| 714 718 | 
             
            test_files: []
         |