| // 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} |
| * @final |
| */ |
| goog.db.Cursor = function() { |
| goog.db.Cursor.base(this, 'constructor'); |
| }; |
| 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' |
| }; |