graphql 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql/compatibility/schema_parser_specification.rb +28 -0
- data/lib/graphql/enum_type.rb +3 -3
- data/lib/graphql/execution_error.rb +13 -1
- data/lib/graphql/introspection.rb +0 -3
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +1 -1
- data/lib/graphql/introspection/type_type.rb +1 -2
- data/lib/graphql/language/parser.rb +2 -2
- data/lib/graphql/language/parser.y +2 -2
- data/lib/graphql/railtie.rb +6 -6
- data/lib/graphql/schema/resolver.rb +0 -1
- data/lib/graphql/schema/warden.rb +17 -10
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +2 -2
- data/lib/graphql/upgrader/member.rb +6 -6
- data/lib/graphql/version.rb +1 -1
- data/spec/fixtures/upgrader/blame_range.transformed.rb +2 -2
- data/spec/fixtures/upgrader/delete_project.transformed.rb +4 -4
- data/spec/fixtures/upgrader/increment_count.transformed.rb +1 -1
- data/spec/fixtures/upgrader/photo.transformed.rb +1 -1
- data/spec/fixtures/upgrader/starrable.transformed.rb +5 -5
- data/spec/fixtures/upgrader/subscribable.transformed.rb +7 -7
- data/spec/fixtures/upgrader/type_x.transformed.rb +6 -6
- data/spec/graphql/execution/multiplex_spec.rb +1 -1
- data/spec/graphql/execution_error_spec.rb +20 -1
- data/spec/graphql/introspection/schema_type_spec.rb +1 -0
- data/spec/graphql/relay/mongo_relation_connection_spec.rb +12 -1
- data/spec/graphql/schema/warden_spec.rb +129 -0
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +17 -9
- data/spec/graphql/upgrader/member_spec.rb +5 -5
- data/spec/spec_helper.rb +20 -1
- data/spec/support/dummy/schema.rb +7 -0
- metadata +2 -21
- data/lib/graphql/introspection/schema_field.rb +0 -16
- data/lib/graphql/introspection/type_by_name_field.rb +0 -22
- data/lib/graphql/introspection/typename_field.rb +0 -12
- data/spec/graphql/introspection/type_by_name_field_spec.rb +0 -38
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 6d3ae1b02473b2855990db63798b1c5d2fea46de
         | 
| 4 | 
            +
              data.tar.gz: cfdc979146afea3eb44a969b66ac3a0763956db7
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 762efe82d940d001685c0cf242e1b6fc0c7ee9a5b77de66c4917268b6d2ae0340346daf707d74d41c9b1dd77b71c2d2d1f887e74e2eae2ab9c7869a787a5a74b
         | 
| 7 | 
            +
              data.tar.gz: 4bcd06d7c866bb65154310cb8d11965902372860747aaaa99ebf44a73ebac3f6b1743e459e47730ba44e7fab57588031352bd1ed63925a42ec89550d32bf7906
         | 
| @@ -78,6 +78,34 @@ module GraphQL | |
| 78 78 | 
             
                        assert_equal [], type.values[2].directives
         | 
| 79 79 | 
             
                      end
         | 
| 80 80 |  | 
| 81 | 
            +
                      def test_it_parses_union_types
         | 
| 82 | 
            +
                        document = parse(
         | 
| 83 | 
            +
                          "union BagOfThings = \n" \
         | 
| 84 | 
            +
                          "A |\n" \
         | 
| 85 | 
            +
                          "B |\n" \
         | 
| 86 | 
            +
                          "C"
         | 
| 87 | 
            +
                        )
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                        union = document.definitions.first
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                        assert_equal GraphQL::Language::Nodes::UnionTypeDefinition, union.class
         | 
| 92 | 
            +
                        assert_equal 'BagOfThings', union.name
         | 
| 93 | 
            +
                        assert_equal 3, union.types.length
         | 
| 94 | 
            +
                        assert_equal [1, 1], union.position
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                        assert_equal GraphQL::Language::Nodes::TypeName, union.types[0].class
         | 
| 97 | 
            +
                        assert_equal 'A', union.types[0].name
         | 
| 98 | 
            +
                        assert_equal [2, 1], union.types[0].position
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                        assert_equal GraphQL::Language::Nodes::TypeName, union.types[1].class
         | 
| 101 | 
            +
                        assert_equal 'B', union.types[1].name
         | 
| 102 | 
            +
                        assert_equal [3, 1], union.types[1].position
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                        assert_equal GraphQL::Language::Nodes::TypeName, union.types[2].class
         | 
| 105 | 
            +
                        assert_equal 'C', union.types[2].name
         | 
| 106 | 
            +
                        assert_equal [4, 1], union.types[2].position
         | 
| 107 | 
            +
                      end
         | 
| 108 | 
            +
             | 
| 81 109 | 
             
                      def test_it_parses_input_types
         | 
| 82 110 | 
             
                        document = parse('
         | 
| 83 111 | 
             
                          input EmptyMutationInput {
         | 
    
        data/lib/graphql/enum_type.rb
    CHANGED
    
    | @@ -12,8 +12,8 @@ module GraphQL | |
| 12 12 | 
             
              #
         | 
| 13 13 | 
             
              # @example An enum of programming languages
         | 
| 14 14 | 
             
              #   LanguageEnum = GraphQL::EnumType.define do
         | 
| 15 | 
            -
              #     name " | 
| 16 | 
            -
              #     description "Programming  | 
| 15 | 
            +
              #     name "Language"
         | 
| 16 | 
            +
              #     description "Programming language for Web projects"
         | 
| 17 17 | 
             
              #     value("PYTHON", "A dynamic, function-oriented language")
         | 
| 18 18 | 
             
              #     value("RUBY", "A very dynamic language aimed at programmer happiness")
         | 
| 19 19 | 
             
              #     value("JAVASCRIPT", "Accidental lingua franca of the web")
         | 
| @@ -57,7 +57,7 @@ module GraphQL | |
| 57 57 | 
             
              #   }
         | 
| 58 58 | 
             
              #
         | 
| 59 59 | 
             
              # @example Enum whose values are different in ActiveRecord-land
         | 
| 60 | 
            -
              #   class Language < ActiveRecord:: | 
| 60 | 
            +
              #   class Language < ActiveRecord::Base
         | 
| 61 61 | 
             
              #     enum language: {
         | 
| 62 62 | 
             
              #       rb: 0
         | 
| 63 63 | 
             
              #     }
         | 
| @@ -12,11 +12,19 @@ module GraphQL | |
| 12 12 | 
             
                attr_accessor :path
         | 
| 13 13 |  | 
| 14 14 | 
             
                # @return [Hash] Optional data for error objects
         | 
| 15 | 
            +
                # @deprecated Use `extensions` instead of `options`. The GraphQL spec
         | 
| 16 | 
            +
                # recommends that any custom entries in an error be under the
         | 
| 17 | 
            +
                # `extensions` key.
         | 
| 15 18 | 
             
                attr_accessor :options
         | 
| 16 19 |  | 
| 17 | 
            -
                 | 
| 20 | 
            +
                # @return [Hash] Optional custom data for error objects which will be added
         | 
| 21 | 
            +
                # under the `extensions` key.
         | 
| 22 | 
            +
                attr_accessor :extensions
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def initialize(message, ast_node: nil, options: nil, extensions: nil)
         | 
| 18 25 | 
             
                  @ast_node = ast_node
         | 
| 19 26 | 
             
                  @options = options
         | 
| 27 | 
            +
                  @extensions = extensions
         | 
| 20 28 | 
             
                  super(message)
         | 
| 21 29 | 
             
                end
         | 
| 22 30 |  | 
| @@ -39,6 +47,10 @@ module GraphQL | |
| 39 47 | 
             
                  if options
         | 
| 40 48 | 
             
                    hash.merge!(options)
         | 
| 41 49 | 
             
                  end
         | 
| 50 | 
            +
                  if extensions
         | 
| 51 | 
            +
                    hash["extensions"] ||= {}
         | 
| 52 | 
            +
                    hash["extensions"].merge!(extensions)
         | 
| 53 | 
            +
                  end
         | 
| 42 54 | 
             
                  hash
         | 
| 43 55 | 
             
                end
         | 
| 44 56 | 
             
              end
         | 
| @@ -5,7 +5,6 @@ module GraphQL | |
| 5 5 | 
             
            end
         | 
| 6 6 |  | 
| 7 7 | 
             
            require "graphql/introspection/base_object"
         | 
| 8 | 
            -
            require "graphql/introspection/typename_field"
         | 
| 9 8 | 
             
            require "graphql/introspection/input_value_type"
         | 
| 10 9 | 
             
            require "graphql/introspection/enum_value_type"
         | 
| 11 10 | 
             
            require "graphql/introspection/type_kind_enum"
         | 
| @@ -14,8 +13,6 @@ require "graphql/introspection/field_type" | |
| 14 13 | 
             
            require "graphql/introspection/directive_location_enum"
         | 
| 15 14 | 
             
            require "graphql/introspection/directive_type"
         | 
| 16 15 | 
             
            require "graphql/introspection/schema_type"
         | 
| 17 | 
            -
            require "graphql/introspection/schema_field"
         | 
| 18 | 
            -
            require "graphql/introspection/type_by_name_field"
         | 
| 19 16 | 
             
            require "graphql/introspection/introspection_query"
         | 
| 20 17 | 
             
            require "graphql/introspection/dynamic_fields"
         | 
| 21 18 | 
             
            require "graphql/introspection/entry_points"
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 | 
             
            module GraphQL
         | 
| 3 3 | 
             
              module Introspection
         | 
| 4 | 
            -
                class DynamicFields <  | 
| 4 | 
            +
                class DynamicFields < Introspection::BaseObject
         | 
| 5 5 | 
             
                  field :__typename, String, "The name of this type", null: false, extras: [:irep_node]
         | 
| 6 6 | 
             
                  def __typename(irep_node:)
         | 
| 7 7 | 
             
                    irep_node.owner_type.name
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 | 
             
            module GraphQL
         | 
| 3 3 | 
             
              module Introspection
         | 
| 4 | 
            -
                class EntryPoints <  | 
| 4 | 
            +
                class EntryPoints < Introspection::BaseObject
         | 
| 5 5 | 
             
                  field :__schema, GraphQL::Schema::LateBoundType.new("__Schema"), "This GraphQL schema", null: false
         | 
| 6 6 | 
             
                  field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system", null: true do
         | 
| 7 7 | 
             
                    argument :name, String, required: true
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 | 
             
            module GraphQL
         | 
| 3 3 | 
             
              module Introspection
         | 
| 4 | 
            -
                class TypeType <  | 
| 4 | 
            +
                class TypeType < Introspection::BaseObject
         | 
| 5 5 | 
             
                  graphql_name "__Type"
         | 
| 6 6 | 
             
                  description "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in "\
         | 
| 7 7 | 
             
                              "GraphQL as represented by the `__TypeKind` enum.\n\n"\
         | 
| @@ -24,7 +24,6 @@ module GraphQL | |
| 24 24 | 
             
                  end
         | 
| 25 25 | 
             
                  field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: true
         | 
| 26 26 | 
             
                  field :of_type, GraphQL::Schema::LateBoundType.new("__Type"), null: true
         | 
| 27 | 
            -
                  introspection true
         | 
| 28 27 |  | 
| 29 28 | 
             
                  def kind
         | 
| 30 29 | 
             
                    @object.kind.name
         | 
| @@ -1651,14 +1651,14 @@ module_eval(<<'.,.,', 'parser.y', 341) | |
| 1651 1651 |  | 
| 1652 1652 | 
             
            module_eval(<<'.,.,', 'parser.y', 345)
         | 
| 1653 1653 | 
             
              def _reduce_141(val, _values, result)
         | 
| 1654 | 
            -
                 return [make_node(:TypeName, name: val[0])]
         | 
| 1654 | 
            +
                 return [make_node(:TypeName, name: val[0], position_source: val[0])]
         | 
| 1655 1655 | 
             
                result
         | 
| 1656 1656 | 
             
              end
         | 
| 1657 1657 | 
             
            .,.,
         | 
| 1658 1658 |  | 
| 1659 1659 | 
             
            module_eval(<<'.,.,', 'parser.y', 346)
         | 
| 1660 1660 | 
             
              def _reduce_142(val, _values, result)
         | 
| 1661 | 
            -
                 val[0] << make_node(:TypeName, name: val[2]) 
         | 
| 1661 | 
            +
                 val[0] << make_node(:TypeName, name: val[2], position_source: val[2]) 
         | 
| 1662 1662 | 
             
                result
         | 
| 1663 1663 | 
             
              end
         | 
| 1664 1664 | 
             
            .,.,
         | 
| @@ -343,8 +343,8 @@ rule | |
| 343 343 | 
             
                  }
         | 
| 344 344 |  | 
| 345 345 | 
             
              union_members:
         | 
| 346 | 
            -
                  name                    { return [make_node(:TypeName, name: val[0])]}
         | 
| 347 | 
            -
                | union_members PIPE name { val[0] << make_node(:TypeName, name: val[2]) }
         | 
| 346 | 
            +
                  name                    { return [make_node(:TypeName, name: val[0], position_source: val[0])]}
         | 
| 347 | 
            +
                | union_members PIPE name { val[0] << make_node(:TypeName, name: val[2], position_source: val[2]) }
         | 
| 348 348 |  | 
| 349 349 | 
             
              union_type_definition:
         | 
| 350 350 | 
             
                  UNION name directives_list_opt EQUALS union_members {
         | 
    
        data/lib/graphql/railtie.rb
    CHANGED
    
    | @@ -40,7 +40,7 @@ module GraphQL | |
| 40 40 | 
             
                        unless File.exists?(destination_file)
         | 
| 41 41 | 
             
                          FileUtils.mkdir_p(File.dirname(destination_file))
         | 
| 42 42 | 
             
                          File.open(destination_file, 'w') do |f|
         | 
| 43 | 
            -
                            f. | 
| 43 | 
            +
                            f.puts "class Types::BaseScalar < GraphQL::Schema::Scalar\nend"
         | 
| 44 44 | 
             
                          end
         | 
| 45 45 | 
             
                        end
         | 
| 46 46 |  | 
| @@ -48,7 +48,7 @@ module GraphQL | |
| 48 48 | 
             
                        unless File.exists?(destination_file)
         | 
| 49 49 | 
             
                          FileUtils.mkdir_p(File.dirname(destination_file))
         | 
| 50 50 | 
             
                          File.open(destination_file, 'w') do |f|
         | 
| 51 | 
            -
                            f. | 
| 51 | 
            +
                            f.puts "class Types::BaseInputObject < GraphQL::Schema::InputObject\nend"
         | 
| 52 52 | 
             
                          end
         | 
| 53 53 | 
             
                        end
         | 
| 54 54 |  | 
| @@ -56,7 +56,7 @@ module GraphQL | |
| 56 56 | 
             
                        unless File.exists?(destination_file)
         | 
| 57 57 | 
             
                          FileUtils.mkdir_p(File.dirname(destination_file))
         | 
| 58 58 | 
             
                          File.open(destination_file, 'w') do |f|
         | 
| 59 | 
            -
                            f. | 
| 59 | 
            +
                            f.puts "class Types::BaseEnum < GraphQL::Schema::Enum\nend"
         | 
| 60 60 | 
             
                          end
         | 
| 61 61 | 
             
                        end
         | 
| 62 62 |  | 
| @@ -64,7 +64,7 @@ module GraphQL | |
| 64 64 | 
             
                        unless File.exists?(destination_file)
         | 
| 65 65 | 
             
                          FileUtils.mkdir_p(File.dirname(destination_file))
         | 
| 66 66 | 
             
                          File.open(destination_file, 'w') do |f|
         | 
| 67 | 
            -
                            f. | 
| 67 | 
            +
                            f.puts "class Types::BaseUnion < GraphQL::Schema::Union\nend"
         | 
| 68 68 | 
             
                          end
         | 
| 69 69 | 
             
                        end
         | 
| 70 70 |  | 
| @@ -72,14 +72,14 @@ module GraphQL | |
| 72 72 | 
             
                        unless File.exists?(destination_file)
         | 
| 73 73 | 
             
                          FileUtils.mkdir_p(File.dirname(destination_file))
         | 
| 74 74 | 
             
                          File.open(destination_file, 'w') do |f|
         | 
| 75 | 
            -
                            f. | 
| 75 | 
            +
                            f.puts "module Types::BaseInterface\n  include GraphQL::Schema::Interface\nend"
         | 
| 76 76 | 
             
                          end
         | 
| 77 77 | 
             
                        end
         | 
| 78 78 |  | 
| 79 79 | 
             
                        destination_file = File.join(base_dir, "types", "base_object.rb")
         | 
| 80 80 | 
             
                        unless File.exists?(destination_file)
         | 
| 81 81 | 
             
                          File.open(destination_file, 'w') do |f|
         | 
| 82 | 
            -
                            f. | 
| 82 | 
            +
                            f.puts "class Types::BaseObject < GraphQL::Schema::Object\nend"
         | 
| 83 83 | 
             
                          end
         | 
| 84 84 | 
             
                        end
         | 
| 85 85 | 
             
                      end
         | 
| @@ -136,13 +136,17 @@ module GraphQL | |
| 136 136 | 
             
                  end
         | 
| 137 137 |  | 
| 138 138 | 
             
                  def visible_type?(type_defn)
         | 
| 139 | 
            -
                    visible?(type_defn) | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 139 | 
            +
                    return false unless visible?(type_defn)
         | 
| 140 | 
            +
                    return true if root_type?(type_defn)
         | 
| 141 | 
            +
                    return true if type_defn.introspection?
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                    if type_defn.kind.union?
         | 
| 144 | 
            +
                      visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
         | 
| 145 | 
            +
                    elsif type_defn.kind.interface?
         | 
| 146 | 
            +
                      visible_possible_types?(type_defn)
         | 
| 147 | 
            +
                    else
         | 
| 148 | 
            +
                      referenced?(type_defn) || visible_abstract_type?(type_defn)
         | 
| 149 | 
            +
                    end
         | 
| 146 150 | 
             
                  end
         | 
| 147 151 |  | 
| 148 152 | 
             
                  def root_type?(type_defn)
         | 
| @@ -154,6 +158,10 @@ module GraphQL | |
| 154 158 | 
             
                    members.any? { |m| visible?(m) }
         | 
| 155 159 | 
             
                  end
         | 
| 156 160 |  | 
| 161 | 
            +
                  def orphan_type?(type_defn)
         | 
| 162 | 
            +
                    @schema.orphan_types.include?(type_defn)
         | 
| 163 | 
            +
                  end
         | 
| 164 | 
            +
             | 
| 157 165 | 
             
                  def visible_abstract_type?(type_defn)
         | 
| 158 166 | 
             
                    type_defn.kind.object? && (
         | 
| 159 167 | 
             
                        interfaces(type_defn).any? ||
         | 
| @@ -161,9 +169,8 @@ module GraphQL | |
| 161 169 | 
             
                      )
         | 
| 162 170 | 
             
                  end
         | 
| 163 171 |  | 
| 164 | 
            -
                  def  | 
| 165 | 
            -
                    (type_defn. | 
| 166 | 
            -
                      @schema.possible_types(type_defn).any? { |t| visible_type?(t) }
         | 
| 172 | 
            +
                  def visible_possible_types?(type_defn)
         | 
| 173 | 
            +
                    @schema.possible_types(type_defn).any? { |t| visible_type?(t) }
         | 
| 167 174 | 
             
                  end
         | 
| 168 175 |  | 
| 169 176 | 
             
                  def visible?(member)
         | 
| @@ -19,7 +19,7 @@ module GraphQL | |
| 19 19 | 
             
                    field = context.warden.get_field(parent_type, ast_field.name)
         | 
| 20 20 |  | 
| 21 21 | 
             
                    if field.nil?
         | 
| 22 | 
            -
                      if | 
| 22 | 
            +
                      if parent_type.kind.union?
         | 
| 23 23 | 
             
                        context.errors << message("Selections can't be made directly on unions (see selections on #{parent_type.name})", parent, context: context)
         | 
| 24 24 | 
             
                      else
         | 
| 25 25 | 
             
                        context.errors << message("Field '#{ast_field.name}' doesn't exist on type '#{parent_type.name}'", ast_field, context: context)
         | 
| @@ -29,8 +29,8 @@ module GraphQL | |
| 29 29 | 
             
                      else
         | 
| 30 30 | 
             
                        "Selections can't be made on scalars (%{node_name} returns #{resolved_type.name} but has selections [#{ast_node.selections.map(&:name).join(", ")}])"
         | 
| 31 31 | 
             
                      end
         | 
| 32 | 
            -
                    elsif resolved_type.kind. | 
| 33 | 
            -
                      " | 
| 32 | 
            +
                    elsif resolved_type.kind.fields? && ast_node.selections.none?
         | 
| 33 | 
            +
                      "Field must have selections (%{node_name} returns #{resolved_type.name} but has no selections. Did you mean '#{ast_node.name} { ... }'?)"
         | 
| 34 34 | 
             
                    else
         | 
| 35 35 | 
             
                      nil
         | 
| 36 36 | 
             
                    end
         | 
| @@ -356,10 +356,10 @@ module GraphQL | |
| 356 356 | 
             
                      # This is not good, it will hit false positives
         | 
| 357 357 | 
             
                      # Should use AST to make this substitution
         | 
| 358 358 | 
             
                      if obj_arg_name != "_"
         | 
| 359 | 
            -
                        proc_body.gsub!(/([^\w:.]|^)#{obj_arg_name}([^\w:]|$)/, '\ | 
| 359 | 
            +
                        proc_body.gsub!(/([^\w:.]|^)#{obj_arg_name}([^\w:]|$)/, '\1object\2')
         | 
| 360 360 | 
             
                      end
         | 
| 361 361 | 
             
                      if ctx_arg_name != "_"
         | 
| 362 | 
            -
                        proc_body.gsub!(/([^\w:.]|^)#{ctx_arg_name}([^\w:]|$)/, '\ | 
| 362 | 
            +
                        proc_body.gsub!(/([^\w:.]|^)#{ctx_arg_name}([^\w:]|$)/, '\1context\2')
         | 
| 363 363 | 
             
                      end
         | 
| 364 364 |  | 
| 365 365 | 
             
                      method_defn = "def #{@proc_name}(**#{args_arg_name})\n#{method_defn_indent}  #{proc_body}\n#{method_defn_indent}end\n"
         | 
| @@ -491,8 +491,8 @@ module GraphQL | |
| 491 491 | 
             
                      # - Get the three argument names (obj, arg, ctx)
         | 
| 492 492 | 
             
                      # - Get the proc body
         | 
| 493 493 | 
             
                      # - Find and replace:
         | 
| 494 | 
            -
                      #  - The ctx argument becomes  | 
| 495 | 
            -
                      #  - The obj argument becomes  | 
| 494 | 
            +
                      #  - The ctx argument becomes `context`
         | 
| 495 | 
            +
                      #  - The obj argument becomes `object`
         | 
| 496 496 | 
             
                      # - Args is trickier:
         | 
| 497 497 | 
             
                      #   - If it's not used, remove it
         | 
| 498 498 | 
             
                      #   - If it's used, abandon ship and make it `**args`
         | 
| @@ -513,10 +513,10 @@ module GraphQL | |
| 513 513 | 
             
                      # This is not good, it will hit false positives
         | 
| 514 514 | 
             
                      # Should use AST to make this substitution
         | 
| 515 515 | 
             
                      if obj_arg_name != "_"
         | 
| 516 | 
            -
                        proc_body.gsub!(/([^\w:.]|^)#{obj_arg_name}([^\w:]|$)/, '\ | 
| 516 | 
            +
                        proc_body.gsub!(/([^\w:.]|^)#{obj_arg_name}([^\w:]|$)/, '\1object\2')
         | 
| 517 517 | 
             
                      end
         | 
| 518 518 | 
             
                      if ctx_arg_name != "_"
         | 
| 519 | 
            -
                        proc_body.gsub!(/([^\w:.]|^)#{ctx_arg_name}([^\w:]|$)/, '\ | 
| 519 | 
            +
                        proc_body.gsub!(/([^\w:.]|^)#{ctx_arg_name}([^\w:]|$)/, '\1context\2')
         | 
| 520 520 | 
             
                      end
         | 
| 521 521 |  | 
| 522 522 | 
             
                      method_def_indent = " " * (processor.resolve_indent - 2)
         | 
    
        data/lib/graphql/version.rb
    CHANGED
    
    
| @@ -13,13 +13,13 @@ module Platform | |
| 13 13 | 
             
                  field :starting_line, Integer, description: "The starting line for the range", null: false
         | 
| 14 14 |  | 
| 15 15 | 
             
                  def starting_line
         | 
| 16 | 
            -
                     | 
| 16 | 
            +
                    object.lines.first[:lineno]
         | 
| 17 17 | 
             
                  end
         | 
| 18 18 |  | 
| 19 19 | 
             
                  field :ending_line, Integer, description: "The ending line for the range", null: false
         | 
| 20 20 |  | 
| 21 21 | 
             
                  def ending_line
         | 
| 22 | 
            -
                     | 
| 22 | 
            +
                    object.lines.first[:lineno] + (object.lines.length - 1)
         | 
| 23 23 | 
             
                  end
         | 
| 24 24 |  | 
| 25 25 | 
             
                  field :commit, Objects::Commit, description: "Identifies the line author", null: false
         | 
| @@ -12,13 +12,13 @@ module Platform | |
| 12 12 |  | 
| 13 13 | 
             
                  def resolve(**inputs)
         | 
| 14 14 | 
             
                    project =  Platform::Helpers::NodeIdentification.typed_object_from_id(
         | 
| 15 | 
            -
                      [Objects::Project], inputs[:project_id],  | 
| 15 | 
            +
                      [Objects::Project], inputs[:project_id], context
         | 
| 16 16 | 
             
                    )
         | 
| 17 17 |  | 
| 18 | 
            -
                     | 
| 19 | 
            -
                     | 
| 18 | 
            +
                    context[:permission].can_modify?("DeleteProject", project).sync
         | 
| 19 | 
            +
                    context[:abilities].authorize_content(:project, :destroy, owner: project.owner)
         | 
| 20 20 |  | 
| 21 | 
            -
                    project.enqueue_delete(actor:  | 
| 21 | 
            +
                    project.enqueue_delete(actor: context[:viewer])
         | 
| 22 22 |  | 
| 23 23 | 
             
                    { owner: project.owner }
         | 
| 24 24 | 
             
                  end
         | 
| @@ -20,7 +20,7 @@ module Platform | |
| 20 20 | 
             
                    { abcDef: 1 }
         | 
| 21 21 | 
             
                    some_method do { xyzAbc: 1 } end
         | 
| 22 22 |  | 
| 23 | 
            -
                    thing = Platform::Helpers::NodeIdentification.typed_object_from_id(Objects::Thing, inputs[:thing_id],  | 
| 23 | 
            +
                    thing = Platform::Helpers::NodeIdentification.typed_object_from_id(Objects::Thing, inputs[:thing_id], context)
         | 
| 24 24 | 
             
                    raise Errors::Validation.new("Thing not found.") unless thing
         | 
| 25 25 |  | 
| 26 26 | 
             
                    ThingActivity.track(thing.id, Time.now.change(min: 0, sec: 0))
         | 
| @@ -13,9 +13,9 @@ module Platform | |
| 13 13 | 
             
                  end
         | 
| 14 14 |  | 
| 15 15 | 
             
                  def viewer_has_starred(**arguments)
         | 
| 16 | 
            -
                    if  | 
| 16 | 
            +
                    if context[:viewer]
         | 
| 17 17 | 
             
                      ->(test_inner_proc) do
         | 
| 18 | 
            -
                         | 
| 18 | 
            +
                        context[:viewer].starred?(object)
         | 
| 19 19 | 
             
                      end
         | 
| 20 20 | 
             
                    else
         | 
| 21 21 | 
             
                      false
         | 
| @@ -27,11 +27,11 @@ module Platform | |
| 27 27 | 
             
                  end
         | 
| 28 28 |  | 
| 29 29 | 
             
                  def stargazers(**arguments)
         | 
| 30 | 
            -
                    scope = case  | 
| 30 | 
            +
                    scope = case object
         | 
| 31 31 | 
             
                    when Repository
         | 
| 32 | 
            -
                       | 
| 32 | 
            +
                      object.stars
         | 
| 33 33 | 
             
                    when Gist
         | 
| 34 | 
            -
                      GistStar.where(gist_id:  | 
| 34 | 
            +
                      GistStar.where(gist_id: object.id)
         | 
| 35 35 | 
             
                    end
         | 
| 36 36 |  | 
| 37 37 | 
             
                    table = scope.table_name
         | 
| @@ -11,17 +11,17 @@ module Platform | |
| 11 11 | 
             
                  field :viewer_subscription, Enums::SubscriptionState, description: "Identifies if the viewer is watching, not watching, or ignoring the subscribable entity.", null: false
         | 
| 12 12 |  | 
| 13 13 | 
             
                  def viewer_subscription
         | 
| 14 | 
            -
                    if  | 
| 14 | 
            +
                    if context[:viewer].nil?
         | 
| 15 15 | 
             
                      return "unsubscribed"
         | 
| 16 16 | 
             
                    end
         | 
| 17 17 |  | 
| 18 | 
            -
                    subscription_status_response =  | 
| 18 | 
            +
                    subscription_status_response = object.async_subscription_status(context[:viewer]).sync
         | 
| 19 19 |  | 
| 20 20 | 
             
                    if subscription_status_response.failed?
         | 
| 21 21 | 
             
                      error = Platform::Errors::ServiceUnavailable.new("Subscriptions are currently unavailable. Please try again later.")
         | 
| 22 | 
            -
                      error.ast_node =  | 
| 23 | 
            -
                      error.path =  | 
| 24 | 
            -
                       | 
| 22 | 
            +
                      error.ast_node = context.irep_node.ast_node
         | 
| 23 | 
            +
                      error.path = context.path
         | 
| 24 | 
            +
                      context.errors << error
         | 
| 25 25 | 
             
                      return "unavailable"
         | 
| 26 26 | 
             
                    end
         | 
| 27 27 |  | 
| @@ -38,9 +38,9 @@ module Platform | |
| 38 38 | 
             
                  field :viewer_can_subscribe, Boolean, description: "Check if the viewer is able to change their subscription status for the repository.", null: false
         | 
| 39 39 |  | 
| 40 40 | 
             
                  def viewer_can_subscribe
         | 
| 41 | 
            -
                    return false if  | 
| 41 | 
            +
                    return false if context[:viewer].nil?
         | 
| 42 42 |  | 
| 43 | 
            -
                     | 
| 43 | 
            +
                    object.async_subscription_status(context[:viewer]).then(&:success?)
         | 
| 44 44 | 
             
                  end
         | 
| 45 45 |  | 
| 46 46 | 
             
                  field :issues, function: Platform::Functions::Issues.new, description: "A list of issues associated with the milestone.", connection: true
         | 
| @@ -23,12 +23,12 @@ module Platform | |
| 23 23 | 
             
                  def f4(**arguments)
         | 
| 24 24 | 
             
                    Class1.new(
         | 
| 25 25 | 
             
                      a: Class2.new(
         | 
| 26 | 
            -
                        b:  | 
| 27 | 
            -
                        c:  | 
| 26 | 
            +
                        b: object.b_1,
         | 
| 27 | 
            +
                        c: object.c_1
         | 
| 28 28 | 
             
                      ),
         | 
| 29 29 | 
             
                      d: Class3.new(
         | 
| 30 | 
            -
                        b:  | 
| 31 | 
            -
                        c:  | 
| 30 | 
            +
                        b: object.b_2,
         | 
| 31 | 
            +
                        c: object.c_3,
         | 
| 32 32 | 
             
                      )
         | 
| 33 33 | 
             
                    )
         | 
| 34 34 | 
             
                  end
         | 
| @@ -46,9 +46,9 @@ module Platform | |
| 46 46 | 
             
                  field :f10, String, null: true
         | 
| 47 47 |  | 
| 48 48 | 
             
                  def f10
         | 
| 49 | 
            -
                     | 
| 49 | 
            +
                    object.something do |_|
         | 
| 50 50 | 
             
                      xyz_obj.obj
         | 
| 51 | 
            -
                       | 
| 51 | 
            +
                      object.f10
         | 
| 52 52 | 
             
                    end
         | 
| 53 53 | 
             
                  end
         | 
| 54 54 | 
             
                end
         | 
| @@ -92,7 +92,7 @@ describe GraphQL::Execution::Multiplex do | |
| 92 92 | 
             
                    },
         | 
| 93 93 | 
             
                    {
         | 
| 94 94 | 
             
                      "errors" => [{
         | 
| 95 | 
            -
                        "message"=>" | 
| 95 | 
            +
                        "message"=>"Field must have selections (field 'nullableNestedSum' returns LazySum but has no selections. Did you mean 'nullableNestedSum { ... }'?)",
         | 
| 96 96 | 
             
                        "locations"=>[{"line"=>1, "column"=>4}],
         | 
| 97 97 | 
             
                        "fields"=>["query", "validationError"]
         | 
| 98 98 | 
             
                      }]
         | 
| @@ -271,7 +271,26 @@ describe GraphQL::ExecutionError do | |
| 271 271 | 
             
                  assert_equal(expected_result, result)
         | 
| 272 272 | 
             
                end
         | 
| 273 273 | 
             
              end
         | 
| 274 | 
            -
             | 
| 274 | 
            +
             | 
| 275 | 
            +
              describe "extensions in ExecutionError" do
         | 
| 276 | 
            +
                let(:query_string) {%|
         | 
| 277 | 
            +
                {
         | 
| 278 | 
            +
                  executionErrorWithExtensions
         | 
| 279 | 
            +
                }
         | 
| 280 | 
            +
                |}
         | 
| 281 | 
            +
                it "the error is inserted into the errors key with custom data set in `extensions`" do
         | 
| 282 | 
            +
                  expected_result = {
         | 
| 283 | 
            +
                    "data"=>{"executionErrorWithExtensions"=>nil},
         | 
| 284 | 
            +
                    "errors"=>
         | 
| 285 | 
            +
                        [{"message"=>"Permission Denied!",
         | 
| 286 | 
            +
                          "locations"=>[{"line"=>3, "column"=>7}],
         | 
| 287 | 
            +
                          "path"=>["executionErrorWithExtensions"],
         | 
| 288 | 
            +
                          "extensions"=>{"code"=>"permission_denied"}}]
         | 
| 289 | 
            +
                  }
         | 
| 290 | 
            +
                  assert_equal(expected_result, result)
         | 
| 291 | 
            +
                end
         | 
| 292 | 
            +
              end
         | 
| 293 | 
            +
             | 
| 275 294 | 
             
              describe "more than one ExecutionError" do
         | 
| 276 295 | 
             
                let(:query_string) { %|{ multipleErrorsOnNonNullableField} |}
         | 
| 277 296 | 
             
                it "the errors are inserted into the errors key and the data is nil even for a NonNullable field " do
         | 
| @@ -30,6 +30,7 @@ describe GraphQL::Introspection::SchemaType do | |
| 30 30 | 
             
                        {"name"=>"deepNonNull"},
         | 
| 31 31 | 
             
                        {"name"=>"error"},
         | 
| 32 32 | 
             
                        {"name"=>"executionError"},
         | 
| 33 | 
            +
                        {"name"=>"executionErrorWithExtensions"},
         | 
| 33 34 | 
             
                        {"name"=>"executionErrorWithOptions"},
         | 
| 34 35 | 
             
                        {"name"=>"favoriteEdible"},
         | 
| 35 36 | 
             
                        {"name"=>"fromSource"},
         | 
| @@ -1,7 +1,18 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 | 
             
            require 'spec_helper'
         | 
| 3 3 |  | 
| 4 | 
            -
             | 
| 4 | 
            +
            if MONGO_DETECTED
         | 
| 5 | 
            +
              require "support/star_trek/data"
         | 
| 6 | 
            +
              require "support/star_trek/schema"
         | 
| 7 | 
            +
            end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            describe GraphQL::Relay::MongoRelationConnection do
         | 
| 10 | 
            +
              before do
         | 
| 11 | 
            +
                if !MONGO_DETECTED
         | 
| 12 | 
            +
                  skip("Mongo not detected")
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 5 16 | 
             
              def get_names(result)
         | 
| 6 17 | 
             
                ships = result["data"]["federation"]["bases"]["edges"]
         | 
| 7 18 | 
             
                ships.map { |e| e["node"]["name"] }
         | 
| @@ -358,6 +358,135 @@ describe GraphQL::Schema::Warden do | |
| 358 358 | 
             
                  assert_equal false, possible_type_names(res["data"]["LanguageMember"]).include?("Phoneme")
         | 
| 359 359 | 
             
                end
         | 
| 360 360 |  | 
| 361 | 
            +
                it "hides interfaces if all possible types are hidden" do
         | 
| 362 | 
            +
                  sdl = %|
         | 
| 363 | 
            +
                    type Query {
         | 
| 364 | 
            +
                      a: String
         | 
| 365 | 
            +
                      repository: Repository
         | 
| 366 | 
            +
                    }
         | 
| 367 | 
            +
             | 
| 368 | 
            +
                    type Repository implements Node {
         | 
| 369 | 
            +
                      id: ID!
         | 
| 370 | 
            +
                    }
         | 
| 371 | 
            +
             | 
| 372 | 
            +
                    interface Node {
         | 
| 373 | 
            +
                      id: ID!
         | 
| 374 | 
            +
                    }
         | 
| 375 | 
            +
                  |
         | 
| 376 | 
            +
             | 
| 377 | 
            +
                  schema = GraphQL::Schema.from_definition(sdl)
         | 
| 378 | 
            +
             | 
| 379 | 
            +
                  query_string = %|
         | 
| 380 | 
            +
                    {
         | 
| 381 | 
            +
                      Node: __type(name: "Node") { name }
         | 
| 382 | 
            +
                    }
         | 
| 383 | 
            +
                  |
         | 
| 384 | 
            +
             | 
| 385 | 
            +
                  res = schema.execute(query_string)
         | 
| 386 | 
            +
                  assert res["data"]["Node"]
         | 
| 387 | 
            +
             | 
| 388 | 
            +
                  res = schema.execute(query_string, except: ->(m, _) { m.name == "Repository" })
         | 
| 389 | 
            +
                  assert_nil res["data"]["Node"]
         | 
| 390 | 
            +
                end
         | 
| 391 | 
            +
             | 
| 392 | 
            +
                it "hides unions if all possible types are hidden or its references are hidden" do
         | 
| 393 | 
            +
                  sdl = "
         | 
| 394 | 
            +
                    type Query {
         | 
| 395 | 
            +
                      bag: BagOfThings
         | 
| 396 | 
            +
                    }
         | 
| 397 | 
            +
             | 
| 398 | 
            +
                    type A {
         | 
| 399 | 
            +
                      id: ID!
         | 
| 400 | 
            +
                    }
         | 
| 401 | 
            +
             | 
| 402 | 
            +
                    type B {
         | 
| 403 | 
            +
                      id: ID!
         | 
| 404 | 
            +
                    }
         | 
| 405 | 
            +
             | 
| 406 | 
            +
                    type C {
         | 
| 407 | 
            +
                      id: ID!
         | 
| 408 | 
            +
                    }
         | 
| 409 | 
            +
             | 
| 410 | 
            +
                    union BagOfThings = A | B | C
         | 
| 411 | 
            +
                  "
         | 
| 412 | 
            +
             | 
| 413 | 
            +
                  schema = GraphQL::Schema.from_definition(sdl)
         | 
| 414 | 
            +
                  schema.orphan_types = []
         | 
| 415 | 
            +
             | 
| 416 | 
            +
                  query_string = %|
         | 
| 417 | 
            +
                    {
         | 
| 418 | 
            +
                      BagOfThings: __type(name: "BagOfThings") { name }
         | 
| 419 | 
            +
                      Query: __type(name: "Query") { fields { name } }
         | 
| 420 | 
            +
                    }
         | 
| 421 | 
            +
                  |
         | 
| 422 | 
            +
             | 
| 423 | 
            +
                  res = schema.execute(query_string)
         | 
| 424 | 
            +
                  assert res["data"]["BagOfThings"]
         | 
| 425 | 
            +
                  assert_equal ["bag"], res["data"]["Query"]["fields"].map { |f| f["name"] }
         | 
| 426 | 
            +
             | 
| 427 | 
            +
                  # Hide the union when all its possible types are gone. This will cause the field to be hidden too.
         | 
| 428 | 
            +
                  res = schema.execute(query_string, except: ->(m, _) { ["A", "B", "C"].include?(m.name) })
         | 
| 429 | 
            +
                  assert_nil res["data"]["BagOfThings"]
         | 
| 430 | 
            +
                  assert_equal [], res["data"]["Query"]["fields"]
         | 
| 431 | 
            +
             | 
| 432 | 
            +
                  res = schema.execute(query_string, except: ->(m, _) { m.name == "bag" })
         | 
| 433 | 
            +
                  assert_nil res["data"]["BagOfThings"]
         | 
| 434 | 
            +
                  assert_equal [], res["data"]["Query"]["fields"]
         | 
| 435 | 
            +
             | 
| 436 | 
            +
                  # Unreferenced but still visible because orphan type
         | 
| 437 | 
            +
                  schema.orphan_types = [schema.find("BagOfThings")]
         | 
| 438 | 
            +
                  res = schema.execute(query_string, except: ->(m, _) { m.name == "bag" })
         | 
| 439 | 
            +
                  assert res["data"]["BagOfThings"]
         | 
| 440 | 
            +
                end
         | 
| 441 | 
            +
             | 
| 442 | 
            +
                it "hides interfaces if all possible types are hidden or its references are hidden" do
         | 
| 443 | 
            +
                  sdl = "
         | 
| 444 | 
            +
                    type Query {
         | 
| 445 | 
            +
                      node: Node
         | 
| 446 | 
            +
                    }
         | 
| 447 | 
            +
             | 
| 448 | 
            +
                    type A implements Node {
         | 
| 449 | 
            +
                      id: ID!
         | 
| 450 | 
            +
                    }
         | 
| 451 | 
            +
             | 
| 452 | 
            +
                    type B implements Node {
         | 
| 453 | 
            +
                      id: ID!
         | 
| 454 | 
            +
                    }
         | 
| 455 | 
            +
             | 
| 456 | 
            +
                    type C implements Node {
         | 
| 457 | 
            +
                      id: ID!
         | 
| 458 | 
            +
                    }
         | 
| 459 | 
            +
             | 
| 460 | 
            +
                    interface Node {
         | 
| 461 | 
            +
                      id: ID!
         | 
| 462 | 
            +
                    }
         | 
| 463 | 
            +
                  "
         | 
| 464 | 
            +
             | 
| 465 | 
            +
                  schema = GraphQL::Schema.from_definition(sdl)
         | 
| 466 | 
            +
             | 
| 467 | 
            +
                  query_string = %|
         | 
| 468 | 
            +
                    {
         | 
| 469 | 
            +
                      Node: __type(name: "Node") { name }
         | 
| 470 | 
            +
                      Query: __type(name: "Query") { fields { name } }
         | 
| 471 | 
            +
                    }
         | 
| 472 | 
            +
                  |
         | 
| 473 | 
            +
             | 
| 474 | 
            +
                  res = schema.execute(query_string)
         | 
| 475 | 
            +
                  assert res["data"]["Node"]
         | 
| 476 | 
            +
                  assert_equal ["node"], res["data"]["Query"]["fields"].map { |f| f["name"] }
         | 
| 477 | 
            +
             | 
| 478 | 
            +
                  # When the possible types are all hidden, hide the interface and fields pointing to it
         | 
| 479 | 
            +
                  res = schema.execute(query_string, except: ->(m, _) { ["A", "B", "C"].include?(m.name) })
         | 
| 480 | 
            +
                  assert_nil res["data"]["Node"]
         | 
| 481 | 
            +
                  assert_equal [], res["data"]["Query"]["fields"]
         | 
| 482 | 
            +
             | 
| 483 | 
            +
                  # Even when it's not the return value of a field,
         | 
| 484 | 
            +
                  # still show the interface since it allows code reuse
         | 
| 485 | 
            +
                  res = schema.execute(query_string, except: ->(m, _) { m.name == "node" })
         | 
| 486 | 
            +
                  assert_equal "Node", res["data"]["Node"]["name"]
         | 
| 487 | 
            +
                  assert_equal [], res["data"]["Query"]["fields"]
         | 
| 488 | 
            +
                end
         | 
| 489 | 
            +
             | 
| 361 490 | 
             
                it "can't be a fragment condition" do
         | 
| 362 491 | 
             
                  query_string = %|
         | 
| 363 492 | 
             
                  {
         | 
| @@ -6,32 +6,40 @@ describe GraphQL::StaticValidation::FieldsHaveAppropriateSelections do | |
| 6 6 | 
             
              let(:query_string) {"
         | 
| 7 7 | 
             
                query getCheese {
         | 
| 8 8 | 
             
                  okCheese: cheese(id: 1) { fatContent, similarCheese(source: YAK) { source } }
         | 
| 9 | 
            -
                   | 
| 9 | 
            +
                  missingFieldsObject: cheese(id: 1)
         | 
| 10 | 
            +
                  missingFieldsInterface: cheese(id: 1) { selfAsEdible }
         | 
| 10 11 | 
             
                  illegalSelectionCheese: cheese(id: 1) { id { something, ... someFields } }
         | 
| 11 12 | 
             
                  incorrectFragmentSpread: cheese(id: 1) { flavor { ... on String { __typename } } }
         | 
| 12 13 | 
             
                }
         | 
| 13 14 | 
             
              "}
         | 
| 14 15 |  | 
| 15 16 | 
             
              it "adds errors for selections on scalars" do
         | 
| 16 | 
            -
                assert_equal( | 
| 17 | 
            +
                assert_equal(4, errors.length)
         | 
| 17 18 |  | 
| 18 19 | 
             
                illegal_selection_error = {
         | 
| 19 20 | 
             
                  "message"=>"Selections can't be made on scalars (field 'id' returns Int but has selections [something, someFields])",
         | 
| 20 | 
            -
                  "locations"=>[{"line"=> | 
| 21 | 
            +
                  "locations"=>[{"line"=>6, "column"=>47}],
         | 
| 21 22 | 
             
                  "fields"=>["query getCheese", "illegalSelectionCheese", "id"],
         | 
| 22 23 | 
             
                }
         | 
| 23 24 | 
             
                assert_includes(errors, illegal_selection_error, "finds illegal selections on scalars")
         | 
| 24 25 |  | 
| 25 | 
            -
                 | 
| 26 | 
            -
                  "message"=>" | 
| 26 | 
            +
                objects_selection_required_error = {
         | 
| 27 | 
            +
                  "message"=>"Field must have selections (field 'cheese' returns Cheese but has no selections. Did you mean 'cheese { ... }'?)",
         | 
| 27 28 | 
             
                  "locations"=>[{"line"=>4, "column"=>7}],
         | 
| 28 | 
            -
                  "fields"=>["query getCheese", " | 
| 29 | 
            +
                  "fields"=>["query getCheese", "missingFieldsObject"],
         | 
| 30 | 
            +
                }
         | 
| 31 | 
            +
                assert_includes(errors, objects_selection_required_error, "finds objects without selections")
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                interfaces_selection_required_error = {
         | 
| 34 | 
            +
                  "message"=>"Field must have selections (field 'selfAsEdible' returns Edible but has no selections. Did you mean 'selfAsEdible { ... }'?)",
         | 
| 35 | 
            +
                  "locations"=>[{"line"=>5, "column"=>47}],
         | 
| 36 | 
            +
                  "fields"=>["query getCheese", "missingFieldsInterface", "selfAsEdible"],
         | 
| 29 37 | 
             
                }
         | 
| 30 | 
            -
                assert_includes(errors,  | 
| 38 | 
            +
                assert_includes(errors, interfaces_selection_required_error, "finds interfaces without selections")
         | 
| 31 39 |  | 
| 32 40 | 
             
                incorrect_fragment_error = {
         | 
| 33 41 | 
             
                  "message"=>"Selections can't be made on scalars (field 'flavor' returns String but has inline fragments [String])",
         | 
| 34 | 
            -
                  "locations"=>[{"line"=> | 
| 42 | 
            +
                  "locations"=>[{"line"=>7, "column"=>48}],
         | 
| 35 43 | 
             
                  "fields"=>["query getCheese", "incorrectFragmentSpread", "flavor"],
         | 
| 36 44 | 
             
                }
         | 
| 37 45 | 
             
                assert_includes(errors, incorrect_fragment_error, "finds scalar fields with selections")
         | 
| @@ -43,7 +51,7 @@ describe GraphQL::StaticValidation::FieldsHaveAppropriateSelections do | |
| 43 51 | 
             
                  assert_equal(1, errors.length)
         | 
| 44 52 |  | 
| 45 53 | 
             
                  selections_required_error = {
         | 
| 46 | 
            -
                    "message"=> " | 
| 54 | 
            +
                    "message"=> "Field must have selections (anonymous query returns Query but has no selections. Did you mean ' { ... }'?)",
         | 
| 47 55 | 
             
                    "locations"=>[{"line"=>1, "column"=>1}],
         | 
| 48 56 | 
             
                    "fields"=>["query"]
         | 
| 49 57 | 
             
                  }
         | 
| @@ -195,7 +195,7 @@ RUBY | |
| 195 195 | 
             
                end
         | 
| 196 196 |  | 
| 197 197 | 
             
                describe "resolve proc to method" do
         | 
| 198 | 
            -
                  it "converts  | 
| 198 | 
            +
                  it "converts object and context" do
         | 
| 199 199 | 
             
                    old = %{
         | 
| 200 200 | 
             
                      field :firstName, !types.String do
         | 
| 201 201 | 
             
                        resolve ->(obj, arg, ctx) {
         | 
| @@ -211,11 +211,11 @@ RUBY | |
| 211 211 | 
             
                      field :first_name, String, null: false
         | 
| 212 212 |  | 
| 213 213 | 
             
                      def first_name
         | 
| 214 | 
            -
                         | 
| 214 | 
            +
                        context.something
         | 
| 215 215 | 
             
                        other_ctx # test combined identifiers
         | 
| 216 216 |  | 
| 217 | 
            -
                         | 
| 218 | 
            -
                         | 
| 217 | 
            +
                        object[context] + object
         | 
| 218 | 
            +
                        object.given_name
         | 
| 219 219 | 
             
                      end
         | 
| 220 220 | 
             
                    }
         | 
| 221 221 | 
             
                    assert_equal new, upgrade(old)
         | 
| @@ -233,7 +233,7 @@ RUBY | |
| 233 233 | 
             
                      field :first_name, String, null: false
         | 
| 234 234 |  | 
| 235 235 | 
             
                      def first_name
         | 
| 236 | 
            -
                         | 
| 236 | 
            +
                        object.given_name
         | 
| 237 237 | 
             
                      end
         | 
| 238 238 | 
             
                    }
         | 
| 239 239 | 
             
                    assert_equal new, upgrade(old)
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -27,6 +27,22 @@ require "pry" | |
| 27 27 | 
             
            require "minitest/autorun"
         | 
| 28 28 | 
             
            require "minitest/focus"
         | 
| 29 29 | 
             
            require "minitest/reporters"
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            MONGO_DETECTED = begin
         | 
| 32 | 
            +
              require "mongo"
         | 
| 33 | 
            +
              Mongo::Client.new('mongodb://127.0.0.1:27017/graphql_ruby_test',
         | 
| 34 | 
            +
                  connect_timeout: 1,
         | 
| 35 | 
            +
                  socket_timeout: 1,
         | 
| 36 | 
            +
                  server_selection_timeout: 1,
         | 
| 37 | 
            +
                  logger: Logger.new(nil)
         | 
| 38 | 
            +
                )
         | 
| 39 | 
            +
                .database
         | 
| 40 | 
            +
                .collections
         | 
| 41 | 
            +
            rescue StandardError, LoadError => err # rubocop:disable Lint/UselessAssignment
         | 
| 42 | 
            +
              # puts err.message, err.backtrace
         | 
| 43 | 
            +
              false
         | 
| 44 | 
            +
            end
         | 
| 45 | 
            +
             | 
| 30 46 | 
             
            Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new(color: true)
         | 
| 31 47 |  | 
| 32 48 | 
             
            Minitest::Spec.make_my_diffs_pretty!
         | 
| @@ -62,9 +78,12 @@ NO_OP_RESOLVE_TYPE = ->(type, obj, ctx) { | |
| 62 78 |  | 
| 63 79 | 
             
            # Load support files
         | 
| 64 80 | 
             
            Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each do |f|
         | 
| 81 | 
            +
              # These require mongodb in order to run,
         | 
| 82 | 
            +
              # so only load them in the specific tests that require them.
         | 
| 83 | 
            +
              next if f.include?("star_trek")
         | 
| 84 | 
            +
             | 
| 65 85 | 
             
              unless rails_should_be_installed?
         | 
| 66 86 | 
             
                next if f.end_with?('star_wars/data.rb')
         | 
| 67 | 
            -
                next if f.end_with?('star_trek/data.rb')
         | 
| 68 87 | 
             
                next if f.end_with?('base_generator_test.rb')
         | 
| 69 88 | 
             
              end
         | 
| 70 89 | 
             
              require f
         | 
| @@ -381,6 +381,13 @@ module Dummy | |
| 381 381 | 
             
                  }
         | 
| 382 382 | 
             
                end
         | 
| 383 383 |  | 
| 384 | 
            +
                field :executionErrorWithExtensions do
         | 
| 385 | 
            +
                  type GraphQL::INT_TYPE
         | 
| 386 | 
            +
                  resolve ->(t, a, c) {
         | 
| 387 | 
            +
                    GraphQL::ExecutionError.new("Permission Denied!", extensions: { "code" => "permission_denied" })
         | 
| 388 | 
            +
                  }
         | 
| 389 | 
            +
                end
         | 
| 390 | 
            +
             | 
| 384 391 | 
             
                # To test possibly-null fields
         | 
| 385 392 | 
             
                field :maybeNull, MaybeNullType do
         | 
| 386 393 | 
             
                  resolve ->(t, a, c) { OpenStruct.new(cheese: nil) }
         | 
    
        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.8. | 
| 4 | 
            +
              version: 1.8.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Robert Mosolgo
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2018- | 
| 11 | 
            +
            date: 2018-06-01 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: benchmark-ips
         | 
| @@ -304,20 +304,6 @@ dependencies: | |
| 304 304 | 
             
                - - ">="
         | 
| 305 305 | 
             
                  - !ruby/object:Gem::Version
         | 
| 306 306 | 
             
                    version: '0'
         | 
| 307 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 308 | 
            -
              name: algoliasearch-jekyll
         | 
| 309 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 310 | 
            -
                requirements:
         | 
| 311 | 
            -
                - - ">="
         | 
| 312 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 313 | 
            -
                    version: '0'
         | 
| 314 | 
            -
              type: :development
         | 
| 315 | 
            -
              prerelease: false
         | 
| 316 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 317 | 
            -
                requirements:
         | 
| 318 | 
            -
                - - ">="
         | 
| 319 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 320 | 
            -
                    version: '0'
         | 
| 321 307 | 
             
            description: A plain-Ruby implementation of GraphQL.
         | 
| 322 308 | 
             
            email:
         | 
| 323 309 | 
             
            - rdmosolgo@gmail.com
         | 
| @@ -433,12 +419,9 @@ files: | |
| 433 419 | 
             
            - lib/graphql/introspection/field_type.rb
         | 
| 434 420 | 
             
            - lib/graphql/introspection/input_value_type.rb
         | 
| 435 421 | 
             
            - lib/graphql/introspection/introspection_query.rb
         | 
| 436 | 
            -
            - lib/graphql/introspection/schema_field.rb
         | 
| 437 422 | 
             
            - lib/graphql/introspection/schema_type.rb
         | 
| 438 | 
            -
            - lib/graphql/introspection/type_by_name_field.rb
         | 
| 439 423 | 
             
            - lib/graphql/introspection/type_kind_enum.rb
         | 
| 440 424 | 
             
            - lib/graphql/introspection/type_type.rb
         | 
| 441 | 
            -
            - lib/graphql/introspection/typename_field.rb
         | 
| 442 425 | 
             
            - lib/graphql/invalid_name_error.rb
         | 
| 443 426 | 
             
            - lib/graphql/invalid_null_error.rb
         | 
| 444 427 | 
             
            - lib/graphql/language.rb
         | 
| @@ -1005,7 +988,6 @@ files: | |
| 1005 988 | 
             
            - spec/graphql/introspection/input_value_type_spec.rb
         | 
| 1006 989 | 
             
            - spec/graphql/introspection/introspection_query_spec.rb
         | 
| 1007 990 | 
             
            - spec/graphql/introspection/schema_type_spec.rb
         | 
| 1008 | 
            -
            - spec/graphql/introspection/type_by_name_field_spec.rb
         | 
| 1009 991 | 
             
            - spec/graphql/introspection/type_type_spec.rb
         | 
| 1010 992 | 
             
            - spec/graphql/language/block_string_spec.rb
         | 
| 1011 993 | 
             
            - spec/graphql/language/definition_slice_spec.rb
         | 
| @@ -1553,7 +1535,6 @@ test_files: | |
| 1553 1535 | 
             
            - spec/graphql/introspection/input_value_type_spec.rb
         | 
| 1554 1536 | 
             
            - spec/graphql/introspection/introspection_query_spec.rb
         | 
| 1555 1537 | 
             
            - spec/graphql/introspection/schema_type_spec.rb
         | 
| 1556 | 
            -
            - spec/graphql/introspection/type_by_name_field_spec.rb
         | 
| 1557 1538 | 
             
            - spec/graphql/introspection/type_type_spec.rb
         | 
| 1558 1539 | 
             
            - spec/graphql/language/block_string_spec.rb
         | 
| 1559 1540 | 
             
            - spec/graphql/language/definition_slice_spec.rb
         | 
| @@ -1,16 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
            module GraphQL
         | 
| 3 | 
            -
              module Introspection
         | 
| 4 | 
            -
                SchemaField = GraphQL::Field.define do
         | 
| 5 | 
            -
                  name("__schema")
         | 
| 6 | 
            -
                  description("This GraphQL schema")
         | 
| 7 | 
            -
                  type(GraphQL::Schema::LateBoundType.new("__Schema").to_non_null_type)
         | 
| 8 | 
            -
                  resolve ->(o, a, ctx) {
         | 
| 9 | 
            -
                    # Apply wrapping manually since this field isn't wrapped by instrumentation
         | 
| 10 | 
            -
                    schema = ctx.query.schema
         | 
| 11 | 
            -
                    schema_type = schema.introspection_system.schema_type
         | 
| 12 | 
            -
                    schema_type.metadata[:type_class].new(schema, ctx.query.context)
         | 
| 13 | 
            -
                  }
         | 
| 14 | 
            -
                end
         | 
| 15 | 
            -
              end
         | 
| 16 | 
            -
            end
         | 
| @@ -1,22 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
            module GraphQL
         | 
| 3 | 
            -
              module Introspection
         | 
| 4 | 
            -
                TypeByNameField = GraphQL::Field.define do
         | 
| 5 | 
            -
                  name("__type")
         | 
| 6 | 
            -
                  description("A type in the GraphQL system")
         | 
| 7 | 
            -
                  introspection true
         | 
| 8 | 
            -
                  type(GraphQL::Schema::LateBoundType.new("__Type"))
         | 
| 9 | 
            -
                  argument :name, !types.String
         | 
| 10 | 
            -
                  resolve ->(o, args, ctx) {
         | 
| 11 | 
            -
                    type = ctx.warden.get_type(args["name"])
         | 
| 12 | 
            -
                    if type
         | 
| 13 | 
            -
                      # Apply wrapping manually since this field isn't wrapped by instrumentation
         | 
| 14 | 
            -
                      type_type = ctx.schema.introspection_system.type_type
         | 
| 15 | 
            -
                      type_type.metadata[:type_class].new(type, ctx)
         | 
| 16 | 
            -
                    else
         | 
| 17 | 
            -
                      nil
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
                  }
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
              end
         | 
| 22 | 
            -
            end
         | 
| @@ -1,12 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
            module GraphQL
         | 
| 3 | 
            -
              module Introspection
         | 
| 4 | 
            -
                TypenameField = GraphQL::Field.define do
         | 
| 5 | 
            -
                  name "__typename"
         | 
| 6 | 
            -
                  description "The name of this type"
         | 
| 7 | 
            -
                  type -> { !GraphQL::STRING_TYPE }
         | 
| 8 | 
            -
                  introspection true
         | 
| 9 | 
            -
                  resolve ->(obj, a, ctx) { ctx.irep_node.owner_type }
         | 
| 10 | 
            -
                end
         | 
| 11 | 
            -
              end
         | 
| 12 | 
            -
            end
         | 
| @@ -1,38 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
            require "spec_helper"
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            describe GraphQL::Introspection::TypeByNameField do
         | 
| 5 | 
            -
              describe "after instrumentation" do
         | 
| 6 | 
            -
                # Just make sure it returns a new object, not the original field
         | 
| 7 | 
            -
                class DupInstrumenter
         | 
| 8 | 
            -
                  def self.instrument(t, f)
         | 
| 9 | 
            -
                    f.redefine {
         | 
| 10 | 
            -
                      resolve ->(o, a, c) { :no_op }
         | 
| 11 | 
            -
                    }
         | 
| 12 | 
            -
                  end
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                class ArgAnalyzer
         | 
| 16 | 
            -
                  def call(_, _, node)
         | 
| 17 | 
            -
                    if node.ast_node.is_a?(GraphQL::Language::Nodes::Field)
         | 
| 18 | 
            -
                      node.arguments
         | 
| 19 | 
            -
                    end
         | 
| 20 | 
            -
                  end
         | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
             | 
| 23 | 
            -
                let(:instrumented_schema) {
         | 
| 24 | 
            -
                  # This was probably assigned earlier in the test suite, but to simulate an application, clear it.
         | 
| 25 | 
            -
                  GraphQL::Introspection::TypeByNameField.arguments_class = nil
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                  Dummy::Schema.redefine {
         | 
| 28 | 
            -
                    instrument(:field, DupInstrumenter)
         | 
| 29 | 
            -
                    query_analyzer(ArgAnalyzer.new)
         | 
| 30 | 
            -
                  }
         | 
| 31 | 
            -
                }
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                it "still works with __type" do
         | 
| 34 | 
            -
                  res = instrumented_schema.execute("{ __type(name: \"X\") { name } }")
         | 
| 35 | 
            -
                  assert_equal({"data"=>{"__type"=>nil}}, res)
         | 
| 36 | 
            -
                end
         | 
| 37 | 
            -
              end
         | 
| 38 | 
            -
            end
         |