@@ -56,7 +56,57 @@ export async function openClientSideStorage(): Promise<commonStorage.Storage> {
5656 } ;
5757 openRequest . onsuccess = ( ) => {
5858 const db = openRequest . result ;
59- resolve ( ClientSideStorage . create ( db ) ) ;
59+ fixOldFiles ( db ) . then ( ( ) => {
60+ resolve ( ClientSideStorage . create ( db ) ) ;
61+ } )
62+ } ;
63+ } ) ;
64+ }
65+
66+ // The following function allows Alan and Liz to load older projects.
67+ // TODO(lizlooney): Remove this function.
68+ async function fixOldFiles ( db : IDBDatabase ) : Promise < void > {
69+ return new Promise ( ( resolve , reject ) => {
70+ const transaction = db . transaction ( [ FILES_STORE_NAME ] , 'readwrite' ) ;
71+ transaction . oncomplete = ( ) => {
72+ resolve ( ) ;
73+ } ;
74+ transaction . onabort = ( ) => {
75+ console . log ( 'IndexedDB transaction aborted.' ) ;
76+ reject ( new Error ( 'IndexedDB transaction aborted.' ) ) ;
77+ } ;
78+ const filesObjectStore = transaction . objectStore ( FILES_STORE_NAME ) ;
79+ const openCursorRequest = filesObjectStore . openCursor ( ) ;
80+ openCursorRequest . onerror = ( ) => {
81+ console . log ( 'IndexedDB openCursor request failed. openCursorRequest.error is...' ) ;
82+ console . log ( openCursorRequest . error ) ;
83+ reject ( new Error ( 'IndexedDB openCursor request failed.' ) ) ;
84+ } ;
85+ openCursorRequest . onsuccess = ( ) => {
86+ const cursor = openCursorRequest . result ;
87+ if ( cursor ) {
88+ const value = cursor . value ;
89+ if ( ! value . path . startsWith ( '/projects/' ) ) {
90+ const oldFilePath = value . path ;
91+ value . path = '/projects/' + value . path ;
92+ const putRequest = filesObjectStore . put ( value ) ;
93+ putRequest . onerror = ( ) => {
94+ console . log ( 'IndexedDB put request failed. putRequest.error is...' ) ;
95+ console . log ( putRequest . error ) ;
96+ throw new Error ( 'IndexedDB put request failed.' ) ;
97+ } ;
98+ const deleteRequest = filesObjectStore . delete ( oldFilePath ) ;
99+ deleteRequest . onerror = ( ) => {
100+ console . log ( 'IndexedDB delete request failed. deleteRequest.error is...' ) ;
101+ console . log ( deleteRequest . error ) ;
102+ throw new Error ( 'IndexedDB delete request failed.' ) ;
103+ } ;
104+ }
105+ cursor . continue ( ) ;
106+ } else {
107+ // The cursor is done. We have finished reading all the files.
108+ resolve ( ) ;
109+ }
60110 } ;
61111 } ) ;
62112}
@@ -124,13 +174,12 @@ class ClientSideStorage implements commonStorage.Storage {
124174 } ) ;
125175 }
126176
127- async listFilePaths ( opt_filePathRegexPattern ?: string ) : Promise < string [ ] > {
128-
129- const regExp = opt_filePathRegexPattern
130- ? new RegExp ( opt_filePathRegexPattern )
131- : null ;
177+ async list ( path : string ) : Promise < string [ ] > {
178+ if ( ! path . endsWith ( '/' ) ) {
179+ path += '/' ;
180+ }
132181 return new Promise ( ( resolve , reject ) => {
133- const filePaths : string [ ] = [ ] ;
182+ const resultsSet : Set < string > = new Set ( ) ;
134183 const openKeyCursorRequest = this . db . transaction ( [ FILES_STORE_NAME ] , 'readonly' )
135184 . objectStore ( FILES_STORE_NAME )
136185 . openKeyCursor ( ) ;
@@ -143,18 +192,122 @@ class ClientSideStorage implements commonStorage.Storage {
143192 const cursor = openKeyCursorRequest . result ;
144193 if ( cursor && cursor . key ) {
145194 const filePath : string = cursor . key as string ;
146- if ( ! regExp || regExp . test ( filePath ) ) {
147- filePaths . push ( filePath ) ;
195+ if ( filePath . startsWith ( path ) ) {
196+ const relativePath = filePath . substring ( path . length ) ;
197+ const slash = relativePath . indexOf ( '/' ) ;
198+ const result = ( slash != - 1 )
199+ ? relativePath . substring ( 0 , slash + 1 ) // Include the trailing slash.
200+ : relativePath ;
201+ resultsSet . add ( result ) ;
148202 }
149203 cursor . continue ( ) ;
150204 } else {
151205 // The cursor is done. We have finished reading all the files.
152- resolve ( filePaths ) ;
206+ resolve ( [ ... resultsSet ] ) ;
153207 }
154208 } ;
155209 } ) ;
156210 }
157211
212+ async rename ( oldPath : string , newPath : string ) : Promise < void > {
213+ if ( oldPath . endsWith ( '/' ) ) {
214+ return this . renameDirectory ( oldPath , newPath ) ;
215+ }
216+ return this . renameFile ( oldPath , newPath ) ;
217+ }
218+
219+ private async renameDirectory ( oldPath : string , newPath : string ) : Promise < void > {
220+ return new Promise ( ( resolve , reject ) => {
221+ const transaction = this . db . transaction ( [ FILES_STORE_NAME ] , 'readwrite' ) ;
222+ transaction . oncomplete = ( ) => {
223+ resolve ( ) ;
224+ } ;
225+ transaction . onabort = ( ) => {
226+ console . log ( 'IndexedDB transaction aborted.' ) ;
227+ reject ( new Error ( 'IndexedDB transaction aborted.' ) ) ;
228+ } ;
229+ const filesObjectStore = transaction . objectStore ( FILES_STORE_NAME ) ;
230+ const openCursorRequest = filesObjectStore . openCursor ( ) ;
231+ openCursorRequest . onerror = ( ) => {
232+ console . log ( 'IndexedDB openCursor request failed. openCursorRequest.error is...' ) ;
233+ console . log ( openCursorRequest . error ) ;
234+ throw new Error ( 'IndexedDB openCursor request failed.' ) ;
235+ } ;
236+ openCursorRequest . onsuccess = ( ) => {
237+ const cursor = openCursorRequest . result ;
238+ if ( cursor ) {
239+ const value = cursor . value ;
240+ if ( value . path . startsWith ( oldPath ) ) {
241+ const relativePath = value . path . substring ( oldPath . length ) ;
242+ const oldFilePath = value . path ;
243+ value . path = newPath + relativePath ;
244+ const putRequest = filesObjectStore . put ( value ) ;
245+ putRequest . onerror = ( ) => {
246+ console . log ( 'IndexedDB put request failed. putRequest.error is...' ) ;
247+ console . log ( putRequest . error ) ;
248+ throw new Error ( 'IndexedDB put request failed.' ) ;
249+ } ;
250+ putRequest . onsuccess = ( ) => {
251+ const deleteRequest = filesObjectStore . delete ( oldFilePath ) ;
252+ deleteRequest . onerror = ( ) => {
253+ console . log ( 'IndexedDB delete request failed. deleteRequest.error is...' ) ;
254+ console . log ( deleteRequest . error ) ;
255+ throw new Error ( 'IndexedDB delete request failed.' ) ;
256+ } ;
257+ }
258+ }
259+ cursor . continue ( ) ;
260+ } else {
261+ // The cursor is done. We have finished reading all the files.
262+ resolve ( ) ;
263+ }
264+ } ;
265+ } ) ;
266+ }
267+
268+ private async renameFile ( oldPath : string , newPath : string ) : Promise < void > {
269+ return new Promise ( ( resolve , reject ) => {
270+ const transaction = this . db . transaction ( [ FILES_STORE_NAME ] , 'readwrite' ) ;
271+ transaction . oncomplete = ( ) => {
272+ resolve ( ) ;
273+ } ;
274+ transaction . onabort = ( ) => {
275+ console . log ( 'IndexedDB transaction aborted.' ) ;
276+ reject ( new Error ( 'IndexedDB transaction aborted.' ) ) ;
277+ } ;
278+ const filesObjectStore = transaction . objectStore ( FILES_STORE_NAME ) ;
279+ const getRequest = filesObjectStore . get ( oldPath ) ;
280+ getRequest . onerror = ( ) => {
281+ console . log ( 'IndexedDB get request failed. getRequest.error is...' ) ;
282+ console . log ( getRequest . error ) ;
283+ throw new Error ( 'IndexedDB get request failed.' ) ;
284+ } ;
285+ getRequest . onsuccess = ( ) => {
286+ if ( getRequest . result === undefined ) {
287+ console . log ( 'IndexedDB get request succeeded, but the file does not exist.' ) ;
288+ throw new Error ( 'IndexedDB get request succeeded, but the file does not exist.' ) ;
289+ return ;
290+ }
291+ const value = getRequest . result ;
292+ value . path = newPath ;
293+ const putRequest = filesObjectStore . put ( value ) ;
294+ putRequest . onerror = ( ) => {
295+ console . log ( 'IndexedDB put request failed. putRequest.error is...' ) ;
296+ console . log ( putRequest . error ) ;
297+ throw new Error ( 'IndexedDB put request failed.' ) ;
298+ } ;
299+ putRequest . onsuccess = ( ) => {
300+ const deleteRequest = filesObjectStore . delete ( oldPath ) ;
301+ deleteRequest . onerror = ( ) => {
302+ console . log ( 'IndexedDB delete request failed. deleteRequest.error is...' ) ;
303+ console . log ( deleteRequest . error ) ;
304+ throw new Error ( 'IndexedDB delete request failed.' ) ;
305+ } ;
306+ } ;
307+ } ;
308+ } ) ;
309+ }
310+
158311 async fetchFileContentText ( filePath : string ) : Promise < string > {
159312 return new Promise ( ( resolve , reject ) => {
160313 const getRequest = this . db . transaction ( [ FILES_STORE_NAME ] , 'readonly' )
@@ -213,7 +366,52 @@ class ClientSideStorage implements commonStorage.Storage {
213366 } ) ;
214367 }
215368
216- async deleteFile ( filePath : string ) : Promise < void > {
369+ async delete ( path : string ) : Promise < void > {
370+ if ( path . endsWith ( '/' ) ) {
371+ return this . deleteDirectory ( path ) ;
372+ }
373+ return this . deleteFile ( path ) ;
374+ }
375+
376+ private async deleteDirectory ( path : string ) : Promise < void > {
377+ return new Promise ( ( resolve , reject ) => {
378+ const transaction = this . db . transaction ( [ FILES_STORE_NAME ] , 'readwrite' ) ;
379+ transaction . oncomplete = ( ) => {
380+ resolve ( ) ;
381+ } ;
382+ transaction . onabort = ( ) => {
383+ console . log ( 'IndexedDB transaction aborted.' ) ;
384+ reject ( new Error ( 'IndexedDB transaction aborted.' ) ) ;
385+ } ;
386+ const filesObjectStore = transaction . objectStore ( FILES_STORE_NAME ) ;
387+ const openKeyCursorRequest = filesObjectStore . openKeyCursor ( ) ;
388+ openKeyCursorRequest . onerror = ( ) => {
389+ console . log ( 'IndexedDB openKeyCursor request failed. openKeyCursorRequest.error is...' ) ;
390+ console . log ( openKeyCursorRequest . error ) ;
391+ throw new Error ( 'IndexedDB openKeyCursor request failed.' ) ;
392+ } ;
393+ openKeyCursorRequest . onsuccess = ( ) => {
394+ const cursor = openKeyCursorRequest . result ;
395+ if ( cursor && cursor . key ) {
396+ const filePath : string = cursor . key as string ;
397+ if ( filePath . startsWith ( path ) ) {
398+ const deleteRequest = filesObjectStore . delete ( filePath ) ;
399+ deleteRequest . onerror = ( ) => {
400+ console . log ( 'IndexedDB delete request failed. deleteRequest.error is...' ) ;
401+ console . log ( deleteRequest . error ) ;
402+ throw new Error ( 'IndexedDB delete request failed.' ) ;
403+ } ;
404+ }
405+ cursor . continue ( ) ;
406+ } else {
407+ // The cursor is done. We have finished reading all the files.
408+ resolve ( ) ;
409+ }
410+ } ;
411+ } ) ;
412+ }
413+
414+ private async deleteFile ( filePath : string ) : Promise < void > {
217415 return new Promise ( ( resolve , reject ) => {
218416 const transaction = this . db . transaction ( [ FILES_STORE_NAME ] , 'readwrite' ) ;
219417 transaction . oncomplete = ( ) => {
0 commit comments