07 mayo, 2009

jLinq, el LINQ de Javascript

jLinq es una versión Javascript del popular lenguaje LINQ (Language Integrated Query) de Microsoft que permite consultas nativas semejantes a las de SQL en los lenguajes .NET.

En este caso, jLinq ataca a arrays de objetos Javascript en memoria y permite realizar consultas sobre ellos con una sintaxis basada en funciones encadenadas (como jQuery), pero que contiene todos los componentes para seleccionar y filtrar que ofrece SQL. Por ejemplo:

var results = jLinq.from(data.users)
    .startsWith("first", "a")
    .or("j").or("m")
    .orEndsWith("y")
    .orderBy("admin","age")
    .select();
Es fácil identificar la función from() (indica el array de objetos sobre el que se realizará la consulta), la función orderBy() (ordena los resultados a partir de los campos indicados) y la función select() (devuelve los datos filtrados hasta el momento). El resto de funciones emulan las posibilidades que SQL ofrece en la cláusula "where".

En concreto, el ejemplo anterior obtiene los usuarios cuyo nombre(first) empiece por "a", "j" o "m" o que termine por "y", y los ordena por los campos administrador(admin) y edad(age).

La demo de jLinq incluye un completo tutorial para aprender sus posibilidades paso a paso, permitiendo probar online los resultados de las consultas de ejemplo. Algunos apuntes:

  • Por defecto se entiende que las funciones de filtrado se unen por ANDs (y lógico) a menos que se especifique expresamente la función or().
  • Si queremos obtener una lista de los usuarios que son administradores junto con los que no lo son pero tienen permiso de borrado, NO podemos hacer lo siguiente ya que todo se evalua a la vez y la consulta no devolvería nada:
var results = jLinq.from(data.users) 
.is("admin") 
.isNot("admin") 
.contains("permissions", "delete") 
.select(); 
La forma correcta es:
var results = jLinq.from(data.users)  
.is("admin") 
.orCombine(function(q) { 
q.isNot("admin") 
.contains("permissions", "delete"); 
}) 
.orderBy("admin") 
.select();
  • Una forma de obtener los usuarios que empiecen por a,b,c,d,e y ordenarlos inversamente:
jLinq.from(data.users).startsWith('first', ['a','b','c','d','e']).orderBy("-first").select();
  • Para el típico join de dos tablas (aquí data.users y data.locations):
var results = jLinq.from(data.users) 
.join(data.locations, //el array fuente 
"location", //el alias a usar (cuando se haga el join) 
"locationId", // el id de localización del user 
"id" // el id de localización 
) 
.select(function(r) { 
return { 
fullname:r.first + " " + r.last, 
city:r.location.city, 
state:r.location.state 
}; 
}); 
Básicamente realiza una consulta en la tabla data.locations uniendo el campo locationId de data.users con el campo id de data.locations. También se puede observar como seleccionar los campos a visualizar dentro de la función que se pasa como parámetro al select).
  • Los comandos disponibles son:
    • especificación de origen: from
    • acciones: and, andNot, combine, debug, ignoreCase, not, or, orCombine, orNot, useCase
    • consultas: con 2 parámetros between, betweenEquals, con 1 parámetro contains, empty, endsWith, equals, greater, greaterEquals, is, isNot, less, lessEquals, match, startsWith, y where.
    • selección: all, any, at, count, distinct, each, first, groupBy, join, last, none, orderBy, select, skipTake, take, toTable
Sin duda, supone una forma programática de conseguir lo mismo que con SQL y evitar el proceso de parseado. Pero el afán por seguir el estándar SQL, aunque hay que decir que está muy extendido, impide ver las posibilidades que el propio Javascript puede ofrecer para este tipo de trabajo. Sigue resultando más claro leer una simple consulta SQL. El objetivo sería conseguir la claridad de SQL aprovechando la flexibilidad que Javascript ofrece. Ahí creo que CouchDB va mejor enfocado, aunque la claridad deja que desear.

Publicar un comentario en la entrada

Últimos links en indiza.com