cursor.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // Copyright 2012 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. * @fileoverview Wrapper for a IndexedDB cursor.
  16. *
  17. */
  18. goog.provide('goog.db.Cursor');
  19. goog.require('goog.async.Deferred');
  20. goog.require('goog.db.Error');
  21. goog.require('goog.db.KeyRange');
  22. goog.require('goog.debug');
  23. goog.require('goog.events.EventTarget');
  24. /**
  25. * Creates a new IDBCursor wrapper object. Should not be created directly,
  26. * access cursor through object store.
  27. * @see goog.db.ObjectStore#openCursor
  28. *
  29. * @constructor
  30. * @extends {goog.events.EventTarget}
  31. * @final
  32. */
  33. goog.db.Cursor = function() {
  34. goog.db.Cursor.base(this, 'constructor');
  35. };
  36. goog.inherits(goog.db.Cursor, goog.events.EventTarget);
  37. /**
  38. * Underlying IndexedDB cursor object.
  39. *
  40. * @type {IDBCursor}
  41. * @private
  42. */
  43. goog.db.Cursor.prototype.cursor_ = null;
  44. /**
  45. * Advances the cursor to the next position along its direction. When new data
  46. * is available, the NEW_DATA event will be fired. If the cursor has reached the
  47. * end of the range it will fire the COMPLETE event. If opt_key is specified it
  48. * will advance to the key it matches in its direction.
  49. *
  50. * This wraps the native #continue method on the underlying object.
  51. *
  52. * @param {IDBKeyType=} opt_key The optional key to advance to.
  53. */
  54. goog.db.Cursor.prototype.next = function(opt_key) {
  55. if (opt_key) {
  56. this.cursor_['continue'](opt_key);
  57. } else {
  58. this.cursor_['continue']();
  59. }
  60. };
  61. /**
  62. * Updates the value at the current position of the cursor in the object store.
  63. * If the cursor points to a value that has just been deleted, a new value is
  64. * created.
  65. *
  66. * @param {*} value The value to be stored.
  67. * @return {!goog.async.Deferred} The resulting deferred request.
  68. */
  69. goog.db.Cursor.prototype.update = function(value) {
  70. var msg = 'updating via cursor with value ';
  71. var d = new goog.async.Deferred();
  72. var request;
  73. try {
  74. request = this.cursor_.update(value);
  75. } catch (err) {
  76. msg += goog.debug.deepExpose(value);
  77. d.errback(goog.db.Error.fromException(err, msg));
  78. return d;
  79. }
  80. request.onsuccess = function(ev) { d.callback(); };
  81. request.onerror = function(ev) {
  82. msg += goog.debug.deepExpose(value);
  83. d.errback(goog.db.Error.fromRequest(ev.target, msg));
  84. };
  85. return d;
  86. };
  87. /**
  88. * Deletes the value at the cursor's position, without changing the cursor's
  89. * position. Once the value is deleted, the cursor's value is set to null.
  90. *
  91. * @return {!goog.async.Deferred} The resulting deferred request.
  92. */
  93. goog.db.Cursor.prototype.remove = function() {
  94. var msg = 'deleting via cursor';
  95. var d = new goog.async.Deferred();
  96. var request;
  97. try {
  98. request = this.cursor_['delete']();
  99. } catch (err) {
  100. d.errback(goog.db.Error.fromException(err, msg));
  101. return d;
  102. }
  103. request.onsuccess = function(ev) { d.callback(); };
  104. request.onerror = function(ev) {
  105. d.errback(goog.db.Error.fromRequest(ev.target, msg));
  106. };
  107. return d;
  108. };
  109. /**
  110. * @return {*} The value for the value at the cursor's position. Undefined
  111. * if no current value, or null if value has just been deleted.
  112. */
  113. goog.db.Cursor.prototype.getValue = function() {
  114. return this.cursor_['value'];
  115. };
  116. /**
  117. * @return {IDBKeyType} The key for the value at the cursor's position. If
  118. * the cursor is outside its range, this is undefined.
  119. */
  120. goog.db.Cursor.prototype.getKey = function() {
  121. return this.cursor_.key;
  122. };
  123. /**
  124. * Opens a value cursor from IDBObjectStore or IDBIndex over the specified key
  125. * range. Returns a cursor object which is able to iterate over the given range.
  126. * @param {!(IDBObjectStore|IDBIndex)} source Data source to open cursor.
  127. * @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
  128. * over the whole data source.
  129. * @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
  130. * moves in a forward direction with duplicates.
  131. * @return {!goog.db.Cursor} The cursor.
  132. * @throws {goog.db.Error} If there was a problem opening the cursor.
  133. */
  134. goog.db.Cursor.openCursor = function(source, opt_range, opt_direction) {
  135. var cursor = new goog.db.Cursor();
  136. var request;
  137. try {
  138. var range = opt_range ? opt_range.range() : null;
  139. if (opt_direction) {
  140. request = source.openCursor(range, opt_direction);
  141. } else {
  142. request = source.openCursor(range);
  143. }
  144. } catch (ex) {
  145. cursor.dispose();
  146. throw goog.db.Error.fromException(ex, source.name);
  147. }
  148. request.onsuccess = function(e) {
  149. cursor.cursor_ = e.target.result || null;
  150. if (cursor.cursor_) {
  151. cursor.dispatchEvent(goog.db.Cursor.EventType.NEW_DATA);
  152. } else {
  153. cursor.dispatchEvent(goog.db.Cursor.EventType.COMPLETE);
  154. }
  155. };
  156. request.onerror = function(e) {
  157. cursor.dispatchEvent(goog.db.Cursor.EventType.ERROR);
  158. };
  159. return cursor;
  160. };
  161. /**
  162. * Possible cursor directions.
  163. * @see http://www.w3.org/TR/IndexedDB/#idl-def-IDBCursor
  164. *
  165. * @enum {string}
  166. */
  167. goog.db.Cursor.Direction = {
  168. NEXT: 'next',
  169. NEXT_NO_DUPLICATE: 'nextunique',
  170. PREV: 'prev',
  171. PREV_NO_DUPLICATE: 'prevunique'
  172. };
  173. /**
  174. * Event types that the cursor can dispatch. COMPLETE events are dispatched when
  175. * a cursor is depleted of values, a NEW_DATA event if there is new data
  176. * available, and ERROR if an error occurred.
  177. *
  178. * @enum {string}
  179. */
  180. goog.db.Cursor.EventType = {
  181. COMPLETE: 'c',
  182. ERROR: 'e',
  183. NEW_DATA: 'n'
  184. };