DataMapperで比較的高速にidだけ取得する

dm-core-1.2.0の話です。

現在の検索条件でidだけ取得したい、、10000件くらい。って要望、よくあると思う。:fieldsで指定しても、モデルのインスタンスを作るため、sqlを直接実行した時にはかなわなかったりする。

なので、DataMapper::Collectionに次のようなメソッドを生やしている。

module DataMapper
  class Collection < LazyArray
    def select_statement(repository_name = :default)
      DataMapper.repository(repository_name).adapter.__send__(:select_statement, self.query)
    end

    def sql_select(repository_name = :default)
      return [] unless self.query.valid?
      sql, args = select_statement(repository_name)
      DataMapper.repository(repository_name).adapter.select(sql, *args)
    end
  end
end

モデルのクラスメソッドにしないのは、クエリチェインするとクエリが壊れる恐れがある ため。

SQLとパラメータの取得方法についてはmonoさんの記事を参考しにした。

使い方

:fields と組み合わせて使う。 :fields で指定した要素が1つの場合はStructを作らずに値がそのまま入るので便利。

User.all(:name.like => 'a%').all(fields: [:id]).sql_select
# => [1,2,3]

参考