Trabajando con Arel
ActiveRecord en Rails 3.0 sufrió un cambio significativo al cambiar la forma en como se generan las consultas de SQL. Y es que a partir de esta versión, ActiveRecord hace uso de ARel.
ARel es su definición oficial es la “Interpretación Orientada a Objetos de Algebra Relacional”, siendo la Algebra Relacional un modelo matemático para la representación de “queries” sobre datos.
Y si llegaron a este punto y leyeron palabras como “álgebra”, “matemático”; no, no paren de leer.
Algebra Relacional, suena como a algo “muy matemático”, ¿pero en términos de ActiveRecord que beneficios tenemos o en que se traduce?
Bueno hay 2 beneficios muy visibles del uso de ARel.
Primeramente ActiveRecord nos permite encadenar “queries”, lo que se traduce que programaticamente podemos crear consultas mas complejas, pero también nos ayuda a realizar una refactorizacion mas simple para eliminar duplicidad.
» Company.where(:code => ‘TST’).to_sql
=> “SELECT `companies`.* FROM `companies` WHERE (`companies`.`code` = ‘TST’) ORDER BY code desc”
» Company.where(:code => ‘TST’).where(:name => ‘Company’).to_sql
=> “SELECT `companies`.* FROM `companies` WHERE (`companies`.`code` = ‘TST’) AND (`companies`.`name` = ‘Company’) ORDER BY code desc”
» Company.where(:code => ‘TST’).order(:active).limit(20).to_sql
=> “SELECT `companies`.* FROM `companies` WHERE (`companies`.`code` = ‘TST’) ORDER BY code desc, active LIMIT 20”
ActiveRecord hace un buen trabajo creando una abstracción sobre ARel, con una interface simple para hacer consultas.
El segundo punto importante es que al momento de formar una consulta programaticamente ARel nos proporciona un objeto Query, el cual un no se ejecuta y que nos permite agregar mas “queries” a nuestra consulta en base a la información que nos proporciona el usuario.
» query = Company.where(:code => ‘TST’)
» query = query.order(:active)
» query = query.limit(20)
» query.to_sql
=> “SELECT `companies`.* FROM `companies` WHERE (`companies`.`code` = ‘TST’) ORDER BY code desc, active LIMIT 20”
Es decir podemos modificar nuestra consulta programaticamente antes de que sea enviada al servidor de base de datos para su ejecución.
A través del API de ActiveRecord podemos crear consultas de cierta complejidad, pero llega un momento en que la única forma de escribir nuestra consulta es usar código de SQL parcialmente, por ejemplo: No podemos escribir una consulta con OR únicamente usando el API de ActiveRecord.
» Company.where(‘code = ? or name = ?’, ‘TST’, ‘Company’).to_sql
=> “SELECT `companies`.* FROM `companies` WHERE (code = ‘TST’ or name = ‘Company’) ORDER BY code desc”
Podemos notar el ‘code = ? or name = ?’, ‘TST’, ‘Company’ que no se ve muy orientado a objetos. En las consultas mostradas previamente en este post hemos usado ARel de manera indirecta, ahora llega el momento de usarlo directamente para que nuestra consulta nuevamente se “sienta” mas orientada a objetos.
Lo primero que tenemos que hacer para utilizar ARel directamente es contar con la referencia de la tabla sobre la que vamos a ejecutar nuestra consulta, esto lo hacemos a través de nuestro modelo:
» company_table = Company.arel_table
Ahora podemos crear una consulta de la siguiente manera:
» company_table[:code].eq(‘TST’).to_sql
=> “`companies`.`code` = ‘TST’”
» Company.where(company_table[:code].eq(‘TST’)).order(‘code desc’).to_sql
=> “SELECT `companies`.* FROM `companies` WHERE (`companies`.`code` = ‘TST’) ORDER BY code desc”
Para lograr nuestra consulta con OR usando ARel en conjunto con ActiveRecord, simplemente tenemos que construir la parte del OR con ARel y dejar el resto a ActiveRecord.
» Company.where(company_table[:code].eq(‘TST’).or(company_table[:name].eq(‘Company’))).to_sql
=> “SELECT `companies`.* FROM `companies` WHERE ((`companies`.`code` = ‘TST’ OR `companies`.`name` = ‘Company’)) ORDER BY code desc”
Como podemos ver ARel es una buen avance sobre ActiveRecord en Rails para la realización de consultas, algo positivo es que aunque ActiveRecord nos presenta su API para consultas, no es posible acceder a ARel directamente.
Actualmente ARel es solo utilizado en ActiveRecord, por lo que tiene una conexión a este, pero en e sitio de ARel mencionan que dentro de los planes a futuro esta el romper esta relación, haciendo posible que ARel pueda utilizarse fuera de Rails y que el motor generador de las consultas trabaje con otros repositorios fuera de RBDMS, como puede ser XML o IMAP.
