HTML5 Web SQL Database framework

An interesting innovation introduced with HTML5 is the ability to save data permanently (till the next browser cache clear) in a local database using SQLite commands. The direct use of this API is, however, "uncomfortable" and repetitive, overburdening code with logics that should instead be collected in lower-level procedures. So I developed a Javascript class that simplifies versioning, writing and reading operations, to make the Web SQL Database API easier to use.

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);
    }
}

Usage

Create/open database:

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

Check database version:

View source
var ver = db.version();

First creation:

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); } );

Upgrade 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); } );

Execute an SQL command or an array of commands:

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); });

Execute an SQL query:

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);
    }
);

Check whether Web SQL Database API is available:

View source
var canUseWebDb = db.webDbImplemented();

That's all! I hope this library will be useful to you!

Leave a comment

Make sure you enter the (*) required information where indicated. Your avatar will be grabbed from Gravatar.com.

enter your site URL...

8 comments

  • Stefano Storti Stefano Storti 10/10/2013 7:05 PM

    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 10/07/2013 2:23 PM

    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 10/18/2012 5:59 PM

    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 09/12/2012 10:01 PM

    I already do

  • gilber gilber 09/12/2012 9:11 PM

    and to use variables from a form?

  • gilbert gilbert 09/12/2012 2:57 PM

    muchas gracias, from colombia

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

    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 7:16 PM

    for update an record?

Google