HTML5 Web SQL Database framework

Un'interessante novità introdotta con HTML5 è la possibilità di salvare dati permanenti (fino alla prossima pulizia cache del browser) in un database locale tramite comandi SQLite. L'utilizzo diretto di quest'API risulta però piuttosto "scomodo" e ripetitivo, appesantendo quindi il codice con logiche che andrebbero invece raccolte in procedure a più basso livello. Ho quindi sviluppato una classe Javascript che semplifica le operazioni di versioning, scrittura e lettura dei record, in modo da rendere l'API Web SQL Database più fruibile.

View source
/**
 * HTML5 Web SQL Database framework
 * Author: Stefano Storti
 * Licence: GNU General Public License version 3.0 or later <http://www.gnu.org/licenses/gpl-3.0.html>
 */
 
var db = new function Database() {
    
    this._db = null;
    
    /**
     * Open database
     */
    this.open = function(name, descr, ver, size) {
        if (ver == undefined)
            ver = "";
        
        this._db = window.openDatabase(name, ver, descr, size);
    }
    
    /**
     * Database version
     */
    this.version = function() {
        return this._db.version;
    }
    
    /**
     * Execute an SQL command or an array of commands
     */
    this.execute = function(sql, onSuccess, onError) {
        this._db.transaction(function(tx) {
            
            if (sql.constructor == Array) {
                for (i = 0; i < sql.length; i++)
                    tx.executeSql(sql[i]);
            }
            else {
                tx.executeSql(sql);
            }
            
        }, onError, onSuccess);
    }
    
    /**
     * Execute an SQL query
     */
    this.query = function(sql, onSuccess, onError) {
        this._db.transaction(function(tx) {
            tx.executeSql(sql, [], onSuccess, onError);
        }, onError);
    }
    
    /**
     * Upgrade to new version
     * sqlVers = [{ver: "1", sql: "sql command 1"}, {ver: "2.0", sql: "sql command 2.0"}, {ver: "3.1", sql: "sql command 3.1"}, ...]
     */
    this.upgrade = function(sqlVers, onSuccess, onError) {
        var currentVer = 0;
        if (this._db.version)
            currentVer = parseFloat(this._db.version);
        var sqlExec = new Array();
        
        for (i = 0; i < sqlVers.length; i++) {
            var ver = parseFloat(sqlVers[i].ver);
            var sql = sqlVers[i].sql;
            if (ver > currentVer) {
                sqlExec.push(sql);
            }
        }
        
        var currentVer = this._db.version;
        var lastVer = (sqlVers[sqlVers.length - 1]).ver;
        
        if (sqlExec.length > 0) {
            this.changeVersion(currentVer, lastVer, sqlExec, onSuccess, onError);
        }
    }
    
    /**
     * Change database version
     * sql = single SQL command or array of SQL commands
     */
    this.changeVersion = function(oldVer, newVer, sql, onSuccess, onError) {
        this._db.changeVersion(oldVer, newVer, function (tx) {
 
            if (sql.constructor == Array) {
                for (i = 0; i < sql.length; i++)
                    tx.executeSql(sql[i]);
            }
            else {
                tx.executeSql(sql);
            }
          
        }, onError, onSuccess);
    }
    
    /**
     * Check whether can use HTML5 SQLite web database
     */
    this.webDbImplemented = function() {
        return (window.openDatabase != undefined);
    }
}

Utilizzo

Creare/aprire un database:

View source
// db.open(name, descr, ver, size)
db.open("MyWebDatabase", "My Web Database", "", 1024 * 1024);
 

Controllare la versione del database:

View source
var ver = db.version();

Prima creazione:

View source
// Full database creation
var sql = [
    "CREATE TABLE BRANDS (id primary key, name)"
    , "CREATE TABLE CARS (id primary key, name, brand_id)"
];
 
// db.changeVersion(oldVer, newVer, sql, onSuccess, onError)
db.changeVersion("", "1", sql,
        function() { alert("Database created!"); }, function(err) { alert("Error in database creation: "+err.message); } );

Aggiornamento struttura database:

View source
// Upgrade database (database diff): skip SQL command if current database version >= .ver property
var sqlVers = [
    {ver: "2", sql: "ALTER TABLE BRANDS ADD COLUMN country"}
    , {ver: "3", sql: "ALTER TABLE CARS ADD COLUMN production_started"}
    , {ver: "3", sql: "ALTER TABLE CARS ADD COLUMN production_ended"}
    // future upgrades here...
];
 
// db.upgrade(sqlVers, onSuccess, onError)
db.upgrade(sqlVers, function() { alert("Database upgraded!"); }, function(err) { alert("Error in database upgrade: "+err.message); } );

Esegue un comando o un array di comandi SQL:

View source
var sqlInsert = [
    "INSERT INTO BRANDS(id, name, country) VALUES (1, 'Fiat', 'Italy')"
    , "INSERT INTO BRANDS(id, name, country) VALUES (2, 'Alfa Romeo', 'Italy')"
    , "INSERT INTO CARS(id, name, brand_id, production_started) VALUES (1, '500', 1, 2007)"
    , "INSERT INTO CARS(id, name, brand_id, production_started) VALUES (2, 'MiTo', 2, 2008)"
    , "INSERT INTO CARS(id, name, brand_id, production_started) VALUES (2, 'Giulietta', 2, 2010)"
];
            
// db.execute(sql, onSuccess, onError)
db.execute(sql, function() { alert("Database has been populated!"); }, function(err) { alert("Error in executing SQLite command: "+err.message); });

Esegue una query SQL:

View source
// db.query(sql, onSuccess, onError)
db.query('SELECT CARS.name AS car_name, BRANDS.name AS brand_name
          FROM CARS INNER JOIN BRANDS ON CARS.brand_id = BRANDS.id
          ORDER BY CARS.name',
    function(tx, results) {
        for (i = 0; i < results.rows.length; i++)
            alert('Car:'+results.rows.item(i).car_name+', brand: '+results.rows.item(i).brand_name);
    }, function(tx, err) {
        alert("Error in executing SQLite query: "+err.message);
    }
);

Controlla se l'API Web SQL Database è disponibile:

View source
var canUseWebDb = db.webDbImplemented();

Ed è tutto! Spero questa libreria possa tornarvi utile!

Lascia un commento

Assicurati di inserire (*) le informazioni necessarie ove indicato. Il tuo avatar verrà preso da Gravatar.com.

Inserisci l'URL del tuo sito...

8 commenti

  • Stefano Storti Stefano Storti 10/10/2013 19:05

    Ciao Massimo. Se hai un database MySQL, prima dovrai sincronizzare il database locale dell'app con il database online (tramite richiesta dei record via AJAX).
    Se non hai la necessità di tenere sincronizzato il database ma hai solamente dei dati MySQL per inizializzare il database dell'app, puoi esportare le query di creazione del database (le CREATE TABLE e INSERT per intenderci) e poi lanciarle al primo accesso nell'app tramite i comandi della libreria.

  • Massimo Massimo 07/10/2013 14:23

    Ciao, sono Massimo,
    vorrei creare una app sotto android utillizzando html5, css3, jquery mobile, phonegap. Tale app dovrebbe mostrare dei dati proveniente da un DB MySql già pronto. Per fare in modo che l'applicativo lo possa aprire ed eseguire query, dove devo copiare il db? Ovvero quando apro un db esistente con javascript questi dove lo va a cercare?
    L'app dovrà funzionare off-line, quindi il db dovrà essere inglobato nel file *.apk usando Eclipse per il build dell'app dove sposto il db?
    spero di essere stato chiaro. Grazie!
    ps: sarebbe interessante usare la tu classe!
    Saluti
    Massimo Ceraldi

  • manuel2012 manuel2012 18/10/2012 17:59

    Possiedo un database sqlite3
    Tramite html5 vorrei
    aprire il database (anche senza renderlo visibile)
    Interrogarlo tramite select
    Avere le risposte in una finestra del browser
    Finora faccio questo in modo molto rudimentale tramite lo strumento sqlite presente in firefox.
    Da quanto letto sopra dovrebbe essere possibile svolgere la function di cui ho bisogno con html5: potresti indicarmi come fare?
    Grazie in anticipo. Finora tutti quelli a cui ho chiesto mi hanno detto detto che posso interrogare il database solo se si trova sul server...
    Grazie ancora!

  • gilber gilber 12/09/2012 22:01

    I already do

  • gilber gilber 12/09/2012 21:11

    and to use variables from a form?

  • gilbert gilbert 12/09/2012 14:57

    muchas gracias, from colombia

  • Stefano Storti Stefano Storti 12/09/2012 9:26

    Hi Gilber. To update record, as INSERT command, you can use db.execute with your SQLite UPDATE command or array of commands:
    e.g.:
    db.execute("UPDATE TABLE SET field1 = value1 WHERE field2 = value2", function() { // on success }, function(err) { // on error });

  • gilber gilber 09/09/2012 19:16

    for update an record?

Google