module RelationToStruct::ActiveRecordRelationExtension
  extend ::ActiveSupport::Concern

  def to_structs(struct_class)
    raise ArgumentError, 'Expected select_values to be present' unless self.select_values.present?

    relation = spawn

    # See the definition of #pluck in:
    # activerecord/lib/active_record/relation/calculations.rb
    result = klass.connection.select_all(relation.arel)

    if result.columns.size != struct_class.members.size
      raise ArgumentError, 'Expected struct fields and columns lengths to be equal'
    end

    if result.columns.size != result.columns.uniq.size
      raise ArgumentError, 'Expected column names to be unique'
    end

    values_after_casting = result.cast_values()

    if result.columns.size == 1
      values_after_casting.map do |tuple|
        struct_class.new(tuple)
      end
    else
      values_after_casting.map do |tuple|
        struct_class.new(*tuple)
      end
    end
  end
end

::ActiveRecord::Relation.send(:include, RelationToStruct::ActiveRecordRelationExtension)

module RelationToStruct::ActiveRecordRelationExtension
  extend ::ActiveSupport::Concern

  def to_structs(struct_class)
    raise ArgumentError, 'Expected select_values to be present' unless self.select_values.present?

    relation = spawn

    # See the definition of #pluck in:
    # activerecord/lib/active_record/relation/calculations.rb
    result = nil
    if ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR < 2
      result = klass.connection.select_all(relation.arel, nil, bound_attributes)
    else
      result = klass.connection.select_all(relation.arel)
    end

    if result.columns.size != struct_class.members.size
      raise ArgumentError, 'Expected struct fields and columns lengths to be equal'
    end

    if result.columns.size != result.columns.uniq.size
      raise ArgumentError, 'Expected column names to be unique'
    end

    values_after_casting = result.cast_values()

    if result.columns.size == 1
      values_after_casting.map do |tuple|
        struct_class.new(tuple)
      end
    else
      values_after_casting.map do |tuple|
        struct_class.new(*tuple)
      end
    end
  end
end

::ActiveRecord::Relation.send(:include, RelationToStruct::ActiveRecordRelationExtension)

Fix regressions in 5.0 and 5.1.
Fix regressions in 5.0 and 5.1.

When I merged the PR supporting 5.2, I didn't realize that CI wasn't
running appraisal (or sqlite), so breakages in previous versions weren't
apparent. I've since updated CI to run all variants. This restores the
code path for < 5.2 and keeps the new path for 5.2+.
