datamapperでfind(:select => '')みたいなことはできない

dm-core (0.9.11)の話

ARだと、

User.find( :all, :select => 'DISTINCT mail_addr' )

のように、select文を直接書くことができるけど、これはdatamapperではできないらしい。


SQL文を生成しているのはdata_objects_adapter.rbに書かれているread_statementで,fields_statementがSELECTの中身を生成している。

def read_statement(query)
  statement = "SELECT #{fields_statement(query)}"
  statement << " FROM #{quote_table_name(query.model.storage_name(query.repository.name))}"
  statement << links_statement(query)                        if query.links.any?
  statement << " WHERE #{conditions_statement(query)}"       if query.conditions.any?
  statement << " GROUP BY #{group_by_statement(query)}"      if query.unique? && query.fields.any? { |p| p.kind_of?(Property) }
  statement << " ORDER BY #{order_statement(query)}"         if query.order.any?
  statement << " LIMIT #{quote_column_value(query.limit)}"   if query.limit
  statement << " OFFSET #{quote_column_value(query.offset)}" if query.offset && query.offset > 0
  statement
rescue => e
  DataMapper.logger.error("QUERY INVALID: #{query.inspect} (#{e})")
  raise e
end

こんなふうに。

def fields_statement(query)
  qualify = query.links.any?
  query.fields.map { |p| property_to_column_name(query.repository, p, qualify) } * ', '
end
def property_to_column_name(repository, property, qualify)
  table_name = property.model.storage_name(repository.name) if property && property.respond_to?(:model)

  if table_name && qualify # <- qualifyはlinksが存在するかどうか
    "#{quote_table_name(table_name)}.#{quote_column_name(property.field(repository.name))}"
  else
    quote_column_name(property.field(repository.name))
  end
end

property_to_column_nameはrepositoryとpropertyとを受け取ってそれをカラム名にする。カラム名としてはpropertyのfieldが使われる。そして、property.fieldはクオートされる。
だから無理矢理property :foo , :field => 'var + baz as foo'としても、クオートされるのでSQLが通らない。
なので、 SELECT var + baz as foo from ...というSQL文は書けない。