UNPKG

ydn.db

Version:

Javascript database library for IndexedDB, WebDatabase (WebSQL) and WebStorage (localStorage) storage mechanisms supporting version migration, advanced query and transaction workflow.

1,059 lines (933 loc) 28.9 kB
// Copyright 2012 YDN 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 IndexedDB request executor. * * @author kyawtun@yathit.com (Kyaw Tun) */ goog.provide('ydn.db.crud.req.IndexedDb'); goog.require('goog.async.DeferredList'); goog.require('goog.userAgent'); goog.require('ydn.db.crud.req.IRequestExecutor'); goog.require('ydn.db.crud.req.RequestExecutor'); goog.require('ydn.debug.error.InvalidOperationException'); goog.require('ydn.error'); goog.require('ydn.json'); /** * Create a new IDB request executor. * @param {string} dbname database name. * @param {!ydn.db.schema.Database} schema schema. * @constructor * @extends {ydn.db.crud.req.RequestExecutor} * @implements {ydn.db.crud.req.IRequestExecutor} * @struct */ ydn.db.crud.req.IndexedDb = function(dbname, schema) { goog.base(this, dbname, schema); }; goog.inherits(ydn.db.crud.req.IndexedDb, ydn.db.crud.req.RequestExecutor); /** * @protected * @type {goog.debug.Logger} logger. */ ydn.db.crud.req.IndexedDb.prototype.logger = goog.log.getLogger('ydn.db.crud.req.IndexedDb'); /** * * @const {boolean} turn on debug flag to dump debug objects. */ ydn.db.crud.req.IndexedDb.DEBUG = false; // always false here. /** * Large number of requests can cause memory hog without increasing performance. * @const * @type {number} Maximum number of requests created per transaction. */ ydn.db.crud.req.IndexedDb.REQ_PER_TX = 10; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.countStores = function(req, stores) { var me = this; var out = []; var count_store = function(i) { var table = stores[i]; var store = req.getTx().objectStore(table); var request = store.count(); request.onsuccess = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log(event); } out[i] = event.target.result; i++; if (i == stores.length) { req.setDbValue(out); } else { count_store(i); } }; request.onerror = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log(event); } event.preventDefault(); req.setDbValue(request.error, true); }; }; if (stores.length == 0) { req.setDbValue([]); } else { count_store(0); } }; /** * Put objects and return list of key inserted. * @param {ydn.db.Request} rq request. * @param {boolean} is_replace true if `put`, otherwise `add`. * @param {boolean} is_single true if result take only the first result. * @param {string} store_name store name. * @param {!Array.<!Object>} objs object to put. * @param {!Array.<IDBKey>=} opt_keys optional out-of-line keys. */ ydn.db.crud.req.IndexedDb.prototype.insertObjects = function(rq, is_replace, is_single, store_name, objs, opt_keys) { var results = []; var result_count = 0; var has_error = false; var me = this; var mth = is_replace ? 'put' : 'add'; var ob_store = rq.getTx().objectStore(store_name); var msg = rq.getLabel() + ' ' + mth + ' ' + objs.length + ' objects' + ' to store "' + store_name + '"'; goog.log.finest(this.logger, msg); var put = function(i) { if (!goog.isDefAndNotNull(objs[i])) { goog.log.finest(me.logger, 'empty object at ' + i + ' of ' + objs.length); result_count++; if (result_count == objs.length) { rq.setDbValue(results, has_error); } else { var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX; if (next < objs.length) { put(next); } } } var request; var obj = objs[i]; // window.console.log(obj); if (opt_keys && goog.isDefAndNotNull(opt_keys[i])) { if (is_replace) { request = ob_store.put(obj, opt_keys[i]); } else { request = ob_store.add(obj, opt_keys[i]); } } else { if (is_replace) { request = ob_store.put(obj); } else { request = ob_store.add(obj); } } request.onsuccess = function(event) { result_count++; if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, event, i]); } results[i] = event.target.result; if (result_count == objs.length) { rq.setDbValue(is_single ? results[0] : results, has_error); } else { var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX; if (next < objs.length) { put(next); } } }; request.onerror = function(event) { result_count++; if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, event, i]); } var error = request.error; goog.log.finest(me.logger, rq.getLabel() + mth + ' request to "' + store_name + '" cause ' + error.name + ' for object "' + ydn.json.toShortString(objs[i]) + '" at index ' + i + ' of ' + objs.length + ' objects.'); // accessing request.error can cause InvalidStateError, // although it is not possible here since request has already done flag. // http://www.w3.org/TR/IndexedDB/#widl-IDBRequest-error results[i] = error; has_error = true; event.preventDefault(); // not abort the transaction. if (result_count == objs.length) { rq.setDbValue(is_single ? results[0] : results, has_error); } else { var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX; if (next < objs.length) { put(next); } } }; }; if (objs.length > 0) { // send parallel requests for (var i = 0; i < ydn.db.crud.req.IndexedDb.REQ_PER_TX && i < objs.length; i++) { put(i); } } else { rq.setDbValue([]); } }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.putByKeys = function(rq, objs, keys) { var results = []; var result_count = 0; var has_error = false; var out = function() { rq.setDbValue(results, has_error); }; var me = this; var msg = rq.getLabel() + ' putByKeys: of ' + objs.length + ' objects'; goog.log.finest(this.logger, msg); var put = function(i) { /** * @type {!ydn.db.Key} */ var key = keys[i]; var store_name = key.getStoreName(); var store = rq.getTx().objectStore(store_name); var request; if (goog.isNull(store.keyPath)) { request = store.put(objs[i], key.getId()); } else { request = store.put(objs[i]); } request.onsuccess = function(event) { result_count++; //if (ydn.db.crud.req.IndexedDb.DEBUG) { // goog.global.console.log([store_name, event]); //} results[i] = event.target.result; if (result_count == objs.length) { out(); } else { var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX; if (next < objs.length) { put(next); } } }; request.onerror = function(event) { result_count++; if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, event]); } var name = event.name; if (goog.DEBUG) { goog.log.warning(me.logger, 'request result ' + name + ' error when put keys to "' + store_name + '" for object "' + ydn.json.toShortString(objs[i]) + '" at index ' + i + ' of ' + objs.length + ' objects.'); } results[i] = request.error; has_error = true; event.preventDefault(); if (result_count == objs.length) { out(); } else { var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX; if (next < objs.length) { put(next); } } }; }; if (objs.length > 0) { // send parallel requests for (var i = 0; i < ydn.db.crud.req.IndexedDb.REQ_PER_TX && i < objs.length; i++) { put(i); } } else { out(); } }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.putData = function(tx, tx_no, df, store_name, data, delimiter) { var me = this; var store = this.schema.getStore(store_name); var objectStore = tx.objectStore(store_name); var results = []; var prev_pos = data.indexOf('\n'); var fields = data.substr(0, prev_pos).split(delimiter); var types = []; for (var j = 0; j < fields.length; j++) { var index = store.getIndex(fields[j]); if (index) { types[j] = index.getType(); } else if (fields[j] == store.getKeyPath()) { types[j] = store.getType(); } } prev_pos++; var msg = tx_no + ' Loading data ' + ' of ' + fields.length + '-fields record to ' + store_name; goog.log.finest(this.logger, msg); var put = function() { var obj = {}; var next_pos = data.indexOf('\n', prev_pos); var done = false; var text; if (next_pos == -1) { done = true; text = data.substring(prev_pos); } else { text = data.substring(prev_pos, next_pos); prev_pos = next_pos + 1; } var values = text.split(delimiter); for (var j = 0; j < fields.length; j++) { var value = values[j]; if (types[j]) { if (types[j] == ydn.db.schema.DataType.TEXT) { value = goog.string.stripQuotes(value, '"'); } else if (types[j] == ydn.db.schema.DataType.INTEGER) { value = parseInt(value, 10); } else if (types[j] == ydn.db.schema.DataType.NUMERIC) { value = parseFloat(value); } } obj[fields[j]] = value; } //console.log([text, obj]); var request = objectStore.put(obj); request.onsuccess = function(event) { //if (ydn.db.crud.req.IndexedDb.DEBUG) { // goog.global.console.log([store_name, event]); //} results.push(event.target.result); if (done) { df(results); } else { put(); } }; request.onerror = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, event]); } if (goog.DEBUG && event.name == 'DataError') { // give useful info. event = new ydn.db.InvalidKeyException(store + ': ' + text.substring(0, 70)); } event.preventDefault(); df(request.error, true); // abort transaction ? }; }; put(); }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.removeById = function(req, store_name, key) { var me = this; var store = req.getTx().objectStore(store_name); var msg = req.getLabel() + ' clearById: ' + store_name + ' ' + key; goog.log.finest(this.logger, msg); var request = store.openCursor(ydn.db.IDBKeyRange.only(key)); request.onsuccess = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, key, event]); } var cursor = event.target.result; if (cursor) { var r = cursor['delete'](); r.onsuccess = function(e) { req.setDbValue(1); }; r.onerror = function(e) { req.setDbValue(r.error, true); }; } else { req.setDbValue(0); } }; request.onerror = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, key, event]); } event.preventDefault(); req.setDbValue(request.error, true); }; }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.removeByKeys = function(req, keys) { var me = this; var count = 0; var store_name, store, key; var msg = req.getLabel() + ' removeByKeys: ' + keys.length + ' keys'; goog.log.finest(this.logger, msg); var errors = []; var removeAt = function(i) { i++; if (i >= keys.length) { var has_failed = errors.length > 0; if (has_failed) { req.setDbValue(errors, true); } else { req.setDbValue(count); } return; } if (keys[i].getStoreName() != store_name) { store_name = keys[i].getStoreName(); store = req.getTx().objectStore(store_name); } var request = store['delete'](keys[i].getId()); request.onsuccess = function(event) { count++; removeAt(i); }; request.onerror = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, key, event]); } event.preventDefault(); errors[i] = request.error; removeAt(i); }; }; removeAt(-1); }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.removeByKeyRange = function( req, store_name, key_range) { var me = this; var store = req.getTx().objectStore(store_name); var request = store.count(key_range); var msg = req.getLabel() + ' clearByKeyRange: ' + store_name + ' ' + key_range; goog.log.finest(this.logger, msg); request.onsuccess = function(event) { var n = event.target.result; var r = store['delete'](key_range); r.onsuccess = function() { req.setDbValue(n); }; r.onerror = function(e) { req.setDbValue(r.error, true); }; }; request.onerror = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, key_range, event]); } event.preventDefault(); req.setDbValue(request.error, true); }; }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.clearByKeyRange = function( req, store_name, key_range) { var me = this; var store = req.getTx().objectStore(store_name); var msg = req.getLabel() + ' ' + store_name + ' ' + key_range; goog.log.finest(this.logger, msg); var r = store['delete'](key_range); r.onsuccess = function(event) { req.setDbValue(undefined); }; r.onerror = function(event) { event.preventDefault(); req.setDbValue(r.error, true); }; }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.removeByIndexKeyRange = function( req, store_name, index_name, key_range) { var me = this; var store = req.getTx().objectStore(store_name); var index = store.index(index_name); var msg = req.getLabel() + ' clearByIndexKeyRange: ' + store_name + ':' + index_name + ' ' + key_range; goog.log.finest(this.logger, msg); var errors = []; // var request = index.openKeyCursor(key_range); // theoritically key cursor should be able to delete the record, but // according to IndexedDB API spec, it is not. // if this cursor was created using openKeyCursor a DOMException of type // InvalidStateError is thrown. var request = index.openCursor(key_range); var n = 0; request.onsuccess = function(event) { var cursor = event.target.result; if (cursor) { //console.log(cursor); var r = cursor['delete'](); r.onsuccess = function() { n++; cursor['continue'](); }; r.onerror = function(event) { errors.push(r.error); event.preventDefault(); cursor['continue'](); }; } else { var has_failed = errors.length > 0; if (has_failed) { req.setDbValue(errors, true); } else { req.setDbValue(n); } } }; request.onerror = function(event) { event.preventDefault(); req.setDbValue(request.error, true); }; }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.clearByStores = function(req, store_names) { var me = this; var n_todo = store_names.length; var n_done = 0; var msg = req.getLabel() + ' clearByStores: ' + store_names; goog.log.finest(this.logger, msg); for (var i = 0; i < n_todo; i++) { var store_name = store_names[i]; var store = req.getTx().objectStore(store_name); var request = store.clear(); request.onsuccess = function(event) { n_done++; // if (ydn.db.crud.req.IndexedDb.DEBUG) { // goog.global.console.log([n_done, event]); // } if (n_done == n_todo) { req.setDbValue(n_done); } }; request.onerror = function(event) { n_done++; if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([n_done, event]); } event.preventDefault(); if (n_done == n_todo) { req.setDbValue(request.error, true); } }; } }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.getById = function(req, store_name, id) { var me = this; var msg = req.getLabel() + store_name + ':' + id; goog.log.finest(this.logger, msg); var store = req.getTx().objectStore(store_name); var request = store.get(id); request.onsuccess = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, id, event]); } goog.log.finest(me.logger, req.getLabel() + ' record ' + id + (goog.isDefAndNotNull(event.target.result) ? ' ' : ' not ') + ' exists.'); // check for decode blob, since chrome does not support blob var BASE64_MARKER = ';base64,'; var s = event.target.result; if (!store.keyPath && store.indexNames.length == 0 && goog.userAgent.WEBKIT && goog.isString(s) && s.indexOf(BASE64_MARKER) >= 0) { if (s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') { s = s.substr(1, s.length - 2); } var parts = s.split(BASE64_MARKER); var contentType = parts[0].split(':')[1]; var raw = window.atob(parts[1]); var rawLength = raw.length; var uInt8Array = new Uint8Array(rawLength); for (var i = 0; i < rawLength; ++i) { uInt8Array[i] = raw.charCodeAt(i); } var blob = new Blob([uInt8Array.buffer], {type: contentType}); req.setDbValue(blob); } else { req.setDbValue(event.target.result); } }; request.onerror = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, id, event]); } //goog.log.warning(me.logger, 'Error retrieving ' + id + ' in ' + store_name + ' ' + // event.message); event.preventDefault(); req.setDbValue(request.error, true); }; }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.listByIds = function(req, store_name, ids) { var me = this; var results = []; results.length = ids.length; var result_count = 0; var store = req.getTx().objectStore(store_name); var n = ids.length; var msg = req.getLabel() + ' ' + store_name + ':' + n + ' ids'; goog.log.finest(this.logger, msg); var get = function(i) { if (!goog.isDefAndNotNull(ids[i])) { // should we just throw error ? result_count++; results[i] = undefined; if (result_count == n) { req.setDbValue(results); } else { var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX; if (next < n) { get(next); } } } var request; // try { // console.log(tx_no + ': ' + store_name + ' ' + i + ' ' + ids[i]) request = store.get(ids[i]); // } catch (e) { // if (ydn.db.crud.req.IndexedDb.DEBUG) { // goog.global.console.log([store_name, i, ids[i], e]); // if (e.name == 'DataError') { // // http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-get- // // IDBRequest-any-key // throw new ydn.db.InvalidKeyException(ids[i]); // } else { // throw e; // } // } // } request.onsuccess = (function(event) { result_count++; if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, ids, i, event]); } results[i] = event.target.result; if (result_count == n) { req.setDbValue(results); } else { var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX; if (next < n) { get(next); } } }); request.onerror = function(event) { result_count++; if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, ids, i, event]); } event.preventDefault(); req.setDbValue(request.error, true); }; }; if (n > 0) { // send parallel requests for (var i = 0; i < ydn.db.crud.req.IndexedDb.REQ_PER_TX && i < n; i++) { get(i); } } else { req.setDbValue([]); } }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.listByKeys = function(req, keys) { var me = this; var results = []; results.length = keys.length; var result_count = 0; var msg = req.getLabel() + ' ' + keys.length + ' ids'; goog.log.finest(this.logger, msg); var getKey = function(i) { /** * @type {!ydn.db.Key} */ var key = keys[i]; /** * @type {IDBObjectStore} */ var store = req.getTx().objectStore(key.getStoreName()); var request = store.get(key.getId()); request.onsuccess = function(event) { result_count++; if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log(event); } results[i] = event.target.result; if (result_count == keys.length) { req.setDbValue(results); } else { var next = i + ydn.db.crud.req.IndexedDb.REQ_PER_TX; if (next < keys.length) { getKey(next); } } }; request.onerror = function(event) { result_count++; if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([keys, event]); } event.preventDefault(); req.setDbValue(request.error, true); }; }; if (keys.length > 0) { // send parallel requests for (var i = 0; i < ydn.db.crud.req.IndexedDb.REQ_PER_TX && i < keys.length; i++) { getKey(i); } } else { req.setDbValue([]); } }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.countKeyRange = function(req, table, keyRange, index_name, unique) { if (goog.DEBUG && !!index_name && !!unique) { throw new ydn.debug.error.InvalidOperationException( 'unique count not available in IndexedDB'); } var me = this; var store = req.getTx().objectStore(table); var msg = req.getLabel() + ' ' + table + (index_name ? ':' + index_name : '') + (keyRange ? ':' + ydn.json.stringify(keyRange) : ''); goog.log.finest(this.logger, msg); var request; if (goog.isDefAndNotNull(index_name)) { var index = store.index(index_name); if (goog.isDefAndNotNull(keyRange)) { request = index.count(keyRange); } else { request = index.count(); } } else { if (goog.isDefAndNotNull(keyRange)) { request = store.count(keyRange); } else { request = store.count(); } } request.onsuccess = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log(event); } req.setDbValue(event.target.result); }; request.onerror = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log(event); } event.preventDefault(); req.setDbValue(request.error, true); }; }; /** * @inheritDoc */ ydn.db.crud.req.IndexedDb.prototype.list = function(req, type, store_name, index, key_range, limit, offset, reverse, unique, opt_position) { var results = []; var store = req.getTx().objectStore(store_name); var dir = ydn.db.base.getDirection(reverse, unique); var msg = req.getLabel() + ' ' + type + ' ' + store_name + (index ? ':' + index : '') + (key_range ? ydn.json.stringify(key_range) : ''); if (reverse) { msg += ' reverse'; } if (unique) { msg += ' unique'; } if (!!opt_position && goog.isDef(opt_position[0])) { // start position is given, cursor must open after this position. var open = index ? !(goog.isDef(opt_position[1])) : true; var s_key = /** @type {IDBKey} */ (opt_position[0]); var lower = /** @type {IDBKey|undefined} */ (key_range ? key_range.lower : undefined); var upper = /** @type {IDBKey|undefined} */ (key_range ? key_range.upper : undefined); var lowerOpen = key_range ? !!key_range.lowerOpen : false; var upperOpen = key_range ? !!key_range.upperOpen : false; var kr = reverse ? new ydn.db.KeyRange(lower, s_key, lowerOpen, open) : new ydn.db.KeyRange(s_key, upper, open, upperOpen); key_range = kr.toIDBKeyRange(); msg += ' starting from ' + ydn.json.stringify(/** @type {Object} */ (opt_position[0])); if (goog.isDef(opt_position[1])) { msg += ', ' + ydn.json.stringify(/** @type {Object} */ (opt_position[1])); } } goog.log.finest(this.logger, msg); var request; if (type == ydn.db.base.QueryMethod.LIST_KEY || type == ydn.db.base.QueryMethod.LIST_PRIMARY_KEY || type == ydn.db.base.QueryMethod.LIST_KEYS) { // key query if (index) { request = store.index(index).openKeyCursor(key_range, dir); } else { // NOTE: key cursor for object is not available as of IndexedDB API v1. request = store.openCursor(key_range, dir); } } else { // value query if (index) { request = store.index(index).openCursor(key_range, dir); } else { request = store.openCursor(key_range, dir); } } var cued = false; request.onsuccess = function(event) { /** * * @type {IDBCursorWithValue} */ var cursor = event.target.result; if (cursor) { if (!cued) { if (offset > 0) { // if offset is defined, position will be ignored. cued = true; cursor.advance(offset); return; } else if (!!opt_position && !!index && goog.isDef(opt_position[0])) { if (goog.isDef(opt_position[1])) { var cmp = ydn.db.base.indexedDb.cmp(cursor.key, opt_position[0]); var dir = reverse ? -1 : 1; if (cmp == 0) { var cmp2 = ydn.db.base.indexedDb.cmp( cursor.primaryKey, opt_position[1]); // console.log('continue ' + cmp2 + ' ' + // cursor.key + ', ' + cursor.primaryKey); if (cmp2 == 0) { cued = true; // console.log('cued by primary key'); cursor['continue'](); // skip current key return; } else if (cmp2 == dir) { // console.log('cued by primary key passed over'); cued = true; } else { // console.log('continue cueing'); cursor['continue'](); return; } } else { // console.log('cued by key ' + cursor.key + ' passed over'); cued = true; } } else { // console.log('cued by key passed over without primary key'); cued = true; } } else { cued = true; } } // push to result list if (type == ydn.db.base.QueryMethod.LIST_KEY) { results.push(cursor.key); } else if (type == ydn.db.base.QueryMethod.LIST_PRIMARY_KEY) { results.push(cursor.primaryKey); } else if (type == ydn.db.base.QueryMethod.LIST_KEYS) { var obj = {}; if (index) { obj[index] = cursor.key; } if (store.keyPath) { obj[store.keyPath] = cursor.primaryKey; } else { obj[ydn.db.base.SQLITE_SPECIAL_COLUNM_NAME] = cursor.primaryKey; } results.push(obj); } else if (type == ydn.db.base.QueryMethod.LIST_VALUE) { results.push(cursor.value); } else { results.push([cursor.key, cursor.primaryKey, cursor.value]); } // continue if (results.length < limit) { cursor['continue'](); } else { if (opt_position) { opt_position[0] = ydn.db.Key.clone(cursor.key); opt_position[1] = ydn.db.Key.clone(/** @type {IDBKey} */ (cursor.primaryKey)); } // console.log(req + ' by limit', results); req.setDbValue(results); } } else { if (opt_position) { opt_position[0] = undefined; opt_position[1] = undefined; } // console.log(req + ' by cursor', results); req.setDbValue(results); } }; request.onerror = function(event) { if (ydn.db.crud.req.IndexedDb.DEBUG) { goog.global.console.log([store_name, event]); } event.preventDefault(); req.setDbValue(request.error, true); }; };