Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / devtools / shared / async-storage.js
blobdd7ee0674e3450af72d1bb73262a8510b0625072
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
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /**
7 * Adapted from https://github.com/mozilla-b2g/gaia/blob/f09993563fb5fec4393eb71816ce76cb00463190/shared/js/async_storage.js
8 * (converted to use Promises instead of callbacks).
10 * This file defines an asynchronous version of the localStorage API, backed by
11 * an IndexedDB database. It creates a global asyncStorage object that has
12 * methods like the localStorage object.
14 * To store a value use setItem:
16 * asyncStorage.setItem("key", "value");
18 * This returns a promise in case you want confirmation that the value has been stored.
20 * asyncStorage.setItem("key", "newvalue").then(function() {
21 * console.log("new value stored");
22 * });
24 * To read a value, call getItem(), but note that you must wait for a promise
25 * resolution for the value to be retrieved.
27 * asyncStorage.getItem("key").then(function(value) {
28 * console.log("The value of key is:", value);
29 * });
31 * Note that unlike localStorage, asyncStorage does not allow you to store and
32 * retrieve values by setting and querying properties directly. You cannot just
33 * write asyncStorage.key; you have to explicitly call setItem() or getItem().
35 * removeItem(), clear(), length(), and key() are like the same-named methods of
36 * localStorage, and all return a promise.
38 * The asynchronous nature of getItem() makes it tricky to retrieve multiple
39 * values. But unlike localStorage, asyncStorage does not require the values you
40 * store to be strings. So if you need to save multiple values and want to
41 * retrieve them together, in a single asynchronous operation, just group the
42 * values into a single object. The properties of this object may not include
43 * DOM elements, but they may include things like Blobs and typed arrays.
47 "use strict";
49 const DBNAME = "devtools-async-storage";
50 const DBVERSION = 1;
51 const STORENAME = "keyvaluepairs";
52 var db = null;
54 loader.lazyRequireGetter(
55 this,
56 "indexedDB",
57 "resource://devtools/shared/indexed-db.js"
60 function withStore(type, onsuccess, onerror) {
61 if (db) {
62 const transaction = db.transaction(STORENAME, type);
63 const store = transaction.objectStore(STORENAME);
64 onsuccess(store);
65 } else {
66 const openreq = indexedDB.open(DBNAME, DBVERSION);
67 openreq.onerror = function withStoreOnError() {
68 onerror();
70 openreq.onupgradeneeded = function withStoreOnUpgradeNeeded() {
71 // First time setup: create an empty object store
72 openreq.result.createObjectStore(STORENAME);
74 openreq.onsuccess = function withStoreOnSuccess() {
75 db = openreq.result;
76 const transaction = db.transaction(STORENAME, type);
77 const store = transaction.objectStore(STORENAME);
78 onsuccess(store);
83 function getItem(itemKey) {
84 return new Promise((resolve, reject) => {
85 let req;
86 withStore(
87 "readonly",
88 store => {
89 store.transaction.oncomplete = function onComplete() {
90 let value = req.result;
91 if (value === undefined) {
92 value = null;
94 resolve(value);
96 req = store.get(itemKey);
97 req.onerror = function getItemOnError() {
98 console.error("Error in asyncStorage.getItem():", req.error.name);
99 reject(req.error);
102 reject
107 function setItem(itemKey, value) {
108 return new Promise((resolve, reject) => {
109 withStore(
110 "readwrite",
111 store => {
112 store.transaction.oncomplete = resolve;
113 const req = store.put(value, itemKey);
114 req.onerror = function setItemOnError() {
115 console.error("Error in asyncStorage.setItem():", req.error.name);
116 reject(req.error);
119 reject
124 function removeItem(itemKey) {
125 return new Promise((resolve, reject) => {
126 withStore(
127 "readwrite",
128 store => {
129 store.transaction.oncomplete = resolve;
130 const req = store.delete(itemKey);
131 req.onerror = function removeItemOnError() {
132 console.error("Error in asyncStorage.removeItem():", req.error.name);
133 reject(req.error);
136 reject
141 function clear() {
142 return new Promise((resolve, reject) => {
143 withStore(
144 "readwrite",
145 store => {
146 store.transaction.oncomplete = resolve;
147 const req = store.clear();
148 req.onerror = function clearOnError() {
149 console.error("Error in asyncStorage.clear():", req.error.name);
150 reject(req.error);
153 reject
158 function length() {
159 return new Promise((resolve, reject) => {
160 let req;
161 withStore(
162 "readonly",
163 store => {
164 store.transaction.oncomplete = function onComplete() {
165 resolve(req.result);
167 req = store.count();
168 req.onerror = function lengthOnError() {
169 console.error("Error in asyncStorage.length():", req.error.name);
170 reject(req.error.name);
173 reject
178 function key(n) {
179 return new Promise((resolve, reject) => {
180 if (n < 0) {
181 resolve(null);
182 return;
185 let req;
186 withStore(
187 "readonly",
188 store => {
189 store.transaction.oncomplete = function onComplete() {
190 const cursor = req.result;
191 resolve(cursor ? cursor.key : null);
193 let advanced = false;
194 req = store.openCursor();
195 req.onsuccess = function keyOnSuccess() {
196 const cursor = req.result;
197 if (!cursor) {
198 // this means there weren"t enough keys
199 return;
201 if (n === 0 || advanced) {
202 // Either 1) we have the first key, return it if that's what they
203 // wanted, or 2) we"ve got the nth key.
204 return;
207 // Otherwise, ask the cursor to skip ahead n records
208 advanced = true;
209 cursor.advance(n);
211 req.onerror = function keyOnError() {
212 console.error("Error in asyncStorage.key():", req.error.name);
213 reject(req.error);
216 reject
221 exports.getItem = getItem;
222 exports.setItem = setItem;
223 exports.removeItem = removeItem;
224 exports.clear = clear;
225 exports.length = length;
226 exports.key = key;