text: // 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.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 {!Object} value Value to look up in the index.
   * @return {!goog.async.Deferred} The resulting deferred object.
   * @private
   */
  goog.db.Index.prototype.get_ = function(fn, msg, value) {
    var d = new goog.async.Deferred();
    var request;
    try {
      request = this.index_[fn](value);
    } catch (err) {
      msg += ' with value ' + goog.debug.deepExpose(value);
      d.errback(new goog.db.Error(err.code, msg));
      return d;
    }
    request.onsuccess = function(ev) {
      d.callback(ev.target.result);
    };
    request.onerror = function(ev) {
      msg += ' with value ' + goog.debug.deepExpose(value);
      d.errback(new goog.db.Error(
          (/** @type {IDBRequest} */ (ev.target)).errorCode,
          msg));
    };
    return d;
  };
  
  
  /**
   * Fetches a single object from the object store. Even if there are multiple
   * objects that match the given value, this method will get only one of them.
   *
   * @param {!Object} value Value to look up in the index.
   * @return {!goog.async.Deferred} The deferred object that matches the value.
   */
  goog.db.Index.prototype.get = function(value) {
    return this.get_('get', 'getting from index ' + this.getName(), value);
  };
  
  
  /**
   * 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 objects
   * that match the given value, this method will only get one of their keys.
   *
   * @param {!Object} value Value to look up in the index.
   * @return {!goog.async.Deferred} The deferred key for the object that matches
   *     the value.
   */
  goog.db.Index.prototype.getKey = function(value) {
    return this.get_('getKey', 'getting key from index ' + this.getName(), value);
  };
  
  
  /**
   * 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 {!Object=} opt_value Value 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_value) {
    // 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_value) {
        request = this.index_[fn](IDBKeyRange.bound(opt_value, opt_value));
      } else {
        request = this.index_[fn]();
      }
    } catch (err) {
      if (opt_value) {
        msg += ' for value ' + goog.debug.deepExpose(opt_value);
      }
      d.errback(new goog.db.Error(err.code, 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_value) {
        msg += ' for value ' + goog.debug.deepExpose(opt_value);
      }
      d.errback(new goog.db.Error(
          (/** @type {IDBRequest} */ (ev.target)).errorCode,
          msg));
    };
    return d;
  };
  
  
  /**
   * Gets all indexed objects. If the value is provided, gets all indexed objects
   * that match the value instead.
   *
   * @param {!Object=} opt_value Value to look up in the index.
   * @return {!goog.async.Deferred} A deferred array of objects that match the
   *     value.
   */
  goog.db.Index.prototype.getAll = function(opt_value) {
    return this.getAll_(
        'openCursor',
        'getting all from index ' + this.getName(),
        opt_value);
  };
  
  
  /**
   * Gets the keys to look up all the indexed objects. If the value is provided,
   * gets all keys for objects that match the value instead.
   *
   * @param {!Object=} opt_value Value to look up in the index.
   * @return {!goog.async.Deferred} A deferred array of keys for objects that
   *     match the value.
   */
  goog.db.Index.prototype.getAllKeys = function(opt_value) {
    return this.getAll_(
        'openKeyCursor',
        'getting all keys from index ' + this.getName(),
        opt_value);
  };
  