Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/ioIndexedDB.js

Issue 29796555: Issue 6621 (Closed)
Patch Set: Most of the changes from P3 Created June 11, 2018, 7:02 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/io.js ('k') | metadata.edge » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 "use strict";
19
20
21 // values from the DefaultConfig
22 // https://github.com/localForage/localForage/blob/2cdbd74/src/localforage.js#L4 2-L51
23 const localForageDbConfig = {
24 dbName: "localforage",
25 storeName: "keyvaluepairs",
26 version: 2
27 };
28
29 const dbConfig = {
30 dbName: "adblockplus",
31 storeName: "file",
32 keyPath: "fileName",
33 version: 1
34 };
35
36 let db = openDB(dbConfig);
37 let migrationDone = migrateFiles();
38
39 const keyPrefix = "file:";
40
41 /**
42 * Handles migrating all files from localforage db
43 * used in the previous implementation by the localForage library
44 * to the new adblockplus db that we use as a replacement
45 * @return {Promise}
46 * Promise to be resolved or rejected once the operation is completed
47 */
48 function migrateFiles()
49 {
50 return openDB(localForageDbConfig)
51 .then(localForageDb =>
52 {
53 return getAllFiles(localForageDb, localForageDbConfig.storeName)
kzar 2018/06/12 10:46:17 Nit: I guess we can omit the curly braces and the
piscoi.georgiana 2018/06/14 13:41:26 Done.
54 .then(files =>
55 db.then(dbInstance => files.map(file =>
56 Promise.all(saveFile(file, dbInstance, dbConfig.storeName)))))
Sebastian Noack 2018/06/13 00:55:12 Please apologize if I'm wrong, but to me this seem
piscoi.georgiana 2018/06/14 13:41:27 Spot on, thank you! I've fixed it.
57 .then(() =>
58 clearObjectStore(localForageDb, localForageDbConfig.storeName));
59 });
60 }
61
62 function getAllFiles(dbInstance, storeName)
63 {
64 return new Promise((resolve, reject) =>
65 {
66 // edge doesn't currently support getAll method on IDBObjectStore interface
67 // so a cursor is used to iterate over all objects from the store
68 let transaction = dbInstance
69 .transaction([storeName], IDBTransaction.READ_ONLY);
70
71 let store = transaction.objectStore(storeName);
72 let cursorReq = store.openCursor();
73 let filesData = [];
74
75 transaction.oncomplete = event =>
76 {
77 resolve(filesData);
78 };
79
80 cursorReq.onsuccess = event =>
81 {
82 let cursor = event.currentTarget.result;
83 if (cursor)
84 {
85 let value = cursor.value;
86
87 filesData.push({
88 fileName: cursor.key,
89 content: value.content,
90 lastModified: value.lastModified
91 });
92 cursor.continue();
93 }
94 };
95
96 cursorReq.onerror = reject;
97 });
98 }
99
100 function clearObjectStore(dbInstance, storeName)
101 {
102 return new Promise((resolve, reject) =>
103 {
104 let store = getObjectStore(dbInstance, storeName);
105 let req = store.clear();
106
107 req.onsuccess = resolve;
108 req.onerror = reject;
109 });
110 }
111
112 function fileToKey(fileName)
113 {
114 return keyPrefix + fileName;
115 }
116
117 function formatFile(name, data)
118 {
119 return {
120 fileName: fileToKey(name),
121 content: Array.from(data),
122 lastModified: Date.now()
123 };
124 }
125
126 function openDB({dbName, storeName, version, keyPath})
127 {
128 return new Promise((resolve, reject) =>
129 {
130 let req = indexedDB.open(dbName, version);
131
132 req.onsuccess = event =>
133 {
134 return resolve(event.currentTarget.result);
135 };
136
137 req.onerror = reject;
138
139 req.onupgradeneeded = event =>
140 {
141 event
142 .currentTarget
143 .result
144 .createObjectStore(storeName,
145 {
146 keyPath,
147 autoIncrement: true
148 });
149 };
150 });
151 }
152
153 function getObjectStore(dbInstance, storeName)
154 {
155 return dbInstance
156 .transaction([storeName], IDBTransaction.READ_WRITE)
157 .objectStore(storeName);
158 }
159
160 function getFile(fileName, dbInstance, storeName)
161 {
162 return new Promise((resolve, reject) =>
163 {
164 let store = getObjectStore(dbInstance, storeName);
165 let req = store.get(fileToKey(fileName));
166
167 req.onsuccess = event =>
168 {
169 let result = event.currentTarget.result;
170
171 if (result)
172 resolve(result);
173 else
174 reject({type: "NoSuchFile"});
175 };
176 req.onerror = reject;
177 });
178 }
179
180 function saveFile(data, dbInstance, storeName)
181 {
182 return new Promise((resolve, reject) =>
183 {
184 let store = getObjectStore(dbInstance, storeName);
185 let req = store.put(data);
186
187 req.onsuccess = resolve;
188 req.onerror = reject;
189 });
190 }
191
192 function deleteFile(fileName, dbInstance, storeName)
193 {
194 return new Promise((resolve, reject) =>
195 {
196 let store = getObjectStore(dbInstance, storeName);
197 let req = store.delete(fileToKey(fileName));
198
199 req.onsuccess = resolve;
200 req.onerror = reject;
201 });
202 }
203
204 exports.IO =
205 {
206 /**
207 * Writes text lines to a file.
208 * @param {string} fileName
209 * Name of the file to be written
210 * @param {Iterable.<string>} data
211 * An array-like or iterable object containing the lines (without line
212 * endings)
213 * @return {Promise}
214 * Promise to be resolved or rejected once the operation is completed
215 */
216 writeToFile(fileName, data)
217 {
218 return migrationDone
219 .then(() => db)
220 .then(dbInstance =>
221 saveFile(formatFile(fileName, data), dbInstance, dbConfig.storeName));
222 },
223
224 /**
225 * Reads text lines from a file.
226 * @param {string} fileName
227 * Name of the file to be read
228 * @param {TextSink} listener
229 * Function that will be called for each line in the file
230 * @return {Promise}
231 * Promise to be resolved or rejected once the operation is completed
232 */
233 readFromFile(fileName, listener)
234 {
235 return migrationDone
236 .then(() => db)
237 .then(dbInstance => getFile(fileName, dbInstance, dbConfig.storeName))
238 .then(entry =>
239 {
240 for (let line of entry.content)
241 listener(line);
242 });
243 },
244
245 /**
246 * Retrieves file metadata.
247 * @param {string} fileName
248 * Name of the file to be looked up
249 * @return {Promise.<StatData>}
250 * Promise to be resolved with file metadata once the operation is
251 * completed
252 */
253 statFile(fileName)
254 {
255 return migrationDone
256 .then(() => db)
kzar 2018/06/12 10:46:17 Couldn't we do `db.then(dbInstance => ...` instead
piscoi.georgiana 2018/06/14 13:41:27 Yes, it looks better your way. Thank you!
257 .then(dbInstance => getFile(fileName, dbInstance, dbConfig.storeName))
258 .then(entry =>
259 {
260 return {
261 exists: true,
262 lastModified: entry.lastModified
263 };
264 })
265 .catch(error =>
266 {
267 if (error.type == "NoSuchFile")
268 return {exists: false};
269 throw error;
270 });
271 },
272
273 /**
274 * Renames a file.
275 * @param {string} fromFile
276 * Name of the file to be renamed
277 * @param {string} newName
278 * New file name, will be overwritten if exists
279 * @return {Promise}
280 * Promise to be resolved or rejected once the operation is completed
281 */
282 renameFile(fromFile, newName)
283 {
284 return migrationDone
285 .then(() => db)
286 .then(dbInstance =>
287 getFile(fromFile, dbInstance, dbConfig.storeName)
288 .then(fileData =>
289 saveFile(
290 {
291 fileName: fileToKey(newName),
292 content: fileData.content,
293 lastModified: fileData.lastModified
294 },
295 dbInstance,
296 dbConfig.storeName))
297 .then(() => deleteFile(fromFile, dbInstance, dbConfig.storeName)));
298 }
299 };
300
OLDNEW
« no previous file with comments | « lib/io.js ('k') | metadata.edge » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld