Every store has a beginning
Last year I had the honor to participate in Google Summer of Code, my proposal was the integration of Arel into ActiveRecord.
This was a very exciting experience and I would encourage anyone to jump in and participate in next editions. Want to take this opportunity to thank once again to my mentor Bryan Helmkamp and the Rails core team for their guidance.
Few months later the project was merged into Rails and not a long time passed before Pratik Naik making use of relations and Arel created the new Active Record Query Interface which will be included in Rails 3.
Now let’s get down to business.
Arel SQL compilers
I have extracted SQL logic from Arel::Relation into compilers, making Arel easier to extend and support new database adapters.
A GenericCompiler is provided by Arel, here’s an extract of it:
module Arel
module SqlCompiler
class GenericCompiler
attr_reader :relation
def initialize(relation)
@relation = relation
end
def select_sql
build_query \
"SELECT #{select_clauses.join(', ')}",
"FROM #{from_clauses}",
(joins(self) unless joins(self).blank? ),
("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ),
("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ),
("HAVING #{having_clauses.join(', ')}" unless havings.blank? ),
("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ),
("LIMIT #{taken}" unless taken.blank? ),
("OFFSET #{skipped}" unless skipped.blank? ),
("#{locked}" unless locked.blank?)
end
def limited_update_conditions(conditions)
begin
quote_primary_key = engine.quote_column_name(table.name.classify.constantize.primary_key)
rescue NameError
quote_primary_key = engine.quote_column_name("id")
end
"WHERE #{quote_primary_key} IN (SELECT #{quote_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})"
end
# ....
Arel supports MySQL, PostgreSQL and SQLite3 but while I’m writing this, people are working on IBM/DB, Oracle, DO, etc.
Compilers
MySQL compiler inherits from GenericCompiler but redefines limited_update_conditions to return raw conditions since no workaround is needed in this case:
module Arel
module SqlCompiler
class MySQLCompiler < GenericCompiler
def limited_update_conditions(conditions)
conditions
end
end
end
end
In SQLite compiler locks are overridden to return nil since it uses reader/writer locks to control access to the database and the use of explicit locking may generate an invalid query:
module Arel
module SqlCompiler
class SQLiteCompiler < GenericCompiler
def locked
nil
end
end
end
end
Have your own compiler? Send a patch or even better, send a pull request!
