Fluent API para JDBC

Ollin (Olin = movimiento) es una Fluent API enfocada a ejecutar consultas en JDBC. No creo que sea una competencia directa para alguna otra API o framework puesto que su enfoque principal es hacer sencilla la ejecución de queries y el procesamiento de los resultados. Tomé como punto de partida lo que vi en otras API's (a lo mejor notan algún parecido con Spring) aunque nunca las he utilizado. También en gran medida tomé la metáfora de las herramientas de SQL (en mi caso, SQL Developer) en las que sólo abres la aplicación, te conectas y ejecutas queries.

Existen tres puntos clave sobre los cuales funciona la API:

  • Una clase Row para no exponer directamente el ResultSet, esto para tener la idea más clara de estar sobre una fila.
  • Patrón visitador: El API maneja la iteración sobre el resultset invocando a un RowVisitor por cada una de las filas recorridas. Esto permite al programador librarse de la apertura y cierre de recursos (función de la cual se encarga el API).
  • El uso de generics que en conjunción con el estilo fluent de la API permite separar la parte de la ejecución de una consulta de la parte del procesamiento de las filas.

 

El método clave es   que toma una instancia de RowVisitor, el cual implementa la clase RowCounter que como podrán imaginarse contiene una contador que se incrementa con cada visita a una fila. El valor de retorno es la propia instancia de RowVisitor y que gracias al uso de parámetros genéricos es exactamente del mismo tipo (es decir, si pasamos RowCounter, devuelve RowCounter; si pasamos X, devuelve X). Finalmente, se invoca al método   que pertenece a la clase RowCounter para obtener el número de filas (en la práctica nadie cuenta el número de filas de este modo cuando puede hacer un select count).

Un ejemplo con un caso más cotidiano, es el siguiente:

 

El método   devuelve el primer valor encontrado (es decir el objeto en la primera fila y la primera columna), o null si no existen filas dentro del resultset. Como nota de implementación, este método usa internamente una instancia de RowVisitor especializado en la recuperación de del primer valor (como es muy común encontrar queries de este tipo, el API ofrece una forma rápida para ejecutarlos).

He aquí otro ejemplo para imprimir (en un formato básico que incluye el nombre de los campos) las filas recuperadas. Tanto RowCounter como RowPrinter son implementaciones que ya se encuentran en Ollin.

 

Un ejemplo para crear objetos a partir de las filas que se visitan.
 

Para los que no les gusten los métodos encadenados, se puede utilizar otro estilo para recuperar la lista de objetos.

 

Como verán, a diferencia de Spring JDBC, existe un sólo método para ejecutar los queries. La funcionalidad depende del objeto que visita las filas.

El proyecto aún no alcanza la versión 1.0 ya que se podrían agregar nuevas clases a la jerarquia de RowVisitor. También incluye métodos para ejecutar actualizaciones en las tablas (inserts, updates and deletes) los cuales creo que podrían mejorarse (como mencioné al principio, el enfoque principal del API son las consultas debido al tipo de aplicaciones que realizaba en mi anterior trabajo).

Cualquier duda o comentario es bienvenido y de antemano, muchas gracias.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

parámetros

Es importante lo que mencionas al final, la diferencia con el JdbcTemplate de Spring. En particular la clase SimpleJdbcTemplate tiene un buen de métodos, algunos ejemplos:

 

Algo importante es el varargs que tienen al final todos estos métodos. Sirve para utilizar consultas parametrizadas, y de hecho por cada método que mencioné hay un método adicional pero que en vez del varargs recibe un Map, eso sirve para los casos en que usas consultas con parámetros nombrados. Ejemplos:

 

No digo que sea mejor o peor tener un método contra tener muchos. El enfoque de JdbcTemplate es devolverte los resultados de manera inmediata. Tu enfoque es que el método query devuelve un objeto con el que puedes interactuar de distintas formas: pedirle la primera columna del primer registro, o el número de resultados, o los registros directamente, o tal vez incluso un registro en particular. Lo que no veo en tus ejemplos es precisamente cómo se pasan las consultas parametrizadas, porque si el método query recibe únicamente un String, estamos fritos, porque nos limitas a concatenar los parámetros y entonces tu componente nos vuelve vulnerables a ataques de inyección de SQL.

Si es algo que no tiene todavía, es de vital importancia agregárselo. Si tengo chance de revisarlo luego a ver si te puedo ayudar con esa parte, clonaré tu repo y supongo que en Google Code puedo también luego mandarte "pull request".

El último commit fue en

El último commit fue en diciembre del año pasado, porque te tardaste tanto en postear esto? #espregunta

Parámetros en consultas

Hola @ezamudio. Internamente el API utiliza un PreparedStatement tanto por razones de performance como de seguridad. Se pueden establecer valores de parámetros usando el método  .

 

Imagen de ezamudio

varargs

No es más fácil usar varargs como hace el SimpleJdbcTemplate de Spring?

 

Problemas con la documentación

Creo que la principal razón, y de la cual sufrimos muchos como programadores, es todo el proceso de hacer documentos, preparar manuales o averiguar las formas de dar a conocer los proyectos. Pero esto ya lo estoy tratando de arreglar y me ha ayudado mucho publicar entradas en la comunidad.

La otra razón es que cuando llegué a un milestone de Ollin, inmediatamente pasé a otra idea y se quedó en pausa el proyecto y ni tiempo me dio de hacer algo de difusión.

Uso de varargs

No lo había pensado. Voy a considerarlo como una forma adicional de establecer los parámetros ya que pueden existir casos en que se deseen cambiar los parámetros en un query ya creado.

Imagen de ezamudio

cuando se quieran cambiar

Es muy bueno que los puedas ir poniendo después, y/o modificarlos, porque puedes reutilizar queries. Pero muchas veces sólo quieres ejecutar un query con parámetros que ya tienes y no los piensas cambiar ni reutilizar ese query, entonces es más práctico pasarlos en la misma invocación sin tener que pasar cada parámetro en una llamada separada. No digo que sustituyas el comportamiento actual de tu query, sino que lo aumentes, con esta opción.

Completamente de acuerdo

Gracias @ezamudio por la muy buena sugerencia de utilizar varargs.

Por otro lado usar "setXyz"

Por otro lado usar "setXyz" da el beneficio extra de checar el tipo de dato ( ya sé que no tiene setXyz, solo setObject() ) pero eso quizá eventualmente te lleve a lo que el JDBC hace, tener muchos setInt, setString, setDate etc.

Imagen de ezamudio

no es sustitución

Oscar, ya dije que la idea no es reemplazar eso sino solamente complementarlo. Incluso está chido que puedas crear un query pasándole los parámetros junto con el SQL, y luego puedes modificar solamente alguno... por ejemplo:

 

horrible!!!

createQuery("select employee_id, name from app.employee").forEachRow(rowVisitor).getValue()

tener SQL dentro de java , prefiero mil veces tener separado las sentencias sql y luego llamarlas desde java con spring
e ibatis

select
employee_id,
name
from
employee

desde el dao:

List findAll()=this.getSqlMapClientTemplate("sqlListEmployee,null)

y listo nada de concatenar y pasar valores por var (claro que se puede , pero es mucho mas elegante que concatenar)

Coincido

Coincido completamente contigo. En este caso fue un ejemplo simplificado y por esa razón el sql se encuentra dentro del mismo código java. Por lo general en mis proyectos creo archivos de recursos sql, lo cual me permite manejarlos independientemente en un editor especializado (NetBeans reconoce la sintaxis SQL).

Tu comentario me ha dado una idea para agregar un método que cargue las sentencias directamente de archivos de recursos.

Saludos.

A mi no me parece

A mi no me parece "horrible!", quizá menos flexible cuando mucho, pero horrible no.

Imagen de Nopalin

muy buena tu idea man,

muy buena tu idea man, facilita la interacción con una base de datos sin meter el gorro de un ORM cuando el proyecto es monousuario.

En lo particular me agrada mas la idea de meter parámetros con métodos y no como parámetros del mismo método, ya que si de la primer forma puedo ir dejandolos en el siguiente renglos y si son parámetros del mismo método los tengo que dejar en el mismo renglon, jajaja en realidad es una tonteria pero bueno, ya vez que nunca vas a tener contenta a toda la gente.

sobres

Cambios

Ya se encuentran en el repositorio del proyecto los cambios que contemplan la opción de pasar parámetros cuando se crea el Query.

 

El otro cambio importante es la opción de construir un Query desde un archivo de recursos.