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: Created June 1, 2018, 1:58 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
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 // from DefaultConfig https://github.com/localForage/localForage/blob/master/src /localforage.js
kzar 2018/06/04 11:06:07 Please could you improve this comment a bit? For e
piscoi.georgiana 2018/06/05 07:15:54 I didn't knew you can link to line numbers. Thanks
22 const localForageDefs = {
kzar 2018/06/04 11:06:07 Nit: Would you mind naming this one more consisten
piscoi.georgiana 2018/06/05 07:15:55 Done.
23 dbName: "localforage",
24 storeName: "keyvaluepairs",
25 version: 2
26 };
27
28 const dbConfig = {
29 dbName: "adbp",
Sebastian Noack 2018/06/01 19:15:46 This acronym seems somewhat bogus. If we abbreviat
piscoi.georgiana 2018/06/05 07:15:55 Done.
30 storeName: "file",
31 keyPath: "fileName",
32 version: 1
33 };
34
35 let dbInstances = {};
Sebastian Noack 2018/06/01 19:15:46 I wonder whether it would be more appropriate to j
kzar 2018/06/04 11:06:07 Yea, I agree.
piscoi.georgiana 2018/06/05 07:15:54 Done.
piscoi.georgiana 2018/06/05 07:15:55 Done.
36 /**
37 * @type Promise
38 */
39 let migrationStatus = {};
40
41 const keyPrefix = "file:";
42
43 /**
44 * Handles migrating a file, if found, from localforage db to the new one
kzar 2018/06/04 11:06:07 Would you mind specifying what "the new one" is he
piscoi.georgiana 2018/06/05 07:15:54 I've changed it, but I'm not 100% sure
45 * @param {string} fileName
46 * Name of the file to be migrated
47 * @return {Promise}
48 * Promise to be resolved or rejected once the operation is completed
49 */
50 function migrateFile(fileName)
51 {
52 let fileData;
53 if (!migrationStatus[fileName])
kzar 2018/06/04 11:06:07 Nit: When the body of an if statement spans multip
piscoi.georgiana 2018/06/05 07:15:54 It did pass. My editor shows me lint errors, but I
54 migrationStatus[fileName] = new Promise((resolve, reject) =>
Sebastian Noack 2018/06/01 19:15:46 Perhaps, rather than migrating each file on demand
piscoi.georgiana 2018/06/05 07:15:55 Done.
55 {
56 return openDB(localForageDefs)
57 .then(dbInstance =>
58 getFile(fileName, dbInstance, localForageDefs.storeName))
59 .then(file =>
60 {
61 fileData = file;
Sebastian Noack 2018/06/01 19:15:46 Rather than making fileData a non-local variable,
62 return openDB(dbConfig);
63 })
64 .then(dbInstance =>
65 saveFile(fileData, dbInstance, dbConfig.storeName))
66 .then(() =>
67 deleteFile(
68 fileName,
69 dbInstances[localForageDefs.dbName],
70 localForageDefs.storeName)
71 ).then(() => resolve())
72 .catch(error =>
73 {
74 // file or store wasn't found so no migration needed
75 if (error.type == "NoSuchFile" || error == "NotFoundError")
76 {
77 return resolve();
78 }
79 });
80 });
81 return migrationStatus[fileName];
82 }
83
84 function fileToKey(fileName)
85 {
86 return keyPrefix + fileName;
87 }
88
89 function formatFile(name, data)
90 {
91 return {
92 fileName: fileToKey(name),
93 content: Array.from(data),
94 lastModified: Date.now()
95 };
96 }
97
98 function openDB(config)
kzar 2018/06/04 11:06:07 I guess we could destructure `config` here? fun
piscoi.georgiana 2018/06/05 07:15:54 Done.
99 {
100 return new Promise((resolve, reject) =>
101 {
102 const {dbName, storeName, version} = config;
Sebastian Noack 2018/06/01 19:15:46 Sorry, this is matter of taste, but at least for t
piscoi.georgiana 2018/06/05 07:15:55 For me, I guess it's mostly reflex from working on
103
104 if (dbInstances[dbName])
105 return resolve(dbInstances[dbName]);
106
107 const req = indexedDB.open(dbName, version);
108
109 req.onsuccess = (event) =>
110 {
111 dbInstances[dbName] = event.currentTarget.result;
112 return resolve(dbInstances[dbName]);
113 };
114
115 req.onerror = reject;
116
117 req.onupgradeneeded = (event) =>
118 {
119 event
120 .currentTarget
121 .result
122 .createObjectStore(storeName,
123 {
124 keyPath: dbConfig.keyPath,
125 autoIncrement: true
126 });
127 };
128 });
129 }
130
131 function getObjectStore(dbInstance, storeName)
132 {
133 return dbInstance
134 .transaction([storeName], IDBTransaction.READ_WRITE)
135 .objectStore(storeName);
136 }
137
138 function getFile(fileName, dbInstance, storeName, from)
139 {
140 return new Promise((resolve, reject) =>
141 {
142 const store = getObjectStore(dbInstance, storeName);
143 const req = store.get(fileToKey(fileName));
144
145 req.onsuccess = (event) =>
kzar 2018/06/04 11:06:07 Nit: While we don't have a rule about adding / omi
piscoi.georgiana 2018/06/05 07:15:55 Done.
146 {
147 const result = event.currentTarget.result;
148 if (result)
149 resolve(result);
150 else
151 reject({type: "NoSuchFile"});
kzar 2018/06/04 11:06:07 Nit: This line isn't indented correctly.
piscoi.georgiana 2018/06/05 07:15:54 Done.
152 };
153 req.onerror = reject;
154 });
155 }
156
157 function saveFile(data, dbInstance, storeName, from)
158 {
159 return new Promise((resolve, reject) =>
160 {
161 const store = getObjectStore(dbInstance, storeName);
162 const req = store.put(data);
163
164 req.onsuccess = resolve;
165 req.onerror = reject;
166 });
167 }
168
169 function deleteFile(fileName, dbInstance, storeName, from)
170 {
171 return new Promise((resolve, reject) =>
172 {
173 const store = getObjectStore(dbInstance, storeName);
174 const req = store.delete(fileToKey(fileName));
175
176 req.onsuccess = resolve;
177 req.onerror = reject;
178 });
179 }
180
181 exports.IO =
182 {
183 /**
184 * Writes text lines to a file.
185 * @param {string} fileName
186 * Name of the file to be written
187 * @param {Iterable.<string>} data
188 * An array-like or iterable object containing the lines (without line
189 * endings)
190 * @return {Promise}
191 * Promise to be resolved or rejected once the operation is completed
192 */
193
kzar 2018/06/04 11:06:07 Nit: Please could you remove this newline?
piscoi.georgiana 2018/06/05 07:15:54 Done.
194 writeToFile(fileName, data)
195 {
196 return migrateFile(fileName)
197 .then(() => openDB(dbConfig))
198 .then(dbInstance =>
199 saveFile(
200 formatFile(fileName, data),
201 dbInstance,
202 dbConfig.storeName)
203 );
204 },
205
206 /**
207 * Reads text lines from a file.
208 * @param {string} fileName
209 * Name of the file to be read
210 * @param {TextSink} listener
211 * Function that will be called for each line in the file
212 * @return {Promise}
213 * Promise to be resolved or rejected once the operation is completed
214 */
215 readFromFile(fileName, listener)
216 {
217 return migrateFile(fileName)
218 .then(() => openDB(dbConfig))
219 .then(dbInstance =>
220 getFile(
221 fileName,
222 dbInstance,
223 dbConfig.storeName)
224 ).then(entry =>
225 {
226 for (let line of entry.content)
227 listener(line);
228 });
229 },
230
231 /**
232 * Retrieves file metadata.
233 * @param {string} fileName
234 * Name of the file to be looked up
235 * @return {Promise.<StatData>}
236 * Promise to be resolved with file metadata once the operation is
237 * completed
238 */
239 statFile(fileName)
240 {
241 return migrateFile(fileName)
242 .then(() => openDB(dbConfig))
243 .then(dbInstance =>
244 getFile(
245 fileName,
246 dbInstance,
247 dbConfig.storeName)
248 ).then(entry =>
249 {
250 return {
251 exists: true,
252 lastModified: entry.lastModified
253 };
254 })
255 .catch(error =>
256 {
257 if (error.type == "NoSuchFile")
258 return {exists: false};
259 throw error;
260 });
261 },
262
263 /**
264 * Renames a file.
265 * @param {string} fromFile
266 * Name of the file to be renamed
267 * @param {string} newName
268 * New file name, will be overwritten if exists
269 * @return {Promise}
270 * Promise to be resolved or rejected once the operation is completed
271 */
272
kzar 2018/06/04 11:06:07 Nit: Please could you remove this newline?
piscoi.georgiana 2018/06/05 07:15:55 Done.
273 renameFile(fromFile, newName)
274 {
275 return migrateFile(fromFile)
276 .then(() => openDB(dbConfig))
277 .then(dbInstance => getFile(fromFile, dbInstance, dbConfig.storeName))
278 .then(fileData =>
279 saveFile(
280 {
281 fileName: fileToKey(newName),
282 content: fileData.content,
283 lastModified: fileData.lastModified
284 },
285 dbInstances[dbConfig.dbName],
286 dbConfig.storeName)
287 ).then(() =>
288 deleteFile(fromFile, dbInstances[dbConfig.dbName], dbConfig.storeName));
289 }
290 };
291
OLDNEW

Powered by Google App Engine
This is Rietveld