Skip to content
This repository has been archived by the owner on Jan 13, 2022. It is now read-only.

Commit

Permalink
Monotonic key encoding/decoding is implemented.
Browse files Browse the repository at this point in the history
  • Loading branch information
Khamza Davletov committed Jul 18, 2012
1 parent aca67c6 commit 791c626
Show file tree
Hide file tree
Showing 12 changed files with 231 additions and 232 deletions.
52 changes: 24 additions & 28 deletions IDBCursor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -36,7 +36,7 @@ if (window.indexedDB.polyfill)
noOverwrite : false,
value : value
},
me._effectiveKey);
me._effectiveKeyEncoded);
});
return request;
};
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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 + "'))");
}
}
}
Expand All @@ -258,15 +254,15 @@ 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.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;
Expand Down
10 changes: 5 additions & 5 deletions IDBDatabase.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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");
Expand Down Expand Up @@ -142,17 +142,17 @@ 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];
};
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', ?, ?, ?)",
Expand Down
22 changes: 19 additions & 3 deletions IDBFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 ()
Expand Down Expand Up @@ -245,45 +252,54 @@ 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);
}
}

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));
});
Expand Down
52 changes: 20 additions & 32 deletions IDBIndex.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 ?
Expand All @@ -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;
Expand Down
Loading

0 comments on commit 791c626

Please sign in to comment.