Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Implemented indexing.

  • Loading branch information...
commit d9ef7f8eeba2087ae3ecb2abdd831f51aa99c3b9 1 parent 09a10c4
@khamza khamza authored
View
176 IDBCursor.js
@@ -5,13 +5,12 @@ if (window.indexedDB.polyfill)
{
this.source = source;
this.direction = direction || IDBCursor.NEXT;
- this.key = null;
- this.primaryKey = null; // position, effective key
+ this.key = null; // position
+ this.primaryKey = null; // effective key, object store position
this._request = request;
this._range = null;
this._gotValue = true;
- this._objectStorePosition = null; // used for indexes
};
IDBCursor.prototype.update = function (value)
@@ -26,40 +25,51 @@ if (window.indexedDB.polyfill)
IDBCursor.prototype.continue = function (key)
{
- if (!this._gotValue) throw util.exception("InvalidStateError");
+ if (!this._gotValue) throw util.error("InvalidStateError");
+ this._gotValue = false;
var range = this._range;
var filter = util.IDBKeyRange.bound(range.lower, range.upper, range.lowerOpen, range.upperOpen);
- if (key)
+ var isIndex = this.source instanceof util.IDBIndex;
+ var position = this.key;
+ var noDuplicate = [IDBCursor.PREV_NO_DUPLICATE, IDBCursor.NEXT_NO_DUPLICATE].indexOf(this.direction) >= 0;
+ if (key != null)
{
- if (isAsc(this))
+ if (isDesc(this))
{
- if (key <= this.primaryKey) throw util.exception("DataError");
- filter.lower = key;
- filter.lowerOpen = false;
+ if ((isIndex && key > position) || key >= position) throw util.error("DataError");
+ filter.upper = key;
+ filter.upperOpen = false;
}
else
{
- if (key >= this.primaryKey) throw util.exception("DataError");
- filter.upper = key;
- filter.upperOpen = false;
+ if ((isIndex && key < position) || key <= position) throw util.error("DataError");
+ filter.lower = key;
+ filter.lowerOpen = false;
}
}
- else if (this.primaryKey)
+ else if (position != null)
{
- if (isAsc(this))
+ var open = !isIndex || noDuplicate;
+ if (isDesc(this))
{
- filter.lower = this.primaryKey;
- filter.lowerOpen = true;
+ filter.upper = position;
+ filter.upperOpen = open;
}
else
{
- filter.upper = this.primaryKey;
- filter.upperOpen = true;
+ filter.lower = position;
+ filter.lowerOpen = open;
}
}
- iterateCursor(this, filter);
- this._gotValue = false;
+ if (isIndex)
+ {
+ iterateIndexCursor(this, filter);
+ }
+ else
+ {
+ iterateCursor(this, filter);
+ }
};
IDBCursor.prototype.delete = function ()
@@ -67,7 +77,6 @@ if (window.indexedDB.polyfill)
};
-
// Internal methods
function iterateCursor(me, filter)
{
@@ -75,22 +84,24 @@ if (window.indexedDB.polyfill)
me._request.readyState = util.IDBRequest.LOADING;
tx._enqueueRequest(function (sqlTx, nextRequestCallback)
{
- var sql = ["SELECT key, value FROM \"" + me.source.name + "\" WHERE (0 = 0)"];
+ var sql = ["SELECT key, value FROM [" + me.source.name + "]"];
+ var where = [];
var args = [];
if (filter.lower)
{
- sql.push("AND (key >" + (filter.lowerOpen ? "" : "="), "?)");
+ where.push("(key >" + (filter.lowerOpen ? "" : "=") + " ?)");
args.push(w_JSON.stringify(filter.lower));
}
if (filter.upper)
{
- sql.push("AND (key <" + (filter.upperOpen ? "" : "="), "?)");
+ where.push("(key <" + (filter.upperOpen ? "" : "=") + " ?)");
args.push(w_JSON.stringify(filter.upper));
}
-
- sql.push("ORDER BY key");
- if (!isAsc(me)) sql.push("DESC");
- sql.push("LIMIT 1");
+ if (where.length > 0)
+ {
+ sql.push("WHERE", where.join(" AND "))
+ }
+ sql.push("ORDER BY key" + (isDesc(me) ? " DESC" : ""), "LIMIT 1");
sqlTx.executeSql(sql.join(" "), args,
function (tx, results)
@@ -105,7 +116,7 @@ if (window.indexedDB.polyfill)
}
else
{
- var found = found = results.rows.item(0);
+ var found = results.rows.item(0);
me.key = me.primaryKey = w_JSON.parse(found.key);
if (typeof me.value !== "undefined") me.value = w_JSON.parse(found.value);
me._gotValue = true;
@@ -116,7 +127,108 @@ if (window.indexedDB.polyfill)
},
function (tx, sqlError)
{
- var request = m._request;
+ var request = me._request;
+ request.error = sqlError;
+ if (request.onerror) request.onerror(util.event("error", request));
+ nextRequestCallback();
+ });
+ });
+ }
+
+ function iterateIndexCursor(me, filter)
+ {
+ var tx = me.source.objectStore.transaction;
+ me._request.readyState = util.IDBRequest.LOADING;
+ tx._enqueueRequest(function (sqlTx, nextRequestCallback)
+ {
+ var withValue = me instanceof IDBCursorWithValue;
+ var desc = isDesc(me);
+ var objectStoreName = me.source.objectStore.name;
+ var tableName = util.indexTable(objectStoreName, me.source.name);
+ var sql = ["SELECT i.key, i.primaryKey" + (withValue ? ", t.value" : ""),
+ "FROM [" + tableName + "] as i"];
+
+ if (withValue)
+ {
+ sql.push("LEFT JOIN [" + objectStoreName + "] as t ON t.Id = i.recordId");
+ }
+ var where = [], args = [], strPrimaryKey = null;
+ if (filter.lower)
+ {
+ var strLower = w_JSON.stringify(filter.lower);
+ args.push(strLower);
+ if (filter.lowerOpen)
+ {
+ where.push("(i.key > ?)");
+ }
+ else
+ {
+ if (me.primaryKey == null || desc)
+ {
+ where.push("(i.key >= ?)");
+ }
+ else
+ {
+ where.push("((i.key > ?) OR (i.key = ? AND i.primaryKey > ?))");
+ strPrimaryKey = w_JSON.stringify(me.primaryKey);
+ args.push(strLower, strPrimaryKey);
+ }
+ }
+ }
+ if (filter.upper)
+ {
+ var strUpper = w_JSON.stringify(filter.upper);
+ args.push(strUpper);
+ if (filter.upperOpen)
+ {
+ where.push("(i.key < ?)");
+ }
+ else
+ {
+ if (me.primaryKey == null || !desc)
+ {
+ where.push("(i.key <= ?)");
+ }
+ else
+ {
+ where.push("((i.key < ?) OR (i.key = ? AND i.primaryKey < ?))");
+ args.push(strUpper, strPrimaryKey || w_JSON.stringify(me.primaryKey));
+ }
+ }
+ }
+ if (where.length > 0)
+ {
+ sql.push("WHERE", where.join(" AND "))
+ }
+ var sDesc = desc ? " DESC" : "";
+ sql.push("ORDER BY i.key" + sDesc + ", i.primaryKey" + sDesc + " LIMIT 1");
+
+ sqlTx.executeSql(sql.join(" "), args,
+ function (tx, results)
+ {
+ var request = me._request;
+ request.readyState = util.IDBRequest.DONE;
+ if (results.rows.length == 0)
+ {
+ me.key = me.primaryKey = undefined;
+ if (typeof me.value !== "undefined") me.value = undefined;
+ request.result = null;
+ }
+ else
+ {
+ var found = results.rows.item(0);
+ me.key = w_JSON.parse(found.key);
+ me.primaryKey = w_JSON.parse(found.primaryKey);
+ if (typeof me.value !== "undefined") me.value = w_JSON.parse(found.value);
+ me._gotValue = true;
+ request.result = me;
+ }
+ if (request.onsuccess) request.onsuccess(util.event("success", request));
+ nextRequestCallback();
+ },
+ function (tx, sqlError)
+ {
+ var request = me._request;
request.error = sqlError;
if (request.onerror) request.onerror(util.event("error", request));
nextRequestCallback();
@@ -127,9 +239,9 @@ if (window.indexedDB.polyfill)
// Utils
var w_JSON = window.JSON;
- function isAsc(cursor)
+ function isDesc(cursor)
{
- return [IDBCursor.NEXT, IDBCursor.NEXT_NO_DUPLICATE].indexOf(cursor.direction) >= 0;
+ return [IDBCursor.PREV, IDBCursor.PREV_NO_DUPLICATE].indexOf(cursor.direction) >= 0;
}
View
110 IDBDatabase.js
@@ -24,34 +24,40 @@ if (window.indexedDB.polyfill)
throw util.error("ConstraintError");
}
- var op = optionalParameters || { };
- var keyPath = op.keyPath || null;
- var autoIncrement = op.autoIncrement && op.autoIncrement != false || false;
- if (autoIncrement && (keyPath == "" || (keyPath instanceof Array)))
+ var params = optionalParameters || { };
+ var keyPath = util.validateKeyPath(params.keyPath);
+ var autoIncrement = params.autoIncrement && params.autoIncrement != false || false;
+
+ if (autoIncrement && (keyPath === "" || (keyPath instanceof Array)))
{
throw util.error("InvalidAccessError");
}
- if (keyPath != null) keyPath = validateKeyPath(keyPath);
-
return createObjectStore(this, name, keyPath, autoIncrement);
};
IDBDatabase.prototype.deleteObjectStore = function (name)
{
- validateVersionChangeTx(this._versionChangeTx);
+ var tx = this._versionChangeTx;
+ validateVersionChangeTx(tx);
if (this.objectStoreNames.indexOf(name) == -1)
{
throw util.error("NotFoundError");
}
- var i = this.objectStoreNames.indexOf(name);
- if (i > -1) this.objectStoreNames.splice(i, 1);
+ util.arrayRemove(this.objectStoreNames, name);
+ var objectStore = this._objectStores[name];
+ delete this._objectStores[name];
var me = this;
- this._versionChangeTx._enqueueRequest(function (sqlTx, nextRequestCallback)
+ var errorCallback = function (tx, sqlError)
{
- sqlTx.executeSql("DROP TABLE \"" + name + "\"", [], null,
- function (tx, sqlError) { me.objectStoreNames.push(name); }
- );
- sqlTx.executeSql("DELETE FROM " + indexedDB.SCHEMA_TABLE + " WHERE type = 'table' AND name = ?", [name]);
+ me.objectStoreNames.push(name);
+ me._objectStores[name] = objectStore;
+ };
+ tx._enqueueRequest(function (sqlTx, nextRequestCallback)
+ {
+ sqlTx.executeSql("DROP TABLE \"" + name + "\"", null, null, errorCallback);
+ sqlTx.executeSql("DELETE FROM " + indexedDB.SCHEMA_TABLE + " WHERE type = 'table' AND name = ?",
+ [name], null, errorCallback);
+
nextRequestCallback();
});
};
@@ -69,19 +75,33 @@ if (window.indexedDB.polyfill)
IDBDatabase.prototype._loadObjectStores = function (sqlTx, successCallback, errorCallback)
{
var me = this;
- sqlTx.executeSql("SELECT name, keyPath, autoInc FROM " + indexedDB.SCHEMA_TABLE +
- " WHERE type='table'", null,
+ sqlTx.executeSql("SELECT * FROM " + indexedDB.SCHEMA_TABLE +
+ " ORDER BY type DESC", null,
function (sqlTx, resultSet)
{
me._objectStores = { };
- var item = null;
+ var item, objectStore;
for (var i = 0; i < resultSet.rows.length; i++)
{
var item = resultSet.rows.item(i);
-
- me.objectStoreNames.push(item.name);
- me._objectStores[item.name] = new util.IDBObjectStore(
- item.name, w_JSON.parse(item.keyPath), item.autoInc);
+ if (item.type == "table")
+ {
+ me.objectStoreNames.push(item.name);
+ objectStore = new util.IDBObjectStore(item.name, w_JSON.parse(item.keyPath), item.autoInc);
+ objectStore._metaId = item.id;
+ me._objectStores[item.name] = objectStore;
+ }
+ else if (item.type == "index")
+ {
+ for (var name in me._objectStores)
+ {
+ objectStore = me._objectStores[name];
+ if (objectStore._metaId == item.tableId) break;
+ }
+ objectStore.indexNames.push(item.name);
+ objectStore._indexes[item.name] = new util.IDBIndex(objectStore,
+ item.name, item.keyPath, item.unique, item.multiEntry)
+ }
}
if (successCallback) successCallback();
},
@@ -89,7 +109,7 @@ if (window.indexedDB.polyfill)
{
if (errorCallback) errorCallback(sqlError);
});
- }
+ };
// Utils
var w_JSON = window.JSON;
@@ -102,48 +122,32 @@ if (window.indexedDB.polyfill)
}
}
- function validateKeyPath(keyPath)
- {
- if (keyPath === "") return "";
-
- var r = /^([^\d\W]\w*\.)+$/i;
- if (keyPath instanceof Array)
- {
- var i = keyPath.length;
- if (i == 0) throw util.error("SyntaxError");
-
- while (i--)
- {
- if (!r.test(keyPath[i] + ".")) throw util.error("SyntaxError");
- }
- return keyPath;
- }
- if (!r.test(keyPath + ".")) throw util.error("SyntaxError");
- return keyPath;
- }
-
function createObjectStore(me, name, keyPath, autoIncrement)
{
var objectStore = new util.IDBObjectStore(name, keyPath, autoIncrement, me._versionChangeTx);
- me._objectStores[name] = objectStore;
me.objectStoreNames.push(name);
+ me._objectStores[name] = objectStore;
+ var errorCallback = function (tx, sqlError)
+ {
+ util.arrayRemove(me.objectStoreNames, name);
+ delete me._objectStores[name];
+ };
me._versionChangeTx._enqueueRequest(function (sqlTx, nextRequestCallback)
{
sqlTx.executeSql("CREATE TABLE \"" + name + "\" (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
- "key TEXT, value BLOB)", [], null,
- function (tx, sqlError)
- {
- var i = me.objectStoreNames.indexOf(name);
- if (i > -1) me.objectStoreNames.splice(i, 1);
+ "key TEXT, value BLOB)", [], null, errorCallback);
- delete me._objectStores[name];
- }
- );
- sqlTx.executeSql("CREATE INDEX Index_" + name + "_key ON \"" + name + "\" (key)");
+ sqlTx.executeSql("CREATE INDEX INDEX_" + name + "_key ON \"" + name + "\" (key)", [], null, errorCallback);
sqlTx.executeSql("INSERT INTO " + indexedDB.SCHEMA_TABLE +
" (type, name, keyPath, autoInc) VALUES ('table', ?, ?, ?)",
- [name, w_JSON.stringify(keyPath), autoIncrement ? 1 : 0]);
+ [name, w_JSON.stringify(keyPath), autoIncrement ? 1 : 0],
+ function (sqlTx, results)
+ {
+ objectStore._metaId = results.insertId;
+ },
+ errorCallback);
+
nextRequestCallback();
});
return objectStore;
View
54 IDBFactory.js
@@ -6,7 +6,8 @@ if (window.indexedDB.polyfill)
if (version !== undefined)
{
version = parseInt(version);
- if (isNaN(version) || version <= 0) throw util.exception("Invalid version");
+ if (isNaN(version) || version <= 0) throw util.error("TypeError",
+ "The method parameter is missing or invalid.");
}
var request = new util.IDBOpenDBRequest();
request.source = null;
@@ -52,26 +53,36 @@ if (window.indexedDB.polyfill)
function openLowerVersion(request, db, sqldbVersion)
{
var tx = new util.IDBTransaction(db, [], util.IDBTransaction.VERSION_CHANGE);
- tx._enqueueRequest(function (sqlTx, nextRequestCallback)
+ if (sqldbVersion == 0)
{
- request.transaction = db._versionChangeTx = tx;
- if (sqldbVersion == 0)
+ tx._enqueueRequest(function (sqlTx, nextRequestCallback)
{
sqlTx.executeSql("CREATE TABLE '" + indexedDB.SCHEMA_TABLE + "' (" +
- "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
- "type TEXT NOT NULL, " +
- "name TEXT NOT NULL, " +
- "keyPath TEXT, " +
- "autoInc BOOLEAN, " +
- "currentNo INTEGER NOT NULL DEFAULT 1, " +
- "UNIQUE (type, name) ON CONFLICT ROLLBACK)");
- }
+ "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ "type TEXT NOT NULL, " +
+ "name TEXT NOT NULL, " +
+ "keyPath TEXT, " +
+ "currentNo INTEGER NOT NULL DEFAULT 1, " +
+ // specific to tables
+ "autoInc BOOLEAN, " +
+ // specific to indexes
+ "tableId INTEGER, " +
+ "\"unique\" BOOLEAN, " +
+ "multiEntry BOOLEAN, " +
+ "UNIQUE (type, name) ON CONFLICT ROLLBACK)");
+
+ nextRequestCallback();
+ });
+ }
+ tx._enqueueRequest(function (sqlTx, nextRequestCallback)
+ {
db._loadObjectStores(sqlTx,
function ()
{
request.result = db;
if (request.onupgradeneeded)
{
+ request.transaction = db._versionChangeTx = tx;
var e = util.event("onupgradeneeded", request);
e.oldVersion = sqldbVersion;
e.newVersion = db.version;
@@ -139,15 +150,20 @@ if (window.indexedDB.polyfill)
sqldb.changeVersion(sqldb.version, "",
function (tx)
{
- tx.executeSql("SELECT name FROM '" + indexedDB.SCHEMA_TABLE +"'", null,
+
+ tx.executeSql("SELECT a.type, a.name, b.name 'table' FROM " + indexedDB.SCHEMA_TABLE +
+ " a LEFT JOIN " + indexedDB.SCHEMA_TABLE + " b ON a.type = 'index' AND a.tableId = b.Id",
+ null,
function (tx, results)
{
- var i;
- for (i = 0; i < results.rows.length; i++)
+ var name;
+ for (var i = 0; i < results.rows.length; i++)
{
- tx.executeSql("DROP TABLE \"" + results.rows.item(i).name + "\"");
+ var item = results.rows.item(i);
+ name = item.type == 'table' ? item.name : util.indexTable(item.table, item.name);
+ tx.executeSql("DROP TABLE [" + name + "]");
}
- tx.executeSql("DROP TABLE '" + indexedDB.SCHEMA_TABLE + "'");
+ tx.executeSql("DROP TABLE " + indexedDB.SCHEMA_TABLE);
});
},
function (e)
@@ -158,7 +174,7 @@ if (window.indexedDB.polyfill)
{
if (request.onsuccess) request.onsuccess(null);
});
- };
+ }
});
return request;
};
@@ -168,7 +184,7 @@ if (window.indexedDB.polyfill)
{
// TODO: Compare according to doc
return first > second ? 1 : (first == second ? 0 : -1);
- }
+ };
// Utils
function openSqlDB(name)
View
34 IDBIndex.js
@@ -1,34 +1,48 @@
if (window.indexedDB.polyfill)
(function(window, indexedDB, util, undefined)
{
- var IDBIndex = util.IDBIndex = window.IDBIndex = function(source)
+ var IDBIndex = util.IDBIndex = window.IDBIndex = function (objectStore, name, keyPath, unique, multiEntry)
{
- this.name = null;
- this.objectStore = null;
- this.keyPath = null;
- this.multiEntry = null;
- this.unique = null;
+ this.objectStore = objectStore;
+ this.name = name;
+ this.keyPath = keyPath;
+ this.unique = unique;
+ this.multiEntry = multiEntry;
+
+ this._ready = true;
};
IDBIndex.prototype.openCursor = function (range, direction)
{
+ var request = new util.IDBRequest(this);
+ request.readyState = util.IDBRequest.LOADING;
+ var cursor = new util.IDBCursorWithValue(this, direction, request);
- }
+ cursor._range = util.IDBKeyRange.ensureKeyRange(range);
+ cursor.continue();
+ return request;
+ };
IDBIndex.prototype.openKeyCursor = function (range, direction)
{
+ var request = new util.IDBRequest(this);
+ request.readyState = util.IDBRequest.LOADING;
+ var cursor = new util.IDBCursor(this, direction, request);
- }
+ cursor._range = util.IDBKeyRange.ensureKeyRange(range);
+ cursor.continue();
+ return request;
+ };
IDBIndex.prototype.get = function (key)
{
- }
+ };
IDBIndex.prototype.getKey = function (key)
{
- }
+ };
IDBIndex.prototype.count = function (key)
{
View
13 IDBKeyRange.js
@@ -29,4 +29,17 @@ if (window.indexedDB.polyfill)
return new IDBKeyRange(lower, upper, lowerOpen || false, upperOpen || false);
};
+ IDBKeyRange.ensureKeyRange = function (arg)
+ {
+ if (arg == null)
+ {
+ return util.IDBKeyRange.bound();
+ }
+ if ((arg instanceof util.IDBKeyRange))
+ {
+ return arg;
+ }
+ return util.IDBKeyRange.only(arg);
+ }
+
}(window, window.indexedDB.util));
View
349 IDBObjectStore.js
@@ -8,6 +8,9 @@ if (window.indexedDB.polyfill)
this.indexNames = new indexedDB.DOMStringList();
this.transaction = tx;
this.autoIncrement = autoIncrement == true;
+
+ this._metaId = null;
+ this._indexes = { };
};
IDBObjectStore.prototype.put = function (value, key)
@@ -24,53 +27,64 @@ if (window.indexedDB.polyfill)
function storeRecord(me, value, key, noOverwrite)
{
assertReadOnly(me.transaction);
-
- var validation = validateKey(me, value, key);
+ var validation = validateObjectStoreKey(me.keyPath, me.autoIncrement, value, key);
var key = validation.key, strKey = validation.str;
- var request = new util.IDBRequest();
- request.readyState = util.IDBRequest.LOADING;
- request.source = me;
+ var request = new util.IDBRequest(me);
me.transaction._enqueueRequest(function (sqlTx, nextRequestCallback)
{
- runStepsForStoringRecord(request, sqlTx, nextRequestCallback, noOverwrite, value, key, strKey);
+ var context = {
+ request : request,
+ sqlTx : sqlTx,
+ nextRequestCallback : nextRequestCallback,
+ noOverwrite : noOverwrite,
+ value : value
+ };
+ runStepsForStoringRecord(context, key, strKey);
});
return request;
}
- function validateKey(me, value, key)
+ function validateObjectStoreKey(keyPath, autoIncrement, value, key)
{
var key = key, str;
- if (me.keyPath != null)
+ if (keyPath != null)
{
if (key != null) throw util.error("DataError");
- key = extractKeyFromValue(value, me.keyPath);
+ key = extractKeyFromValue(value, keyPath);
}
if (key == null)
{
- if (!me.autoIncrement) throw util.error("DataError");
+ if (!autoIncrement) throw util.error("DataError");
}
else
{
- // NOTE: key validation
str = w_JSON.stringify(key);
- if (typeof key == "boolean") throw util.error("DataError");
-
- if ((/[,[]{.*?}[,\]]/).test(str) ||
- (/^{.*?}$/).test(str) ||
- (/[,[](true|false)[,\]]/).test(str)) throw util.error("DataError");
+ if (notValidKey(str)) throw util.error("DataError");
}
return { key : key, str : str };
}
+ function notValidKey(strKey)
+ {
+ // TODO: key validation according to spec
+ if (strKey === "true" || strKey === "false") return true;
+
+ if ((/[,[]{.*?}[,\]]/).test(strKey) ||
+ (/^{.*?}$/).test(strKey) ||
+ (/[,[](true|false)[,\]]/).test(strKey)) return true;
+
+ return false;
+ }
+
function extractKeyFromValue(value, keyPath)
{
- var key;
+ var key, i;
if (keyPath instanceof Array)
{
key = [];
- for (var i = 0; i < keyPath.length; i++)
+ for (i = 0; i < keyPath.length; i++)
{
key.push(extractKeyFromValue(value, keyPath[i]));
}
@@ -81,7 +95,7 @@ if (window.indexedDB.polyfill)
key = value;
var paths = keyPath.split(".");
- for (var i = 0; i < paths.length; i++)
+ for (i = 0; i < paths.length; i++)
{
if (key == null) return null;
key = key[paths[i]];
@@ -90,45 +104,48 @@ if (window.indexedDB.polyfill)
return key;
}
-
- function runStepsForStoringRecord(request, sqlTx, nextRequestCallback, noOverwrite, value, key, strKey)
+ function runStepsForStoringRecord(context, key, strKey)
{
+ var request = context.request;
var me = request.source;
request.readyState = util.IDBRequest.DONE;
if (me.autoIncrement && (key == null || isPositiveFloat(key)))
{
- sqlTx.executeSql("SELECT currentNo FROM " + indexedDB.SCHEMA_TABLE +
+ context.sqlTx.executeSql("SELECT currentNo FROM " + indexedDB.SCHEMA_TABLE +
" WHERE type='table' AND name = ?", [me.name],
- function (sqlTx, resultSet)
+ function (sqlTx, results)
{
- if (resultSet.rows.length != 1)
+ if (results.rows.length != 1)
{
// error
}
- var currentNo = resultSet.rows.item(0).currentNo;
+ var currentNo = results.rows.item(0).currentNo;
if (key == null)
{
key = currentNo;
strKey = key.toString();
if (me.keyPath != null)
{
- assignKeyToValue(value, me.keyPath, key);
+ assignKeyToValue(context.value, me.keyPath, key);
}
}
if (key >= currentNo)
{
incrementCurrentNumber(sqlTx, me.name, Math.floor(key + 1));
}
- sqlInsertKeyValue(request, sqlTx, nextRequestCallback, noOverwrite, strKey, value);
+ context.sqlTx = sqlTx;
+ sqlInsertKeyValue(context, strKey);
},
- function (tx, sqlError)
+ function (_, sqlError)
{
- // error
+ request.error = sqlError;
+ if (request.onerror) request.onerror(util.event("error", request));
+ context.nextRequestCallback();
});
}
else
{
- sqlInsertKeyValue(request, sqlTx, nextRequestCallback, noOverwrite, strKey, value);
+ sqlInsertKeyValue(context, strKey);
}
}
@@ -143,31 +160,12 @@ if (window.indexedDB.polyfill)
// TODO: error
}
},
- function (tx, sqlError)
+ function (sqlTx, sqlError)
{
// TODO: error
});
}
- function sqlInsertKeyValue(request, sqlTx, nextRequestCallback, noOverwrite, strKey, value)
- {
- var tableName = request.source.name;
- var sql = (noOverwrite ? "INSERT" : "REPLACE") + " INTO \"" + tableName + "\" (key, value) VALUES (?, ?)";
- var strValue = w_JSON.stringify(value);
- sqlTx.executeSql(sql, [strKey, strValue],
- function (tx, resultSet)
- {
- if (request.onsuccess) request.onsuccess(util.event("success", request));
- nextRequestCallback();
- },
- function (tx, sqlError)
- {
- request.error = sqlError;
- if (request.onerror) request.onerror(util.event("error", request));
- nextRequestCallback();
- });
- }
-
function assignKeyToValue(value, keyPath, key)
{
if (!(value instanceof Object) && !(value instanceof Array)) throw util.error("DataError");
@@ -183,6 +181,128 @@ if (window.indexedDB.polyfill)
value[path[path.length - 1]] = key;
}
+
+ function sqlInsertKeyValue(context, strKey)
+ {
+ var request = context.request;
+ var sql = (context.noOverwrite ? "INSERT" : "REPLACE") + " INTO \"" +
+ request.source.name + "\" (key, value) VALUES (?, ?)";
+
+ context.primaryKey = strKey;
+ var strValue = w_JSON.stringify(context.value);
+ context.sqlTx.executeSql(sql, [strKey, strValue],
+ function (sqlTx, results)
+ {
+ context.sqlTx = sqlTx;
+ context.recordId = results.insertId;
+ storeIndexes(context);
+ },
+ function (sqlTx, sqlError)
+ {
+ request.error = sqlError;
+ if (request.onerror) request.onerror(util.event("error", request));
+ context.nextRequestCallback();
+ });
+ }
+
+ function storeIndexes(context)
+ {
+ var request = context.request;
+ var me = request.source;
+ var indexes = [], strKeys = [];
+ for (var indexName in me._indexes)
+ {
+ var index = me._indexes[indexName];
+ if (!index._ready) continue;
+
+ var strKey = getValidIndexKeyString(index, context.value);
+ if (strKey == null) continue;
+
+ strKeys.push(strKey);
+ indexes.push(index);
+ }
+
+ if (indexes.length == 0)
+ {
+ if (request.onsuccess) request.onsuccess(util.event("success", request));
+ context.nextRequestCallback();
+ }
+ else
+ {
+ var lastIndex = indexes.length - 1;
+ for (var i = 0; i < indexes.length; i++)
+ {
+ storeIndex(context, indexes[i], strKeys[i], i == lastIndex);
+ }
+ }
+ }
+
+ function getValidIndexKeyString(index, value)
+ {
+ var key = extractKeyFromValue(value, index.keyPath);
+ if (key == null) return null;
+
+ if (key instanceof Array)
+ {
+ if (key.length == 0) return null;
+ }
+ else
+ {
+ if (notValidKey(w_JSON.stringify(key))) return null;
+ }
+ if (index.multiEntry && (key instanceof Array))
+ {
+ // clean-up
+ var tmp = [], str;
+ for (var i = 0; i < key.length; i++)
+ {
+ str = w_JSON.stringify(key[i]);
+ if (tmp.indexOf(str) >= 0 || notValidKey(str)) continue;
+ tmp.push(str);
+ }
+ if (tmp.length == 0) return null;
+ return tmp;
+ }
+ return w_JSON.stringify(key);
+ }
+
+ function storeIndex(context, index, strKey, isLast)
+ {
+ var indexTable = util.indexTable(index.objectStore.name, index.name);
+
+ var sql = ["INSERT INTO", indexTable, "(recordId, key, primaryKey)"];
+ var args = [];
+ if (index.multiEntry && (strKey instanceof Array))
+ {
+ var select = [];
+ for (var i = 0; i < strKey.length; i++)
+ {
+ sql.push("SELECT ?, ?, ?");
+ args.push(context.recordId, strKey[i], context.primaryKey);
+ }
+ sql.push(select.join(" UNION ALL "))
+ }
+ else
+ {
+ sql.push("VALUES (?, ?, ?)");
+ args.push(context.recordId, strKey, context.primaryKey);
+ }
+ var request = context.request;
+ context.sqlTx.executeSql(sql.join(" "), args,
+ function (_, results)
+ {
+ if (!isLast) return;
+
+ if (request.onsuccess) request.onsuccess(util.event("success", request));
+ context.nextRequestCallback();
+ },
+ function (_, sqlError)
+ {
+ request.error = sqlError;
+ if (request.onerror) request.onerror(util.event("error", request));
+ context.nextRequestCallback();
+ });
+ }
//endregion
IDBObjectStore.prototype.delete = function (key)
@@ -196,12 +316,12 @@ if (window.indexedDB.polyfill)
{
var strKey = w_JSON.stringify(key);
sqlTx.executeSql("DELETE FROM \"" + me.name + "\" WHERE key = ?", [strKey],
- function (tx, resultSet)
+ function (_, results)
{
if (request.onsuccess) request.onsuccess(util.event("success", request));
nextRequestCallback();
},
- function (tx, sqlError)
+ function (_, sqlError)
{
if (request.onerror) request.onerror(sqlError);
nextRequestCallback();
@@ -249,29 +369,69 @@ if (window.indexedDB.polyfill)
request.readyState = util.IDBRequest.LOADING;
var cursor = new util.IDBCursorWithValue(this, direction, request);
- if (range == null)
- {
- range = util.IDBKeyRange.bound();
- }
- else if (!(range instanceof util.IDBKeyRange))
- {
- range = util.IDBKeyRange.only(range);
- }
- cursor._range = range;
+ cursor._range = util.IDBKeyRange.ensureKeyRange(range);
cursor.continue();
return request;
};
IDBObjectStore.prototype.createIndex = function (name, keyPath, optionalParameters)
{
+ validateVersionChangeTx(this.transaction);
+ if (this.indexNames.indexOf(name) >= 0)
+ {
+ throw util.error("ConstraintError");
+ }
+ var keyPath = util.validateKeyPath(keyPath);
+ var params = optionalParameters || { };
+ var unique = params.unique && params.unique != false || false;
+ var multiEntry = params.multiEntry && params.multiEntry != false || false;
+
+ if (keyPath instanceof Array && multiEntry)
+ {
+ throw util.error("NotSupportedError");
+ }
+ return createIndex(this, name, keyPath, unique, multiEntry);
};
IDBObjectStore.prototype.index = function (name)
{
+ if (!this.transaction._active)
+ {
+ throw util.error("InvalidStateError");
+ }
+ var index = this._indexes[name];
+ if (index == null)
+ {
+ throw util.error("NotFoundError");
+ }
+ return index;
};
IDBObjectStore.prototype.deleteIndex = function (indexName)
{
+ validateVersionChangeTx(this.transaction);
+ if (this.indexNames.indexOf(indexName) == -1)
+ {
+ throw util.error("ConstraintError");
+ }
+ util.arrayRemove(this.indexNames, indexName);
+ var index = this._indexes[indexName];
+ delete this._indexes[indexName];
+ var me = this;
+ var errorCallback = function ()
+ {
+ me.indexNames.push(indexName);
+ me._indexes[indexName] = index;
+ };
+ this.transaction._enqueueRequest(function (sqlTx, nextRequestCallback)
+ {
+ sqlTx.executeSql("DROP TABLE " + util.indexTable(me.name, indexName), null, null, errorCallback);
+
+ sqlTx.executeSql("DELETE FROM " + indexedDB.SCHEMA_TABLE + " WHERE type = 'index', name = ?",
+ [indexName], null, errorCallback);
+
+ nextRequestCallback();
+ });
};
IDBObjectStore.prototype.count = function (key)
@@ -289,9 +449,76 @@ if (window.indexedDB.polyfill)
}
}
+ function validateVersionChangeTx(tx)
+ {
+ if (!tx || tx.mode !== util.IDBTransaction.VERSION_CHANGE)
+ {
+ throw util.error("InvalidStateError");
+ }
+ }
+
function isPositiveFloat(value)
{
return typeof value == "number" && value > 0;
}
+ function createIndex(me, name, keyPath, unique, multiEntry)
+ {
+ var index = new util.IDBIndex(me, name, keyPath, unique, multiEntry);
+ index._ready = false;
+ me.indexNames.push(name);
+ me._indexes[name] = index;
+ var errorCallback = function ()
+ {
+ util.arrayRemove(me.indexNames, name);
+ delete me._indexes[name];
+ };
+ me.transaction._enqueueRequest(function (sqlTx, nextRequestCallback)
+ {
+ sqlTx.executeSql("CREATE TABLE " + util.indexTable(me.name, name) + " (recordId INTEGER, key TEXT" +
+ (unique ? " UNIQUE" : "") + ", primaryKey TEXT)", null, null, errorCallback);
+
+ sqlTx.executeSql("INSERT INTO " + indexedDB.SCHEMA_TABLE +
+ " (name, type, keyPath, tableId, \"unique\", multiEntry) VALUES (?, 'index', ?, " +
+ "(SELECT Id FROM " + indexedDB.SCHEMA_TABLE + " WHERE type = 'table' AND name = ?), ?, ?)",
+ [name, w_JSON.stringify(keyPath), me.name, unique ? 1 : 0, multiEntry ? 1 : 0],
+ null, errorCallback);
+
+ sqlTx.executeSql("SELECT id, key, value FROM [" + me.name + "]", null,
+ function (sqlTx, results)
+ {
+ if (results.rows.length == 0) return;
+
+ var sql = ["INSERT INTO [" + util.indexTable(me.name, name) + "]"];
+ var select = [], args = [];
+ for (var i = 0; i < results.rows.length; i++)
+ {
+ var item = results.rows.item(i);
+ var strKey = getValidIndexKeyString(index, w_JSON.parse(item.value));
+ if (strKey == null) continue;
+
+ if (index.multiEntry && (strKey instanceof Array))
+ {
+ for (var j = 0; j < strKey.length; j++)
+ {
+ select.push("SELECT ?, ?, ?");
+ args.push(item.id, strKey[j], item.key);
+ }
+ }
+ else
+ {
+ select.push("SELECT ?, ?, ?");
+ args.push(item.id, strKey, item.key);
+ }
+ }
+ sql.push(select.join(" UNION ALL "));
+ sqlTx.executeSql(sql.join(" "), args);
+ });
+
+ index._ready = true;
+ nextRequestCallback();
+ });
+ return index;
+ }
+
}(window, window.indexedDB, window.indexedDB.util));
View
2  IDBRequest.js
@@ -7,7 +7,7 @@ if (window.indexedDB.polyfill)
this.error = null;
this.source = source;
this.transaction = null;
- this.readyState = null;
+ this.readyState = util.IDBRequest.LOADING;
this.onsuccess = null;
this.onerror = null;
};
View
13 IDBTransaction.js
@@ -30,7 +30,8 @@ if (window.indexedDB.polyfill)
me.error = sqlError;
if (me.onerror) me.onerror(util.event("error", me)); },
function () {
- if (me.oncomplete) me.oncomplete(util.event("success", me)); });
+ if (me.oncomplete) me.oncomplete(util.event("success", me));
+ });
};
function performOperation(me, sqlTx, operationIndex)
@@ -39,13 +40,12 @@ if (window.indexedDB.polyfill)
{
me._active = false;
me._requests = [];
- for (prop in me.db._objectStores)
+ for (var name in me.db._objectStores)
{
- me.db._objectStores[prop].transaction = null;
+ me.db._objectStores[name].transaction = null;
}
return;
}
-
operation = me._requests[operationIndex];
operation(sqlTx, function ()
{
@@ -68,6 +68,11 @@ if (window.indexedDB.polyfill)
}
};
+ IDBTransaction.prototype.abort = function ()
+ {
+
+ };
+
IDBTransaction.prototype._enqueueRequest = function (sqlTxCallback)
{
validateActive(this);
View
16 README
@@ -2,13 +2,13 @@ README
A. Unit Test.
-To run unit tests open index.html in target browser. To verify unit tests against Firefox's native implementation of
-IndexedDB API, open the same page through web (http) server. Because, otherwise Firefox does not let to create
+To run unit tests open index.html in target browser. To verify unit tests against Firefox's native implementation
+of IndexedDB API, open the same page through web (http) server. Because, otherwise Firefox does not let to create
IndexedDB databases under localhost origin.
-Tests sometimes may fail due to their incompleteness in development. Particularly, QUnit's execution of asynchronous
-code needs to be wrapped by stop-start sign posts correctly and there must be one-to-one correspondence between all
-'stops' and 'starts' in the code. However, sometimes it is not easy to foresee which async code get executed at the
-very end, 'start' command may be executed too early leaving other async code with unit tests to be left out of a
-test scope. This results test failures also affects to subsequent tests with outcomes like databases left unclosed
-or current test's 'stop' stops the 'start' from previous unsuccessful test, thus leaving current closing 'start' without a match.
+Tests sometimes may fail due to their incompleteness in development. Particularly, QUnit's execution of asynchronous
+code needs to be wrapped by stop-start sign posts correctly and there must be one-to-one correspondence between all
+'stops' and 'starts' in the code. However, sometimes it is not easy to foresee which async code get executed at the
+very end, 'start' command may be executed too early leaving other async code with unit tests to be left out of a test
+scope. This results test failures also affects to subsequent tests with outcomes like databases left unclosed or current
+test's 'stop' stops the 'start' from previous unsuccessful test, thus leaving current closing 'start' without a match.
View
8 index.html
@@ -40,6 +40,7 @@
<script type="text/javascript" src="test/IDBFactoryTests.js"></script>
<script type="text/javascript" src="test/IDBDatabaseTests.js"></script>
<script type="text/javascript" src="test/IDBObjectStoreTests.js"></script>
+ <script type="text/javascript" src="test/IDBObjectStoreIndexTests.js"></script>
<script type="text/javascript" src="test/IDBCursorTests.js"></script>
<script type="text/javascript" src="test/IDBIndexTests.js"></script>
<script type="text/javascript" src="test/PerformanceTests.js"></script>
@@ -59,10 +60,17 @@ <h2 id="qunit-userAgent"></h2>
//PerformanceTests.run();
+ QUnit.testStart(function()
+ {
+ QUnit.config.current.ignoreGlobalErrors = true;
+ });
+
IDBFactoryTests.run();
IDBDatabaseTests.run();
IDBObjectStoreTests.run();
+ IDBObjectStoreIndexTests.run();
IDBCursorTests.run();
+ IDBIndexTests.run();
</script>
</body>
View
64 indexedDB.polyfill.js
@@ -15,8 +15,7 @@
// Configuration
indexedDB.SCHEMA_TABLE = "__IndexedDBSchemaInfo__";
- indexedDB.INDEXEDDB_METADATA_CURRENT_VERSION = "v1.0";
- indexedDB.DB_PREFIX = "__INDEXEDDB__";
+ indexedDB.DB_PREFIX = "__IndexedDB__";
indexedDB.DB_DESCRIPTION = "IndexedDB ";
indexedDB.DEFAULT_DB_SIZE = 5 * 1024 * 1024;
indexedDB.CURSOR_CHUNK_SIZE = 10;
@@ -31,28 +30,20 @@
};
- indexedDB.util =
+ indexedDB.util = new (function ()
{
- async : function (fn) { w_setTimeout(fn, 0); },
+ this.async = function (fn) { w_setTimeout(fn, 0); };
- exception : function (type, message, innerException)
- {
- var result = new w_Error(message);
- result.type = type;
- result.inner = innerException;
- return result;
- },
-
- error : function (name, message, inner)
+ this.error = function (name, message, innerError)
{
return {
name : name,
message : message,
- inner : inner
+ inner : innerError
}
- },
+ };
- event : function (type, target)
+ this.event = function (type, target)
{
return {
type : type,
@@ -60,8 +51,45 @@
currentTarget : target,
preventDefault : function () { }
};
- }
- };
+ };
+
+ this.validateKeyPath = function (keyPath)
+ {
+ if (keyPath === "") return "";
+ if (keyPath == null) return null;
+
+ var r = /^([^\d\W]\w*\.)+$/i;
+ if (keyPath instanceof Array)
+ {
+ var i = keyPath.length;
+ if (i == 0) throw this.error("SyntaxError");
+
+ while (i--)
+ {
+ if (!r.test(keyPath[i] + ".")) throw this.error("SyntaxError");
+ }
+ return keyPath;
+ }
+ if (!r.test(keyPath + ".")) throw this.error("SyntaxError");
+ return keyPath;
+ };
+
+ this.arrayRemove = function (array, item)
+ {
+ var i = array.indexOf(item);
+ if (i > -1) array.splice(i, 1);
+ };
+
+ this.arrayAdd = function (array, item)
+ {
+ if (array.indexOf(item) == -1) array.push(item);
+ };
+
+ this.indexTable = function (objectStoreName, name)
+ {
+ return indexedDB.DB_PREFIX + "Index__" + objectStoreName + "__" + name;
+ };
+ });
/*
IDBVersionChangeEvent.prototype = new Event(null);
View
2  test/IDBDatabaseTests.js
@@ -72,7 +72,7 @@ var IDBDatabaseTests = new (function ()
ok(true, "Create ObjectStore outside of 'versionchange' transaction");
}
- try { db.createObjectStore(env.cars); }
+ try { db.deleteObjectStore(env.cars); }
catch (ex)
{
ok(true, "Delete ObjectStore outside of 'versionchange' transaction");
View
3  test/IDBFactoryTests.js
@@ -171,7 +171,8 @@ var IDBFactoryTests = new (function ()
promise.fail(function (e)
{
- ok(false, "Testing environment initialization failure. ", e);
+ ok(false, "Testing environment initialization failure. ");
+ console.warn(e);
start();
});
promise.done(function (e)
View
156 test/IDBIndexTests.js
@@ -3,7 +3,11 @@ var IDBIndexTests = new (function ()
// Run
this.run = function ()
{
- module("IDBIndex.");
+ module("IDBIndex");
+ _test("openKeyCursor", testOpenKeyCursor);
+ _test("openCursor", testOpenCursor);
+ _test("Unique index constraint error", testUniqueIndexConstraintError);
+ _test("MultiEntry enabled", testArrayKeyPath);
};
// Environment
@@ -11,19 +15,118 @@ var IDBIndexTests = new (function ()
{
dbname : "TestDatabase",
dbversion : 10,
- // exists
- people : "People",
- cars : "Cars",
- // to delete
- insects : "Insects",
- // to add
- models : "Models"
+ people : {
+ name : "PeopleObjectStore",
+ records : [
+ { value : { name : 'n2', id : 20, email : "e1" }, key : 5},
+ { value : { name : 'n1', id : 10, email : "e5" }, key : 1},
+ { value : { name : 'n4', id : 40, email : "e2" }, key : 4},
+ { value : { name : 'n2', id : 50, email : "e4" }, key : 2},
+ { value : { name : 'n3', id : 30, email : "e3" }, key : 3},
+ { value : { name : ['n6', 'n5', 'n6'], id : 60, email : "e6" }, key : 6}
+ ]
+ },
+ nameIndex : "name",
+ multiNameIndex : "name2",
+ uniqueEmailIndex : "email"
};
-
// Tests
+ function testOpenKeyCursor(db)
+ {
+ expect(6);
+ var people = db.transaction([env.people.name]).objectStore(env.people.name);
+ var request = people.index(env.nameIndex).openKeyCursor(IDBKeyRange.upperBound("n3", true), IDBCursor.PREV);
+ request.onerror = TestUtils.shouldNotReachHereCallback;
+ var i = -1, ii = [0, 3, 1];
+ request.onsuccess = function (e)
+ {
+ var cursor = e.target.result;
+ if (cursor == null)
+ {
+ db.close();
+ start();
+ return;
+ }
+ var rec = env.people.records[ii[++i]];
+ deepEqual(cursor.key, rec.value.name, "Keys should match");
+ deepEqual(cursor.primaryKey, rec.key, "Values should match");
+ cursor.continue();
+ }
+ }
+ function testOpenCursor(db)
+ {
+ expect(6);
+ var tx = db.transaction([env.people.name]);
+ tx.error = TestUtils.shouldNotReachHereCallback;
+ tx.oncomplete = function (e)
+ {
+ db.close();
+ start();
+ };
+ var people = tx.objectStore(env.people.name);
+ var range = IDBKeyRange.bound("n1", "n4", true);
+ var request = people.index(env.nameIndex).openCursor(range, IDBCursor.NEXT_NO_DUPLICATE);
+ request.onerror = TestUtils.shouldNotReachHereCallback;
+ var i = -1, ii = [3, 4, 2];
+ request.onsuccess = function (e)
+ {
+ var cursor = e.target.result;
+ if (!cursor) return;
+
+ var rec = env.people.records[ii[++i]];
+ deepEqual(cursor.key, rec.value.name, "Keys should match");
+ deepEqual(cursor.value, rec.value, "Values should match");
+ cursor.continue();
+ }
+ }
+ function testArrayKeyPath(db)
+ {
+ expect(4);
+ var tx = db.transaction([env.people.name]);
+ tx.onerror = TestUtils.shouldNotReachHereCallback;
+ tx.oncomplete = function (e)
+ {
+ db.close();
+ start();
+ };
+
+ var ix = tx.objectStore(env.people.name).index(env.multiNameIndex);
+ var request = ix.openCursor(IDBKeyRange.bound("n5", "n6"));
+ request.onerror = TestUtils.shouldNotReachHereCallback;
+ var rec = env.people.records[5].value;
+ var names = ["n5", "n6"];
+ var i = -1;
+ request.onsuccess = function (e)
+ {
+ var cursor = e.target.result;
+ if (!cursor) return;
+
+ deepEqual(cursor.key, names[++i], "Keys should match");
+ deepEqual(cursor.value, rec, "Values should match");
+ cursor.continue();
+ }
+ }
+
+ function testUniqueIndexConstraintError(db)
+ {
+ expect(1);
+ db.close();
+ var request = indexedDB.open(env.dbname, env.dbversion + 1);
+ request.onupgradeneeded = function (e)
+ {
+ var db = e.target.result;
+ var tx = e.target.transaction;
+ tx.objectStore(env.people.name).createIndex("name2", "name", { unique : true });
+ };
+ request.onerror = function (e)
+ {
+ ok(true, "It should fail index creating with unique = true");
+ start();
+ }
+ }
// Utils
function _test(name, fn)
@@ -32,17 +135,40 @@ var IDBIndexTests = new (function ()
{
var promise = TestUtils.initDBPromise(env.dbname, env.dbversion, function (db)
{
- db.createObjectStore(env.cars);
- db.createObjectStore(env.people, { });
- db.createObjectStore(env.insects);
+ var rec;
+ var people = db.createObjectStore(env.people.name);
+ for (var i = 0; i < env.people.records.length; i++)
+ {
+ rec = env.people.records[i];
+ people.add(rec.value, rec.key);
+ }
+ people.createIndex(env.nameIndex, "name");
+ people.createIndex(env.multiNameIndex, "name", { multiEntry : true });
+ //people.createIndex(env.uniqueEmailIndex, "email", { unique : true, multiEntry : true });
});
promise.fail(function (e)
{
- ok(false, "Testing environment initialization failure. ", e);
+ ok(false, "Testing environment initialization failure.");
+ console.warn(e);
start();
});
- promise.done(function (e) { fn(); });
+ promise.done(function (e)
+ {
+ var request = indexedDB.open(env.dbname);
+ request.onerror = request.onblocked = TestUtils.shouldNotReachHereCallback;
+ request.onsuccess = function (e)
+ {
+ var db = e.target.result;
+ try { fn(db); }
+ catch (ex)
+ {
+ db && db.close && db.close();
+ console.warn(ex);
+ ok(false, "Exception thrown. " + ex);
+ start();
+ }
+ }
+ });
});
-
}
});
View
2  test/IDBObjectStoreTests.js
@@ -335,7 +335,7 @@ var IDBObjectStoreTests = new (function ()
});
promise.fail(function (e)
{
- ok(false, "Testing environment initialization failure. ");
+ ok(false, "Testing environment initialization failure.");
console.warn(e);
start();
});
Please sign in to comment.
Something went wrong with that request. Please try again.