Using and working with IndexedDB

Below is a sample example code for IndexedDB

//nsr is namespace
(function (nsr, $, undefined) {
    //private variables
    nsr.myTvQ.indexedDB = nsr.myTvQ.indexedDB || {};
    nsr.myTvQ.indexedDB.db = null;
    nsr.myTvQ.indexedDB.version = "1.0";
    
    //saving webkitIndexedDB in global namespace
    if ('webkitIndexedDB' in window) {
        window.indexedDB = window.webkitIndexedDB;
        window.IDBTransaction = window.webkitIDBTransaction;
        window.IDBKeyRange = window.webkitIDBKeyRange;
        window.IDBCursor = window.webkitIDBCursor;
    }
    //global error handler
    nsr.myTvQ.indexedDB.onerror = function (e) {
        console.log("myError: ", e);        
    };
    // callback param in integer, -1 error, 0 exiting, 1 new
    nsr.myTvQ.indexedDB.Open = function (callback) {
        if (nsr.myTvQ.indexedDB.db) {
            if (callback) {
                callback(0);//opened but present
            }
            return;
        }
        var request = indexedDB.open("myTvQDB", "comments bla blah database v1.0");

        request.onsuccess = function (e) {
            var v = nsr.myTvQ.indexedDB.version;
            nsr.myTvQ.indexedDB.db = e.target.result;
            var db = nsr.myTvQ.indexedDB.db;
            console.log('opened indexedDB myTvQDB v:' + db.version);            

            // We can only create Object stores in a setVersion transaction;
            // so if version not found update or create new db
            if (v != db.version) {
                console.log('setting new v ',v, db.version);
                var setVrequest = db.setVersion(v);

                // onsuccess is the only place we can create Object Stores
                setVrequest.onfailure = request.onfailure =  function (e) 
                {        
                    console.log("myError: ", e); 
                    if (callback) {                        
                        callback(-1);
                    }
                };
                setVrequest.onsuccess = function (e) {
                    //create this at last, since update_time is stored in end
                    nsr.myTvQ.indexedDB.DropObjectStore("settings");
                    nsr.myTvQ.indexedDB.CreateSettingsStore();

                    nsr.myTvQ.indexedDB.DropObjectStore("listings");
                    nsr.myTvQ.indexedDB.listing.CreateListingsStore();         
                    if (callback) {
                        callback(1);//created                        
                    }
                };
            } else {
                if (callback) {
                    callback(0);//opened but present
                }
                console.log('object stores are present');
            }
        };

        request.onfailure =  function (e) 
        {        
            console.log("myError: ", e); 
            if (callback) {
                callback(-1);//error
            }
        };
    }
    
    //helper methods
    nsr.myTvQ.indexedDB.Close = function(){
        try {
            var db = nsr.myTvQ.indexedDB.db;
            if (db) {
                db.close();
                nsr.myTvQ.indexedDB.db = null;
                if (callback) {
                    callback(1);
                }
            }   
        } catch (ex) {
            if (callback) {
                callback(-1);
            }
            console.log("Exception in Close() - " + ex.message);
        }
    } 
    nsr.myTvQ.indexedDB.DeleteDatabase = function(callback){
        try {
            var db = nsr.myTvQ.indexedDB.db;
            if (db) {
                db.close();
            }   
            var request =  window.indexedDB.deleteDatabase('myTvQDB');
            request.onsuccess = function (e) {
                nsr.myTvQ.indexedDB.db = null;
                if (callback) {
                    callback(1);
                }
                console.log('Database successfully deleted');
            };
            request.onfailure = function (e) 
            {        
                console.log("myError: ", e); 
                if (callback) {
                    callback(-1);
                }
            };    
        } catch (ex) {
            if (callback) {
                callback(-1);
            }
            console.log("Exception in DeleteDatabase() - " + ex.message);
        }
    }
    
    nsr.myTvQ.indexedDB.DropObjectStore = function (storeName) {
        var db = nsr.myTvQ.indexedDB.db;
        if (db.objectStoreNames.contains(storeName)) {
            db.deleteObjectStore(storeName);
            console.log('objectstore ' + storeName + ' dropped');
        }
    }

    nsr.myTvQ.indexedDB.ForceDropObjectStore = function (storeName) {
        var db = nsr.myTvQ.indexedDB.db;
        var setVrequest = db.setVersion(Math.random());
        setVrequest.onfailure = nsr.myTvQ.indexedDB.onerror;
        setVrequest.onsuccess = function (e) {
            console.log('db.version ', db.version);
            nsr.myTvQ.indexedDB.DropObjectStore(storeName);
        }
    };
    
    //can use to re-create empty ObjectStore
    nsr.myTvQ.indexedDB.ForceCreateObjectStore = function (storeName) {
        console.log('ForceCreateObjectStore', storeName);
        var db = nsr.myTvQ.indexedDB.db;
        var setVrequest = db.setVersion(Math.random());
        setVrequest.onfailure = nsr.myTvQ.indexedDB.onerror;
        setVrequest.onsuccess = function (e) {
            console.log('db.version ', db.version);
            nsr.myTvQ.indexedDB.DropObjectStore(storeName);
            switch(storeName){
                case "listings":
                    nsr.myTvQ.indexedDB.listing.CreateListingsStore();
                    break;	
                case "settings":
                    nsr.myTvQ.indexedDB.listing.CreateSettingsStore();
                    break;	   
                default:
                    break;
                }
            nsr.myTvQ.indexedDB.ResetVersion();
        }
    };
    
    //set version back to old version
    nsr.myTvQ.indexedDB.ResetVersion = function () {
        var db = nsr.myTvQ.indexedDB.db;
        var setVrequest = db.setVersion(nsr.myTvQ.indexedDB.version);
        setVrequest.onfailure = nsr.myTvQ.indexedDB.onerror;
        setVrequest.onsuccess = function (e) {
            console.log('reset db.version ', db.version);
        }
    };
    
    //empty or truncate table
    nsr.myTvQ.indexedDB.ClearAll = function(storeName, callback){
        var db = nsr.myTvQ.indexedDB.db;
        if (db.objectStoreNames.contains(storeName)) {
            var clearTransaction = db.transaction([storeName], IDBTransaction.READ_WRITE);
            var clearRequest = clearTransaction.objectStore(storeName).clear();
            clearRequest.onsuccess = function(event){
                 //event.target.result contains undefined
                 if (callback) {
                    callback(true);
                 }                 
            };
            clearRequest.onerror = function(event){            
                 console.log("myError: ", event);
                 if (callback) {
                    callback(false);
                 }                                  
            };
        }else {
            console.log(storeName+ " doesnot exist ");
            if (callback) {
                    callback(false);
            }                 
        }
    }
    //nsr.myTvQ.indexedDB.ListAll('','store_id',function(l1){console.log(l1);});
    nsr.myTvQ.indexedDB.ListAll = function(storeName, objOrArray, callback){
        var db = nsr.myTvQ.indexedDB.db;
        if (db.objectStoreNames.contains(storeName)) {
            var transaction = db.transaction(storeName, IDBTransaction.READ_ONLY);
            var list = objOrArray ? {} : [] ;
            transaction.oncomplete = function(event) {
                if(callback){
                    //console.log(results);
                    callback(list);
                }
            };
            transaction.onerror = nsr.myTvQ.indexedDB.onerror;
            var cursorRequest = transaction.objectStore(storeName).openCursor();
            
            cursorRequest.onsuccess = function(ev) {
                var cursor = cursorRequest.result || ev.target.result;
                if(!!cursor == false)
                    return;
                if(objOrArray){
                    list[cursor.value[objOrArray]] = cursor.value;
                }
                else{
                    list.push(cursor.value);                
                }
                cursor.continue();
            };      
        }else {
            console.log(storeName+ " doesnot exist ");
            if (callback) {
                    callback(false);
            }                 
        }            
    }
    
    nsr.myTvQ.indexedDB.Delete = function(storeName, key, callback){
        var db = nsr.myTvQ.indexedDB.db;
        var request = db.transaction(storeName, IDBTransaction.READ_WRITE)  
                .objectStore(storeName)  
                .delete(key);  
        request.onsuccess = function(event) {  
          if(callback){
                //console.log(results);
                callback(true);
            }  
        };
        request.onerror = function(event) {  
          if(callback){
                callback(false);
            }  
        };
    }
    
    nsr.myTvQ.indexedDB.CreateSettingsStore = function(callback){
        var db = nsr.myTvQ.indexedDB.db;
        if(!db.objectStoreNames.contains("settings")) {
            //will be used by background to get all past dates and run operations on them
            db.createObjectStore("settings",{keyPath:"Name"});
            console.log('objectstore settings created');
                        
            nsr.myTvQ.indexedDB.SetAllSettings(undefined,callback);
        }
    };
    
    
    
    nsr.myTvQ.indexedDB.GetAllSettings = function(callback){
        var db = nsr.myTvQ.indexedDB.db;        
        var settings = {};
        var transaction = db.transaction(["settings"], IDBTransaction.READ_ONLY);
        transaction.oncomplete = function(event) {  
          if(callback){
            callback(settings);
          }
        }; 
        transaction.onerror = nsr.myTvQ.indexedDB.onerror;
        var store = transaction.objectStore("settings");
        var cursorRequest = store.openCursor(IDBKeyRange.lowerBound(0));
        cursorRequest.onsuccess = function(ev) {
            var cursor = cursorRequest.result || ev.target.result;
            if(!!cursor == false)
                return;
            //console.log(cursor.value);
            settings[cursor.value.Name] = cursor.value.Value;
            cursor.continue();
        };          
    }

    nsr.myTvQ.indexedDB.SetAllSettings = function(settings, callback){
         var db = nsr.myTvQ.indexedDB.db; 
         var transaction = db.transaction(["settings"], IDBTransaction.READ_WRITE);
         var store = transaction.objectStore("settings");
         transaction.oncomplete = function(event) {  
            if(callback){
                console.log('SetAllSettings Initialized');
                callback();
            }
         }; 
         transaction.onerror = nsr.myTvQ.indexedDB.onerror;
         settings = settings || {};
         var init_list = [{"Name":"update_time","Value":settings.update_time || (new Date()).getTime() }                          
                            ,{"Name":"enable_notification","Value":settings.enable_notification || 1}
                            ,{"Name":"default_country","Value":settings.default_country || 'US'}];

         $.each(init_list, function (index0, item0) {
                var request = store.put(item0);
                request.onsuccess = function(event) {};
                request.onerror = function(event) {
                    console.log(event);
                }; 
         });
    }

    nsr.myTvQ.indexedDB.GetSettingsFor = function(name, callback){
        var db = nsr.myTvQ.indexedDB.db;
        var resultset = null;
        var transaction = db.transaction(["settings"], IDBTransaction.READ_ONLY);
        transaction.oncomplete = function(event) {  
          if(callback){
            callback(resultset);
          }
        }; 
        transaction.onerror = nsr.myTvQ.indexedDB.onerror;
        var store = transaction.objectStore("settings");
        var request = store.get(name);  
        request.onerror = function(event) {  
          console.log(event);
        };  
        request.onsuccess = function(event) {  
          resultset = request.result ? request.result.Value : undefined ;  
        };
    }

    nsr.myTvQ.indexedDB.SetSettingsFor = function(name, value, callback){
        var db = nsr.myTvQ.indexedDB.db;
        var transaction = db.transaction(["settings"], IDBTransaction.READ_WRITE);
        transaction.oncomplete = function(event) {  
          if(callback){
            callback(true);
          }
        }; 
        transaction.onerror = function(event) {  
          if(callback){
            callback(false);
          }
        }; 
        var store = transaction.objectStore("settings");
        var request = store.put({"Name":name,"Value":value});  
        request.onerror = function(event) {  
          console.log(event);
        };  
        request.onsuccess = function(event) {};
    }    
    
    ///Show Listings
    nsr.myTvQ.indexedDB.listing.CreateListingsStore = function(callback){
        var db = nsr.myTvQ.indexedDB.db;
        if(!db.objectStoreNames.contains("listings")) {
            var store = db.createObjectStore("listings", { keyPath: "show_id" });
            store.createIndex("countryIndex", "country", { unique: false });
            store.createIndex("country_statusIndex", "country_status", { unique: false });
            store.createIndex("show_name_Index", "show_name", { unique: false });
            console.log('objectstore listing created');  
            if(callback){
                callback(true);
            }          
        }else {
            if(callback){
                console.log('CreateListingsStore already exits');
                callback(true);
            }
        }
    };
    
    nsr.myTvQ.indexedDB.listing.AddListings = function (x2j_list_new, index, callback) {
        //no need to clear, since its add or update.        
        var db = nsr.myTvQ.indexedDB.db;
        var transaction = db.transaction(["listings"], IDBTransaction.READ_WRITE);
        var count = 0;
        transaction.oncomplete = function (event) {
            if (callback) {
                console.log('x2jShowListing Added ' + count + '/' + x2j_list_new.length);
                callback([index, count, x2j_list_new.length]);
            }
        };
        transaction.onerror = nsr.myTvQ.indexedDB.onerror;
        var store = transaction.objectStore("listings");
        console.log('AddListings looping'+index);
        $.each(x2j_list_new, function (index0, item0) {
            var request = store.put(item0);
            request.onsuccess = function (event) {
                count++;
                // event.target.result == show_id  
            };
        });        
    };

    nsr.myTvQ.listing.AddListingsInChunks = function (progressElemId, callback) {
        $(progressElemId).html('(Listing is older than 14 days, fetching latest from server)');
        nsr.myTvQ.listing.GetListingsFromTvRage(function (x2j_list_new) {
            if (!x2j_list_new) {
                if (callback) {
                    $(progressElemId).html('(Encountered Error while fetching, please try again later.)');
                    callback(false);
                    return;
                }
            }
            console.log('x2j_list_new now calling AddListings');
            
            //http://stackoverflow.com/questions/8495687/split-array-into-chunks      
            var i = 0, j = x2j_list_new.length, temp_array, chunk = 500;
            $(progressElemId).html('(Got a total of '+j+' Shows)');
            //http://www.kryogenix.org/days/2009/07/03/not-blocking-the-ui-in-tight-javascript-loops
            function doWork() {
                temp_array = x2j_list_new.slice(i, i + chunk);
                nsr.myTvQ.indexedDB.listing.AddListings(temp_array, i, function (cnt) {
                    if (cnt[0] >= j - chunk) {
                        console.log('AddListings ALL DONE', cnt);
                        if (callback) {
                            $(progressElemId).html('(Saving Shows locally 100% Comlepete. Now generating screen. Almost there... )');
                            callback(true);
                            return;
                        }
                    }
                    $(progressElemId).html('(Saving '+j+' Shows locally, '+(((i + chunk >=j ? j: i + chunk)/j)*100).toFixed(2) +'% Done.)');
                    console.log(cnt);
                });
                i += chunk;
                if (i < j) {
                    setTimeout(doWork, 100);
                }
            };
            setTimeout(doWork, 100);            
        });
    } 
    
    nsr.myTvQ.indexedDB.listing.GetAllCountries = function (callback) {
        var db = nsr.myTvQ.indexedDB.db;
        var resultset = [];
        var transaction = db.transaction(["listings"], IDBTransaction.READ_ONLY);
        transaction.oncomplete = function(event) {  
          if(callback){
            callback(resultset);
          }
        }; 
        transaction.onerror = nsr.myTvQ.indexedDB.onerror;
        var store = transaction.objectStore("listings");

        var countryIndex = store.index("countryIndex");
        
        var cursorRequest = countryIndex.openKeyCursor(null, IDBCursor.NEXT_NO_DUPLICATE);
        cursorRequest.onsuccess = function(ev) {
          var cursor = cursorRequest.result;
          if (cursor) {
            resultset.push(cursor.key);
            //console.log(cursor.value);//undefined
            cursor.continue();
          }
        };
    };    

    nsr.myTvQ.indexedDB.listing.GetListingByCountry = function (country, callback) {
        console.log("GetListingBy country");
        var resultset = [];
        var db = nsr.myTvQ.indexedDB.db;
        var transaction = db.transaction(["listings"], IDBTransaction.READ_ONLY);
        transaction.oncomplete = function(event) {  
            if(callback){
            callback(resultset);
            }
        }; 
        transaction.onerror = nsr.myTvQ.indexedDB.onerror;
        var store = transaction.objectStore("listings");

        var countryIndex = store.index("countryIndex");
            
        var cursorRequest = countryIndex.openCursor(new IDBKeyRange.only(country));
        cursorRequest.onsuccess = function(ev) {
            var cursor = cursorRequest.result;
            if (cursor) {
            resultset.push(cursor.value);
                
            cursor.continue();
            }
        };
    };

    nsr.myTvQ.indexedDB.listing.GetListingByCountryStatus = function (country, status, callback) {
        var resultset = [];
        var db = nsr.myTvQ.indexedDB.db;
        var transaction = db.transaction(["listings"], IDBTransaction.READ_ONLY);
        transaction.oncomplete = function(event) {  
          if(callback){
            callback(resultset);
          }
        }; 
        transaction.onerror = nsr.myTvQ.indexedDB.onerror;
        var store = transaction.objectStore("listings");

        var country_statusIndex = store.index("country_statusIndex");
        var cursorRequest = country_statusIndex.openCursor(new IDBKeyRange.only(country +'_'+ status));
        cursorRequest.onsuccess = function(ev) {
          var cursor = cursorRequest.result;
          if (cursor) {
            resultset.push(cursor.value);
            //console.log(cursor.value);
            cursor.continue();
          }          
        };
    };
    
    //from ="A", to="B"
    nsr.myTvQ.indexedDB.listing.GetCountryByRange = function (from, to) {
        var db = nsr.myTvQ.indexedDB.db;
        var resultset = [];
        var transaction = db.transaction(["listings"], IDBTransaction.READ_ONLY);
        transaction.oncomplete = function(event) {  
            console.log(resultset);
        }; 
        transaction.onerror = nsr.myTvQ.indexedDB.onerror;
        var store = transaction.objectStore("listings");

        var countryIndex = store.index("countryIndex");
        
        var cursorRequest = countryIndex.openKeyCursor(IDBKeyRange.bound(from,to,false,true), IDBCursor.NEXT_NO_DUPLICATE);
        cursorRequest.onsuccess = function(ev) {
          var cursor = cursorRequest.result;
          if (cursor) {
            resultset.push(cursor.key);
            //console.log(cursor.value);//undefined
            cursor.continue();
          }
        };
    };
    
    //chrome doesnot support count yet.
    nsr.myTvQ.indexedDB.listing.CountListing = function (callback) {        
        var db = nsr.myTvQ.indexedDB.db;
        var transaction = db.transaction(["listings"], IDBTransaction.READ_ONLY);
        var count = 0;
        transaction.oncomplete = function(event) {  
          if(callback){
            callback(count);
          }
        };
        transaction.onerror = nsr.myTvQ.indexedDB.onerror;
        var store = transaction.objectStore("listings");

        var keyRange = IDBKeyRange.lowerBound(0);
        var showidRequest  = store.openCursor(keyRange);
        showidRequest.onsuccess = function(ev) {
          var result = ev.target.result;
          if(!!result == false)
            return;
                      
            count++;
            result.continue();          
        };
    }

    nsr.myTvQ.indexedDB.listing.CountListingBy = function (country, callback) {        
        var db = nsr.myTvQ.indexedDB.db;
        var transaction = db.transaction(["listings"], IDBTransaction.READ_ONLY);
        var count=0;
        transaction.oncomplete = function(event) {  
          if(callback){
            //console.log(count);
            callback(count);
          }
        };
        transaction.onerror = nsr.myTvQ.indexedDB.onerror;
        var store = transaction.objectStore("listings");

        var countryIndex = store.index("countryIndex");
        
        var cursorRequest = countryIndex.openCursor(new IDBKeyRange.only(country));
        cursorRequest.onsuccess = function(ev) {
          var cursor = cursorRequest.result;
          if(!!cursor == false)
            return;

          count++;
          cursor.continue();
        };        
    }                           

} (window.nsr = window.nsr || {}, jQuery));
\