Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Monotonic key encoding/decoding is implemented.

  • Loading branch information...
commit 791c626d6c8d55b579f973a6fb980713431a41c0 1 parent aca67c6
Khamza Davletov authored
View
52 IDBCursor.js
@@ -11,7 +11,7 @@ if (window.indexedDB.polyfill)
this._request = request;
this._range = null;
this._gotValue = true;
- this._effectiveKey = null;
+ this._effectiveKeyEncoded = null;
};
IDBCursor.prototype.update = function (value)
@@ -36,7 +36,7 @@ if (window.indexedDB.polyfill)
noOverwrite : false,
value : value
},
- me._effectiveKey);
+ me._effectiveKeyEncoded);
});
return request;
};
@@ -64,7 +64,7 @@ if (window.indexedDB.polyfill)
var me = this;
objectStore.transaction._queueOperation(function (sqlTx, nextRequestCallback)
{
- objectStore._deleteRecord(sqlTx, me._effectiveKey,
+ objectStore._deleteRecord(sqlTx, me._effectiveKeyEncoded,
function ()
{
if (request.onsuccess) request.onsuccess(util.event("success", request));
@@ -130,18 +130,16 @@ if (window.indexedDB.polyfill)
me._request.readyState = util.IDBRequest.LOADING;
tx._queueOperation(function (sqlTx, nextRequestCallback)
{
- var sql = ["SELECT key, value FROM [" + me.source.name + "]"];
+ var sql = ["SELECT hex(key) 'key', value FROM [" + me.source.name + "]"];
var where = [];
var args = [];
if (filter.lower != null)
{
- where.push("(key >" + (filter.lowerOpen ? "" : "=") + " ?)");
- args.push(util.encodeKey(filter.lower));
+ where.push("(key >" + (filter.lowerOpen ? "" : "=") + " X'" + util.encodeKey(filter.lower) + "')");
}
if (filter.upper != null)
{
- where.push("(key <" + (filter.upperOpen ? "" : "=") + " ?)");
- args.push(util.encodeKey(filter.upper));
+ where.push("(key <" + (filter.upperOpen ? "" : "=") + " X'" + util.encodeKey(filter.upper) + "')");
}
if (where.length > 0)
{
@@ -157,14 +155,14 @@ if (window.indexedDB.polyfill)
request.readyState = util.IDBRequest.DONE;
if (results.rows.length < filter.count)
{
- me.key = me.primaryKey = me._effectiveKey = undefined;
+ me.key = me.primaryKey = me._effectiveKeyEncoded = undefined;
if (typeof me.value !== "undefined") me.value = undefined;
request.result = null;
}
else
{
var found = results.rows.item(filter.count - 1);
- me._effectiveKey = found.key;
+ me._effectiveKeyEncoded = found.key;
me.key = me.primaryKey = util.decodeKey(found.key);
if (typeof me.value !== "undefined") me.value = w_JSON.parse(found.value);
me._gotValue = true;
@@ -193,53 +191,51 @@ if (window.indexedDB.polyfill)
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" : ""),
+ var sql = ["SELECT hex(i.key) 'key', hex(i.primaryKey) '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 = [];
+ var where = [], args = [], encoded;
if (filter.lower != null)
{
- var strLower = util.encodeKey(filter.lower);
- args.push(strLower);
+ encoded = util.encodeKey(filter.lower);
if (filter.lowerOpen)
{
- where.push("(i.key > ?)");
+ where.push("(i.key > X'" + encoded + "')");
}
else
{
- if (me._effectiveKey == null || desc)
+ if (me._effectiveKeyEncoded == null || desc)
{
- where.push("(i.key >= ?)");
+ where.push("(i.key >= X'" + encoded+ "')");
}
else
{
- where.push("((i.key > ?) OR (i.key = ? AND i.primaryKey > ?))");
- args.push(strLower, me._effectiveKey);
+ where.push("((i.key > X'" + encoded + "') OR (i.key = X'" + encoded +
+ "' AND i.primaryKey > X'" + me._effectiveKeyEncoded + "'))");
}
}
}
if (filter.upper != null)
{
- var strUpper = util.encodeKey(filter.upper);
- args.push(strUpper);
+ encoded = util.encodeKey(filter.upper);
if (filter.upperOpen)
{
- where.push("(i.key < ?)");
+ where.push("(i.key < X'" + encoded + "')");
}
else
{
- if (me._effectiveKey == null || !desc)
+ if (me._effectiveKeyEncoded == null || !desc)
{
- where.push("(i.key <= ?)");
+ where.push("(i.key <= X'" + encoded + "')");
}
else
{
- where.push("((i.key < ?) OR (i.key = ? AND i.primaryKey < ?))");
- args.push(strUpper, me._effectiveKey);
+ where.push("((i.key < X'" + encoded + "') OR (i.key = X'" + encoded +
+ "' AND i.primaryKey < X'" + me._effectiveKeyEncoded + "'))");
}
}
}
@@ -258,7 +254,7 @@ if (window.indexedDB.polyfill)
request.readyState = util.IDBRequest.DONE;
if (results.rows.length < filter.count)
{
- me.key = me.primaryKey = me._effectiveKey = undefined;
+ me.key = me.primaryKey = me._effectiveKeyEncoded = undefined;
if (typeof me.value !== "undefined") me.value = undefined;
request.result = null;
}
@@ -266,7 +262,7 @@ if (window.indexedDB.polyfill)
{
var found = results.rows.item(filter.count - 1);
me.key = util.decodeKey(found.key);
- me._effectiveKey = found.primaryKey;
+ me._effectiveKeyEncoded = found.primaryKey;
me.primaryKey = util.decodeKey(found.primaryKey);
if (typeof me.value !== "undefined") me.value = w_JSON.parse(found.value);
me._gotValue = true;
View
10 IDBDatabase.js
@@ -49,7 +49,7 @@ if (window.indexedDB.polyfill)
var objectStore = this._objectStores[name];
delete this._objectStores[name];
var me = this;
- var errorCallback = function (tx, sqlError)
+ var errorCallback = function (_, sqlError)
{
me.objectStoreNames.push(name);
me._objectStores[name] = objectStore;
@@ -66,7 +66,7 @@ if (window.indexedDB.polyfill)
IDBDatabase.prototype.transaction = function (storeNames, mode)
{
- // TODO: 4.2.1. throw InvalidStateError if a transaction being createing within transaction callback
+ // TODO: 4.2.1. throw InvalidStateError if a transaction being creating within transaction callback
if (storeNames instanceof Array || storeNames == null)
{
if (storeNames.length == 0) throw util.error("InvalidAccessError");
@@ -142,7 +142,7 @@ if (window.indexedDB.polyfill)
var objectStore = new util.IDBObjectStore(name, keyPath, autoIncrement, me._versionChangeTransaction);
me.objectStoreNames.push(name);
me._objectStores[name] = objectStore;
- var errorCallback = function (tx, sqlError)
+ var errorCallback = function (_, sqlError)
{
util.arrayRemove(me.objectStoreNames, name);
delete me._objectStores[name];
@@ -150,9 +150,9 @@ if (window.indexedDB.polyfill)
me._versionChangeTransaction._queueOperation(function (sqlTx, nextRequestCallback)
{
sqlTx.executeSql("CREATE TABLE [" + name + "] (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
- "key TEXT UNIQUE, value BLOB)", [], null, errorCallback);
+ "key BLOB UNIQUE, value BLOB)", null, null, errorCallback);
- sqlTx.executeSql("CREATE INDEX INDEX_" + name + "_key ON [" + name + "] (key)", [], null, errorCallback);
+ sqlTx.executeSql("CREATE INDEX INDEX_" + name + "_key ON [" + name + "] (key)", null, null, errorCallback);
sqlTx.executeSql("INSERT INTO " + indexedDB.SCHEMA_TABLE +
" (type, name, keyPath, autoInc) VALUES ('table', ?, ?, ?)",
View
22 IDBFactory.js
@@ -5,6 +5,7 @@ if (window.indexedDB.polyfill)
indexedDB.open = function (name, version)
{
+ console.group
if (arguments.length == 2 && version == undefined) throw util.error("TypeError");
if (version !== undefined)
{
@@ -168,24 +169,30 @@ if (window.indexedDB.polyfill)
// IDBFactory.deleteDatabase
indexedDB.deleteDatabase = function (name)
{
+ console.groupCollapsed("indexedDB.deleteDatabase('%s')", name);
// INFO: There is no way to delete database in Web SQL Database API.
var database = getOriginDatabase(name);
database.deletePending = true;
var request = new util.IDBOpenDBRequest(null);
util.async(function()
{
+ console.log("deleteDatabase async started.");
request.readyState = util.IDBRequest.DONE;
var sqldb = openSqlDB(name);
if (sqldb.version == "")
{
+ console.log("Database deleted succesfully. (No such database was found)");
+ console.groupEnd();
database.deletePending = false;
if (request.onsuccess) request.onsuccess(util.event("success", request));
}
else
{
+ console.log("Deleting existing database");
fireVersionChangeEvent(request, name, parseInt(sqldb.version), null);
util.wait(function ()
{
+ console.log("Waiting %d connection to be closed", database.connections.length);
return database.connections.length == 0;
},
function ()
@@ -245,12 +252,14 @@ if (window.indexedDB.polyfill)
var conn = database.connections[i];
if (conn._closePending) continue;
+ console.log("Open connection found, firing versionchange event on them.");
anyOpenConnection = true;
var event = new util.IDBVersionChangeEvent("versionchange", request, oldVersion, newVersion);
if (conn.onversionchange) conn.onversionchange(event);
}
if (anyOpenConnection)
{
+ console.log("Open connection found, firing onblocked event.");
var event = new util.IDBVersionChangeEvent("blocked", request, oldVersion, newVersion);
if (request.onblocked) request.onblocked(event);
}
@@ -258,32 +267,39 @@ if (window.indexedDB.polyfill)
function deleteDatabase(request, sqldb, database)
{
+ console.log("Setting sql database version %d to empty.", sqldb.version);
sqldb.changeVersion(sqldb.version, "",
function (sqlTx)
{
+ console.log("Selecting all tables and indexes from schema table.");
sqlTx.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)
+ function (sqlTx, results)
{
var name;
for (var i = 0; i < results.rows.length; i++)
{
var item = results.rows.item(i);
name = item.type == 'table' ? item.name : util.indexTable(item.table, item.name);
- tx.executeSql("DROP TABLE [" + name + "]");
+ console.log("Dropping table %s.", name);
+ sqlTx.executeSql("DROP TABLE [" + name + "]");
}
- tx.executeSql("DROP TABLE " + indexedDB.SCHEMA_TABLE);
+ console.log("Dropping schema table.");
+ sqlTx.executeSql("DROP TABLE " + indexedDB.SCHEMA_TABLE);
});
},
function (sqlError)
{
+ console.error("Database (version %d) deletion failed.", sqldb.version, sqlError);
database.deletePending = false;
request.error = sqlError;
if (request.onerror) request.onerror(util.event("error", request));
},
function ()
{
+ console.log("Database deleted successfully.");
+ console.groupEnd();
database.deletePending = false;
if (request.onsuccess) request.onsuccess(util.event("success", request));
});
View
52 IDBIndex.js
@@ -23,27 +23,23 @@ if (window.indexedDB.polyfill)
IDBIndex.prototype.get = function (key)
{
- key = util.validateKeyOrRange(key);
+ var encodedKeyOrRange = util.validateKeyOrRange(key);
var request = new util.IDBRequest(this);
var me = this;
this.objectStore.transaction._queueOperation(function (sqlTx, nextRequestCallback)
{
var sql = ["SELECT s.value FROM [" + util.indexTable(me) + "] AS i INNER JOIN"];
- sql.push("[" + me.objectStore.name + "] AS s ON s.id = i.recordId")
- var args = [];
- if (key instanceof util.IDBKeyRange)
+ sql.push("[" + me.objectStore.name + "] AS s ON s.id = i.recordId");
+ if (encodedKeyOrRange instanceof util.IDBKeyRange)
{
- var filter = key._getSqlFilter("i.key");
- sql.push("WHERE", filter.sql);
- args = filter.args;
+ sql.push("WHERE", encodedKeyOrRange._getSqlFilter("i.key"));
}
- else if (key != null)
+ else if (encodedKeyOrRange != null)
{
- sql.push("WHERE (i.key = ?)");
- args.push(key);
+ sql.push("WHERE (i.key = X'" + encodedKeyOrRange + "')");
}
sql.push("ORDER BY i.key, i.primaryKey LIMIT 1");
- sqlTx.executeSql(sql.join(" "), args,
+ sqlTx.executeSql(sql.join(" "), null,
function (_, results)
{
request.result = results.rows.length > 0 ? w_JSON.parse(results.rows.item(0).value) : undefined;
@@ -62,26 +58,22 @@ if (window.indexedDB.polyfill)
IDBIndex.prototype.getKey = function (key)
{
- key = util.validateKeyOrRange(key);
+ var encodedKeyOrRange = util.validateKeyOrRange(key);
var request = new util.IDBRequest(this);
var me = this;
this.objectStore.transaction._queueOperation(function (sqlTx, nextRequestCallback)
{
- var sql = ["SELECT primaryKey FROM [" + util.indexTable(me) + "]"];
- var args = [];
- if (key instanceof util.IDBKeyRange)
+ var sql = ["SELECT hex(primaryKey) 'primaryKey' FROM [" + util.indexTable(me) + "]"];
+ if (encodedKeyOrRange instanceof util.IDBKeyRange)
{
- var filter = key._getSqlFilter();
- sql.push("WHERE", filter.sql);
- args = filter.args;
+ sql.push("WHERE", encodedKeyOrRange._getSqlFilter());
}
- else if (key != null)
+ else if (encodedKeyOrRange != null)
{
- sql.push("WHERE (key = ?)");
- args.push(key);
+ sql.push("WHERE (key = X'" + encodedKeyOrRange + "')");
}
sql.push("LIMIT 1");
- sqlTx.executeSql(sql.join(" "), args,
+ sqlTx.executeSql(sql.join(" "), null,
function (_, results)
{
request.result = results.rows.length > 0 ?
@@ -101,25 +93,21 @@ if (window.indexedDB.polyfill)
IDBIndex.prototype.count = function (key)
{
- key = util.validateKeyOrRange(key);
+ var encodedKeyOrRange = util.validateKeyOrRange(key);
var request = new util.IDBRequest(this);
var me = this;
this.objectStore.transaction._queueOperation(function (sqlTx, nextRequestCallback)
{
var sql = ["SELECT COUNT(recordId) AS 'count' FROM [" + util.indexTable(me) + "]"];
- var args = [];
- if (key instanceof util.IDBKeyRange)
+ if (encodedKeyOrRange instanceof util.IDBKeyRange)
{
- var filter = key._getSqlFilter();
- sql.push("WHERE", filter.sql);
- args = filter.args;
+ sql.push("WHERE", encodedKeyOrRange._getSqlFilter());
}
- else if (key != null)
+ else if (encodedKeyOrRange != null)
{
- sql.push("WHERE (key = ?)");
- args.push(key);
+ sql.push("WHERE (key = X'" + encodedKeyOrRange + "')");
}
- sqlTx.executeSql(sql.join(" "), args,
+ sqlTx.executeSql(sql.join(" "), null,
function (_, results)
{
request.result = results.rows.item(0).count;
View
21 IDBKeyRange.js
@@ -50,32 +50,25 @@ if (window.indexedDB.polyfill)
IDBKeyRange.prototype._getSqlFilter = function (keyColumnName)
{
if (keyColumnName == undefined) keyColumnName = "key";
-
- var sql = [], args = [];
- var hasLower = this.lower != null, hasUpper = this.upper != null;
-
+ var sql = [], hasLower = this.lower != null, hasUpper = this.upper != null;
if (this.lower == this.upper)
{
- sql.push("(" + keyColumnName + " = ?)");
- args = [this.lower];
+ sql.push("(" + keyColumnName + " = X'" + util.encodeKey(this.lower) + "')");
}
else
{
if (hasLower)
{
- sql.push("(? <" + (this.lowerOpen ? "" : "=") + " " + keyColumnName + ")");
- args.push(util.encodeKey(this.lower));
+ sql.push("(X'" + util.encodeKey(this.lower) + "' <" +
+ (this.lowerOpen ? "" : "=") + " " + keyColumnName + ")");
}
if (hasUpper)
{
- sql.push("(" + keyColumnName + " <" + (this.upperOpen ? "" : "=") + " ?)");
- args.push(util.encodeKey(this.upper));
+ sql.push("(" + keyColumnName + " <" +
+ (this.upperOpen ? "" : "=") + " X'" + util.encodeKey(this.upper) +"')");
}
}
- return { sql : sql.join(" AND "), args : args };
+ return sql.join(" AND ");
};
- // Utils
- var w_JSON = window.JSON;
-
}(window, window.indexedDB.util));
View
95 IDBObjectStore.js
@@ -46,7 +46,7 @@ if (window.indexedDB.polyfill)
function validateObjectStoreKey(keyPath, autoIncrement, value, key)
{
- var key = key, str;
+ var key = key, encodedKey;
if (keyPath != null)
{
if (key != null) throw util.error("DataError");
@@ -84,7 +84,7 @@ if (window.indexedDB.polyfill)
if (key == null)
{
key = currentNo;
- encodedKey = key.toString();
+ encodedKey = util.encodeKey(key);
if (me.keyPath != null)
{
assignKeyToValue(context.value, me.keyPath, key);
@@ -121,7 +121,7 @@ if (window.indexedDB.polyfill)
// TODO: error
}
},
- function (sqlTx, sqlError)
+ function (_, sqlError)
{
// TODO: error
});
@@ -203,26 +203,26 @@ if (window.indexedDB.polyfill)
return encodedKey;
}
- function storeIndex(context, index, strKey, isLast)
+ function storeIndex(context, index, encodedKey, 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))
+ if (index.multiEntry && (encodedKey instanceof Array))
{
var select = [];
- for (var i = 0; i < strKey.length; i++)
+ for (var i = 0; i < encodedKey.length; i++)
{
- sql.push("SELECT ?, ?, ?");
- args.push(context.recordId, strKey[i], context.primaryKey);
+ sql.push("SELECT ?, X'" + encodedKey[i] + "', X'" + context.primaryKeyEncoded + "'");
+ args.push(context.recordId);
}
sql.push(select.join(" UNION ALL "))
}
else
{
- sql.push("VALUES (?, ?, ?)");
- args.push(context.recordId, strKey, context.primaryKey);
+ sql.push("VALUES (?, X'" + encodedKey + "', X'" + context.primaryKeyEncoded +"')");
+ args.push(context.recordId);
}
var request = context.request;
context.sqlTx.executeSql(sql.join(" "), args,
@@ -270,22 +270,19 @@ if (window.indexedDB.polyfill)
IDBObjectStore.prototype.get = function (key)
{
- key = util.validateKeyOrRange(key);
+ var encodedKeyOrRange = util.validateKeyOrRange(key);
var request = new util.IDBRequest(this);
var me = this;
me.transaction._queueOperation(function (sqlTx, nextRequestCallback)
{
var where = "", args = [];
- if (key instanceof util.IDBKeyRange)
+ if (encodedKeyOrRange instanceof util.IDBKeyRange)
{
- var filter = key._getSqlFilter();
- where = "WHERE " + filter.sql;
- args = filter.args;
+ where = "WHERE " + encodedKeyOrRange._getSqlFilter();
}
- else if (key != null)
+ else if (encodedKeyOrRange != null)
{
- where = "WHERE (key = ?)";
- args.push(key);
+ where = "WHERE (key = X'" + encodedKeyOrRange + "')";
}
sqlTx.executeSql("SELECT [value] FROM [" + me.name + "] " + where +" LIMIT 1", args,
@@ -404,22 +401,19 @@ if (window.indexedDB.polyfill)
IDBObjectStore.prototype.count = function (key)
{
- key = util.validateKeyOrRange(key);
+ var encodedKeyOrRange = util.validateKeyOrRange(key);
var request = new util.IDBRequest(this);
var me = this;
this.transaction._queueOperation(function (sqlTx, nextRequestCallback)
{
var where = "", args = [];
- if (key instanceof util.IDBKeyRange)
+ if (encodedKeyOrRange instanceof util.IDBKeyRange)
{
- var filter = key._getSqlFilter();
- where = "WHERE " + filter.sql;
- args = filter.args;
+ where = "WHERE " + encodedKeyOrRange._getSqlFilter();
}
- else if (key != null)
+ else if (encodedKeyOrRange != null)
{
- where = "WHERE (key = ?)";
- args.push(key);
+ where = "WHERE (key = X'" + encodedKeyOrRange + "')";
}
sqlTx.executeSql("SELECT COUNT(id) AS 'count' FROM [" + me.name + "] " + where, args,
function (_, results)
@@ -438,32 +432,29 @@ if (window.indexedDB.polyfill)
return request;
};
- IDBObjectStore.prototype._deleteRecord = function (sqlTx, strKeyOrRange, onsuccess, onerror)
+ IDBObjectStore.prototype._deleteRecord = function (sqlTx, encodedKeyOrRange, onsuccess, onerror)
{
var objectStore = this;
- var sql, where, args = [];
- if (strKeyOrRange instanceof util.IDBKeyRange)
+ var sql, where;
+ if (encodedKeyOrRange instanceof util.IDBKeyRange)
{
- var filter = strKeyOrRange._getSqlFilter();
- where = "WHERE " + filter.sql;
- args = filter.args;
+ where = "WHERE " + encodedKeyOrRange._getSqlFilter();
}
else
{
- where = "WHERE (key = ?)";
- args.push(strKeyOrRange);
+ where = "WHERE (key = X'" + encodedKeyOrRange + "')";
}
for (var indexName in objectStore._indexes)
{
var index = objectStore._indexes[indexName];
sql = ["DELETE FROM [" + util.indexTable(objectStore.name, index.name) + "]"];
- if (args.length > 0)
+ if (where)
{
sql.push("WHERE recordId IN (SELECT id FROM [" + objectStore.name + "]", where + ")");
}
- sqlTx.executeSql(sql.join(" "), args, null, onerror);
+ sqlTx.executeSql(sql.join(" "), null, null, onerror);
}
- sqlTx.executeSql("DELETE FROM [" + objectStore.name + "] " + where, args, onsuccess, onerror);
+ sqlTx.executeSql("DELETE FROM [" + objectStore.name + "] " + where, null, onsuccess, onerror);
};
IDBObjectStore.prototype._insertOrReplaceRecord = function (context, encodedKey)
@@ -481,17 +472,17 @@ if (window.indexedDB.polyfill)
}
var me = this;
var encodedValue = w_JSON.stringify(context.value);
- context.sqlTx.executeSql("INSERT INTO [" + me.name + "] (key, value) VALUES (?, ?)",
- [encodedKey, encodedValue],
+ context.sqlTx.executeSql("INSERT INTO [" + me.name + "] (key, value) VALUES (X'" + encodedKey + "', ?)",
+ [encodedValue],
function (sqlTx, results)
{
context.objectStore = me;
context.sqlTx = sqlTx;
- context.primaryKey = encodedKey;
+ context.primaryKeyEncoded = encodedKey;
context.recordId = results.insertId;
storeIndexes(context);
},
- function (sqlTx, sqlError)
+ function (_, sqlError)
{
// TODO: proper error handling
request.error = util.error("ConstraintError");
@@ -521,8 +512,8 @@ if (window.indexedDB.polyfill)
};
me.transaction._queueOperation(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("CREATE TABLE " + util.indexTable(me.name, name) + " (recordId INTEGER, key BLOB" +
+ (unique ? " UNIQUE" : "") + ", primaryKey BLOB)", null, null, errorCallback);
sqlTx.executeSql("INSERT INTO " + indexedDB.SCHEMA_TABLE +
" (name, type, keyPath, tableId, [unique], multiEntry) VALUES (?, 'index', ?, " +
@@ -530,7 +521,7 @@ if (window.indexedDB.polyfill)
[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,
+ sqlTx.executeSql("SELECT id, hex(key) 'key', value FROM [" + me.name + "]", null,
function (sqlTx, results)
{
if (results.rows.length == 0) return;
@@ -540,21 +531,21 @@ if (window.indexedDB.polyfill)
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;
+ var encodedKey = getValidIndexKeyString(index, w_JSON.parse(item.value));
+ if (encodedKey == null) continue;
- if (index.multiEntry && (strKey instanceof Array))
+ if (index.multiEntry && (encodedKey instanceof Array))
{
- for (var j = 0; j < strKey.length; j++)
+ for (var j = 0; j < encodedKey.length; j++)
{
- select.push("SELECT ?, ?, ?");
- args.push(item.id, strKey[j], item.key);
+ select.push("SELECT ?, X'" + encodedKey[j] + "', X'" + item.key + "'");
+ args.push(item.id);
}
}
else
{
- select.push("SELECT ?, ?, ?");
- args.push(item.id, strKey, item.key);
+ select.push("SELECT ?, X'" + encodedKey + "', X'" + item.key + "'");
+ args.push(item.id);
}
}
sql.push(select.join(" UNION ALL "));
View
4 IDBRequest.js
@@ -1,5 +1,5 @@
if (window.indexedDB.polyfill)
-(function(window, indexedDB, util, undefined)
+(function(window, util, undefined)
{
var IDBRequest = util.IDBRequest = window.IDBRequest = function(source)
{
@@ -23,4 +23,4 @@ if (window.indexedDB.polyfill)
IDBOpenDBRequest.prototype = new IDBRequest();
IDBOpenDBRequest.prototype.constructor = IDBOpenDBRequest;
-}(window, window.indexedDB, window.indexedDB.util));
+}(window, window.indexedDB.util));
View
3  IDBTransaction.js
@@ -58,8 +58,7 @@ if (window.indexedDB.polyfill)
}*/
return;
}
- operation = me._requests[operationIndex];
- operation(sqlTx, function ()
+ me._requests[operationIndex](sqlTx, function ()
{
performOperation(me, sqlTx, operationIndex + 1);
});
View
4 README
@@ -4,13 +4,11 @@ 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 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.
-
B. Useful Resources.
1) Test suits http://w3c-test.org/webapps/IndexedDB/.
-Among test suits from w3c-test.org/webapps/IndexedDB/tests/submissions/Microsoft/ the following are failing: idbobjectstore_count2 & index_sort_order & objectstore_keyorder (lacking monotonic encoding), idbobjectstore_get3 (lacking Date support). In sum 4 tests failed out of 107. Last Update: Jule 9, 2012.
+Among test suits from w3c-test.org/webapps/IndexedDB/tests/submissions/Microsoft/ the following are failing: idbobjectstore_get3 (JSON lacks Date support). In sum 4 tests failed out of 107. Last Update: Jule 9, 2012.
2) Mozilla IndexedDB implementation: http://hg.mozilla.org/mozilla-central/file/895e12563245/dom/indexedDB/ and http://people.mozilla.org/~jcranmer2/c-ccov-js/mozilla/dom/indexedDB/.
View
34 indexedDB.init.js
@@ -37,6 +37,7 @@
this.error = function (name, message, innerError)
{
+ console.gro
return {
name : name,
message : message,
@@ -118,14 +119,15 @@
return key;
};
- this.validateKeyOrRange = function (encodedKey)
+ this.validateKeyOrRange = function (key)
{
- if (!(encodedKey instanceof this.IDBKeyRange))
+ if (key == null) return null;
+ if (!(key instanceof this.IDBKeyRange))
{
- encodedKey = this.encodeKey(encodedKey);
- if (encodedKey === null) throw this.error("DataError");
+ key = this.encodeKey(key);
+ if (key === null) throw this.error("DataError");
}
- return encodedKey;
+ return key;
};
this.wait = function (conditionFunc, bodyFunc, async)
@@ -177,4 +179,26 @@
// Cached
var w_setTimeout = window.setTimeout;
+ // Temp
+ var db = openDatabase("__TEMP__32D0E022D11311E1B4DD4EB66188709B", "", null, null);
+ db.transaction(function (sqlTx)
+ {
+ var exec = sqlTx.constructor.prototype.executeSql;
+ sqlTx.constructor.prototype.executeSql = function (sql, args, callback, errorCallback)
+ {
+ console.log("[SQL]: %s; args: %o", sql, args);
+ exec.call(this, sql, args,
+ function (sqlTx, results)
+ {
+ if (callback) callback(sqlTx, results);
+ },
+ function (sqlTx, sqlError)
+ {
+ console.error("[SQL Error]: ", sqlError);
+ if (errorCallback) errorCallback(sqlTx, sqlError);
+ })
+ }
+ });
+
+
}(window));
View
157 key.js
@@ -27,7 +27,7 @@
Chars (3FFF+80) - FFFF are encoded as 11xxxxxx xxxxxxxx xx000000
This ensures that the first byte is never encoded as 0, which means that the
- string terminator (per basic-stategy table) sorts before any character.
+ string terminator (per basic-strategy table) sorts before any character.
The reason that (3FFF+80) - FFFF is encoded "shifted up" 6 bits is to maximize
the chance that the last character is 0. See below for why.
@@ -67,7 +67,7 @@
We could use a much higher number than 3 at no complexity or performance cost,
however it seems unlikely that it'll make a practical difference, and the low
- limit makes testing eaiser.
+ limit makes testing easier.
As a final optimization we do a post-encoding step which drops all 0s at the
@@ -93,12 +93,12 @@ if (window.indexedDB.polyfill)
util.encodeKey = function (key)
{
- var stack = [key], buffer = [], type = 0, dataType, obj, tmp;
+ var stack = [key], writer = new HexStringWriter(), type = 0, dataType, obj;
while ((obj = stack.pop()) !== undefined)
{
if (type % 4 === 0 && type + TYPE_ARRAY > MAX_TYPE_BYTE_SIZE)
{
- buffer.push(type);
+ writer.write(type);
type = 0;
}
dataType = typeof obj;
@@ -114,35 +114,35 @@ if (window.indexedDB.polyfill)
}
else
{
- buffer.push(type);
+ writer.write(type);
}
}
else if (dataType === "number")
{
type += TYPE_NUMBER;
- buffer.push(type);
- encodeNumber(buffer, obj);
+ writer.write(type);
+ encodeNumber(writer, obj);
}
else if (obj instanceof Date)
{
type += TYPE_DATE;
- buffer.push(type);
- encodeNumber(buffer, obj.valueOf());
+ writer.write(type);
+ encodeNumber(writer, obj.valueOf());
}
else if (dataType === "string")
{
type += TYPE_STRING;
- buffer.push(type);
- encodeString(buffer, obj);
+ writer.write(type);
+ encodeString(writer, obj);
}
else if (obj === ARRAY_TERMINATOR)
{
- buffer.push(BYTE_TERMINATOR);
+ writer.write(BYTE_TERMINATOR);
}
else return null;
type = 0;
}
- return bufferToUnicodeString(buffer);
+ return writer.trim().toString();
};
util.decodeKey = function (encodedKey)
@@ -150,22 +150,22 @@ if (window.indexedDB.polyfill)
var rootArray = []; // one-element root array that contains the result
var parentArray = rootArray;
var type, arrayStack = [], depth, tmp;
- var byteReader = new ByteReader(encodedKey);
- while (byteReader.read() != null)
+ var reader = new HexStringReader(encodedKey);
+ while (reader.read() != null)
{
- if (byteReader.current === 0) // end of array
+ if (reader.current === 0) // end of array
{
parentArray = arrayStack.pop();
continue;
}
- if (byteReader.current === null)
+ if (reader.current === null)
{
return rootArray[0];
}
do
{
- depth = byteReader.current / 4 | 0;
- type = byteReader.current % 4;
+ depth = reader.current / 4 | 0;
+ type = reader.current % 4;
for (var i = 0; i < depth; i++)
{
tmp = [];
@@ -173,24 +173,24 @@ if (window.indexedDB.polyfill)
arrayStack.push(parentArray);
parentArray = tmp;
}
- if (type === 0 && byteReader.current + TYPE_ARRAY > MAX_TYPE_BYTE_SIZE)
+ if (type === 0 && reader.current + TYPE_ARRAY > MAX_TYPE_BYTE_SIZE)
{
- byteReader.read();
+ reader.read();
}
else break;
} while (true);
if (type === TYPE_NUMBER)
{
- parentArray.push(decodeNumber(byteReader));
+ parentArray.push(decodeNumber(reader));
}
else if (type === TYPE_DATE)
{
- parentArray.push(new Date(decodeNumber(byteReader)));
+ parentArray.push(new Date(decodeNumber(reader)));
}
else if (type === TYPE_STRING)
{
- parentArray.push(decodeString(byteReader));
+ parentArray.push(decodeString(reader));
}
else if (type === 0) // empty array case
{
@@ -246,7 +246,7 @@ if (window.indexedDB.polyfill)
return { sign : s, exponent : e, mantissa : m };
}
- function encodeNumber(buffer, number)
+ function encodeNumber(writer, number)
{
var number = ieee754(number);
if (number.sign)
@@ -256,40 +256,37 @@ if (window.indexedDB.polyfill)
}
var word, m = number.mantissa;
- buffer.push((number.sign ? 0 : 0x80) | (number.exponent >> 4));
- buffer.push((number.exponent & 0xF) << 4 | (0 | m / p48));
+ writer.write((number.sign ? 0 : 0x80) | (number.exponent >> 4));
+ writer.write((number.exponent & 0xF) << 4 | (0 | m / p48));
m %= p48; word = 0 | m / p32;
- buffer.push(word >> 8, word & 0xFF);
+ writer.write(word >> 8, word & 0xFF);
m %= p32; word = 0 | m / p16;
- buffer.push(word >> 8, word & 0xFF);
+ writer.write(word >> 8, word & 0xFF);
word = m % p16;
- buffer.push(word >> 8, word & 0xFF);
+ writer.write(word >> 8, word & 0xFF);
}
- function decodeNumber(byteReader)
+ function decodeNumber(reader)
{
- var b = byteReader.read();
+ var b = reader.read() | 0;
var sign = b >> 7 ? false : true;
var s = sign ? -1 : 1;
var e = (b & 0x7F) << 4;
- b = byteReader.read();
+ b = reader.read() | 0;
e += b >> 4;
if (sign) e = 0x7FF - e;
var tmp = [sign ? (0xF - (b & 0xF)) : b & 0xF];
var i = 6;
- while (i--) tmp.push(sign ? (0xFF - byteReader.read()) : byteReader.read());
+ while (i--) tmp.push(sign ? (0xFF - (reader.read() | 0)) : reader.read() | 0);
var m = 0; i = 7;
- while (i--)
- {
- m = m / 256 + tmp[i];
- }
+ while (i--) m = m / 256 + tmp[i];
m /= 16;
if (m === 0 && e === 0) return 0;
@@ -298,7 +295,7 @@ if (window.indexedDB.polyfill)
var secondLayer = 0x3FFF + 0x7F;
- function encodeString(buffer, string)
+ function encodeString(writer, string)
{
/* 3 layers:
Chars 0 - 7E are encoded as 0xxxxxxx with 1 added
@@ -310,58 +307,58 @@ if (window.indexedDB.polyfill)
var code = string.charCodeAt(i);
if (code <= 0x7E)
{
- buffer.push(code + 1);
+ writer.write(code + 1);
}
else if (code <= secondLayer)
{
code -= 0x7F;
- buffer.push(0x80 | code >> 8, code & 0xFF);
+ writer.write(0x80 | code >> 8, code & 0xFF);
}
else
{
- buffer.push(0xC0 | code >> 10, code >> 2 | 0xFF, (code | 3) << 6);
+ writer.write(0xC0 | code >> 10, code >> 2 | 0xFF, (code | 3) << 6);
}
}
- buffer.push(BYTE_TERMINATOR);
+ writer.write(BYTE_TERMINATOR);
}
- function decodeString(byteReader)
+ function decodeString(reader)
{
- var buffer = [], layer = 0, unicode = 0, count = 0, byte, tmp;
+ var buffer = [], layer = 0, unicode = 0, count = 0, $byte, tmp;
while (true)
{
- byte = byteReader.read();
- if (byte === 0 || byte == null) break;
+ $byte = reader.read();
+ if ($byte === 0 || $byte == null) break;
if (layer === 0)
{
- tmp = byte >> 6;
+ tmp = $byte >> 6;
if (tmp < 2)
{
- buffer.push(String.fromCharCode(byte - 1));
+ buffer.push(String.fromCharCode($byte - 1));
}
else // tmp equals 2 or 3
{
layer = tmp;
- unicode = byte << 10;
+ unicode = $byte << 10;
count++;
}
}
else if (layer === 2)
{
- buffer.push(String.fromCharCode(unicode + byte + 0x7F));
+ buffer.push(String.fromCharCode(unicode + $byte + 0x7F));
layer = unicode = count = 0;
}
else // layer === 3
{
if (count === 2)
{
- unicode += byte << 2;
+ unicode += $byte << 2;
count++;
}
else // count === 3
{
- buffer.push(String.fromCharCode(unicode | byte >> 6));
+ buffer.push(String.fromCharCode(unicode | $byte >> 6));
layer = unicode = count = 0;
}
}
@@ -369,48 +366,42 @@ if (window.indexedDB.polyfill)
return buffer.join("");
}
- var ByteReader = function (string)
+ var HexStringReader = function (string)
{
this.current = null;
var string = string;
- var code, index = -1, high = false;
+ var lastIndex = string.length - 1;
+ var index = -1;
this.read = function ()
{
- high = !high;
- if (high)
- {
- index++;
- code = string.charCodeAt(index);
- }
- if (isNaN(code))
- {
- this.current = null;
- }
- else
- {
- this.current = high ? code >> 8 : code & 0xFF;
- }
- return this.current;
+ return this.current = index < lastIndex ? parseInt(string[++index] + string[++index], 16) : null;
}
};
- function bufferToUnicodeString(buffer)
+ var HexStringWriter = function()
{
- var index = buffer.length;
- while (buffer[--index] === 0);
- buffer.length = ++index;
-
- if ((index & 1) === 1) buffer.push(0);
- var result = [], length = buffer.length >> 1;
-
- for (var i = 0; i < length; i++)
+ var buffer = [], c;
+ this.write = function ($byte)
+ {
+ for (var i = 0; i < arguments.length; i++)
+ {
+ c = arguments[i].toString(16);
+ buffer.push(c.length === 2 ? c : c = "0" + c);
+ }
+ };
+ this.toString = function ()
+ {
+ return buffer.length ? buffer.join("") : null;
+ };
+ this.trim = function()
{
- index = i << 1;
- result.push(String.fromCharCode(buffer[index] << 8 | buffer[index + 1]));
+ var length = buffer.length;
+ while (buffer[--length] === "00");
+ buffer.length = ++length;
+ return this;
}
- return result.join("");
- }
+ };
}(window.indexedDB.util));
View
9 w3c-tests/testharness.js
@@ -363,13 +363,16 @@ policies and contribution forms [3].
function __delayFuncCall(func)
{
+ var delay = 25;
+ window.setTimeout(function () {
window.setTimeout(function () {
window.setTimeout(function () {
window.setTimeout(function () {
func();
- }, 10);
- }, 10);
- }, 10);
+ }, delay);
+ }, delay);
+ }, delay);
+ }, delay);
}
Please sign in to comment.
Something went wrong with that request. Please try again.