Adding float-no-zero branch hosted build
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Wrapper for a IndexedDB cursor.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.db.Cursor');
|
||||
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.db.Error');
|
||||
goog.require('goog.debug');
|
||||
goog.require('goog.events.EventTarget');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new IDBCursor wrapper object. Should not be created directly,
|
||||
* access cursor through object store.
|
||||
* @see goog.db.ObjectStore#openCursor
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.events.EventTarget}
|
||||
*/
|
||||
goog.db.Cursor = function() {
|
||||
goog.base(this);
|
||||
};
|
||||
goog.inherits(goog.db.Cursor, goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* Underlying IndexedDB cursor object.
|
||||
*
|
||||
* @type {IDBCursor}
|
||||
* @private
|
||||
*/
|
||||
goog.db.Cursor.prototype.cursor_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Advances the cursor to the next position along its direction. When new data
|
||||
* is available, the NEW_DATA event will be fired. If the cursor has reached the
|
||||
* end of the range it will fire the COMPLETE event. If opt_key is specified it
|
||||
* will advance to the key it matches in its direction.
|
||||
*
|
||||
* This wraps the native #continue method on the underlying object.
|
||||
*
|
||||
* @param {IDBKeyType=} opt_key The optional key to advance to.
|
||||
*/
|
||||
goog.db.Cursor.prototype.next = function(opt_key) {
|
||||
if (opt_key) {
|
||||
this.cursor_['continue'](opt_key);
|
||||
} else {
|
||||
this.cursor_['continue']();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Updates the value at the current position of the cursor in the object store.
|
||||
* If the cursor points to a value that has just been deleted, a new value is
|
||||
* created.
|
||||
*
|
||||
* @param {*} value The value to be stored.
|
||||
* @return {!goog.async.Deferred} The resulting deferred request.
|
||||
*/
|
||||
goog.db.Cursor.prototype.update = function(value) {
|
||||
var msg = 'updating via cursor with value ';
|
||||
var d = new goog.async.Deferred();
|
||||
var request;
|
||||
|
||||
try {
|
||||
request = this.cursor_.update(value);
|
||||
} catch (err) {
|
||||
msg += goog.debug.deepExpose(value);
|
||||
d.errback(goog.db.Error.fromException(err, msg));
|
||||
return d;
|
||||
}
|
||||
request.onsuccess = function(ev) {
|
||||
d.callback();
|
||||
};
|
||||
request.onerror = function(ev) {
|
||||
msg += goog.debug.deepExpose(value);
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, msg));
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deletes the value at the cursor's position, without changing the cursor's
|
||||
* position. Once the value is deleted, the cursor's value is set to null.
|
||||
*
|
||||
* @return {!goog.async.Deferred} The resulting deferred request.
|
||||
*/
|
||||
goog.db.Cursor.prototype.remove = function() {
|
||||
var msg = 'deleting via cursor';
|
||||
var d = new goog.async.Deferred();
|
||||
var request;
|
||||
|
||||
try {
|
||||
request = this.cursor_['delete']();
|
||||
} catch (err) {
|
||||
d.errback(goog.db.Error.fromException(err, msg));
|
||||
return d;
|
||||
}
|
||||
request.onsuccess = function(ev) {
|
||||
d.callback();
|
||||
};
|
||||
request.onerror = function(ev) {
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, msg));
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {*} The value for the value at the cursor's position. Undefined
|
||||
* if no current value, or null if value has just been deleted.
|
||||
*/
|
||||
goog.db.Cursor.prototype.getValue = function() {
|
||||
return this.cursor_['value'];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {IDBKeyType} The key for the value at the cursor's position. If
|
||||
* the cursor is outside its range, this is undefined.
|
||||
*/
|
||||
goog.db.Cursor.prototype.getKey = function() {
|
||||
return this.cursor_.key;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Opens a value cursor from IDBObjectStore or IDBIndex over the specified key
|
||||
* range. Returns a cursor object which is able to iterate over the given range.
|
||||
* @param {!(IDBObjectStore|IDBIndex)} source Data source to open cursor.
|
||||
* @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
|
||||
* over the whole data source.
|
||||
* @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
|
||||
* moves in a forward direction with duplicates.
|
||||
* @return {!goog.db.Cursor} The cursor.
|
||||
* @throws {goog.db.Error} If there was a problem opening the cursor.
|
||||
*/
|
||||
goog.db.Cursor.openCursor = function(source, opt_range, opt_direction) {
|
||||
var cursor = new goog.db.Cursor();
|
||||
var request;
|
||||
|
||||
try {
|
||||
var range = opt_range ? opt_range.range() : null;
|
||||
if (opt_direction) {
|
||||
request = source.openCursor(range, opt_direction);
|
||||
} else {
|
||||
request = source.openCursor(range);
|
||||
}
|
||||
} catch (ex) {
|
||||
cursor.dispose();
|
||||
throw goog.db.Error.fromException(ex, source.name);
|
||||
}
|
||||
request.onsuccess = function(e) {
|
||||
cursor.cursor_ = e.target.result || null;
|
||||
if (cursor.cursor_) {
|
||||
cursor.dispatchEvent(goog.db.Cursor.EventType.NEW_DATA);
|
||||
} else {
|
||||
cursor.dispatchEvent(goog.db.Cursor.EventType.COMPLETE);
|
||||
}
|
||||
};
|
||||
request.onerror = function(e) {
|
||||
cursor.dispatchEvent(goog.db.Cursor.EventType.ERROR);
|
||||
};
|
||||
return cursor;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Possible cursor directions.
|
||||
* @see http://www.w3.org/TR/IndexedDB/#idl-def-IDBCursor
|
||||
*
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.db.Cursor.Direction = {
|
||||
NEXT: 'next',
|
||||
NEXT_NO_DUPLICATE: 'nextunique',
|
||||
PREV: 'prev',
|
||||
PREV_NO_DUPLICATE: 'prevunique'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Event types that the cursor can dispatch. COMPLETE events are dispatched when
|
||||
* a cursor is depleted of values, a NEW_DATA event if there is new data
|
||||
* available, and ERROR if an error occurred.
|
||||
*
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.db.Cursor.EventType = {
|
||||
COMPLETE: 'c',
|
||||
ERROR: 'e',
|
||||
NEW_DATA: 'n'
|
||||
};
|
||||
@@ -0,0 +1,182 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Wrappers for the HTML5 IndexedDB. The wrappers export nearly
|
||||
* the same interface as the standard API, but return goog.async.Deferred
|
||||
* objects instead of request objects and use Closure events. The wrapper works
|
||||
* and has been tested on Chrome version 22+. It may work on older Chrome
|
||||
* versions, but they aren't explicitly supported.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* <code>
|
||||
* goog.db.openDatabase('mydb', 1, function(ev, db, tx) {
|
||||
* db.createObjectStore('mystore');
|
||||
* }).addCallback(function(db) {
|
||||
* var putTx = db.createTransaction(
|
||||
* [],
|
||||
* goog.db.Transaction.TransactionMode.READ_WRITE);
|
||||
* var store = putTx.objectStore('mystore');
|
||||
* store.put('value', 'key');
|
||||
* goog.listen(putTx, goog.db.Transaction.EventTypes.COMPLETE, function() {
|
||||
* var getTx = db.createTransaction([]);
|
||||
* var request = getTx.objectStore('mystore').get('key');
|
||||
* request.addCallback(function(result) {
|
||||
* ...
|
||||
* });
|
||||
* });
|
||||
* </code>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.db');
|
||||
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.db.Error');
|
||||
goog.require('goog.db.IndexedDb');
|
||||
goog.require('goog.db.Transaction');
|
||||
|
||||
|
||||
/**
|
||||
* The IndexedDB factory object.
|
||||
*
|
||||
* @type {IDBFactory}
|
||||
* @private
|
||||
*/
|
||||
goog.db.indexedDb_ = goog.global.indexedDB || goog.global.mozIndexedDB ||
|
||||
goog.global.webkitIndexedDB || goog.global.moz_indexedDB;
|
||||
|
||||
|
||||
/**
|
||||
* A callback that's called if a blocked event is received. When a database is
|
||||
* supposed to be deleted or upgraded (i.e. versionchange), and there are open
|
||||
* connections to this database, a block event will be fired to prevent the
|
||||
* operations from going through until all such open connections are closed.
|
||||
* This callback can be used to notify users that they should close other tabs
|
||||
* that have open connections, or to close the connections manually. Databases
|
||||
* can also listen for the {@link goog.db.IndexedDb.EventType.VERSION_CHANGE}
|
||||
* event to automatically close themselves when they're blocking such
|
||||
* operations.
|
||||
*
|
||||
* This is passed a VersionChangeEvent that has the version of the database
|
||||
* before it was deleted, and "null" as the new version.
|
||||
*
|
||||
* @typedef {function(!goog.db.IndexedDb.VersionChangeEvent)}
|
||||
*/
|
||||
goog.db.BlockedCallback;
|
||||
|
||||
|
||||
/**
|
||||
* A callback that's called when opening a database whose internal version is
|
||||
* lower than the version passed to {@link goog.db.openDatabase}.
|
||||
*
|
||||
* This callback is passed three arguments: a VersionChangeEvent with both the
|
||||
* old version and the new version of the database; the database that's being
|
||||
* opened, for which you can create and delete object stores; and the version
|
||||
* change transaction, with which you can abort the version change.
|
||||
*
|
||||
* Note that the transaction is not active, which means that it can't be used to
|
||||
* make changes to the database. However, since there is a transaction running,
|
||||
* you can't create another one via {@link goog.db.IndexedDb.createTransaction}.
|
||||
* This means that it's not possible to manipulate the database other than
|
||||
* creating or removing object stores in this callback.
|
||||
*
|
||||
* @typedef {function(!goog.db.IndexedDb.VersionChangeEvent,
|
||||
* !goog.db.IndexedDb,
|
||||
* !goog.db.Transaction)}
|
||||
*/
|
||||
goog.db.UpgradeNeededCallback;
|
||||
|
||||
|
||||
/**
|
||||
* Opens a database connection and wraps it.
|
||||
*
|
||||
* @param {string} name The name of the database to open.
|
||||
* @param {number=} opt_version The expected version of the database. If this is
|
||||
* larger than the actual version, opt_onUpgradeNeeded will be called
|
||||
* (possibly after opt_onBlocked; see {@link goog.db.BlockedCallback}). If
|
||||
* this is passed, opt_onUpgradeNeeded must be passed as well.
|
||||
* @param {goog.db.UpgradeNeededCallback=} opt_onUpgradeNeeded Called if
|
||||
* opt_version is greater than the old version of the database. If
|
||||
* opt_version is passed, this must be passed as well.
|
||||
* @param {goog.db.BlockedCallback=} opt_onBlocked Called if there are active
|
||||
* connections to the database.
|
||||
* @return {!goog.async.Deferred} The deferred database object.
|
||||
*/
|
||||
goog.db.openDatabase = function(name, opt_version, opt_onUpgradeNeeded,
|
||||
opt_onBlocked) {
|
||||
goog.asserts.assert(
|
||||
goog.isDef(opt_version) == goog.isDef(opt_onUpgradeNeeded),
|
||||
'opt_version must be passed to goog.db.openDatabase if and only if ' +
|
||||
'opt_onUpgradeNeeded is also passed');
|
||||
|
||||
var d = new goog.async.Deferred();
|
||||
var openRequest = opt_version ?
|
||||
goog.db.indexedDb_.open(name, opt_version) :
|
||||
goog.db.indexedDb_.open(name);
|
||||
openRequest.onsuccess = function(ev) {
|
||||
var db = new goog.db.IndexedDb(ev.target.result);
|
||||
d.callback(db);
|
||||
};
|
||||
openRequest.onerror = function(ev) {
|
||||
var msg = 'opening database ' + name;
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, msg));
|
||||
};
|
||||
openRequest.onupgradeneeded = function(ev) {
|
||||
if (!opt_onUpgradeNeeded) return;
|
||||
var db = new goog.db.IndexedDb(ev.target.result);
|
||||
opt_onUpgradeNeeded(
|
||||
new goog.db.IndexedDb.VersionChangeEvent(ev.oldVersion, ev.newVersion),
|
||||
db,
|
||||
new goog.db.Transaction(ev.target.transaction, db));
|
||||
};
|
||||
openRequest.onblocked = function(ev) {
|
||||
if (opt_onBlocked) {
|
||||
opt_onBlocked(new goog.db.IndexedDb.VersionChangeEvent(
|
||||
ev.oldVersion, ev.newVersion));
|
||||
}
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deletes a database once all open connections have been closed.
|
||||
*
|
||||
* @param {string} name The name of the database to delete.
|
||||
* @param {goog.db.BlockedCallback=} opt_onBlocked Called if there are active
|
||||
* connections to the database.
|
||||
* @return {goog.async.Deferred} A deferred object that will fire once the
|
||||
* database is deleted.
|
||||
*/
|
||||
goog.db.deleteDatabase = function(name, opt_onBlocked) {
|
||||
var d = new goog.async.Deferred();
|
||||
var deleteRequest = goog.db.indexedDb_.deleteDatabase(name);
|
||||
deleteRequest.onsuccess = function(ev) {
|
||||
d.callback();
|
||||
};
|
||||
deleteRequest.onerror = function(ev) {
|
||||
var msg = 'deleting database ' + name;
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, msg));
|
||||
};
|
||||
deleteRequest.onblocked = function(ev) {
|
||||
if (opt_onBlocked) {
|
||||
opt_onBlocked(new goog.db.IndexedDb.VersionChangeEvent(
|
||||
ev.oldVersion, ev.newVersion));
|
||||
}
|
||||
};
|
||||
return d;
|
||||
};
|
||||
@@ -0,0 +1,359 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Error classes for the IndexedDB wrapper.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.db.Error');
|
||||
goog.provide('goog.db.Error.ErrorCode');
|
||||
goog.provide('goog.db.Error.ErrorName');
|
||||
goog.provide('goog.db.Error.VersionChangeBlockedError');
|
||||
|
||||
goog.require('goog.debug.Error');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A database error. Since the stack trace can be unhelpful in an asynchronous
|
||||
* context, the error provides a message about where it was produced.
|
||||
*
|
||||
* @param {number|!DOMError} error The DOMError instance returned by the
|
||||
* browser for Chrome22+, or an error code for previous versions.
|
||||
* @param {string} context A description of where the error occured.
|
||||
* @param {string=} opt_message Additional message.
|
||||
* @constructor
|
||||
* @extends {goog.debug.Error}
|
||||
*/
|
||||
goog.db.Error = function(error, context, opt_message) {
|
||||
var errorCode = null;
|
||||
var internalError = null;
|
||||
if (goog.isNumber(error)) {
|
||||
errorCode = error;
|
||||
internalError = {name: goog.db.Error.getName(errorCode)};
|
||||
} else {
|
||||
internalError = error;
|
||||
errorCode = goog.db.Error.getCode(error.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* The code for this error.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
this.code = errorCode;
|
||||
|
||||
/**
|
||||
* The DOMException as returned by the browser.
|
||||
*
|
||||
* @type {!DOMError}
|
||||
* @private
|
||||
*/
|
||||
this.error_ = /** @type {!DOMError} */ (internalError);
|
||||
|
||||
var msg = 'Error ' + context + ': ' + this.getName();
|
||||
if (opt_message) {
|
||||
msg += ', ' + opt_message;
|
||||
}
|
||||
goog.base(this, msg);
|
||||
};
|
||||
goog.inherits(goog.db.Error, goog.debug.Error);
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The name of the error.
|
||||
*/
|
||||
goog.db.Error.prototype.getName = function() {
|
||||
return this.error_.name;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A specific kind of database error. If a Version Change is unable to proceed
|
||||
* due to other open database connections, it will block and this error will be
|
||||
* thrown.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.debug.Error}
|
||||
*/
|
||||
goog.db.Error.VersionChangeBlockedError = function() {
|
||||
goog.base(this, 'Version change blocked');
|
||||
};
|
||||
goog.inherits(goog.db.Error.VersionChangeBlockedError, goog.debug.Error);
|
||||
|
||||
|
||||
/**
|
||||
* Synthetic error codes for database errors, for use when IndexedDB
|
||||
* support is not available. This numbering differs in practice
|
||||
* from the browser implementations, but it is not meant to be reliable:
|
||||
* this object merely ensures that goog.db.Error is loadable on platforms
|
||||
* that do not support IndexedDB.
|
||||
*
|
||||
* @enum {number}
|
||||
* @private
|
||||
*/
|
||||
goog.db.Error.DatabaseErrorCode_ = {
|
||||
UNKNOWN_ERR: 1,
|
||||
NON_TRANSIENT_ERR: 2,
|
||||
NOT_FOUND_ERR: 3,
|
||||
CONSTRAINT_ERR: 4,
|
||||
DATA_ERR: 5,
|
||||
NOT_ALLOWED_ERR: 6,
|
||||
TRANSACTION_INACTIVE_ERR: 7,
|
||||
ABORT_ERR: 8,
|
||||
READ_ONLY_ERR: 9,
|
||||
TRANSIENT_ERR: 11,
|
||||
TIMEOUT_ERR: 10,
|
||||
QUOTA_ERR: 11,
|
||||
INVALID_ACCESS_ERR: 12,
|
||||
INVALID_STATE_ERR: 13
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Error codes for database errors.
|
||||
* @see http://www.w3.org/TR/IndexedDB/#idl-def-IDBDatabaseException
|
||||
*
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.db.Error.ErrorCode = {
|
||||
UNKNOWN_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).UNKNOWN_ERR,
|
||||
NON_TRANSIENT_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).NON_TRANSIENT_ERR,
|
||||
NOT_FOUND_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).NOT_FOUND_ERR,
|
||||
CONSTRAINT_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).CONSTRAINT_ERR,
|
||||
DATA_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).DATA_ERR,
|
||||
NOT_ALLOWED_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).NOT_ALLOWED_ERR,
|
||||
TRANSACTION_INACTIVE_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).TRANSACTION_INACTIVE_ERR,
|
||||
ABORT_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).ABORT_ERR,
|
||||
READ_ONLY_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).READ_ONLY_ERR,
|
||||
TIMEOUT_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).TIMEOUT_ERR,
|
||||
QUOTA_ERR: (goog.global.IDBDatabaseException ||
|
||||
goog.global.webkitIDBDatabaseException ||
|
||||
goog.db.Error.DatabaseErrorCode_).QUOTA_ERR,
|
||||
INVALID_ACCESS_ERR: (goog.global.DOMException ||
|
||||
goog.db.Error.DatabaseErrorCode_).INVALID_ACCESS_ERR,
|
||||
INVALID_STATE_ERR: (goog.global.DOMException ||
|
||||
goog.db.Error.DatabaseErrorCode_).INVALID_STATE_ERR
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Translates an error code into a more useful message.
|
||||
*
|
||||
* @param {number} code Error code.
|
||||
* @return {string} A debug message.
|
||||
*/
|
||||
goog.db.Error.getMessage = function(code) {
|
||||
switch (code) {
|
||||
case goog.db.Error.ErrorCode.UNKNOWN_ERR:
|
||||
return 'Unknown error';
|
||||
case goog.db.Error.ErrorCode.NON_TRANSIENT_ERR:
|
||||
return 'Invalid operation';
|
||||
case goog.db.Error.ErrorCode.NOT_FOUND_ERR:
|
||||
return 'Required database object not found';
|
||||
case goog.db.Error.ErrorCode.CONSTRAINT_ERR:
|
||||
return 'Constraint unsatisfied';
|
||||
case goog.db.Error.ErrorCode.DATA_ERR:
|
||||
return 'Invalid data';
|
||||
case goog.db.Error.ErrorCode.NOT_ALLOWED_ERR:
|
||||
return 'Operation disallowed';
|
||||
case goog.db.Error.ErrorCode.TRANSACTION_INACTIVE_ERR:
|
||||
return 'Transaction not active';
|
||||
case goog.db.Error.ErrorCode.ABORT_ERR:
|
||||
return 'Request aborted';
|
||||
case goog.db.Error.ErrorCode.READ_ONLY_ERR:
|
||||
return 'Modifying operation not allowed in a read-only transaction';
|
||||
case goog.db.Error.ErrorCode.TIMEOUT_ERR:
|
||||
return 'Transaction timed out';
|
||||
case goog.db.Error.ErrorCode.QUOTA_ERR:
|
||||
return 'Database storage space quota exceeded';
|
||||
case goog.db.Error.ErrorCode.INVALID_ACCESS_ERR:
|
||||
return 'Invalid operation';
|
||||
case goog.db.Error.ErrorCode.INVALID_STATE_ERR:
|
||||
return 'Invalid state';
|
||||
default:
|
||||
return 'Unrecognized exception with code ' + code;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Names of all possible errors as returned from the browser.
|
||||
* @see http://www.w3.org/TR/IndexedDB/#exceptions
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.db.Error.ErrorName = {
|
||||
ABORT_ERR: 'AbortError',
|
||||
CONSTRAINT_ERR: 'ConstraintError',
|
||||
DATA_CLONE_ERR: 'DataCloneError',
|
||||
DATA_ERR: 'DataError',
|
||||
INVALID_ACCESS_ERR: 'InvalidAccessError',
|
||||
INVALID_STATE_ERR: 'InvalidStateError',
|
||||
NOT_FOUND_ERR: 'NotFoundError',
|
||||
QUOTA_EXCEEDED_ERR: 'QuotaExceededError',
|
||||
READ_ONLY_ERR: 'ReadOnlyError',
|
||||
SYNTAX_ERROR: 'SyntaxError',
|
||||
TIMEOUT_ERR: 'TimeoutError',
|
||||
TRANSACTION_INACTIVE_ERR: 'TransactionInactiveError',
|
||||
UNKNOWN_ERR: 'UnknownError',
|
||||
VERSION_ERR: 'VersionError'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Translates an error name to an error code. This is purely kept for backwards
|
||||
* compatibility with Chrome21.
|
||||
*
|
||||
* @param {string} name The name of the erorr.
|
||||
* @return {number} The error code corresponding to the error.
|
||||
*/
|
||||
goog.db.Error.getCode = function(name) {
|
||||
switch (name) {
|
||||
case goog.db.Error.ErrorName.UNKNOWN_ERR:
|
||||
return goog.db.Error.ErrorCode.UNKNOWN_ERR;
|
||||
case goog.db.Error.ErrorName.NOT_FOUND_ERR:
|
||||
return goog.db.Error.ErrorCode.NOT_FOUND_ERR;
|
||||
case goog.db.Error.ErrorName.CONSTRAINT_ERR:
|
||||
return goog.db.Error.ErrorCode.CONSTRAINT_ERR;
|
||||
case goog.db.Error.ErrorName.DATA_ERR:
|
||||
return goog.db.Error.ErrorCode.DATA_ERR;
|
||||
case goog.db.Error.ErrorName.TRANSACTION_INACTIVE_ERR:
|
||||
return goog.db.Error.ErrorCode.TRANSACTION_INACTIVE_ERR;
|
||||
case goog.db.Error.ErrorName.ABORT_ERR:
|
||||
return goog.db.Error.ErrorCode.ABORT_ERR;
|
||||
case goog.db.Error.ErrorName.READ_ONLY_ERR:
|
||||
return goog.db.Error.ErrorCode.READ_ONLY_ERR;
|
||||
case goog.db.Error.ErrorName.TIMEOUT_ERR:
|
||||
return goog.db.Error.ErrorCode.TIMEOUT_ERR;
|
||||
case goog.db.Error.ErrorName.QUOTA_EXCEEDED_ERR:
|
||||
return goog.db.Error.ErrorCode.QUOTA_ERR;
|
||||
case goog.db.Error.ErrorName.INVALID_ACCESS_ERR:
|
||||
return goog.db.Error.ErrorCode.INVALID_ACCESS_ERR;
|
||||
case goog.db.Error.ErrorName.INVALID_STATE_ERR:
|
||||
return goog.db.Error.ErrorCode.INVALID_STATE_ERR;
|
||||
default:
|
||||
return goog.db.Error.ErrorCode.UNKNOWN_ERR;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts an error code used by the old spec, to an error name used by the
|
||||
* latest spec.
|
||||
* @see http://www.w3.org/TR/IndexedDB/#exceptions
|
||||
*
|
||||
* @param {!goog.db.Error.ErrorCode|number} code The error code to convert.
|
||||
* @return {!goog.db.Error.ErrorName} The corresponding name of the error.
|
||||
*/
|
||||
goog.db.Error.getName = function(code) {
|
||||
switch (code) {
|
||||
case goog.db.Error.ErrorCode.UNKNOWN_ERR:
|
||||
return goog.db.Error.ErrorName.UNKNOWN_ERR;
|
||||
case goog.db.Error.ErrorCode.NOT_FOUND_ERR:
|
||||
return goog.db.Error.ErrorName.NOT_FOUND_ERR;
|
||||
case goog.db.Error.ErrorCode.CONSTRAINT_ERR:
|
||||
return goog.db.Error.ErrorName.CONSTRAINT_ERR;
|
||||
case goog.db.Error.ErrorCode.DATA_ERR:
|
||||
return goog.db.Error.ErrorName.DATA_ERR;
|
||||
case goog.db.Error.ErrorCode.TRANSACTION_INACTIVE_ERR:
|
||||
return goog.db.Error.ErrorName.TRANSACTION_INACTIVE_ERR;
|
||||
case goog.db.Error.ErrorCode.ABORT_ERR:
|
||||
return goog.db.Error.ErrorName.ABORT_ERR;
|
||||
case goog.db.Error.ErrorCode.READ_ONLY_ERR:
|
||||
return goog.db.Error.ErrorName.READ_ONLY_ERR;
|
||||
case goog.db.Error.ErrorCode.TIMEOUT_ERR:
|
||||
return goog.db.Error.ErrorName.TIMEOUT_ERR;
|
||||
case goog.db.Error.ErrorCode.QUOTA_ERR:
|
||||
return goog.db.Error.ErrorName.QUOTA_EXCEEDED_ERR;
|
||||
case goog.db.Error.ErrorCode.INVALID_ACCESS_ERR:
|
||||
return goog.db.Error.ErrorName.INVALID_ACCESS_ERR;
|
||||
case goog.db.Error.ErrorCode.INVALID_STATE_ERR:
|
||||
return goog.db.Error.ErrorName.INVALID_STATE_ERR;
|
||||
default:
|
||||
return goog.db.Error.ErrorName.UNKNOWN_ERR;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an goog.db.Error instance from an IDBRequest. This abstraction is
|
||||
* necessary to provide backwards compatibility with Chrome21.
|
||||
*
|
||||
* @param {!IDBRequest} request The request that failed.
|
||||
* @param {string} message The error message to add to err if it's wrapped.
|
||||
* @return {!goog.db.Error} The error that caused the failure.
|
||||
*/
|
||||
goog.db.Error.fromRequest = function(request, message) {
|
||||
if ('error' in request) {
|
||||
// Chrome 21 and before.
|
||||
return new goog.db.Error(request.error, message);
|
||||
} else if ('name' in request) {
|
||||
// Chrome 22+.
|
||||
var errorName = goog.db.Error.getName(request.errorCode);
|
||||
return new goog.db.Error(
|
||||
/**@type {!DOMError} */ ({name: errorName}), message);
|
||||
} else {
|
||||
return new goog.db.Error(/** @type {!DOMError} */ (
|
||||
{name: goog.db.Error.ErrorName.UNKNOWN_ERR}), message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an goog.db.Error instance from an DOMException. This abstraction
|
||||
* is necessary to provide backwards compatibility with Chrome21.
|
||||
*
|
||||
* @param {!IDBDatabaseException} ex The exception that was thrown.
|
||||
* @param {string} message The error message to add to err if it's wrapped.
|
||||
* @return {!goog.db.Error} The error that caused the failure.
|
||||
* @suppress {invalidCasts} The cast from IDBDatabaseException to DOMError
|
||||
* is invalid and will not compile.
|
||||
*/
|
||||
goog.db.Error.fromException = function(ex, message) {
|
||||
if ('name' in ex) {
|
||||
// Chrome 21 and before.
|
||||
return new goog.db.Error(/** @type {!DOMError} */ (ex), message);
|
||||
} else if ('code' in ex) {
|
||||
// Chrome 22+.
|
||||
var errorName = goog.db.Error.getName(ex.code);
|
||||
return new goog.db.Error(
|
||||
/** @type {!DOMError} */ ({name: errorName}), message);
|
||||
} else {
|
||||
return new goog.db.Error(/** @type {!DOMError} */ (
|
||||
{name: goog.db.Error.ErrorName.UNKNOWN_ERR}), message);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,245 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Wrapper for an IndexedDB index.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.db.Index');
|
||||
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.db.Cursor');
|
||||
goog.require('goog.db.Error');
|
||||
goog.require('goog.debug');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates an IDBIndex wrapper object. Indexes are associated with object
|
||||
* stores and provide methods for looking up objects based on their non-key
|
||||
* properties. Should not be created directly, access through the object store
|
||||
* it belongs to.
|
||||
* @see goog.db.ObjectStore#getIndex
|
||||
*
|
||||
* @param {!IDBIndex} index Underlying IDBIndex object.
|
||||
* @constructor
|
||||
*/
|
||||
goog.db.Index = function(index) {
|
||||
/**
|
||||
* Underlying IndexedDB index object.
|
||||
*
|
||||
* @type {!IDBIndex}
|
||||
* @private
|
||||
*/
|
||||
this.index_ = index;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} Name of the index.
|
||||
*/
|
||||
goog.db.Index.prototype.getName = function() {
|
||||
return this.index_.name;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} Key path of the index.
|
||||
*/
|
||||
goog.db.Index.prototype.getKeyPath = function() {
|
||||
return this.index_.keyPath;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} True if the index enforces that there is only one object
|
||||
* for each unique value it indexes on.
|
||||
*/
|
||||
goog.db.Index.prototype.isUnique = function() {
|
||||
return this.index_.unique;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for get and getKey.
|
||||
*
|
||||
* @param {string} fn Function name to call on the index to get the request.
|
||||
* @param {string} msg Message to give to the error.
|
||||
* @param {IDBKeyType} key The key to look up in the index.
|
||||
* @return {!goog.async.Deferred} The resulting deferred object.
|
||||
* @private
|
||||
*/
|
||||
goog.db.Index.prototype.get_ = function(fn, msg, key) {
|
||||
var d = new goog.async.Deferred();
|
||||
var request;
|
||||
try {
|
||||
request = this.index_[fn](key);
|
||||
} catch (err) {
|
||||
msg += ' with key ' + goog.debug.deepExpose(key);
|
||||
d.errback(goog.db.Error.fromException(err, msg));
|
||||
return d;
|
||||
}
|
||||
request.onsuccess = function(ev) {
|
||||
d.callback(ev.target.result);
|
||||
};
|
||||
request.onerror = function(ev) {
|
||||
msg += ' with key ' + goog.debug.deepExpose(key);
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, msg));
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fetches a single object from the object store. Even if there are multiple
|
||||
* objects that match the given key, this method will get only one of them.
|
||||
*
|
||||
* @param {IDBKeyType} key Key to look up in the index.
|
||||
* @return {!goog.async.Deferred} The deferred object for the given record.
|
||||
*/
|
||||
goog.db.Index.prototype.get = function(key) {
|
||||
return this.get_('get', 'getting from index ' + this.getName(), key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Looks up a single object from the object store and gives back the key that
|
||||
* it's listed under in the object store. Even if there are multiple records
|
||||
* that match the given key, this method returns the first.
|
||||
*
|
||||
* @param {IDBKeyType} key Key to look up in the index.
|
||||
* @return {!goog.async.Deferred} The deferred key for the record that matches
|
||||
* the key.
|
||||
*/
|
||||
goog.db.Index.prototype.getKey = function(key) {
|
||||
return this.get_('getKey', 'getting key from index ' + this.getName(), key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for getAll and getAllKeys.
|
||||
*
|
||||
* @param {string} fn Function name to call on the index to get the request.
|
||||
* @param {string} msg Message to give to the error.
|
||||
* @param {IDBKeyType=} opt_key Key to look up in the index.
|
||||
* @return {!goog.async.Deferred} The resulting deferred array of objects.
|
||||
* @private
|
||||
*/
|
||||
goog.db.Index.prototype.getAll_ = function(fn, msg, opt_key) {
|
||||
// This is the most common use of IDBKeyRange. If more specific uses of
|
||||
// cursors are needed then a full wrapper should be created.
|
||||
var IDBKeyRange = goog.global.IDBKeyRange || goog.global.webkitIDBKeyRange;
|
||||
var d = new goog.async.Deferred();
|
||||
var request;
|
||||
try {
|
||||
if (opt_key) {
|
||||
request = this.index_[fn](IDBKeyRange.only(opt_key));
|
||||
} else {
|
||||
request = this.index_[fn]();
|
||||
}
|
||||
} catch (err) {
|
||||
if (opt_key) {
|
||||
msg += ' for key ' + goog.debug.deepExpose(opt_key);
|
||||
}
|
||||
d.errback(goog.db.Error.fromException(err, msg));
|
||||
return d;
|
||||
}
|
||||
var result = [];
|
||||
request.onsuccess = function(ev) {
|
||||
var cursor = ev.target.result;
|
||||
if (cursor) {
|
||||
result.push(cursor.value);
|
||||
cursor['continue']();
|
||||
} else {
|
||||
d.callback(result);
|
||||
}
|
||||
};
|
||||
request.onerror = function(ev) {
|
||||
if (opt_key) {
|
||||
msg += ' for key ' + goog.debug.deepExpose(opt_key);
|
||||
}
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, msg));
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets all indexed objects. If the key is provided, gets all indexed objects
|
||||
* that match the key instead.
|
||||
*
|
||||
* @param {IDBKeyType=} opt_key Key to look up in the index.
|
||||
* @return {!goog.async.Deferred} A deferred array of objects that match the
|
||||
* key.
|
||||
*/
|
||||
goog.db.Index.prototype.getAll = function(opt_key) {
|
||||
return this.getAll_(
|
||||
'openCursor',
|
||||
'getting all from index ' + this.getName(),
|
||||
opt_key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the keys to look up all the indexed objects. If the key is provided,
|
||||
* gets all records for objects that match the key instead.
|
||||
*
|
||||
* @param {IDBKeyType=} opt_key Key to look up in the index.
|
||||
* @return {!goog.async.Deferred} A deferred array of keys for objects that
|
||||
* match the key.
|
||||
*/
|
||||
goog.db.Index.prototype.getAllKeys = function(opt_key) {
|
||||
return this.getAll_(
|
||||
'openKeyCursor',
|
||||
'getting all keys from index ' + this.getName(),
|
||||
opt_key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Opens a cursor over the specified key range. Returns a cursor object which is
|
||||
* able to iterate over the given range.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* <code>
|
||||
* var cursor = index.openCursor(goog.db.Range.bound('a', 'c'));
|
||||
*
|
||||
* var key = goog.events.listen(
|
||||
* cursor, goog.db.Cursor.EventType.NEW_DATA,
|
||||
* function() {
|
||||
* // Do something with data.
|
||||
* cursor.next();
|
||||
* });
|
||||
*
|
||||
* goog.events.listenOnce(
|
||||
* cursor, goog.db.Cursor.EventType.COMPLETE,
|
||||
* function() {
|
||||
* // Clean up listener, and perform a finishing operation on the data.
|
||||
* goog.events.unlistenByKey(key);
|
||||
* });
|
||||
* </code>
|
||||
*
|
||||
* @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
|
||||
* over the whole object store.
|
||||
* @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
|
||||
* moves in a forward direction with duplicates.
|
||||
* @return {!goog.db.Cursor} The cursor.
|
||||
* @throws {goog.db.Error} If there was a problem opening the cursor.
|
||||
*/
|
||||
goog.db.Index.prototype.openCursor = function(opt_range, opt_direction) {
|
||||
return goog.db.Cursor.openCursor(this.index_, opt_range, opt_direction);
|
||||
};
|
||||
@@ -0,0 +1,337 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Wrapper for an IndexedDB database.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.db.IndexedDb');
|
||||
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.db.Error');
|
||||
goog.require('goog.db.Error.VersionChangeBlockedError');
|
||||
goog.require('goog.db.ObjectStore');
|
||||
goog.require('goog.db.Transaction');
|
||||
goog.require('goog.db.Transaction.TransactionMode');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.events.EventHandler');
|
||||
goog.require('goog.events.EventTarget');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates an IDBDatabase wrapper object. The database object has methods for
|
||||
* setting the version to change the structure of the database and for creating
|
||||
* transactions to get or modify the stored records. Should not be created
|
||||
* directly, call {@link goog.db.openDatabase} to set up the connection.
|
||||
*
|
||||
* @param {!IDBDatabase} db Underlying IndexedDB database object.
|
||||
* @constructor
|
||||
* @extends {goog.events.EventTarget}
|
||||
*/
|
||||
goog.db.IndexedDb = function(db) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* Underlying IndexedDB database object.
|
||||
*
|
||||
* @type {!IDBDatabase}
|
||||
* @private
|
||||
*/
|
||||
this.db_ = db;
|
||||
|
||||
/**
|
||||
* Internal event handler that listens to IDBDatabase events.
|
||||
* @type {!goog.events.EventHandler}
|
||||
* @private
|
||||
*/
|
||||
this.eventHandler_ = new goog.events.EventHandler(this);
|
||||
|
||||
this.eventHandler_.listen(
|
||||
this.db_,
|
||||
goog.db.IndexedDb.EventType.ABORT,
|
||||
goog.bind(
|
||||
this.dispatchEvent,
|
||||
this,
|
||||
goog.db.IndexedDb.EventType.ABORT));
|
||||
this.eventHandler_.listen(
|
||||
this.db_,
|
||||
goog.db.IndexedDb.EventType.ERROR,
|
||||
this.dispatchError_);
|
||||
this.eventHandler_.listen(
|
||||
this.db_,
|
||||
goog.db.IndexedDb.EventType.VERSION_CHANGE,
|
||||
this.dispatchVersionChange_);
|
||||
};
|
||||
goog.inherits(goog.db.IndexedDb, goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* True iff the database connection is open.
|
||||
*
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.open_ = true;
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches a wrapped error event based on the given event.
|
||||
*
|
||||
* @param {Event} ev The error event given to the underlying IDBDatabase.
|
||||
* @private
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.dispatchError_ = function(ev) {
|
||||
this.dispatchEvent({
|
||||
type: goog.db.IndexedDb.EventType.ERROR,
|
||||
errorCode: /** @type {IDBRequest} */ (ev.target).errorCode
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches a wrapped version change event based on the given event.
|
||||
*
|
||||
* @param {Event} ev The version change event given to the underlying
|
||||
* IDBDatabase.
|
||||
* @private
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.dispatchVersionChange_ = function(ev) {
|
||||
this.dispatchEvent(new goog.db.IndexedDb.VersionChangeEvent(
|
||||
ev.oldVersion, ev.newVersion));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Closes the database connection. Metadata queries can still be made after this
|
||||
* method is called, but otherwise this wrapper should not be used further.
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.close = function() {
|
||||
if (this.open_) {
|
||||
this.db_.close();
|
||||
this.open_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether a connection is open and the database can be used.
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.isOpen = function() {
|
||||
return this.open_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The name of this database.
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.getName = function() {
|
||||
return this.db_.name;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The current database version.
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.getVersion = function() {
|
||||
return this.db_.version;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {DOMStringList} List of object stores in this database.
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.getObjectStoreNames = function() {
|
||||
return this.db_.objectStoreNames;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates an object store in this database. Can only be called inside a
|
||||
* {@link goog.db.UpgradeNeededCallback} or the callback for the Deferred
|
||||
* returned from #setVersion.
|
||||
*
|
||||
* @param {string} name Name for the new object store.
|
||||
* @param {Object=} opt_params Options object. The available options are:
|
||||
* keyPath, which is a string and determines what object attribute
|
||||
* to use as the key when storing objects in this object store; and
|
||||
* autoIncrement, which is a boolean, which defaults to false and determines
|
||||
* whether the object store should automatically generate keys for stored
|
||||
* objects. If keyPath is not provided and autoIncrement is false, then all
|
||||
* insert operations must provide a key as a parameter.
|
||||
* @return {goog.db.ObjectStore} The newly created object store.
|
||||
* @throws {goog.db.Error} If there's a problem creating the object store.
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.createObjectStore = function(name, opt_params) {
|
||||
try {
|
||||
return new goog.db.ObjectStore(this.db_.createObjectStore(
|
||||
name, opt_params));
|
||||
} catch (ex) {
|
||||
throw goog.db.Error.fromException(ex, 'creating object store ' + name);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deletes an object store. Can only be called inside a
|
||||
* {@link goog.db.UpgradeNeededCallback} or the callback for the Deferred
|
||||
* returned from #setVersion.
|
||||
*
|
||||
* @param {string} name Name of the object store to delete.
|
||||
* @throws {goog.db.Error} If there's a problem deleting the object store.
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.deleteObjectStore = function(name) {
|
||||
try {
|
||||
this.db_.deleteObjectStore(name);
|
||||
} catch (ex) {
|
||||
throw goog.db.Error.fromException(ex, 'deleting object store ' + name);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Updates the version of the database and returns a Deferred transaction.
|
||||
* The database's structure can be changed inside this Deferred's callback, but
|
||||
* nowhere else. This means adding or deleting object stores, and adding or
|
||||
* deleting indexes. The version change will not succeed unless there are no
|
||||
* other connections active for this database anywhere. A new database
|
||||
* connection should be opened after the version change is finished to pick
|
||||
* up changes.
|
||||
*
|
||||
* This is deprecated, and only supported on Chrome prior to version 25. New
|
||||
* applications should use the version parameter to {@link goog.db.openDatabase}
|
||||
* instead.
|
||||
*
|
||||
* @param {string} version The new version of the database.
|
||||
* @return {!goog.async.Deferred} The deferred transaction for changing the
|
||||
* version.
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.setVersion = function(version) {
|
||||
var self = this;
|
||||
var d = new goog.async.Deferred();
|
||||
var request = this.db_.setVersion(version);
|
||||
request.onsuccess = function(ev) {
|
||||
// the transaction is in the result field (the transaction field is null
|
||||
// for version change requests)
|
||||
d.callback(new goog.db.Transaction(ev.target.result, self));
|
||||
};
|
||||
request.onerror = function(ev) {
|
||||
// If a version change is blocked, onerror and onblocked may both fire.
|
||||
// Check d.hasFired() to avoid an AlreadyCalledError.
|
||||
if (!d.hasFired()) {
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, 'setting version'));
|
||||
}
|
||||
};
|
||||
request.onblocked = function(ev) {
|
||||
// If a version change is blocked, onerror and onblocked may both fire.
|
||||
// Check d.hasFired() to avoid an AlreadyCalledError.
|
||||
if (!d.hasFired()) {
|
||||
d.errback(new goog.db.Error.VersionChangeBlockedError());
|
||||
}
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new transaction.
|
||||
*
|
||||
* @param {!Array.<string>} storeNames A list of strings that contains the
|
||||
* transaction's scope, the object stores that this transaction can operate
|
||||
* on.
|
||||
* @param {goog.db.Transaction.TransactionMode=} opt_mode The mode of the
|
||||
* transaction. If not present, the default is READ_ONLY. For VERSION_CHANGE
|
||||
* transactions call {@link goog.db.IndexedDB#setVersion} instead.
|
||||
* @return {!goog.db.Transaction} The wrapper for the newly created transaction.
|
||||
* @throws {goog.db.Error} If there's a problem creating the transaction.
|
||||
*/
|
||||
goog.db.IndexedDb.prototype.createTransaction = function(storeNames, opt_mode) {
|
||||
try {
|
||||
// IndexedDB on Chrome 22+ requires that opt_mode not be passed rather than
|
||||
// be explicitly passed as undefined.
|
||||
var transaction = opt_mode ?
|
||||
this.db_.transaction(storeNames, opt_mode) :
|
||||
this.db_.transaction(storeNames);
|
||||
return new goog.db.Transaction(transaction, this);
|
||||
} catch (ex) {
|
||||
throw goog.db.Error.fromException(ex, 'creating transaction');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.db.IndexedDb.prototype.disposeInternal = function() {
|
||||
goog.base(this, 'disposeInternal');
|
||||
this.eventHandler_.dispose();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Event types fired by a database.
|
||||
*
|
||||
* @enum {string} The event types for the web socket.
|
||||
*/
|
||||
goog.db.IndexedDb.EventType = {
|
||||
|
||||
/**
|
||||
* Fired when a transaction is aborted and the event bubbles to its database.
|
||||
*/
|
||||
ABORT: 'abort',
|
||||
|
||||
/**
|
||||
* Fired when a transaction has an error.
|
||||
*/
|
||||
ERROR: 'error',
|
||||
|
||||
/**
|
||||
* Fired when someone (possibly in another window) is attempting to modify the
|
||||
* structure of the database. Since a change can only be made when there are
|
||||
* no active database connections, this usually means that the database should
|
||||
* be closed so that the other client can make its changes.
|
||||
*/
|
||||
VERSION_CHANGE: 'versionchange'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Event representing a (possibly attempted) change in the database structure.
|
||||
*
|
||||
* At time of writing, no Chrome versions support oldVersion or newVersion. See
|
||||
* http://crbug.com/153122.
|
||||
*
|
||||
* @param {number} oldVersion The previous version of the database.
|
||||
* @param {number} newVersion The version the database is being or has been
|
||||
* updated to.
|
||||
* @constructor
|
||||
* @extends {goog.events.Event}
|
||||
*/
|
||||
goog.db.IndexedDb.VersionChangeEvent = function(oldVersion, newVersion) {
|
||||
goog.base(this, goog.db.IndexedDb.EventType.VERSION_CHANGE);
|
||||
|
||||
/**
|
||||
* The previous version of the database.
|
||||
* @type {number}
|
||||
*/
|
||||
this.oldVersion = oldVersion;
|
||||
|
||||
/**
|
||||
* The version the database is being or has been updated to.
|
||||
* @type {number}
|
||||
*/
|
||||
this.newVersion = newVersion;
|
||||
};
|
||||
goog.inherits(goog.db.IndexedDb.VersionChangeEvent, goog.events.Event);
|
||||
@@ -0,0 +1,117 @@
|
||||
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Wrapper for a IndexedDB key range.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.db.KeyRange');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new IDBKeyRange wrapper object. Should not be created directly,
|
||||
* instead use one of the static factory methods. For example:
|
||||
* @see goog.db.KeyRange.bound
|
||||
* @see goog.db.KeyRange.lowerBound
|
||||
*
|
||||
* @param {!IDBKeyRange} range Underlying IDBKeyRange object.
|
||||
* @constructor
|
||||
*/
|
||||
goog.db.KeyRange = function(range) {
|
||||
/**
|
||||
* Underlying IDBKeyRange object.
|
||||
*
|
||||
* @type {!IDBKeyRange}
|
||||
* @private
|
||||
*/
|
||||
this.range_ = range;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The IDBKeyRange.
|
||||
* @type {!Object}
|
||||
* @private
|
||||
*/
|
||||
goog.db.KeyRange.IDB_KEY_RANGE_ = goog.global.IDBKeyRange ||
|
||||
goog.global.webkitIDBKeyRange;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new key range for a single value.
|
||||
*
|
||||
* @param {IDBKeyType} key The single value in the range.
|
||||
* @return {!goog.db.KeyRange} The key range.
|
||||
*/
|
||||
goog.db.KeyRange.only = function(key) {
|
||||
return new goog.db.KeyRange(goog.db.KeyRange.IDB_KEY_RANGE_.only(key));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a key range with upper and lower bounds.
|
||||
*
|
||||
* @param {IDBKeyType} lower The value of the lower bound.
|
||||
* @param {IDBKeyType} upper The value of the upper bound.
|
||||
* @param {boolean=} opt_lowerOpen If true, the range excludes the lower bound
|
||||
* value.
|
||||
* @param {boolean=} opt_upperOpen If true, the range excludes the upper bound
|
||||
* value.
|
||||
* @return {!goog.db.KeyRange} The key range.
|
||||
*/
|
||||
goog.db.KeyRange.bound = function(lower, upper, opt_lowerOpen, opt_upperOpen) {
|
||||
return new goog.db.KeyRange(goog.db.KeyRange.IDB_KEY_RANGE_.bound(
|
||||
lower, upper, opt_lowerOpen, opt_upperOpen));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a key range with a lower bound only, finishes at the last record.
|
||||
*
|
||||
* @param {IDBKeyType} lower The value of the lower bound.
|
||||
* @param {boolean=} opt_lowerOpen If true, the range excludes the lower bound
|
||||
* value.
|
||||
* @return {!goog.db.KeyRange} The key range.
|
||||
*/
|
||||
goog.db.KeyRange.lowerBound = function(lower, opt_lowerOpen) {
|
||||
return new goog.db.KeyRange(goog.db.KeyRange.IDB_KEY_RANGE_.lowerBound(
|
||||
lower, opt_lowerOpen));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a key range with a upper bound only, starts at the first record.
|
||||
*
|
||||
* @param {IDBKeyType} upper The value of the upper bound.
|
||||
* @param {boolean=} opt_upperOpen If true, the range excludes the upper bound
|
||||
* value.
|
||||
* @return {!goog.db.KeyRange} The key range.
|
||||
*/
|
||||
goog.db.KeyRange.upperBound = function(upper, opt_upperOpen) {
|
||||
return new goog.db.KeyRange(goog.db.KeyRange.IDB_KEY_RANGE_.upperBound(
|
||||
upper, opt_upperOpen));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns underlying key range object. This is used in ObjectStore's openCursor
|
||||
* and count methods.
|
||||
* @return {!IDBKeyRange}
|
||||
*/
|
||||
goog.db.KeyRange.prototype.range = function() {
|
||||
return this.range_;
|
||||
};
|
||||
@@ -0,0 +1,399 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Wrapper for an IndexedDB object store.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.db.ObjectStore');
|
||||
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.db.Cursor');
|
||||
goog.require('goog.db.Error');
|
||||
goog.require('goog.db.Index');
|
||||
goog.require('goog.debug');
|
||||
goog.require('goog.events');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates an IDBObjectStore wrapper object. Object stores have methods for
|
||||
* storing and retrieving records, and are accessed through a transaction
|
||||
* object. They also have methods for creating indexes associated with the
|
||||
* object store. They can only be created when setting the version of the
|
||||
* database. Should not be created directly, access object stores through
|
||||
* transactions.
|
||||
* @see goog.db.IndexedDb#setVersion
|
||||
* @see goog.db.Transaction#objectStore
|
||||
*
|
||||
* @param {!IDBObjectStore} store The backing IndexedDb object.
|
||||
* @constructor
|
||||
*
|
||||
* TODO(user): revisit msg in exception and errors in this class. In newer
|
||||
* Chrome (v22+) the error/request come with a DOM error string that is
|
||||
* already very descriptive.
|
||||
*/
|
||||
goog.db.ObjectStore = function(store) {
|
||||
/**
|
||||
* Underlying IndexedDB object store object.
|
||||
*
|
||||
* @type {!IDBObjectStore}
|
||||
* @private
|
||||
*/
|
||||
this.store_ = store;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The name of the object store.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.getName = function() {
|
||||
return this.store_.name;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for put and add.
|
||||
*
|
||||
* @param {string} fn Function name to call on the object store.
|
||||
* @param {string} msg Message to give to the error.
|
||||
* @param {*} value Value to insert into the object store.
|
||||
* @param {IDBKeyType=} opt_key The key to use.
|
||||
* @return {!goog.async.Deferred} The resulting deferred request.
|
||||
* @private
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.insert_ = function(fn, msg, value, opt_key) {
|
||||
// TODO(user): refactor wrapping an IndexedDB request in a Deferred by
|
||||
// creating a higher-level abstraction for it (mostly affects here and
|
||||
// goog.db.Index)
|
||||
var d = new goog.async.Deferred();
|
||||
var request;
|
||||
try {
|
||||
// put or add with (value, undefined) throws an error, so we need to check
|
||||
// for undefined ourselves
|
||||
if (opt_key) {
|
||||
request = this.store_[fn](value, opt_key);
|
||||
} else {
|
||||
request = this.store_[fn](value);
|
||||
}
|
||||
} catch (ex) {
|
||||
msg += goog.debug.deepExpose(value);
|
||||
if (opt_key) {
|
||||
msg += ', with key ' + goog.debug.deepExpose(opt_key);
|
||||
}
|
||||
d.errback(goog.db.Error.fromException(ex, msg));
|
||||
return d;
|
||||
}
|
||||
request.onsuccess = function(ev) {
|
||||
d.callback();
|
||||
};
|
||||
var self = this;
|
||||
request.onerror = function(ev) {
|
||||
msg += goog.debug.deepExpose(value);
|
||||
if (opt_key) {
|
||||
msg += ', with key ' + goog.debug.deepExpose(opt_key);
|
||||
}
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, msg));
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an object to the object store. Replaces existing objects with the
|
||||
* same key.
|
||||
*
|
||||
* @param {*} value The value to put.
|
||||
* @param {IDBKeyType=} opt_key The key to use. Cannot be used if the
|
||||
* keyPath was specified for the object store. If the keyPath was not
|
||||
* specified but autoIncrement was not enabled, it must be used.
|
||||
* @return {!goog.async.Deferred} The deferred put request.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.put = function(value, opt_key) {
|
||||
return this.insert_(
|
||||
'put',
|
||||
'putting into ' + this.getName() + ' with value',
|
||||
value,
|
||||
opt_key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an object to the object store. Requires that there is no object with
|
||||
* the same key already present.
|
||||
*
|
||||
* @param {*} value The value to add.
|
||||
* @param {IDBKeyType=} opt_key The key to use. Cannot be used if the
|
||||
* keyPath was specified for the object store. If the keyPath was not
|
||||
* specified but autoIncrement was not enabled, it must be used.
|
||||
* @return {!goog.async.Deferred} The deferred add request.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.add = function(value, opt_key) {
|
||||
return this.insert_(
|
||||
'add',
|
||||
'adding into ' + this.getName() + ' with value ',
|
||||
value,
|
||||
opt_key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes an object from the store. No-op if there is no object present with
|
||||
* the given key.
|
||||
*
|
||||
* @param {IDBKeyType} key The key to remove objects under.
|
||||
* @return {!goog.async.Deferred} The deferred remove request.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.remove = function(key) {
|
||||
var d = new goog.async.Deferred();
|
||||
var request;
|
||||
try {
|
||||
request = this.store_['delete'](key);
|
||||
} catch (err) {
|
||||
var msg = 'removing from ' + this.getName() + ' with key ' +
|
||||
goog.debug.deepExpose(key);
|
||||
d.errback(goog.db.Error.fromException(err, msg));
|
||||
return d;
|
||||
}
|
||||
request.onsuccess = function(ev) {
|
||||
d.callback();
|
||||
};
|
||||
var self = this;
|
||||
request.onerror = function(ev) {
|
||||
var msg = 'removing from ' + self.getName() + ' with key ' +
|
||||
goog.debug.deepExpose(key);
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, msg));
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets an object from the store. If no object is present with that key
|
||||
* the result is {@code undefined}.
|
||||
*
|
||||
* @param {IDBKeyType} key The key to look up.
|
||||
* @return {!goog.async.Deferred} The deferred get request.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.get = function(key) {
|
||||
var d = new goog.async.Deferred();
|
||||
var request;
|
||||
try {
|
||||
request = this.store_.get(key);
|
||||
} catch (err) {
|
||||
var msg = 'getting from ' + this.getName() + ' with key ' +
|
||||
goog.debug.deepExpose(key);
|
||||
d.errback(goog.db.Error.fromException(err, msg));
|
||||
return d;
|
||||
}
|
||||
request.onsuccess = function(ev) {
|
||||
d.callback(ev.target.result);
|
||||
};
|
||||
var self = this;
|
||||
request.onerror = function(ev) {
|
||||
var msg = 'getting from ' + self.getName() + ' with key ' +
|
||||
goog.debug.deepExpose(key);
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, msg));
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets all objects from the store and returns them as an array.
|
||||
*
|
||||
* @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
|
||||
* over the whole object store.
|
||||
* @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
|
||||
* moves in a forward direction with duplicates.
|
||||
* @return {!goog.async.Deferred} The deferred getAll request.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.getAll = function(opt_range, opt_direction) {
|
||||
var d = new goog.async.Deferred();
|
||||
var cursor;
|
||||
try {
|
||||
cursor = this.openCursor(opt_range, opt_direction);
|
||||
} catch (err) {
|
||||
d.errback(err);
|
||||
return d;
|
||||
}
|
||||
|
||||
var result = [];
|
||||
var key = goog.events.listen(
|
||||
cursor, goog.db.Cursor.EventType.NEW_DATA, function() {
|
||||
result.push(cursor.getValue());
|
||||
cursor.next();
|
||||
});
|
||||
|
||||
goog.events.listenOnce(cursor, [
|
||||
goog.db.Cursor.EventType.ERROR,
|
||||
goog.db.Cursor.EventType.COMPLETE
|
||||
], function(evt) {
|
||||
cursor.dispose();
|
||||
if (evt.type == goog.db.Cursor.EventType.COMPLETE) {
|
||||
d.callback(result);
|
||||
} else {
|
||||
d.errback();
|
||||
}
|
||||
});
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Opens a cursor over the specified key range. Returns a cursor object which is
|
||||
* able to iterate over the given range.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* <code>
|
||||
* var cursor = objectStore.openCursor(goog.db.Range.bound('a', 'c'));
|
||||
*
|
||||
* var key = goog.events.listen(
|
||||
* cursor, goog.db.Cursor.EventType.NEW_DATA, function() {
|
||||
* // Do something with data.
|
||||
* cursor.next();
|
||||
* });
|
||||
*
|
||||
* goog.events.listenOnce(
|
||||
* cursor, goog.db.Cursor.EventType.COMPLETE, function() {
|
||||
* // Clean up listener, and perform a finishing operation on the data.
|
||||
* goog.events.unlistenByKey(key);
|
||||
* });
|
||||
* </code>
|
||||
*
|
||||
* @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
|
||||
* over the whole object store.
|
||||
* @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
|
||||
* moves in a forward direction with duplicates.
|
||||
* @return {!goog.db.Cursor} The cursor.
|
||||
* @throws {goog.db.Error} If there was a problem opening the cursor.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.openCursor = function(opt_range, opt_direction) {
|
||||
return goog.db.Cursor.openCursor(this.store_, opt_range, opt_direction);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deletes all objects from the store.
|
||||
*
|
||||
* @return {!goog.async.Deferred} The deferred clear request.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.clear = function() {
|
||||
var msg = 'clearing store ' + this.getName();
|
||||
var d = new goog.async.Deferred();
|
||||
var request;
|
||||
try {
|
||||
request = this.store_.clear();
|
||||
} catch (err) {
|
||||
d.errback(goog.db.Error.fromException(err, msg));
|
||||
return d;
|
||||
}
|
||||
request.onsuccess = function(ev) {
|
||||
d.callback();
|
||||
};
|
||||
request.onerror = function(ev) {
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, msg));
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates an index in this object store. Can only be called inside the callback
|
||||
* for the Deferred returned from goog.db.IndexedDb#setVersion.
|
||||
*
|
||||
* @param {string} name Name of the index to create.
|
||||
* @param {string} keyPath Attribute to index on.
|
||||
* @param {!Object=} opt_parameters Optional parameters object. The only
|
||||
* available option is unique, which defaults to false. If unique is true,
|
||||
* the index will enforce that there is only ever one object in the object
|
||||
* store for each unique value it indexes on.
|
||||
* @return {goog.db.Index} The newly created, wrapped index.
|
||||
* @throws {goog.db.Error} In case of an error creating the index.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.createIndex = function(
|
||||
name, keyPath, opt_parameters) {
|
||||
try {
|
||||
return new goog.db.Index(this.store_.createIndex(
|
||||
name, keyPath, opt_parameters));
|
||||
} catch (ex) {
|
||||
var msg = 'creating new index ' + name + ' with key path ' + keyPath;
|
||||
throw goog.db.Error.fromException(ex, msg);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets an index.
|
||||
*
|
||||
* @param {string} name Name of the index to fetch.
|
||||
* @return {goog.db.Index} The requested wrapped index.
|
||||
* @throws {goog.db.Error} In case of an error getting the index.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.getIndex = function(name) {
|
||||
try {
|
||||
return new goog.db.Index(this.store_.index(name));
|
||||
} catch (ex) {
|
||||
var msg = 'getting index ' + name;
|
||||
throw goog.db.Error.fromException(ex, msg);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deletes an index from the object store. Can only be called inside the
|
||||
* callback for the Deferred returned from goog.db.IndexedDb#setVersion.
|
||||
*
|
||||
* @param {string} name Name of the index to delete.
|
||||
* @throws {goog.db.Error} In case of an error deleting the index.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.deleteIndex = function(name) {
|
||||
try {
|
||||
this.store_.deleteIndex(name);
|
||||
} catch (ex) {
|
||||
var msg = 'deleting index ' + name;
|
||||
throw goog.db.Error.fromException(ex, msg);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets number of records within a key range.
|
||||
*
|
||||
* @param {!goog.db.KeyRange=} opt_range The key range. If undefined, this will
|
||||
* count all records in the object store.
|
||||
* @return {!goog.async.Deferred} The deferred number of records.
|
||||
*/
|
||||
goog.db.ObjectStore.prototype.count = function(opt_range) {
|
||||
var request;
|
||||
var d = new goog.async.Deferred();
|
||||
|
||||
try {
|
||||
var range = opt_range ? opt_range.range() : null;
|
||||
request = this.store_.count(range);
|
||||
} catch (ex) {
|
||||
d.errback(goog.db.Error.fromException(ex, this.getName()));
|
||||
}
|
||||
request.onsuccess = function(ev) {
|
||||
d.callback(ev.target.result);
|
||||
};
|
||||
request.onerror = function(ev) {
|
||||
d.errback(goog.db.Error.fromRequest(ev.target, this.getName()));
|
||||
};
|
||||
return d;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Wrapper for an IndexedDB transaction.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.db.Transaction');
|
||||
goog.provide('goog.db.Transaction.TransactionMode');
|
||||
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.db.Error');
|
||||
goog.require('goog.db.ObjectStore');
|
||||
goog.require('goog.events.EventHandler');
|
||||
goog.require('goog.events.EventTarget');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new transaction. Transactions contain methods for accessing object
|
||||
* stores and are created from the database object. Should not be created
|
||||
* directly, open a database and call createTransaction on it.
|
||||
* @see goog.db.IndexedDb#createTransaction
|
||||
*
|
||||
* @param {!IDBTransaction} tx IndexedDB transaction to back this wrapper.
|
||||
* @param {!goog.db.IndexedDb} db The database that this transaction modifies.
|
||||
* @constructor
|
||||
* @extends {goog.events.EventTarget}
|
||||
*/
|
||||
goog.db.Transaction = function(tx, db) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* Underlying IndexedDB transaction object.
|
||||
*
|
||||
* @type {!IDBTransaction}
|
||||
* @private
|
||||
*/
|
||||
this.tx_ = tx;
|
||||
|
||||
/**
|
||||
* The database that this transaction modifies.
|
||||
*
|
||||
* @type {!goog.db.IndexedDb}
|
||||
* @private
|
||||
*/
|
||||
this.db_ = db;
|
||||
|
||||
/**
|
||||
* Event handler for this transaction.
|
||||
*
|
||||
* @type {!goog.events.EventHandler}
|
||||
* @private
|
||||
*/
|
||||
this.eventHandler_ = new goog.events.EventHandler(this);
|
||||
|
||||
// TODO(user): remove these casts once the externs file is updated to
|
||||
// correctly reflect that IDBTransaction extends EventTarget
|
||||
this.eventHandler_.listen(
|
||||
/** @type {EventTarget} */ (this.tx_),
|
||||
'complete',
|
||||
goog.bind(
|
||||
this.dispatchEvent,
|
||||
this,
|
||||
goog.db.Transaction.EventTypes.COMPLETE));
|
||||
this.eventHandler_.listen(
|
||||
/** @type {EventTarget} */ (this.tx_),
|
||||
'abort',
|
||||
goog.bind(
|
||||
this.dispatchEvent,
|
||||
this,
|
||||
goog.db.Transaction.EventTypes.ABORT));
|
||||
this.eventHandler_.listen(
|
||||
/** @type {EventTarget} */ (this.tx_),
|
||||
'error',
|
||||
this.dispatchError_);
|
||||
};
|
||||
goog.inherits(goog.db.Transaction, goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches an error event based on the given event, wrapping the error
|
||||
* if necessary.
|
||||
*
|
||||
* @param {Event} ev The error event given to the underlying IDBTransaction.
|
||||
* @private
|
||||
*/
|
||||
goog.db.Transaction.prototype.dispatchError_ = function(ev) {
|
||||
if (ev.target instanceof goog.db.Error) {
|
||||
this.dispatchEvent({
|
||||
type: goog.db.Transaction.EventTypes.ERROR,
|
||||
target: ev.target
|
||||
});
|
||||
} else {
|
||||
this.dispatchEvent({
|
||||
type: goog.db.Transaction.EventTypes.ERROR,
|
||||
target: goog.db.Error.fromRequest(
|
||||
/** @type {!IDBRequest} */ (ev.target), 'in transaction')
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Event types the Transaction can dispatch. COMPLETE events are dispatched
|
||||
* when the transaction is committed. If a transaction is aborted it dispatches
|
||||
* both an ABORT event and an ERROR event with the ABORT_ERR code. Error events
|
||||
* are dispatched on any error.
|
||||
*
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.db.Transaction.EventTypes = {
|
||||
COMPLETE: 'complete',
|
||||
ABORT: 'abort',
|
||||
ERROR: 'error'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {goog.db.Transaction.TransactionMode} The transaction's mode.
|
||||
*/
|
||||
goog.db.Transaction.prototype.getMode = function() {
|
||||
return /** @type {goog.db.Transaction.TransactionMode} */ (this.tx_.mode);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.db.IndexedDb} The database that this transaction modifies.
|
||||
*/
|
||||
goog.db.Transaction.prototype.getDatabase = function() {
|
||||
return this.db_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Opens an object store to do operations on in this transaction. The requested
|
||||
* object store must be one that is in this transaction's scope.
|
||||
* @see goog.db.IndexedDb#createTransaction
|
||||
*
|
||||
* @param {string} name The name of the requested object store.
|
||||
* @return {!goog.db.ObjectStore} The wrapped object store.
|
||||
* @throws {goog.db.Error} In case of error getting the object store.
|
||||
*/
|
||||
goog.db.Transaction.prototype.objectStore = function(name) {
|
||||
try {
|
||||
return new goog.db.ObjectStore(this.tx_.objectStore(name));
|
||||
} catch (ex) {
|
||||
throw goog.db.Error.fromException(ex, 'getting object store ' + name);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.async.Deferred} A deferred that will fire once the
|
||||
* transaction is complete. It fires the errback chain if an error occurs
|
||||
* in the transaction, or if it is aborted.
|
||||
*/
|
||||
goog.db.Transaction.prototype.wait = function() {
|
||||
var d = new goog.async.Deferred();
|
||||
goog.events.listenOnce(
|
||||
this, goog.db.Transaction.EventTypes.COMPLETE, goog.bind(d.callback, d));
|
||||
goog.events.listenOnce(
|
||||
this, goog.db.Transaction.EventTypes.ABORT, function() {
|
||||
d.errback(new goog.db.Error(goog.db.Error.ErrorCode.ABORT_ERR,
|
||||
'waiting for transaction to complete'));
|
||||
});
|
||||
goog.events.listenOnce(
|
||||
this, goog.db.Transaction.EventTypes.ERROR, function(e) {
|
||||
d.errback(e.target);
|
||||
});
|
||||
|
||||
var db = this.getDatabase();
|
||||
return d.addCallback(function() {
|
||||
return db;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Aborts this transaction. No pending operations will be applied to the
|
||||
* database. Dispatches an ABORT event.
|
||||
*/
|
||||
goog.db.Transaction.prototype.abort = function() {
|
||||
this.tx_.abort();
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.db.Transaction.prototype.disposeInternal = function() {
|
||||
goog.base(this, 'disposeInternal');
|
||||
this.eventHandler_.dispose();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The three possible transaction modes.
|
||||
* @see http://www.w3.org/TR/IndexedDB/#idl-def-IDBTransaction
|
||||
*
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.db.Transaction.TransactionMode = {
|
||||
READ_ONLY: 'readonly',
|
||||
READ_WRITE: 'readwrite',
|
||||
VERSION_CHANGE: 'versionchange'
|
||||
};
|
||||
Reference in New Issue
Block a user