├── README.md ├── bower.json └── src └── indexeddb.js /README.md: -------------------------------------------------------------------------------- 1 | angular-indexedDB 2 | ================= 3 | 4 | An angularjs serviceprovider to utilize indexedDB with angular 5 | 6 | ####Important: This repository isn't maintained by me anymore. Look [over here](https://github.com/bramski/angular-indexedDB) for current versions, as [Bram Whillock](https://github.com/bramski) took over as main contributor. 7 | 8 | ## Installation 9 | 10 | For installation the use of Bower is recommended. 11 | 12 | ### Bower 13 | Call the following command on your command line: 14 | 15 | ```sh 16 | bower install --save angularjs-indexedDB 17 | ``` 18 | 19 | And add the following line to your html file, for example `index.html`: 20 | 21 | ```html 22 | 23 | ``` 24 | 25 | 26 | ### Manual 27 | 28 | - Download file. 29 | - Add the following line to your html file: 30 | 31 | ```html 32 | 33 | ``` 34 | 35 | ## Usage 36 | 37 | Normally, and as a recommendation, you have only one indexedDB per app. 38 | Thus in your `app.js` where you define your module, you do: 39 | 40 | ```javascript 41 | angular.module('myModuleName', ['xc.indexedDB']) 42 | .config(function ($indexedDBProvider) { 43 | $indexedDBProvider 44 | .connection('myIndexedDB') 45 | .upgradeDatabase(myVersion, function(event, db, tx){ 46 | var objStore = db.createObjectStore('people', {keyPath: 'ssn'}); 47 | objStore.createIndex('name_idx', 'name', {unique: false}); 48 | objStore.createIndex('age_idx', 'age', {unique: false}); 49 | }); 50 | }); 51 | ``` 52 | The connection method takes the databasename as parameter, 53 | the upgradeCallback has 3 parameters: 54 | function callback(event, database, transaction). For upgrading your db structure, see 55 | https://developer.mozilla.org/en-US/docs/IndexedDB/Using_IndexedDB. 56 | 57 | You can also define your own error handlers, overwriting the default ones, which log to console. 58 | 59 | 60 | Inside your controller you use `$indexedDB` like this: 61 | 62 | ```javascript 63 | angular.module('myModuleName') 64 | .controller('myControllerName', function($scope, $indexedDB) { 65 | 66 | $scope.objects = []; 67 | 68 | var OBJECT_STORE_NAME = 'people'; 69 | 70 | /** 71 | * @type {ObjectStore} 72 | */ 73 | var myObjectStore = $indexedDB.objectStore(OBJECT_STORE_NAME); 74 | 75 | myObjectStore.insert({"ssn": "444-444-222-111","name": "John Doe", "age": 57}).then(function(e){...}); 76 | 77 | myObjectStore.getAll().then(function(results) { 78 | // Update scope 79 | $scope.objects = results; 80 | }); 81 | 82 | /** 83 | * execute a query: 84 | * presuming we've an index on 'age' field called 'age_idx' 85 | * find all persons older than 40 years 86 | */ 87 | 88 | var myQuery = $indexedDB.queryBuilder().$index('age_idx').$gt(40).$asc.compile(); 89 | myObjectStore.each(myQuery).then(function(cursor){ 90 | cursor.key; 91 | cursor.value; 92 | ... 93 | }); 94 | }); 95 | ``` 96 | 97 | QueryBuilder aka IDBKeyRange maybe needs some revision. 98 | This is all the info you get for now, for more read the code, it's ndoc-annotated! 99 | 100 | Important note: this software is in alpha state and therefore it's used at your own risk, 101 | don't make me liable for any damages or loss of data! 102 | 103 | Status Update: I'm sorry to say that I've abandoned angularJS for now and therefore have no plans for features or updates. This may change in the future. Apart from that I will apply updates submitted as pull requests when I find the time and see use. 104 | 105 | Anyone willing to join as active developer is welcome to drop me a note and help keep this project alive. 106 | 107 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-indexedDB", 3 | "version": "0.0.0", 4 | "homepage": "https://github.com/bramski/angular-indexedDB", 5 | "authors": [ 6 | "webcss " 7 | ], 8 | "description": "An angularjs serviceprovider to utilize indexedDB with angular", 9 | "main": "src/indexeddb.js", 10 | "keywords": [ 11 | "angularjs", 12 | "indexeddb", 13 | "angular" 14 | ], 15 | "license": "MIT" 16 | } 17 | -------------------------------------------------------------------------------- /src/indexeddb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license $indexedDBProvider 3 | * (c) 2013 Clemens Capitain (webcss) 4 | * License: MIT 5 | */ 6 | 7 | 'use strict'; 8 | 9 | angular.module('xc.indexedDB', []).provider('$indexedDB', function() { 10 | var module = this, 11 | /** IDBTransaction mode constants */ 12 | READONLY = "readonly", 13 | READWRITE = "readwrite", 14 | VERSIONCHANGE = "versionchange", 15 | /** IDBCursor direction and skip behaviour constants */ 16 | NEXT = "next", 17 | NEXTUNIQUE = "nextunique", 18 | PREV = "prev", 19 | PREVUNIQUE = "prevunique"; 20 | 21 | /** predefined variables */ 22 | module.dbName = ''; 23 | module.dbVersion = 1; 24 | module.db = null; 25 | module.dbPromise = null; 26 | module.debugMode = false; 27 | 28 | /** predefined callback functions, can be customized in angular.config */ 29 | module.onTransactionComplete = function(e) { 30 | if(module.debugMode) console.log('Transaction completed.'); 31 | }; 32 | module.onTransactionAbort = function(e) { 33 | if(module.debugMode) console.log('Transaction aborted: '+ (e.target.webkitErrorMessage || e.target.error.message || e.target.errorCode)); 34 | }; 35 | module.onTransactionError = function(e) { 36 | if(module.debugMode) console.log('Transaction failed: ' + e.target.errorCode); 37 | }; 38 | module.onDatabaseError = function(e) { 39 | if(module.debugMode) alert("Database error: " + (e.target.webkitErrorMessage || e.target.errorCode)); 40 | }; 41 | module.onDatabaseBlocked = function(e) { 42 | // If some other tab is loaded with the database, then it needs to be closed 43 | // before we can proceed. 44 | if(module.debugMode) alert("Database is blocked. Try close other tabs with this page open and reload this page!"); 45 | }; 46 | 47 | /** 48 | * @ngdoc function 49 | * @name $indexedDBProvider.connection 50 | * @function 51 | * 52 | * @description 53 | * sets the name of the database to use 54 | * 55 | * @param {string} databaseName database name. 56 | * @returns {object} this 57 | */ 58 | module.connection = function(databaseName) { 59 | module.dbName = databaseName; 60 | return this; 61 | }; 62 | 63 | /** 64 | * @ngdoc function 65 | * @name $indexedDBProvider.upgradeDatabase 66 | * @function 67 | * 68 | * @description provides version number and steps to upgrade the database wrapped in a 69 | * callback function 70 | * 71 | * @param {number} newVersion new version number for the database. 72 | * @param {function} callback the callback which proceeds the upgrade 73 | * @returns {object} this 74 | */ 75 | module.upgradeDatabase = function(newVersion, callback) { 76 | module.dbVersion = newVersion; 77 | module.upgradeCallback = callback; 78 | return this; 79 | }; 80 | 81 | module.$get = ['$q', '$rootScope', '$window', function($q, $rootScope, $window) { 82 | 83 | if(!('indexedDB' in $window)) { 84 | $window.indexedDB = $window.mozIndexedDB || $window.webkitIndexedDB || $window.msIndexedDB; 85 | } 86 | 87 | var IDBKeyRange = $window.IDBKeyRange || $window.mozIDBKeyRange || $window.webkitIDBKeyRange || $window.msIDBKeyRange; 88 | 89 | /** 90 | * @ngdoc object 91 | * @name defaultQueryOptions 92 | * @function 93 | * 94 | * @description optionally specify for cursor requests: 95 | * - which index to use 96 | * - a keyRange to apply 97 | * - the direction of traversal (bottom to top/top to bottom) 98 | */ 99 | var defaultQueryOptions = { 100 | useIndex: undefined, 101 | keyRange: null, 102 | direction: NEXT 103 | }; 104 | /** 105 | * @ngdoc object 106 | * @name dbPromise 107 | * @function 108 | * 109 | * @description open the database specified in $indexedDBProvider.connection and 110 | * $indexdDBProvider.upgradeDatabase and returns a promise for this connection 111 | * @params 112 | * @returns {object} promise $q.promise to fullfill connection 113 | */ 114 | var dbPromise = function() { 115 | var dbReq, deferred; 116 | 117 | if (!module.dbPromise) { 118 | deferred = $q.defer(); 119 | module.dbPromise = deferred.promise; 120 | 121 | dbReq = $window.indexedDB.open(module.dbName, module.dbVersion || 1); 122 | dbReq.onsuccess = function(e) { 123 | module.db = dbReq.result; 124 | $rootScope.$apply(function(){ 125 | deferred.resolve(module.db); 126 | }); 127 | }; 128 | dbReq.onblocked = module.onDatabaseBlocked; 129 | dbReq.onerror = module.onDatabaseError; 130 | dbReq.onupgradeneeded = function(e) { 131 | var db = e.target.result, tx = e.target.transaction; 132 | if(module.debugMode) console.log('upgrading database "' + db.name + '" from version ' + e.oldVersion+ 133 | ' to version ' + e.newVersion + '...'); 134 | module.upgradeCallback && module.upgradeCallback(e, db, tx); 135 | }; 136 | } 137 | 138 | return module.dbPromise; 139 | }; 140 | /** 141 | * @ngdoc object 142 | * @name ObjectStore 143 | * @function 144 | * 145 | * @description wrapper for IDBObjectStore 146 | * 147 | * @params {string} storeName name of the objectstore 148 | */ 149 | var ObjectStore = function(storeName) { 150 | this.storeName = storeName; 151 | this.transaction = undefined; 152 | }; 153 | ObjectStore.prototype = { 154 | /** 155 | * @ngdoc method 156 | * @name ObjectStore.internalObjectStore 157 | * @function 158 | * 159 | * @description used internally to retrieve an objectstore 160 | * with the correct transaction mode 161 | * 162 | * @params {string} storeName name of the objectstore 163 | * @params {string} mode transaction mode to use for operation 164 | * @returns {object} IDBObjectStore the objectstore in question 165 | */ 166 | internalObjectStore: function(storeName, mode) { 167 | var me = this; 168 | return dbPromise().then(function(db){ 169 | me.transaction = db.transaction([storeName], mode || READONLY); 170 | me.transaction.oncomplete = module.onTransactionComplete; 171 | me.transaction.onabort = module.onTransactionAbort; 172 | me.onerror = module.onTransactionError; 173 | 174 | return me.transaction.objectStore(storeName); 175 | }); 176 | }, 177 | /** 178 | * @ngdoc method 179 | * @name ObjectStore.abort 180 | * @function 181 | * 182 | * @description abort the current transaction 183 | */ 184 | "abort": function() { 185 | if (this.transaction) { 186 | this.transaction.abort(); 187 | } 188 | }, 189 | /** 190 | * @ngdoc method 191 | * @name ObjectStore.insert 192 | * @function 193 | * 194 | * @description wrapper for IDBObjectStore.add. 195 | * input data can be a single object or an array of objects for 196 | * bulk insertions within a single transaction 197 | * 198 | * @params {object or array} data the data to insert 199 | * @returns {object} $q.promise a promise on successfull execution 200 | */ 201 | "insert": function(data){ 202 | var d = $q.defer(); 203 | return this.internalObjectStore(this.storeName, READWRITE).then(function(store){ 204 | var req; 205 | if (angular.isArray(data)) { 206 | data.forEach(function(item, i){ 207 | req = store.add(item); 208 | req.onnotify = function(e) { 209 | $rootScope.$apply(function(){ 210 | d.notify(e.target.result); 211 | }); 212 | } 213 | req.onerror = function(e) { 214 | $rootScope.$apply(function(){ 215 | d.reject(e.target.result); 216 | }); 217 | }; 218 | req.onsuccess = function(e) { 219 | if(i == data.length - 1) { 220 | $rootScope.$apply(function(){ 221 | d.resolve(e.target.result); 222 | }); 223 | } 224 | }; 225 | }); 226 | } else { 227 | req = store.add(data); 228 | req.onsuccess = req.onerror = function(e) { 229 | $rootScope.$apply(function(){ 230 | d.resolve(e.target.result); 231 | }); 232 | }; 233 | } 234 | return d.promise; 235 | }); 236 | }, 237 | /** 238 | * @ngdoc method 239 | * @name ObjectStore.upsert 240 | * @function 241 | * 242 | * @description wrapper for IDBObjectStore.put. 243 | * modifies existing values or inserts as new value if nonexistant 244 | * input data can be a single object or an array of objects for 245 | * bulk updates/insertions within a single transaction 246 | * 247 | * @params {object or array} data the data to upsert 248 | * @returns {object} $q.promise a promise on successfull execution 249 | */ 250 | "upsert": function(data){ 251 | var d = $q.defer(); 252 | return this.internalObjectStore(this.storeName, READWRITE).then(function(store){ 253 | var req; 254 | if (angular.isArray(data)) { 255 | data.forEach(function(item, i){ 256 | req = store.put(item); 257 | req.onnotify = function(e) { 258 | $rootScope.$apply(function(){ 259 | d.notify(e.target.result); 260 | }); 261 | } 262 | req.onerror = function(e) { 263 | $rootScope.$apply(function(){ 264 | d.reject(e.target.result); 265 | }); 266 | }; 267 | req.onsuccess = function(e) { 268 | if(i == data.length - 1) { 269 | $rootScope.$apply(function(){ 270 | d.resolve(e.target.result); 271 | }); 272 | } 273 | }; 274 | }); 275 | } else { 276 | req = store.put(data); 277 | req.onsuccess = req.onerror = function(e) { 278 | $rootScope.$apply(function(){ 279 | d.resolve(e.target.result); 280 | }); 281 | }; 282 | } 283 | return d.promise; 284 | }); 285 | }, 286 | /** 287 | * @ngdoc method 288 | * @name ObjectStore.delete 289 | * @function 290 | * 291 | * @description wrapper for IDBObjectStore.delete. 292 | * deletes the value for the specified primary key 293 | * 294 | * @params {any value} key primary key to indetify a value 295 | * @returns {object} $q.promise a promise on successfull execution 296 | */ 297 | "delete": function(key) { 298 | var d = $q.defer(); 299 | return this.internalObjectStore(this.storeName, READWRITE).then(function(store){ 300 | var req = store.delete(key); 301 | req.onsuccess = req.onerror = function(e) { 302 | $rootScope.$apply(function(){ 303 | d.resolve(e.target.result); 304 | }); 305 | }; 306 | return d.promise; 307 | }); 308 | }, 309 | /** 310 | * @ngdoc method 311 | * @name ObjectStore.clear 312 | * @function 313 | * 314 | * @description wrapper for IDBObjectStore.clear. 315 | * removes all data in an objectstore 316 | * 317 | * @returns {object} $q.promise a promise on successfull execution 318 | */ 319 | "clear": function() { 320 | var d = $q.defer(); 321 | return this.internalObjectStore(this.storeName, READWRITE).then(function(store){ 322 | var req = store.clear(); 323 | req.onsuccess = req.onerror = function(e) { 324 | $rootScope.$apply(function(){ 325 | d.resolve(e.target.result); 326 | }); 327 | }; 328 | return d.promise; 329 | }); 330 | }, 331 | /** 332 | * @ngdoc method 333 | * @name ObjectStore.count 334 | * @function 335 | * 336 | * @description wrapper for IDBObjectStore.count. 337 | * returns the number of values in the objectstore, as a promise 338 | * 339 | * @returns {object} $q.promise a promise on successfull execution 340 | */ 341 | "count": function() { 342 | return this.internalObjectStore(this.storeName, READONLY).then(function(store){ 343 | return store.count(); 344 | }); 345 | }, 346 | /** 347 | * @ngdoc method 348 | * @name ObjectStore.find 349 | * @function 350 | * 351 | * @description wrapper for IDBObjectStore.get and IDBIndex.get. 352 | * retrieves a single value with specified key, or index-key 353 | * 354 | * @params {any value} keyOrIndex the key to value, or an indexName 355 | * @params {any value} key the key of an index (*optional*) 356 | * @returns {any value} value ...wrapped in a promise 357 | */ 358 | "find": function(keyOrIndex, keyIfIndex){ 359 | var d = $q.defer(); 360 | var promise = d.promise; 361 | return this.internalObjectStore(this.storeName, READONLY).then(function(store){ 362 | var req; 363 | 364 | if(keyIfIndex) { 365 | req = store.index(keyOrIndex).get(keyIfIndex); 366 | } else { 367 | req = store.get(keyOrIndex); 368 | } 369 | req.onsuccess = req.onerror = function(e) { 370 | $rootScope.$apply(function(){ 371 | d.resolve(e.target.result); 372 | }); 373 | }; 374 | return promise; 375 | }); 376 | }, 377 | /** 378 | * @ngdoc method 379 | * @name ObjectStore.getAll 380 | * @function 381 | * 382 | * @description wrapper for IDBObjectStore.getAll (or shim). 383 | * retrieves all values from objectstore using IDBObjectStore.getAll 384 | * or a cursor request if getAll is not implemented 385 | * 386 | * @returns {array} values ...wrapped in a promise 387 | */ 388 | "getAll": function() { 389 | var results = [], d = $q.defer(); 390 | return this.internalObjectStore(this.storeName, READONLY).then(function(store){ 391 | var req; 392 | if (store.getAll) { 393 | req = store.getAll(); 394 | req.onsuccess = req.onerror = function(e) { 395 | $rootScope.$apply(function(){ 396 | d.resolve(e.target.result); 397 | }); 398 | }; 399 | } else { 400 | req = store.openCursor(); 401 | req.onsuccess = function(e) { 402 | var cursor = e.target.result; 403 | if(cursor){ 404 | results.push(cursor.value); 405 | cursor.continue(); 406 | } else { 407 | $rootScope.$apply(function(){ 408 | d.resolve(results); 409 | }); 410 | } 411 | }; 412 | req.onerror = function(e) { 413 | d.reject(e.target.result); 414 | }; 415 | } 416 | return d.promise; 417 | }); 418 | }, 419 | /** 420 | * @ngdoc method 421 | * @name ObjectStore.each 422 | * @function 423 | * 424 | * @description wrapper for IDBObjectStore.openCursor or IDBIndex.openCursor. 425 | * returns a promise that is resolved when the cursor reaches an end. 426 | * On every "onsuccess" event of the cursor, the callback function is called, passing the cursor itself 427 | * https://developer.mozilla.org/en-US/docs/IndexedDB/Using_IndexedDB#Using_a_cursor 428 | * 429 | * @params {Function} onsuccessCallback the callback which runs when the onsuccess event is triggered 430 | * @params {object} options optional query parameters, see defaultQueryOptions 431 | * and QueryBuilder for details 432 | * @returns {object} IDBCursor ...wrapped in a promise 433 | */ 434 | "each": function(callback, options){ 435 | var d = $q.defer(); 436 | return this.internalObjectStore(this.storeName, READWRITE).then(function(store){ 437 | var req; 438 | options = options || defaultQueryOptions; 439 | if(options.useIndex) { 440 | req = store.index(options.useIndex).openCursor(options.keyRange, options.direction); 441 | } else { 442 | req = store.openCursor(options.keyRange, options.direction); 443 | } 444 | req.onsuccess = req.onerror = function(e) { 445 | $rootScope.$apply(function(){ 446 | if(!e.target.result){ 447 | d.resolve(e.target.result); 448 | } 449 | callback(e.target.result); 450 | }); 451 | }; 452 | return d.promise; 453 | }); 454 | } 455 | }; 456 | 457 | /** 458 | * @ngdoc object 459 | * @name QueryBuilder 460 | * @function 461 | * 462 | * @description utility object to easily create IDBKeyRange for cursor queries 463 | */ 464 | var QueryBuilder = function() { 465 | this.result = defaultQueryOptions; 466 | }; 467 | QueryBuilder.prototype = { 468 | /** 469 | * @ngdoc method 470 | * @name QueryBuilder.$lt 471 | * @function 472 | * 473 | * @description set an upper bound, e.g. A < value, excluding value 474 | * 475 | * @params {any value} value bound value 476 | * @returns {object} this QueryBuilder, for chaining params 477 | */ 478 | "$lt": function(value) { 479 | this.result.keyRange = IDBKeyRange.upperBound(value, true); 480 | return this; 481 | }, 482 | /** 483 | * @ngdoc method 484 | * @name QueryBuilder.$gt 485 | * @function 486 | * 487 | * @description set a lower bound, e.g. A > value, excluding value 488 | * 489 | * @params {any value} value bound value 490 | * @returns {object} this QueryBuilder, for chaining params 491 | */ 492 | "$gt": function(value) { 493 | this.result.keyRange = IDBKeyRange.lowerBound(value, true); 494 | return this; 495 | }, 496 | /** 497 | * @ngdoc method 498 | * @name QueryBuilder.$lte 499 | * @function 500 | * 501 | * @description set an upper bound, e.g. A <= value, including value 502 | * 503 | * @params {any value} value bound value 504 | * @returns {object} this QueryBuilder, for chaining params 505 | */ 506 | "$lte": function(value) { 507 | this.result.keyRange = IDBKeyRange.upperBound(value); 508 | return this; 509 | }, 510 | /** 511 | * @ngdoc method 512 | * @name QueryBuilder.$gte 513 | * @function 514 | * 515 | * @description set an upper bound, e.g. A >= value, including value 516 | * 517 | * @params {any value} value bound value 518 | * @returns {object} this QueryBuilder, for chaining params 519 | */ 520 | "$gte": function(value) { 521 | this.result.keyRange = IDBKeyRange.lowerBound(value); 522 | return this; 523 | }, 524 | /** 525 | * @ngdoc method 526 | * @name QueryBuilder.$eq 527 | * @function 528 | * 529 | * @description exact match, e.g. A = value 530 | * 531 | * @params {any value} value bound value 532 | * @returns {object} this QueryBuilder, for chaining params 533 | */ 534 | "$eq": function(value) { 535 | this.result.keyRange = IDBKeyRange.only(value); 536 | return this; 537 | }, 538 | /** 539 | * @ngdoc method 540 | * @name QueryBuilder.$between 541 | * @function 542 | * 543 | * @description set an upper and lower bound, e.g. low >= value <= hi, 544 | * optionally including value 545 | * 546 | * @params {any value} lowValue lower bound value 547 | * @params {any value} hiValue upper bound value 548 | * @params {boolean} exLow optional, exclude lower bound value 549 | * @params {boolean} exHi optional, exclude upper bound value 550 | * @returns {object} this QueryBuilder, for chaining params 551 | */ 552 | "$between": function(lowValue, hiValue, exLow, exHi) { 553 | this.result.keyRange = IDBKeyRange.bound(lowValue,hiValue,exLow||false,exHi||false); 554 | return this; 555 | }, 556 | /** 557 | * @ngdoc method 558 | * @name QueryBuilder.$asc 559 | * @function 560 | * 561 | * @description set the direction of traversal to ascending (natural) 562 | * 563 | * @params {boolean} unique return only distinct values, skipping 564 | * duplicates (*optional*) 565 | * @returns {object} this QueryBuilder, for chaining params 566 | */ 567 | "$asc": function(unique) { 568 | this.result.order = (unique)? NEXTUNIQUE: NEXT; 569 | return this; 570 | }, 571 | /** 572 | * @ngdoc method 573 | * @name QueryBuilder.$desc 574 | * @function 575 | * 576 | * @description set the direction of traversal to descending order 577 | * 578 | * @params {boolean} unique return only distinct values, skipping 579 | * duplicates (*optional*) 580 | * @returns {object} this QueryBuilder, for chaining params 581 | */ 582 | "$desc": function(unique) { 583 | this.result.order = (unique)? PREVUNIQUE: PREV; 584 | return this; 585 | }, 586 | /** 587 | * @ngdoc method 588 | * @name QueryBuilder.$index 589 | * @function 590 | * 591 | * @description optionally specify an index to use 592 | * 593 | * @params {string} indexName index to use 594 | * @returns {object} this QueryBuilder, for chaining params 595 | */ 596 | "$index": function(indexName) { 597 | this.result.useIndex = indexName; 598 | return this; 599 | }, 600 | /** 601 | * @ngdoc method 602 | * @name QueryBuilder.compile 603 | * @function 604 | * 605 | * @description returns an object to be passed to ObjectStore.each 606 | * @returns {object} queryOptions 607 | */ 608 | "compile": function() { 609 | return this.result; 610 | } 611 | }; 612 | 613 | /** 614 | * @ngdoc angular.$provider 615 | * @name $indexedDB 616 | * @function 617 | * 618 | * @description indexedDB provider object 619 | */ 620 | return { 621 | /** 622 | * @ngdoc method 623 | * @name $indexedDB.objectStore 624 | * @function 625 | * 626 | * @description an IDBObjectStore to use 627 | * 628 | * @params {string} storename the name of the objectstore to use 629 | * @returns {object} ObjectStore 630 | */ 631 | "objectStore": function(storeName) { 632 | return new ObjectStore(storeName); 633 | }, 634 | /** 635 | * @ngdoc method 636 | * @name $indexedDB.dbInfo 637 | * @function 638 | * 639 | * @description statistical information about the current database 640 | * - database name and version 641 | * - objectstores in in database with name, value count, keyPath, 642 | * autoincrement flag and current assigned indices 643 | * 644 | * @returns {object} DBInfo 645 | */ 646 | "dbInfo": function() { 647 | var storeNames, stores = [], tx, store; 648 | return dbPromise().then(function(db){ 649 | storeNames = Array.prototype.slice.apply(db.objectStoreNames); 650 | tx = db.transaction(storeNames, READONLY); 651 | storeNames.forEach(function(storeName){ 652 | store = tx.objectStore(storeName); 653 | stores.push({ 654 | name: storeName, 655 | keyPath: store.keyPath, 656 | autoIncrement: store.autoIncrement, 657 | count: store.count(), 658 | indices: Array.prototype.slice.apply(store.indexNames) 659 | }); 660 | }); 661 | return { 662 | name: db.name, 663 | version: db.version, 664 | objectStores: stores 665 | }; 666 | }); 667 | }, 668 | /** 669 | * @ngdoc method 670 | * @name $indexedDB.close 671 | * @function 672 | * 673 | * @description closes the current active database 674 | * @returns {object} this 675 | */ 676 | "closeDB": function() { 677 | dbPromise().then(function(db){ 678 | db.close(); 679 | }); 680 | 681 | module.db = null; 682 | module.dbPromise = null; 683 | 684 | return this; 685 | }, 686 | /** 687 | * @ngdoc method 688 | * @name $indexedDB.switchDB 689 | * @function 690 | * 691 | * @description closes the current active database and opens another one 692 | * 693 | * @params {string} databaseName the name of the database to use 694 | * @params {number} version the version number of the database 695 | * @params {Function} upgradeCallBack the callback which proceeds the upgrade 696 | * @returns {object} this 697 | */ 698 | "switchDB": function(databaseName, version, upgradeCallback) { 699 | this.closeDB(); 700 | module.dbName = databaseName; 701 | module.dbVersion = version || 1; 702 | module.upgradeCallback = upgradeCallback || function() {}; 703 | return this; 704 | }, 705 | /** 706 | * @ngdoc method 707 | * @name $indexedDB.queryBuilder 708 | * @function 709 | * 710 | * @description provides access to the QueryBuilder utility 711 | * 712 | * @returns {object} QueryBuilder 713 | */ 714 | "queryBuilder": function() { 715 | return new QueryBuilder(); 716 | } 717 | }; 718 | }]; 719 | }); 720 | --------------------------------------------------------------------------------