Almacenamiento de datos (SQL)

Mediante el manejo de la API de almacenamiento de datos (Storage) de Apache Cordova podemos, entre otras cosas, crear y manipular bases de datos SQL Lite, basándose en la especificación para Web SQL de W3C.

Esta API permite además almacenar información mediante el uso de pares clave-valor (localStorage), basándose también en especificaciones W3C. Sin embargo, en la práctica, esta forma no es muy recomendable ya que no es capaz de almacenar datos de forma permanente. La comunidad de usuarios y desarrolladores suele desaconsejar su uso.

Mediante los métodos y propiedades para JavaScript de esta API, desarrollaremos una aplicación Cordova capaz de crear y modificar una pequeña base de datos SQL.

1. Permisos

Esta API viene implementada por defecto en Cordova. Sin embargo, nunca viene mal asegurarse de que está incluida en las propiedades de nuestro proyecto. Si revisamos el fichero /res/xml/config.xml deberíamos encontrar la siguiente línea:

<plugin name="Storage" value="org.apache.cordova.Storage" />

2. Crear una base de datos

Mediante la siguiente instrucción de JavaScript se crea un nuevo objeto de tipo Database:

var dbShell = window.openDatabase(database_name, database_version, database_displayname, database_size);

Para el método window.openDatabase() se deben especificar los siguientes parámetros:

  • database_name: Nombre de la base de datos
  • database_version: Versión de la base de datos
  • database_displayname: Nombre a modo de “alias” que se va a presentar para la base de datos
  • database_size: Tamaño de la base de datos en bytes. También se puede especificar en múltiplos de 1024 (ver ejemplos)
var db = window.openDatabase("test", "1.0", "Test DB", 2000000);
var db = window.openDatabase("test", "1.0", "Test DB", 1024*1024);

3. Consultas

Para realizar consultas sobre la base de datos, se utiliza el objeto SQLTransaction. Este objeto contiene un solo método, executeSql(), el cual contiene el código SQL de la consulta.

tx.executeSql('CREATE TABLE IF NOT EXISTS DEMO (id unique, data)');

4. SQLResultSet

Se trata de un objeto que se crea cuando se llama al callback de SQLTransaction. Contiene algunas propiedades:

  • isertId: la ID de la última fila afectada por la consulta SQL
  • rowsAffected: Número de filas afectadas por la consulta SQL
  • rows: propiedad SQLResultSetRowList que representa las filas devueltas. Si se devuelve ninguna, el objeto estará vacío.

Es posible que todo esto quede más claro viéndolo en un ejemplo. La clave está en jugar con la llamada a los correspondientes callback:

function queryDB(tx) {
    tx.executeSql('SELECT * FROM DEMO', [], querySuccess, errorCB);
}

function querySuccess(tx, results) {
    console.log("Returned rows = " + results.rows.length);
    // this will be true since it was a select statement and so rowsAffected was 0
    if (!results.rowsAffected) {
        console.log('No rows affected!');
        return false;
    }
    // for an insert statement, this property will return the ID of the last inserted row
    console.log("Last inserted row ID = " + results.insertId);
}

function errorCB(err) {
    alert("Error processing SQL: "+err.code);
}

var db = window.openDatabase("Database", "1.0", "Cordova Demo", 200000);
db.transaction(queryDB, errorCB);

querySuccess() es una función callback que se llama desde el método executeSql() que genera la consulta. Esa función va a ser llamada si la consulta SQL se realiza con éxito. En ella, se utilizan las propiedades de SQLResultSet y SQLResultSetRowList para mostrar información referente al resultado.

5. SQLResultSetRowList

Se trata de una propiedad de SQLResultSet que contiene las filas devueltas por una consulta SQL. Contiene propiedades y métodos adicionales.

  • length: Propiedad que devuelve el número de filas resultantes de ejecutar la consulta
  • item: Método que devuelve una fila determinada por un índice concreto, representado por un objeto de JavaScript.

Ejemplo de funcionamiento:

function queryDB(tx) {
    tx.executeSql('SELECT * FROM DEMO', [], querySuccess, errorCB);
}

function querySuccess(tx, results) {
    var len = results.rows.length;
    console.log("DEMO table: " + len + " rows found.");
    for (var i=0; i<len; i++){
        console.log("Row = " + i + " ID = " + results.rows.item(i).id + " Data =  " + results.rows.item(i).data);
    }
}

function errorCB(err) {
    alert("Error processing SQL: "+err.code);
}

var db = window.openDatabase("Database", "1.0", "Cordova Demo", 200000);
db.transaction(queryDB, errorCB);

Utilizando length e item, se recorren las filas del resultado de la consulta mediante un bucle for. Haciendo uso del contador i sobre el método item se obtiene la información deseada (nótese que se hace la llamada a los nombres de las columnas como si se trataran de propiedades de JavaScript). Con la propiedad length se especifica el número de iteraciones.

6. Errores

Cuando se da un error en la consulta SQL, se devuelve un objeto de tipo SQLError. Se puede conocer el tipo de error bien por código o por mensaje, haciendo uso de las dos únicas propiedades que posee respectivamente: code y message.

function errorCB(err) {
        console.log("Error processing SQL: "+err.code);
    }