Repository: rails/rails
File: activerecord/lib/active_record/relation/calculations.rb (Ruby)

Code before:
    def pick(*column_names)
      if loaded? && all_attributes?(column_names)
        result = records.pick(*column_names)
        return @async ? Promise::Complete.new(result) : result
      end

      limit(1).pluck(*column_names).then(&:first)
    end

    # Same as <tt>#pick</tt> but perform the query asynchronously and returns an <tt>ActiveRecord::Promise</tt>
    def async_pick(*column_names)
      async.pick(*column_names)
    end

    # Returns the base model's ID's for the relation using the table's primary key
    #
    #   Person.ids # SELECT people.id FROM people
    #   Person.joins(:companies).ids # SELECT people.id FROM people INNER JOIN companies ON companies.id = people.company_id
    def ids
      if loaded?
        result = records.pluck(*Array(primary_key))
        return @async ? Promise::Complete.new(result) : result
      end

      if has_include?(primary_key)
        relation = apply_join_dependency.distinct
        return relation.ids
      end

      columns = arel_columns(Array(primary_key))
      relation = spawn
      relation.select_values = columns
      result = if relation.where_clause.contradiction?
        ActiveRecord::Result.empty
      else
        skip_query_cache_if_necessary do
          klass.connection.select_all(relation, "#{klass.name} Ids", async: @async)
        end
      end

      result.then { |result| type_cast_pluck_values(result, columns) }
    end

    # Same as <tt>#ids</tt> but perform the query asynchronously and returns an <tt>ActiveRecord::Promise</tt>
    def async_ids
      async.ids
    end

    private
      def all_attributes?(column_names)
        (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?

Review comment (suggestion):
As far as I understand technically we could keep using `distinct` and only switch to `group` in case if `order_values` are present, right? Something like:
```ruby
relation = apply_join_dependency
relation = if order_values.empty?
 relation.distinct
else
 relation.group(*primary_keys)
end
```

But there is no reason in doing that as database executes these in the same way based on

>group will give us the same result using the same execution plan.

I guess if someone runs into a concern with using `group` we can think of adding a branch but for now using `group` all the times seems reasonable



Code after:
    def pick(*column_names)
      if loaded? && all_attributes?(column_names)
        result = records.pick(*column_names)
        return @async ? Promise::Complete.new(result) : result
      end

      limit(1).pluck(*column_names).then(&:first)
    end

    # Same as <tt>#pick</tt> but perform the query asynchronously and returns an <tt>ActiveRecord::Promise</tt>
    def async_pick(*column_names)
      async.pick(*column_names)
    end

    # Returns the base model's ID's for the relation using the table's primary key
    #
    #   Person.ids # SELECT people.id FROM people
    #   Person.joins(:companies).ids # SELECT people.id FROM people INNER JOIN companies ON companies.id = people.company_id
    def ids
      primary_key_array = Array(primary_key)

      if loaded?
        result = records.pluck(*primary_key_array)
        return @async ? Promise::Complete.new(result) : result
      end

      if has_include?(primary_key)
        relation = apply_join_dependency.group(*primary_key_array)
        return relation.ids
      end

      columns = arel_columns(primary_key_array)
      relation = spawn
      relation.select_values = columns

      result = if relation.where_clause.contradiction?
        ActiveRecord::Result.empty
      else
        skip_query_cache_if_necessary do
          klass.connection.select_all(relation, "#{klass.name} Ids", async: @async)
        end
      end

      result.then { |result| type_cast_pluck_values(result, columns) }
    end

    # Same as <tt>#ids</tt> but perform the query asynchronously and returns an <tt>ActiveRecord::Promise</tt>
    def async_ids
      async.ids
    end