|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 let DEBUG = 0; |
|
8 let debug; |
|
9 if (DEBUG) { |
|
10 debug = function (s) { dump("-*- IndexedDBHelper: " + s + "\n"); } |
|
11 } else { |
|
12 debug = function (s) {} |
|
13 } |
|
14 |
|
15 const Cu = Components.utils; |
|
16 const Cc = Components.classes; |
|
17 const Ci = Components.interfaces; |
|
18 |
|
19 this.EXPORTED_SYMBOLS = ["IndexedDBHelper"]; |
|
20 |
|
21 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
22 Cu.import("resource://gre/modules/Services.jsm"); |
|
23 Cu.importGlobalProperties(["indexedDB"]); |
|
24 |
|
25 this.IndexedDBHelper = function IndexedDBHelper() {} |
|
26 |
|
27 IndexedDBHelper.prototype = { |
|
28 |
|
29 // Cache the database |
|
30 _db: null, |
|
31 |
|
32 // Close the database |
|
33 close: function close() { |
|
34 if (this._db) { |
|
35 this._db.close(); |
|
36 this._db = null; |
|
37 } |
|
38 }, |
|
39 |
|
40 /** |
|
41 * Open a new database. |
|
42 * User has to provide upgradeSchema. |
|
43 * |
|
44 * @param successCb |
|
45 * Success callback to call once database is open. |
|
46 * @param failureCb |
|
47 * Error callback to call when an error is encountered. |
|
48 */ |
|
49 open: function open(aSuccessCb, aFailureCb) { |
|
50 let self = this; |
|
51 if (DEBUG) debug("Try to open database:" + self.dbName + " " + self.dbVersion); |
|
52 let req = indexedDB.open(this.dbName, this.dbVersion); |
|
53 req.onsuccess = function (event) { |
|
54 if (DEBUG) debug("Opened database:" + self.dbName + " " + self.dbVersion); |
|
55 self._db = event.target.result; |
|
56 self._db.onversionchange = function(event) { |
|
57 if (DEBUG) debug("WARNING: DB modified from a different window."); |
|
58 } |
|
59 aSuccessCb && aSuccessCb(); |
|
60 }; |
|
61 |
|
62 req.onupgradeneeded = function (aEvent) { |
|
63 if (DEBUG) { |
|
64 debug("Database needs upgrade:" + self.dbName + aEvent.oldVersion + aEvent.newVersion); |
|
65 debug("Correct new database version:" + (aEvent.newVersion == this.dbVersion)); |
|
66 } |
|
67 |
|
68 let _db = aEvent.target.result; |
|
69 self.upgradeSchema(req.transaction, _db, aEvent.oldVersion, aEvent.newVersion); |
|
70 }; |
|
71 req.onerror = function (aEvent) { |
|
72 if (DEBUG) debug("Failed to open database: " + self.dbName); |
|
73 aFailureCb && aFailureCb(aEvent.target.error.name); |
|
74 }; |
|
75 req.onblocked = function (aEvent) { |
|
76 if (DEBUG) debug("Opening database request is blocked."); |
|
77 }; |
|
78 }, |
|
79 |
|
80 /** |
|
81 * Use the cached DB or open a new one. |
|
82 * |
|
83 * @param successCb |
|
84 * Success callback to call. |
|
85 * @param failureCb |
|
86 * Error callback to call when an error is encountered. |
|
87 */ |
|
88 ensureDB: function ensureDB(aSuccessCb, aFailureCb) { |
|
89 if (this._db) { |
|
90 if (DEBUG) debug("ensureDB: already have a database, returning early."); |
|
91 aSuccessCb && aSuccessCb(); |
|
92 return; |
|
93 } |
|
94 this.open(aSuccessCb, aFailureCb); |
|
95 }, |
|
96 |
|
97 /** |
|
98 * Start a new transaction. |
|
99 * |
|
100 * @param txn_type |
|
101 * Type of transaction (e.g. "readwrite") |
|
102 * @param store_name |
|
103 * The object store you want to be passed to the callback |
|
104 * @param callback |
|
105 * Function to call when the transaction is available. It will |
|
106 * be invoked with the transaction and the `store' object store. |
|
107 * @param successCb |
|
108 * Success callback to call on a successful transaction commit. |
|
109 * The result is stored in txn.result. |
|
110 * @param failureCb |
|
111 * Error callback to call when an error is encountered. |
|
112 */ |
|
113 newTxn: function newTxn(txn_type, store_name, callback, successCb, failureCb) { |
|
114 this.ensureDB(function () { |
|
115 if (DEBUG) debug("Starting new transaction" + txn_type); |
|
116 let txn = this._db.transaction(Array.isArray(store_name) ? store_name : this.dbStoreNames, txn_type); |
|
117 if (DEBUG) debug("Retrieving object store", this.dbName); |
|
118 let stores; |
|
119 if (Array.isArray(store_name)) { |
|
120 stores = []; |
|
121 for (let i = 0; i < store_name.length; ++i) { |
|
122 stores.push(txn.objectStore(store_name[i])); |
|
123 } |
|
124 } else { |
|
125 stores = txn.objectStore(store_name); |
|
126 } |
|
127 |
|
128 txn.oncomplete = function (event) { |
|
129 if (DEBUG) debug("Transaction complete. Returning to callback."); |
|
130 if (successCb) { |
|
131 successCb(txn.result); |
|
132 } |
|
133 }; |
|
134 |
|
135 txn.onabort = function (event) { |
|
136 if (DEBUG) debug("Caught error on transaction"); |
|
137 /* |
|
138 * event.target.error may be null |
|
139 * if txn was aborted by calling txn.abort() |
|
140 */ |
|
141 if (failureCb) { |
|
142 if (event.target.error) { |
|
143 failureCb(event.target.error.name); |
|
144 } else { |
|
145 failureCb("UnknownError"); |
|
146 } |
|
147 } |
|
148 }; |
|
149 callback(txn, stores); |
|
150 }.bind(this), failureCb); |
|
151 }, |
|
152 |
|
153 /** |
|
154 * Initialize the DB. Does not call open. |
|
155 * |
|
156 * @param aDBName |
|
157 * DB name for the open call. |
|
158 * @param aDBVersion |
|
159 * Current DB version. User has to implement upgradeSchema. |
|
160 * @param aDBStoreName |
|
161 * ObjectStore that is used. |
|
162 */ |
|
163 initDBHelper: function initDBHelper(aDBName, aDBVersion, aDBStoreNames) { |
|
164 this.dbName = aDBName; |
|
165 this.dbVersion = aDBVersion; |
|
166 this.dbStoreNames = aDBStoreNames; |
|
167 } |
|
168 } |