Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/db/objectstore.js
2868 views
1
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Wrapper for an IndexedDB object store.
17
*
18
*/
19
20
21
goog.provide('goog.db.ObjectStore');
22
23
goog.require('goog.async.Deferred');
24
goog.require('goog.db.Cursor');
25
goog.require('goog.db.Error');
26
goog.require('goog.db.Index');
27
goog.require('goog.db.KeyRange');
28
goog.require('goog.debug');
29
goog.require('goog.events');
30
31
32
33
/**
34
* Creates an IDBObjectStore wrapper object. Object stores have methods for
35
* storing and retrieving records, and are accessed through a transaction
36
* object. They also have methods for creating indexes associated with the
37
* object store. They can only be created when setting the version of the
38
* database. Should not be created directly, access object stores through
39
* transactions.
40
* @see goog.db.UpgradeNeededCallback
41
* @see goog.db.Transaction#objectStore
42
*
43
* @param {!IDBObjectStore} store The backing IndexedDb object.
44
* @constructor
45
* @final
46
*
47
* TODO(arthurhsu): revisit msg in exception and errors in this class. In newer
48
* Chrome (v22+) the error/request come with a DOM error string that is
49
* already very descriptive.
50
*/
51
goog.db.ObjectStore = function(store) {
52
/**
53
* Underlying IndexedDB object store object.
54
*
55
* @type {!IDBObjectStore}
56
* @private
57
*/
58
this.store_ = store;
59
};
60
61
62
/**
63
* @return {string} The name of the object store.
64
*/
65
goog.db.ObjectStore.prototype.getName = function() {
66
return this.store_.name;
67
};
68
69
70
/**
71
* Helper function for put and add.
72
*
73
* @param {string} fn Function name to call on the object store.
74
* @param {string} msg Message to give to the error.
75
* @param {*} value Value to insert into the object store.
76
* @param {IDBKeyType=} opt_key The key to use.
77
* @return {!goog.async.Deferred} The resulting deferred request.
78
* @private
79
*/
80
goog.db.ObjectStore.prototype.insert_ = function(fn, msg, value, opt_key) {
81
// TODO(user): refactor wrapping an IndexedDB request in a Deferred by
82
// creating a higher-level abstraction for it (mostly affects here and
83
// goog.db.Index)
84
var d = new goog.async.Deferred();
85
var request;
86
try {
87
// put or add with (value, undefined) throws an error, so we need to check
88
// for undefined ourselves
89
if (opt_key) {
90
request = this.store_[fn](value, opt_key);
91
} else {
92
request = this.store_[fn](value);
93
}
94
} catch (ex) {
95
msg += goog.debug.deepExpose(value);
96
if (opt_key) {
97
msg += ', with key ' + goog.debug.deepExpose(opt_key);
98
}
99
d.errback(goog.db.Error.fromException(ex, msg));
100
return d;
101
}
102
request.onsuccess = function(ev) {
103
d.callback(ev.target.result);
104
};
105
request.onerror = function(ev) {
106
msg += goog.debug.deepExpose(value);
107
if (opt_key) {
108
msg += ', with key ' + goog.debug.deepExpose(opt_key);
109
}
110
d.errback(goog.db.Error.fromRequest(ev.target, msg));
111
};
112
return d;
113
};
114
115
116
/**
117
* Adds an object to the object store. Replaces existing objects with the
118
* same key.
119
*
120
* @param {*} value The value to put.
121
* @param {IDBKeyType=} opt_key The key to use. Cannot be used if the
122
* keyPath was specified for the object store. If the keyPath was not
123
* specified but autoIncrement was not enabled, it must be used.
124
* @return {!goog.async.Deferred} The deferred put request.
125
*/
126
goog.db.ObjectStore.prototype.put = function(value, opt_key) {
127
return this.insert_(
128
'put', 'putting into ' + this.getName() + ' with value', value, opt_key);
129
};
130
131
132
/**
133
* Adds an object to the object store. Requires that there is no object with
134
* the same key already present.
135
*
136
* @param {*} value The value to add.
137
* @param {IDBKeyType=} opt_key The key to use. Cannot be used if the
138
* keyPath was specified for the object store. If the keyPath was not
139
* specified but autoIncrement was not enabled, it must be used.
140
* @return {!goog.async.Deferred} The deferred add request.
141
*/
142
goog.db.ObjectStore.prototype.add = function(value, opt_key) {
143
return this.insert_(
144
'add', 'adding into ' + this.getName() + ' with value ', value, opt_key);
145
};
146
147
148
/**
149
* Removes an object from the store. No-op if there is no object present with
150
* the given key.
151
*
152
* @param {IDBKeyType|!goog.db.KeyRange} keyOrRange The key or range to remove
153
* objects under.
154
* @return {!goog.async.Deferred} The deferred remove request.
155
*/
156
goog.db.ObjectStore.prototype.remove = function(keyOrRange) {
157
var d = new goog.async.Deferred();
158
var request;
159
try {
160
request = this.store_['delete'](
161
keyOrRange instanceof goog.db.KeyRange ? keyOrRange.range() :
162
keyOrRange);
163
} catch (err) {
164
var msg = 'removing from ' + this.getName() + ' with key ' +
165
goog.debug.deepExpose(keyOrRange);
166
d.errback(goog.db.Error.fromException(err, msg));
167
return d;
168
}
169
request.onsuccess = function(ev) { d.callback(); };
170
var self = this;
171
request.onerror = function(ev) {
172
var msg = 'removing from ' + self.getName() + ' with key ' +
173
goog.debug.deepExpose(keyOrRange);
174
d.errback(goog.db.Error.fromRequest(ev.target, msg));
175
};
176
return d;
177
};
178
179
180
/**
181
* Gets an object from the store. If no object is present with that key
182
* the result is {@code undefined}.
183
*
184
* @param {IDBKeyType} key The key to look up.
185
* @return {!goog.async.Deferred} The deferred get request.
186
*/
187
goog.db.ObjectStore.prototype.get = function(key) {
188
var d = new goog.async.Deferred();
189
var request;
190
try {
191
request = this.store_.get(key);
192
} catch (err) {
193
var msg = 'getting from ' + this.getName() + ' with key ' +
194
goog.debug.deepExpose(key);
195
d.errback(goog.db.Error.fromException(err, msg));
196
return d;
197
}
198
request.onsuccess = function(ev) { d.callback(ev.target.result); };
199
var self = this;
200
request.onerror = function(ev) {
201
var msg = 'getting from ' + self.getName() + ' with key ' +
202
goog.debug.deepExpose(key);
203
d.errback(goog.db.Error.fromRequest(ev.target, msg));
204
};
205
return d;
206
};
207
208
209
/**
210
* Gets all objects from the store and returns them as an array.
211
*
212
* @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
213
* over the whole object store.
214
* @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
215
* moves in a forward direction with duplicates.
216
* @return {!goog.async.Deferred} The deferred getAll request.
217
*/
218
goog.db.ObjectStore.prototype.getAll = function(opt_range, opt_direction) {
219
var d = new goog.async.Deferred();
220
var cursor;
221
try {
222
cursor = this.openCursor(opt_range, opt_direction);
223
} catch (err) {
224
d.errback(err);
225
return d;
226
}
227
228
var result = [];
229
goog.events.listen(cursor, goog.db.Cursor.EventType.NEW_DATA, function() {
230
result.push(cursor.getValue());
231
cursor.next();
232
});
233
234
goog.events.listenOnce(
235
cursor,
236
[goog.db.Cursor.EventType.ERROR, goog.db.Cursor.EventType.COMPLETE],
237
function(evt) {
238
cursor.dispose();
239
if (evt.type == goog.db.Cursor.EventType.COMPLETE) {
240
d.callback(result);
241
} else {
242
d.errback();
243
}
244
});
245
return d;
246
};
247
248
249
/**
250
* Opens a cursor over the specified key range. Returns a cursor object which is
251
* able to iterate over the given range.
252
*
253
* Example usage:
254
*
255
* <code>
256
* var cursor = objectStore.openCursor(goog.db.Range.bound('a', 'c'));
257
*
258
* var key = goog.events.listen(
259
* cursor, goog.db.Cursor.EventType.NEW_DATA, function() {
260
* // Do something with data.
261
* cursor.next();
262
* });
263
*
264
* goog.events.listenOnce(
265
* cursor, goog.db.Cursor.EventType.COMPLETE, function() {
266
* // Clean up listener, and perform a finishing operation on the data.
267
* goog.events.unlistenByKey(key);
268
* });
269
* </code>
270
*
271
* @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
272
* over the whole object store.
273
* @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
274
* moves in a forward direction with duplicates.
275
* @return {!goog.db.Cursor} The cursor.
276
* @throws {goog.db.Error} If there was a problem opening the cursor.
277
*/
278
goog.db.ObjectStore.prototype.openCursor = function(opt_range, opt_direction) {
279
return goog.db.Cursor.openCursor(this.store_, opt_range, opt_direction);
280
};
281
282
283
/**
284
* Deletes all objects from the store.
285
*
286
* @return {!goog.async.Deferred} The deferred clear request.
287
*/
288
goog.db.ObjectStore.prototype.clear = function() {
289
var msg = 'clearing store ' + this.getName();
290
var d = new goog.async.Deferred();
291
var request;
292
try {
293
request = this.store_.clear();
294
} catch (err) {
295
d.errback(goog.db.Error.fromException(err, msg));
296
return d;
297
}
298
request.onsuccess = function(ev) { d.callback(); };
299
request.onerror = function(ev) {
300
d.errback(goog.db.Error.fromRequest(ev.target, msg));
301
};
302
return d;
303
};
304
305
306
/**
307
* Creates an index in this object store. Can only be called inside a
308
* {@link goog.db.UpgradeNeededCallback}.
309
*
310
* @param {string} name Name of the index to create.
311
* @param {string} keyPath Attribute to index on.
312
* @param {!Object=} opt_parameters Optional parameters object. The only
313
* available option is unique, which defaults to false. If unique is true,
314
* the index will enforce that there is only ever one object in the object
315
* store for each unique value it indexes on.
316
* @return {!goog.db.Index} The newly created, wrapped index.
317
* @throws {goog.db.Error} In case of an error creating the index.
318
*/
319
goog.db.ObjectStore.prototype.createIndex = function(
320
name, keyPath, opt_parameters) {
321
try {
322
return new goog.db.Index(
323
this.store_.createIndex(name, keyPath, opt_parameters));
324
} catch (ex) {
325
var msg = 'creating new index ' + name + ' with key path ' + keyPath;
326
throw goog.db.Error.fromException(ex, msg);
327
}
328
};
329
330
331
/**
332
* Gets an index.
333
*
334
* @param {string} name Name of the index to fetch.
335
* @return {!goog.db.Index} The requested wrapped index.
336
* @throws {goog.db.Error} In case of an error getting the index.
337
*/
338
goog.db.ObjectStore.prototype.getIndex = function(name) {
339
try {
340
return new goog.db.Index(this.store_.index(name));
341
} catch (ex) {
342
var msg = 'getting index ' + name;
343
throw goog.db.Error.fromException(ex, msg);
344
}
345
};
346
347
348
/**
349
* Deletes an index from the object store. Can only be called inside a
350
* {@link goog.db.UpgradeNeededCallback}.
351
*
352
* @param {string} name Name of the index to delete.
353
* @throws {goog.db.Error} In case of an error deleting the index.
354
*/
355
goog.db.ObjectStore.prototype.deleteIndex = function(name) {
356
try {
357
this.store_.deleteIndex(name);
358
} catch (ex) {
359
var msg = 'deleting index ' + name;
360
throw goog.db.Error.fromException(ex, msg);
361
}
362
};
363
364
365
/**
366
* Gets number of records within a key range.
367
*
368
* @param {!goog.db.KeyRange=} opt_range The key range. If undefined, this will
369
* count all records in the object store.
370
* @return {!goog.async.Deferred} The deferred number of records.
371
*/
372
goog.db.ObjectStore.prototype.count = function(opt_range) {
373
var d = new goog.async.Deferred();
374
375
try {
376
var range = opt_range ? opt_range.range() : null;
377
var request = this.store_.count(range);
378
request.onsuccess = function(ev) { d.callback(ev.target.result); };
379
var self = this;
380
request.onerror = function(ev) {
381
d.errback(goog.db.Error.fromRequest(ev.target, self.getName()));
382
};
383
} catch (ex) {
384
d.errback(goog.db.Error.fromException(ex, this.getName()));
385
}
386
387
return d;
388
};
389
390