Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / sdk / IndexedDBModel.js
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /**
32  * @constructor
33  * @extends {WebInspector.TargetAwareObject}
34  */
35 WebInspector.IndexedDBModel = function(target)
36 {
37     WebInspector.TargetAwareObject.call(this, target);
38     this._agent = target.indexedDBAgent();
39     this._agent.enable();
40
41     target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginAdded, this._securityOriginAdded, this);
42     target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginRemoved, this._securityOriginRemoved, this);
43
44     /** @type {!Map.<!WebInspector.IndexedDBModel.DatabaseId, !WebInspector.IndexedDBModel.Database>} */
45     this._databases = new Map();
46     /** @type {!Object.<string, !Array.<string>>} */
47     this._databaseNamesBySecurityOrigin = {};
48     this._reset();
49 }
50
51 WebInspector.IndexedDBModel.KeyTypes = {
52     NumberType:  "number",
53     StringType:  "string",
54     DateType:    "date",
55     ArrayType:   "array"
56 };
57
58 WebInspector.IndexedDBModel.KeyPathTypes = {
59     NullType:    "null",
60     StringType:  "string",
61     ArrayType:   "array"
62 };
63
64 WebInspector.IndexedDBModel.keyFromIDBKey = function(idbKey)
65 {
66     if (typeof(idbKey) === "undefined" || idbKey === null)
67         return null;
68
69     var key = {};
70     switch (typeof(idbKey)) {
71     case "number":
72         key.number = idbKey;
73         key.type = WebInspector.IndexedDBModel.KeyTypes.NumberType;
74         break;
75     case "string":
76         key.string = idbKey;
77         key.type = WebInspector.IndexedDBModel.KeyTypes.StringType;
78         break;
79     case "object":
80         if (idbKey instanceof Date) {
81             key.date = idbKey.getTime();
82             key.type = WebInspector.IndexedDBModel.KeyTypes.DateType;
83         } else if (idbKey instanceof Array) {
84             key.array = [];
85             for (var i = 0; i < idbKey.length; ++i)
86                 key.array.push(WebInspector.IndexedDBModel.keyFromIDBKey(idbKey[i]));
87             key.type = WebInspector.IndexedDBModel.KeyTypes.ArrayType;
88         }
89         break;
90     default:
91         return null;
92     }
93     return key;
94 }
95
96 WebInspector.IndexedDBModel.keyRangeFromIDBKeyRange = function(idbKeyRange)
97 {
98     var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
99     if (typeof(idbKeyRange) === "undefined" || idbKeyRange === null)
100         return null;
101
102     var keyRange = {};
103     keyRange.lower = WebInspector.IndexedDBModel.keyFromIDBKey(idbKeyRange.lower);
104     keyRange.upper = WebInspector.IndexedDBModel.keyFromIDBKey(idbKeyRange.upper);
105     keyRange.lowerOpen = idbKeyRange.lowerOpen;
106     keyRange.upperOpen = idbKeyRange.upperOpen;
107     return keyRange;
108 }
109
110 /**
111  * @param {!IndexedDBAgent.KeyPath} keyPath
112  */
113 WebInspector.IndexedDBModel.idbKeyPathFromKeyPath = function(keyPath)
114 {
115     var idbKeyPath;
116     switch (keyPath.type) {
117     case WebInspector.IndexedDBModel.KeyPathTypes.NullType:
118         idbKeyPath = null;
119         break;
120     case WebInspector.IndexedDBModel.KeyPathTypes.StringType:
121         idbKeyPath = keyPath.string;
122         break;
123     case WebInspector.IndexedDBModel.KeyPathTypes.ArrayType:
124         idbKeyPath = keyPath.array;
125         break;
126     }
127     return idbKeyPath;
128 }
129
130 WebInspector.IndexedDBModel.keyPathStringFromIDBKeyPath = function(idbKeyPath)
131 {
132     if (typeof idbKeyPath === "string")
133         return "\"" + idbKeyPath + "\"";
134     if (idbKeyPath instanceof Array)
135         return "[\"" + idbKeyPath.join("\", \"") + "\"]";
136     return null;
137 }
138
139 WebInspector.IndexedDBModel.EventTypes = {
140     DatabaseAdded: "DatabaseAdded",
141     DatabaseRemoved: "DatabaseRemoved",
142     DatabaseLoaded: "DatabaseLoaded"
143 }
144
145 WebInspector.IndexedDBModel.prototype = {
146     _reset: function()
147     {
148         for (var securityOrigin in this._databaseNamesBySecurityOrigin)
149             this._removeOrigin(securityOrigin);
150         var securityOrigins = this.target().resourceTreeModel.securityOrigins();
151         for (var i = 0; i < securityOrigins.length; ++i)
152             this._addOrigin(securityOrigins[i]);
153     },
154
155     refreshDatabaseNames: function()
156     {
157         for (var securityOrigin in this._databaseNamesBySecurityOrigin)
158             this._loadDatabaseNames(securityOrigin);
159     },
160
161     /**
162      * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
163      */
164     refreshDatabase: function(databaseId)
165     {
166         this._loadDatabase(databaseId);
167     },
168
169     /**
170      * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
171      * @param {string} objectStoreName
172      * @param {function()} callback
173      */
174     clearObjectStore: function(databaseId, objectStoreName, callback)
175     {
176         this._agent.clearObjectStore(databaseId.securityOrigin, databaseId.name, objectStoreName, callback);
177     },
178
179     /**
180      * @param {!WebInspector.Event} event
181      */
182     _securityOriginAdded: function(event)
183     {
184         var securityOrigin = /** @type {string} */ (event.data);
185         this._addOrigin(securityOrigin);
186     },
187
188     /**
189      * @param {!WebInspector.Event} event
190      */
191     _securityOriginRemoved: function(event)
192     {
193         var securityOrigin = /** @type {string} */ (event.data);
194         this._removeOrigin(securityOrigin);
195     },
196
197     /**
198      * @param {string} securityOrigin
199      */
200     _addOrigin: function(securityOrigin)
201     {
202         console.assert(!this._databaseNamesBySecurityOrigin[securityOrigin]);
203         this._databaseNamesBySecurityOrigin[securityOrigin] = [];
204         this._loadDatabaseNames(securityOrigin);
205     },
206
207     /**
208      * @param {string} securityOrigin
209      */
210     _removeOrigin: function(securityOrigin)
211     {
212         console.assert(this._databaseNamesBySecurityOrigin[securityOrigin]);
213         for (var i = 0; i < this._databaseNamesBySecurityOrigin[securityOrigin].length; ++i)
214             this._databaseRemoved(securityOrigin, this._databaseNamesBySecurityOrigin[securityOrigin][i]);
215         delete this._databaseNamesBySecurityOrigin[securityOrigin];
216     },
217
218     /**
219      * @param {string} securityOrigin
220      * @param {!Array.<string>} databaseNames
221      */
222     _updateOriginDatabaseNames: function(securityOrigin, databaseNames)
223     {
224         var newDatabaseNames = {};
225         for (var i = 0; i < databaseNames.length; ++i)
226             newDatabaseNames[databaseNames[i]] = true;
227         var oldDatabaseNames = {};
228         for (var i = 0; i < this._databaseNamesBySecurityOrigin[securityOrigin].length; ++i)
229             oldDatabaseNames[this._databaseNamesBySecurityOrigin[securityOrigin][i]] = true;
230
231         this._databaseNamesBySecurityOrigin[securityOrigin] = databaseNames;
232
233         for (var databaseName in oldDatabaseNames) {
234             if (!newDatabaseNames[databaseName])
235                 this._databaseRemoved(securityOrigin, databaseName);
236         }
237         for (var databaseName in newDatabaseNames) {
238             if (!oldDatabaseNames[databaseName])
239                 this._databaseAdded(securityOrigin, databaseName);
240         }
241     },
242
243     /**
244      * @param {string} securityOrigin
245      * @param {string} databaseName
246      */
247     _databaseAdded: function(securityOrigin, databaseName)
248     {
249         var databaseId = new WebInspector.IndexedDBModel.DatabaseId(securityOrigin, databaseName);
250         this.dispatchEventToListeners(WebInspector.IndexedDBModel.EventTypes.DatabaseAdded, databaseId);
251     },
252
253     /**
254      * @param {string} securityOrigin
255      * @param {string} databaseName
256      */
257     _databaseRemoved: function(securityOrigin, databaseName)
258     {
259         var databaseId = new WebInspector.IndexedDBModel.DatabaseId(securityOrigin, databaseName);
260         this.dispatchEventToListeners(WebInspector.IndexedDBModel.EventTypes.DatabaseRemoved, databaseId);
261     },
262
263     /**
264      * @param {string} securityOrigin
265      */
266     _loadDatabaseNames: function(securityOrigin)
267     {
268         /**
269          * @param {?Protocol.Error} error
270          * @param {!Array.<string>} databaseNames
271          * @this {WebInspector.IndexedDBModel}
272          */
273         function callback(error, databaseNames)
274         {
275             if (error) {
276                 console.error("IndexedDBAgent error: " + error);
277                 return;
278             }
279
280             if (!this._databaseNamesBySecurityOrigin[securityOrigin])
281                 return;
282             this._updateOriginDatabaseNames(securityOrigin, databaseNames);
283         }
284
285         this._agent.requestDatabaseNames(securityOrigin, callback.bind(this));
286     },
287
288     /**
289      * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
290      */
291     _loadDatabase: function(databaseId)
292     {
293         /**
294          * @param {?Protocol.Error} error
295          * @param {!IndexedDBAgent.DatabaseWithObjectStores} databaseWithObjectStores
296          * @this {WebInspector.IndexedDBModel}
297          */
298         function callback(error, databaseWithObjectStores)
299         {
300             if (error) {
301                 console.error("IndexedDBAgent error: " + error);
302                 return;
303             }
304
305             if (!this._databaseNamesBySecurityOrigin[databaseId.securityOrigin])
306                 return;
307             var databaseModel = new WebInspector.IndexedDBModel.Database(databaseId, databaseWithObjectStores.version, databaseWithObjectStores.intVersion);
308             this._databases.put(databaseId, databaseModel);
309             for (var i = 0; i < databaseWithObjectStores.objectStores.length; ++i) {
310                 var objectStore = databaseWithObjectStores.objectStores[i];
311                 var objectStoreIDBKeyPath = WebInspector.IndexedDBModel.idbKeyPathFromKeyPath(objectStore.keyPath);
312                 var objectStoreModel = new WebInspector.IndexedDBModel.ObjectStore(objectStore.name, objectStoreIDBKeyPath, objectStore.autoIncrement);
313                 for (var j = 0; j < objectStore.indexes.length; ++j) {
314                      var index = objectStore.indexes[j];
315                      var indexIDBKeyPath = WebInspector.IndexedDBModel.idbKeyPathFromKeyPath(index.keyPath);
316                      var indexModel = new WebInspector.IndexedDBModel.Index(index.name, indexIDBKeyPath, index.unique, index.multiEntry);
317                      objectStoreModel.indexes[indexModel.name] = indexModel;
318                 }
319                 databaseModel.objectStores[objectStoreModel.name] = objectStoreModel;
320             }
321
322             this.dispatchEventToListeners(WebInspector.IndexedDBModel.EventTypes.DatabaseLoaded, databaseModel);
323         }
324
325         this._agent.requestDatabase(databaseId.securityOrigin, databaseId.name, callback.bind(this));
326     },
327
328     /**
329      * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
330      * @param {string} objectStoreName
331      * @param {webkitIDBKeyRange} idbKeyRange
332      * @param {number} skipCount
333      * @param {number} pageSize
334      * @param {function(!Array.<!WebInspector.IndexedDBModel.Entry>, boolean)} callback
335      */
336     loadObjectStoreData: function(databaseId, objectStoreName, idbKeyRange, skipCount, pageSize, callback)
337     {
338         this._requestData(databaseId, databaseId.name, objectStoreName, "", idbKeyRange, skipCount, pageSize, callback);
339     },
340
341     /**
342      * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
343      * @param {string} objectStoreName
344      * @param {string} indexName
345      * @param {webkitIDBKeyRange} idbKeyRange
346      * @param {number} skipCount
347      * @param {number} pageSize
348      * @param {function(!Array.<!WebInspector.IndexedDBModel.Entry>, boolean)} callback
349      */
350     loadIndexData: function(databaseId, objectStoreName, indexName, idbKeyRange, skipCount, pageSize, callback)
351     {
352         this._requestData(databaseId, databaseId.name, objectStoreName, indexName, idbKeyRange, skipCount, pageSize, callback);
353     },
354
355     /**
356      * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
357      * @param {string} databaseName
358      * @param {string} objectStoreName
359      * @param {string} indexName
360      * @param {webkitIDBKeyRange} idbKeyRange
361      * @param {number} skipCount
362      * @param {number} pageSize
363      * @param {function(!Array.<!WebInspector.IndexedDBModel.Entry>, boolean)} callback
364      */
365     _requestData: function(databaseId, databaseName, objectStoreName, indexName, idbKeyRange, skipCount, pageSize, callback)
366     {
367         /**
368          * @param {?Protocol.Error} error
369          * @param {!Array.<!IndexedDBAgent.DataEntry>} dataEntries
370          * @param {boolean} hasMore
371          * @this {WebInspector.IndexedDBModel}
372          */
373         function innerCallback(error, dataEntries, hasMore)
374         {
375             if (error) {
376                 console.error("IndexedDBAgent error: " + error);
377                 return;
378             }
379
380             if (!this._databaseNamesBySecurityOrigin[databaseId.securityOrigin])
381                 return;
382             var entries = [];
383             for (var i = 0; i < dataEntries.length; ++i) {
384                 var key = WebInspector.RemoteObject.fromLocalObject(JSON.parse(dataEntries[i].key));
385                 var primaryKey = WebInspector.RemoteObject.fromLocalObject(JSON.parse(dataEntries[i].primaryKey));
386                 var value = WebInspector.RemoteObject.fromLocalObject(JSON.parse(dataEntries[i].value));
387                 entries.push(new WebInspector.IndexedDBModel.Entry(key, primaryKey, value));
388             }
389             callback(entries, hasMore);
390         }
391
392         var keyRange = WebInspector.IndexedDBModel.keyRangeFromIDBKeyRange(idbKeyRange);
393         this._agent.requestData(databaseId.securityOrigin, databaseName, objectStoreName, indexName, skipCount, pageSize, keyRange ? keyRange : undefined, innerCallback.bind(this));
394     },
395
396     __proto__: WebInspector.TargetAwareObject.prototype
397 }
398
399 /**
400  * @constructor
401  * @param {!WebInspector.RemoteObject} key
402  * @param {!WebInspector.RemoteObject} primaryKey
403  * @param {!WebInspector.RemoteObject} value
404  */
405 WebInspector.IndexedDBModel.Entry = function(key, primaryKey, value)
406 {
407     this.key = key;
408     this.primaryKey = primaryKey;
409     this.value = value;
410 }
411
412 /**
413  * @constructor
414  * @param {string} securityOrigin
415  * @param {string} name
416  */
417 WebInspector.IndexedDBModel.DatabaseId = function(securityOrigin, name)
418 {
419     this.securityOrigin = securityOrigin;
420     this.name = name;
421 }
422
423 WebInspector.IndexedDBModel.DatabaseId.prototype = {
424     /**
425      * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
426      * @return {boolean}
427      */
428     equals: function(databaseId)
429     {
430         return this.name === databaseId.name && this.securityOrigin === databaseId.securityOrigin;
431     },
432 }
433 /**
434  * @constructor
435  * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
436  * @param {string} version
437  */
438 WebInspector.IndexedDBModel.Database = function(databaseId, version, intVersion)
439 {
440     this.databaseId = databaseId;
441     this.version = version;
442     this.intVersion = intVersion;
443     this.objectStores = {};
444 }
445
446 /**
447  * @constructor
448  * @param {string} name
449  * @param {*} keyPath
450  */
451 WebInspector.IndexedDBModel.ObjectStore = function(name, keyPath, autoIncrement)
452 {
453     this.name = name;
454     this.keyPath = keyPath;
455     this.autoIncrement = autoIncrement;
456     this.indexes = {};
457 }
458
459 WebInspector.IndexedDBModel.ObjectStore.prototype = {
460     /**
461      * @type {string}
462      */
463     get keyPathString()
464     {
465         return WebInspector.IndexedDBModel.keyPathStringFromIDBKeyPath(this.keyPath);
466     }
467 }
468
469 /**
470  * @constructor
471  * @param {string} name
472  * @param {*} keyPath
473  */
474 WebInspector.IndexedDBModel.Index = function(name, keyPath, unique, multiEntry)
475 {
476     this.name = name;
477     this.keyPath = keyPath;
478     this.unique = unique;
479     this.multiEntry = multiEntry;
480 }
481
482 WebInspector.IndexedDBModel.Index.prototype = {
483     /**
484      * @type {string}
485      */
486     get keyPathString()
487     {
488         return WebInspector.IndexedDBModel.keyPathStringFromIDBKeyPath(this.keyPath);
489     }
490 }