2015-10-19

Tengo, queries a la base de datos en sandro

En los últimos días implementé el módulo sandro/tengo. Lo que hice fue una forma "objetosa" de contruir queries de SQL y procesar los resultados, usando como base JDBC. La idea es evitar los problemas de seguridad por inyección que plagan los usos de las bases de datos sin restringir la funcionalidad. El código que hice lo probé con sqlite3, y debería andar con cualquier base de datos que sea ANSI-SQL y tenga driver de JDBC.

Acá les dejo un ejemplo de cómo hacer un query usando tengo. Asumiendo que connection es una conexión a la base de datos y hay una tabla person (id integer, name string, rank integer), así hago un query:

define(
  {
    tengo: "sandro/tengo"
  },
  function(m) {

    // Some code before, constructing the JDBC connection

    var _ = m.tengo.ansiBuilder

    // SELECT * FROM person ORDER BY id DESC;
    var results = _.select({
      from: "person",
      order_by: _.desc("id")
    }).map(connection, function(rs) {
      return {

        name: "" + rs.getString("name"), 
        id: rs.getInt("id")
      }
    })


    // SELECT count(1) as c, rank FROM person GROUP BY rank HAVING c > 1
    var results2 = _.select({
      columns: [ _.alias("c",_.invoke("count", _.int(1))), "rank" ],
      from: "person",
      group_by: "rank",
      having: _.gt("c", _.int(1))
    }).map(connection, function(rs) {
      return {

        c: rs.getInt("c"), 
        rank:rs.getInt("rank")
      }
    })
 


    // You can process the results here
  }
)

En la implementación actual podés hacer SELECTs con un montón de opciones (TODO: documentar todo). La idea subyacente es que las queries se arman haciendo árboles de objetos que generan los queries con objetos inmutables siguiendo la sintaxis de SQL (para que puedan usar los conocimientos de SQL que ya tienen), y estos objetos se encargan de escapar el SQL. Para que sea menos verbose, los strings son transformados en símbolos de SQL (como columnas o tablas), los números en expresiones que representan el número en punto flotante y los arrays en expresiones separadas por comas, que está buenísimo para hacer queries con varias tablas, requerir varias columnas o hacer ORDER BY con varios criterios.

Lo siguiente que toca es hacer que se pueda hacer UPDATE, DELETE, INSERT. Y después toca CREATE TABLE y DROP TABLE.

¿Qué frameworks conocen que les dejen hacer queries tan fácilmente? Lo más parecido que se me ocurre es el API de bajo nivel de SQLAlchemy, pero como los elementos de las queries son stateful, es mucho más quilombo.